Skip to content

Add pluggable image-comparison strategies with auto-selection, benchmarking, and test harness - #2

Merged
wforney merged 11 commits into
masterfrom
copilot/upgrade-to-latest-framework
Aug 13, 2026
Merged

Add pluggable image-comparison strategies with auto-selection, benchmarking, and test harness#2
wforney merged 11 commits into
masterfrom
copilot/upgrade-to-latest-framework

Conversation

Copilot AI commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

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

    • Introduced ComparisonStrategy with:
      • LegacyDominantChannel
      • MeanAbsoluteDifference (MAD)
      • DifferenceHash (dHash)
      • Auto
    • Added ComparisonStrategySelector to choose strategy in Auto mode based on image characteristics (size/aspect profile).
  • Comparer refactor

    • BitmapCompare now supports fixed strategy or Auto.
    • Added LastStrategyUsed and strategy-specific default thresholds via IsSimilar(...).
    • Implemented new algorithms:
      • MAD on normalized images using LockBits (no GetPixel hot path).
      • dHash (64-bit perceptual hash) similarity via Hamming distance.
  • CLI and operational behavior

    • Added optional flags:
      • --strategy=auto|legacy|mad|dhash
      • --benchmark
      • --benchmark-iterations=<n>
    • Matching output now reports similarity and strategy used.
    • Argument parsing was corrected to avoid dropping positional args and to surface invalid benchmark iteration input.
  • Benchmarking

    • Added ComparisonBenchmark with per-strategy timing + average similarity.
    • Includes warm-up before timing to reduce JIT bias across strategies.
  • Tests and docs

    • Added ImageComparator.Tests console test project covering:
      • identical-vs-different ranking across strategies
      • auto-selection behavior
      • benchmark result shape
    • Updated README with strategy/benchmark usage and test invocation.
    • Updated CI workflow to use .NET 10 and run the test project.
var comparer = new BitmapCompare(ComparisonStrategy.Auto);
var isMatch = comparer.IsSimilar(imageA, imageB, out var similarity);

Console.WriteLine(
    $"match={isMatch}, sim={similarity:F3}, strategy={comparer.LastStrategyUsed}");

Copilot AI and others added 3 commits August 13, 2026 02:38
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>
@wforney
wforney marked this pull request as ready for review August 13, 2026 03:17
Copilot AI lite review requested due to automatic review settings August 13, 2026 03:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ComparisonStrategy plus selector logic and integrates it into BitmapCompare with Auto selection and strategy-specific thresholds.
  • Adds ComparisonBenchmark and CLI wiring (--strategy, --benchmark, --benchmark-iterations) to report timing/similarity per strategy.
  • Adds a new ImageComparator.Tests console 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.

Comment thread ImageComparator/ComparisonStrategySelector.cs Outdated
Comment thread ImageComparator/Program.cs Outdated
Comment thread ImageComparator/Program.cs Outdated
Comment thread ImageComparator/BitmapCompare.cs Outdated
Comment thread ImageComparator/BitmapCompare.cs

@wforney wforney left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Use TUnit for the tests. You can use nuget packages for the benchmark library too.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 13, 2026 03:23
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
wforney and others added 2 commits August 12, 2026 20:24
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>
@wforney

wforney commented Aug 13, 2026

Copy link
Copy Markdown
Member

@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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 --strategy values currently fall back to auto silently. 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, imageC being a solid blue bitmap can yield the same dHash as the solid red bitmap, making sameSimilarity > differentSimilarity fail for DifferenceHash. 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);

Comment thread ImageComparator/BitmapCompare.cs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  • ProcessBitmap currently walks the pixel buffer one byte at a time (++p) and reads p[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=25 as 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>

Copilot AI commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Do this too... 💡 Add a code-review agent skill or configure MCP servers for contex...

Done in ce034d1: added .github/skills/code-review/SKILL.md with repository-specific code-review guidance.

@copilot Use TUnit for the tests. You can use nuget packages for the benchmark library too.

Done in ce034d1: tests are now using TUnit (package reference plus [Test] methods with TUnit assertions).

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

@wforney wforney left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot The CI is broken. Fix it.

Co-authored-by: wforney <79032+wforney@users.noreply.github.com>

Copilot AI commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot The CI is broken. Fix it.

Fixed in cf5adcb: the failing TUnit ranking test now uses a non-uniform fixture so DifferenceHash no longer collapses the identical and different cases to the same hash in CI.

Copilot AI commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot The CI is broken. Fix it.

Addressed in cf5adcb. The dHash ranking fixture was stabilized and the CI run is now passing.

@copilot Use TUnit for the tests. You can use nuget packages for the benchmark library too.

Addressed in ce034d1 by migrating the test project to TUnit.

Copilot AI requested a review from wforney August 13, 2026 05:49
@wforney
wforney merged commit e56acf4 into master Aug 13, 2026
4 checks passed
@wforney
wforney deleted the copilot/upgrade-to-latest-framework branch August 13, 2026 05:52
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.

3 participants