Skip to content

Instantly share code, notes, and snippets.

@zwcloud
Forked from tocsoft/ImageComparer.cs
Last active October 13, 2018 04:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zwcloud/2b52825bcc4408d4d5e076409adaf44a to your computer and use it in GitHub Desktop.
Save zwcloud/2b52825bcc4408d4d5e076409adaf44a to your computer and use it in GitHub Desktop.
Compare 2 images using ImageSharp
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing;
using System;
using Xunit;
namespace ImageSharp.Extension
{
/// <summary>
/// Class to perform simple image comparisons.
/// </summary>
public static class ImageComparer
{
const int DefaultScalingFactor = 16;
const int DefaultSegmentThreshold = 3;
const float DefaultImageThreshold = 0f;
public static void VisualComparer<TColorA, TColorB>(Image<TColorA> expected, Image<TColorB> actual, float imageTheshold = DefaultImageThreshold, byte segmentThreshold = DefaultSegmentThreshold, int scalingFactor = DefaultScalingFactor)
where TColorA : struct, IPixel<TColorA>
where TColorB : struct, IPixel<TColorB>
{
var percentage = expected.PercentageDifference(actual, segmentThreshold, scalingFactor);
Assert.InRange(percentage, 0, imageTheshold);
}
public static float PercentageDifference<TColorA, TColorB>(this Image<TColorA> source, Image<TColorB> target, byte segmentThreshold = DefaultSegmentThreshold, int scalingFactor = DefaultScalingFactor)
where TColorA : struct, IPixel<TColorA>
where TColorB : struct, IPixel<TColorB>
{
// code adapted from https://www.codeproject.com/Articles/374386/Simple-image-comparison-in-NET
DenseMatrix<byte> differences = GetDifferences(source, target, scalingFactor);
int diffPixels = 0;
foreach (byte b in differences.Data)
{
if (b > segmentThreshold) { diffPixels++; }
}
return diffPixels / 256f;
}
private static DenseMatrix<byte> GetDifferences<TColorA, TColorB>(Image<TColorA> source, Image<TColorB> target, int scalingFactor)
where TColorA : struct, IPixel<TColorA>
where TColorB : struct, IPixel<TColorB>
{
DenseMatrix<byte> differences = new DenseMatrix<byte>(scalingFactor, scalingFactor);
DenseMatrix<byte> firstGray = source.GetGrayScaleValues(scalingFactor);
DenseMatrix<byte> secondGray = target.GetGrayScaleValues(scalingFactor);
for (int y = 0; y < scalingFactor; y++)
{
for (int x = 0; x < scalingFactor; x++)
{
differences[x, y] = (byte)Math.Abs(firstGray[x, y] - secondGray[x, y]);
}
}
return differences;
}
private static DenseMatrix<byte> GetGrayScaleValues<TColorA>(this Image<TColorA> source, int scalingFactor)
where TColorA : struct, IPixel<TColorA>
{
Rgba32 pixel = Rgba32.Black;
var clonedImage = source.Clone();
clonedImage.Mutate(context => context.Resize(scalingFactor, scalingFactor));
clonedImage.Mutate(context => context.Grayscale());
using (clonedImage)
{
DenseMatrix<byte> grayScale = new DenseMatrix<byte>(scalingFactor, scalingFactor);
for (int y = 0; y < scalingFactor; y++)
{
for (int x = 0; x < scalingFactor; x++)
{
clonedImage[x, y].ToRgba32(ref pixel);
grayScale[x, y] = pixel.R;
}
}
return grayScale;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment