用感知哈希算法(C#)检查图片相似度

2025/11 22 17:11

首先在.net core工程文件(.csproj)中,添加图片库sixlabors的引用

  <ItemGroup>

    ...
    <Reference Include="System.Xml" />
    <PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
  </ItemGroup>

然后添加一个Zefirrat的感知哈希算法代码

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

namespace Zefirrat
{
    public class ComparerOpt
    {
        public ComparerOpt(byte Accuracy = AccuracyValues.Medium, double CustomRatio = 0.00005)
        {
            this.Accuracy = Accuracy;
            this.CustomRatio = CustomRatio;
        }

        public byte Accuracy { get; private set; }
        public double CustomRatio { get; private set; }
        public static class AccuracyValues
        {
            public const byte VeryHigh = 1;
            public const byte High = 20;
            public const byte Medium = 50;
            public const byte Low = 90;
            public const byte VeryLow = byte.MaxValue;
        }
    }

    public class Zefirrat
    {
        public static double[] ImgToVector(Image image)
        {
            image.Mutate(i => i.Grayscale());
            image.Mutate(i => i.Resize(new Size(16, 16)));
            var result = new List<double>();
            using (var cloned = image.CloneAs<RgbaVector>())
            {
                for (var i = 0; i < cloned.Size.Height; i++)
                {
                    for (var j = 0; j < cloned.Size.Width; j++)
                    {
                        result.Add(cloned[i, j].ToVector4().Length());
                    }
                }
            }
            return result.ToArray();
        }

        private static bool CompareSimilarity(Image image1, Image image2, ComparerOpt opt)
        {
            var vectors1 = ImgToVector(image1);
            var vectors2 = ImgToVector(image2);
            return CompareSimilarity(vectors1, vectors2, opt);
        }

        public static bool CompareSimilarity(double[] vectors1, double[] vectors2, ComparerOpt opt)
        {
            var standardDeviation1 =
                CalculateStandardDeviation(vectors1, vectors1.Sum() / vectors1.Length, vectors1.Length);
            var standardDeviation2 =
                CalculateStandardDeviation(vectors2, vectors2.Sum() / vectors2.Length, vectors2.Length);
            var standardDeviation3 = CalculateStandardDeviation(vectors1.Concat(vectors2)
                    .ToArray(),
                (vectors1.Sum() + vectors2.Sum()) / (vectors1.Length + vectors2.Length),
                vectors1.Length + vectors2.Length);

            var accuracy = opt.CustomRatio * opt.Accuracy;

            return Math.Abs(standardDeviation3 - standardDeviation1) < accuracy &&
                Math.Abs(standardDeviation3 - standardDeviation2) < accuracy;
        }

        private static double CalculateStandardDeviation(IEnumerable<double> converted2, double s, int n)
        {
            var tmp = 0.0;
            foreach (var x in converted2)
            {
                tmp += Math.Pow(x - s, 2);
            }
            var sko = Math.Sqrt(tmp / n);
            return sko;
        }

        public static bool AreSimilar(string image1, string image2, ComparerOpt _options)
        {
            using var imageSharp1 = Image.Load(image1);
            using var imageSharp2 = Image.Load(image2);
            return CompareSimilarity(imageSharp1, imageSharp2, _options);
        }
    }
}

使用方法示例

var opt = new Zefirrat.ComparerOpt(39);
var ret = Zefirrat.Zefirrat.AreSimilar("d:/1.png", "d:/2.png", opt);
Console.WriteLine(ret);