Skip to content

Make the ImageScaleBrightness, ImageFilter and BinaryMatrix kernel tests real tests - #1669

Open
Gin890 wants to merge 7 commits into
mainfrom
test-kernels-real-images
Open

Gin890 wants to merge 7 commits into
mainfrom
test-kernels-real-images

Conversation

@Gin890

@Gin890 Gin890 commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Make the ImageScaleBrightness, ImageFilter and BinaryMatrix kernel tests real tests. Each test now checks every SIMD and NEON implementation that the CPU supports against a scalar reference, on real images.

Before, these tests were debug code. They were not registered, so CI did not run them. They tested only the implementation that the dispatch picks, and had timing loops.

The new tests found three bugs. Each fix is its own commit:

  • x86 scale_brightness(): SSE4.1, AVX2 and AVX-512 rounded each channel to the nearest integer, but Default and NEON truncate. Now all of them truncate. On x86, this changes some channels by 1 in ExactImageMatcher and ImageMatchDetector.
  • PackedBinaryMatrix::submatrix(): if the width is a multiple of 64, or the height is a multiple of the tile height, it cleared the whole last column or row of tiles. The tile height depends on the CPU (4 to 64 rows), so the result was different on each machine. SparseBinaryMatrix::submatrix() got this fix in ecdc7fc. In production, this changes SubObjectTemplateMatcher::rmsd_with_background_replace().
  • filter_rgb32_range() with several filters in one call: it passed a field that is not set yet as the replace flag, so the result was undefined. It now passes each filter's own flag. The PokemonLA MountDetector uses this function. This broke in 5bb2f45. A new test checks this function and to_blackwhite_rgb32_range() with several filters.

Other changes:

The images are from the CommandLineTests repo. No width or height is a multiple of 8, so the tests also check the leftover pixels after the SIMD loops and the tiles at the edges. #1554 also changes these three test files, so it will need a merge fix.

0 test files added, 3 test files changed:

  • SerialPrograms/Source/Kernels/ImageScaleBrightness/Kernels_ImageScaleBrightness_Tests.cpp
  • SerialPrograms/Source/Kernels/ImageFilters/Kernels_ImageFilter_Tests.cpp
  • SerialPrograms/Source/Kernels/BinaryMatrix/Kernels_BinaryMatrix_Tests.cpp

Test results: all tests pass on all six CI runners. These runs used the first 5 commits on the previous main (d315488), before the multi-filter fix and its test. Each implementation runs on 4 images.

Runners Implementations tested
Ubuntu clang, Windows Clang (AVX-512) Brightness and range filters: Default, SSE4.1 or SSE4.2, AVX2, AVX-512
Mask and binary matrix: 64x4 Default, 64x8 SSE4.2, 64x16 AVX2, 64x32 and 64x64 AVX-512
Tile: 64x4 Default
Ubuntu Default, Windows Default, Mac Intel (AVX2) Brightness and range filters: Default, SSE4.1 or SSE4.2, AVX2
Mask and binary matrix: 64x4 Default, 64x8 SSE4.2, 64x16 AVX2
Tile: 64x4 Default
Mac (Apple Silicon) Brightness and range filters: Default, NEON
Mask and binary matrix: 64x4 Default, 64x8 NEON
Tile: 64x4 Default, 64x8 NEON
NEON PartialWordAccess

🤖 Generated with Claude Code

Gin and others added 7 commits October 21, 2026 22:56
The SSE4.1, AVX2 and AVX-512 versions round the scaled channels to the
nearest integer, but Default and NEON truncate. So on x86 a channel can
come out 1 higher: 102 * 1.3 = 132.6 gives 133 instead of 132. Use the
truncating conversion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ImageScaleBrightness test was debug code. It was not registered, it
only ran the implementation that the dispatch picks, it checked nothing,
and it ran a 500-iteration timing loop.

Add one test for each image and each implementation that the CPU
supports, including Default. Each test scales a guard-page copy of the
image with three sets of scales and compares every pixel with a scalar
reference. The images are from the CommandLineTests repo, and their
widths cover every remainder mod 4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mages

The old ImageFilter tests were debug code: they were not registered, ran
3-second timing loops, and only ran the implementation the CPU dispatch picks.
Now each range filter and filter_by_mask() implementation that the build has
and the CPU supports gets a test on 4 CommandLineTests images, checked against
a scalar reference.
The two Euclidean tests are removed. Kernels::RGB32Euclidean covers them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
If the submatrix width is a multiple of 64, or its height a multiple of the
tile height, submatrix() called clear_padding() with 0 bits and cleared the
whole last column or row of tiles. The tile height depends on the CPU (4 to
64), so results were different on each machine.
SparseBinaryMatrix::submatrix() got this fix in ecdc7fc. This makes the
packed version the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The old BinaryMatrix test was debug code: it was not registered, ran timing
loops, and only checked the matrix type the CPU dispatch picks.
Now each matrix type that the build has and the CPU supports gets a test on
4 CommandLineTests images. It checks compress_rgb32_to_binary_range(), the
bitwise operations and submatrix() against the image pixels, and that the
padding bits stay 0. The tile checks now also run on the Default tile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The overload that runs several range filters in one call passed the filter's
pixels_in_range, which is not set yet, as replace_color_within_range. It
should pass the filter's own flag, invert. This broke in 5bb2f45. The
PokemonLA MountDetector uses this overload.
Also set pixels_in_range to 0 in both multi-filter structs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add a test that runs filter_rgb32_range() and to_blackwhite_rgb32_range()
with 8 filters in one call, and checks each output against the scalar
reference. It fails without the fix in the previous commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant