Add pluggable image-comparison strategies with auto-selection, benchmarking, and test harness - #2
Conversation
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This pull request refactors the image comparison logic from a single heuristic into a strategy-based pipeline, adding runtime strategy selection (Auto), built-in benchmarking, and a lightweight console-based test harness to validate behavior across strategies.
Changes:
- Introduces
ComparisonStrategyplus selector logic and integrates it intoBitmapComparewithAutoselection and strategy-specific thresholds. - Adds
ComparisonBenchmarkand CLI wiring (--strategy,--benchmark,--benchmark-iterations) to report timing/similarity per strategy. - Adds a new
ImageComparator.Testsconsole test project and updates CI/docs to run it.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Documents available strategies, CLI usage, benchmarking, and test invocation. |
| ImageComparator/Program.cs | Adds argument parsing, benchmarking output, and strategy-aware compare flow. |
| ImageComparator/ImageComparator.csproj | Moves app to net10.0 and updates Windows compatibility package version. |
| ImageComparator/ComparisonStrategySelector.cs | Implements Auto strategy selection heuristic based on image size/aspect. |
| ImageComparator/ComparisonStrategy.cs | Defines the strategy enum (legacy, mad, dhash, auto). |
| ImageComparator/ComparisonBenchmark.cs | Adds per-strategy benchmarking and result shape. |
| ImageComparator/BitmapCompare.cs | Implements strategy dispatch + MAD/dHash algorithms and IsSimilar helper. |
| ImageComparator.Tests/Program.cs | Adds console-based tests for ranking, auto-selection, and benchmark results. |
| ImageComparator.Tests/ImageComparator.Tests.csproj | Adds a net10.0 console test project referencing the main project. |
| ImageComparator.sln | Adds test project and additional solution configurations. |
| .github/workflows/ci.yml | Updates CI to use .NET 10 and run the test project. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
@copilot Do this too... 💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs. |
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
ImageComparator/Program.cs:203
- Unknown
--strategyvalues currently fall back toautosilently. This makes typos (e.g.--strategy=dahs) hard to diagnose and can lead to unexpected algorithm selection. Consider emitting a warning when the provided value isn't recognized.
private static ComparisonStrategy ParseStrategy(string value)
{
var normalized = value.Trim().ToLowerInvariant();
return normalized switch
{
"legacy" => ComparisonStrategy.LegacyDominantChannel,
"mad" => ComparisonStrategy.MeanAbsoluteDifference,
"dhash" => ComparisonStrategy.DifferenceHash,
ImageComparator.Tests/Program.cs:60
- The dHash strategy compares adjacent pixel luminance, so any solid-color image produces an all-zero hash regardless of the color. As written,
imageCbeing a solid blue bitmap can yield the same dHash as the solid red bitmap, makingsameSimilarity > differentSimilarityfail forDifferenceHash. Use a patterned/gradient "different" image so dHash can detect a change.
using var imageA = CreateSolidBitmap(Color.Red);
using var imageB = CreateSolidBitmap(Color.Red);
using var imageC = CreateSolidBitmap(Color.Blue);
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.
Suppressed comments (3)
ImageComparator/BitmapCompare.cs:223
ProcessBitmapcurrently walks the pixel buffer one byte at a time (++p) and readsp[0],p[1],p[2]on each step. That mixes channels across adjacent bytes/pixels and also maps the underlying 24bpp BGR layout into the wrong RGB fields, producing incorrect channel sums and therefore incorrect legacy similarity results.
for (var x = 0; x < width; ++x)
{
data.R += p[0];
data.G += p[1];
data.B += p[2];
ImageComparator/Program.cs:22
- When only one of the two directories is provided via args, this prompt block overwrites the already-provided value by re-reading both directories. Prompt only for the missing directory so partial CLI invocation works as expected.
if (goodDirectory is null || badDirectory is null)
{
Console.WriteLine("Please input the source image directory (good images):");
goodDirectory = Console.ReadLine();
Console.WriteLine("Please input the destination image directory (incorrect images):");
README.md:18
- The usage example shows
--benchmark-iterations=25as if 25 is the required value; this is a default/placeholder. Using<n>avoids implying a fixed iteration count.
dotnet run --project ImageComparator/ImageComparator.csproj -- <goodDir> <badDir> [fileType] [--strategy=auto|legacy|mad|dhash] [--benchmark] [--benchmark-iterations=25]
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
Done in
Done in |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: wforney <79032+wforney@users.noreply.github.com>
Fixed in |
This upgrades the comparator from a single legacy heuristic to a strategy-based pipeline, with optional paths and runtime selection of the most suitable algorithm. It also adds built-in benchmarking and a lightweight test harness to evaluate and guard behavior across strategies.
Strategy model + runtime selection
ComparisonStrategywith:LegacyDominantChannelMeanAbsoluteDifference(MAD)DifferenceHash(dHash)AutoComparisonStrategySelectorto choose strategy inAutomode based on image characteristics (size/aspect profile).Comparer refactor
BitmapComparenow supports fixed strategy orAuto.LastStrategyUsedand strategy-specific default thresholds viaIsSimilar(...).LockBits(noGetPixelhot path).CLI and operational behavior
--strategy=auto|legacy|mad|dhash--benchmark--benchmark-iterations=<n>Benchmarking
ComparisonBenchmarkwith per-strategy timing + average similarity.Tests and docs
ImageComparator.Testsconsole test project covering: