C#结合OpenCVSharp4图片相似度识别

OpenCVSharp4图片相似度识别

需求背景:需要计算两个图片的相似度,然后将相似的图片进行归纳

一、图片相似度算法

由于我是CRUD后端仔,对图像处理没什么概念。因此网上调研了几种相似度算法分析其适用场景。

直方图算法

获取要比较的2个图片的直方图数据,然后再将直方图数据归一化比较,最终得到一个相似指数,通过设定相似指数的边界,以此判断是否相同图片。

平均值哈希算法 aHash

转灰度压缩之后计算均值,最终通过像素比较得出哈希值,速度很快,但敏感度很高,稍有变化就会极大影响判定结果,精准度较差。因此比较适用于缩略图比较,最常用的就是以图搜图

感知哈希算法 pHash

在均值哈希基础上加入DCT(离散余弦变化),两次DCT就可以很好的将图像按照频度分开,取左上角高能低频信息做均值哈希,因此,精确度很高,但是速度方面较差一些。相比较aHashpHash更加适合用于缩略图比较,也非常适合比较两个近似图片是否相等。

差异值哈希算法 dHash

灰度压缩之后,比较相邻像素之间差异。假设有10×10的图像,每行10个像素,就会产生9个差异值,一共10行,就一共有9×10=90个差异值。最终生成哈希值即指纹。速度上来说,介于aHashpHash之间,精准度同样也介于aHashpHash之间。

结构相似性算法 SSIM

SSIM(structural similarity),结构相似性,是一种衡量两幅图像相似度的指标。SSIM算法主要用于检测两张相同尺寸的图像的相似度、或者检测图像的失真程度。原论文中,SSIM算法主要通过分别比较两个图像的亮度,对比度,结构,然后对这三个要素加权并用乘积表示。

SSIM算法在设计上考虑了人眼的视觉特性,它能够考虑到图像的结构信息在人的感知上的模糊变化,该模型还引入了一些与感知上的变化有关的感知现象,包含亮度mask和对比mask,结构信息指的是像素之间有着内部的依赖性,尤其是空间上靠近的像素点。这些依赖性携带着目标对象视觉感知上的重要信息。

经过调研对比,这里就选择SSIM算法。

二、下载OpenCVSharp4

通过NuGet包管理器进行下载。搜索OpenCVSharp4下载。

请注意其描述信息:OpenCV wrapper for .NET. Since this package includes only core managed libraries, another package of native bindings for your OS is required (OpenCvSharp4.runtime.*).

这是说:OpenCV 包只是一个核心库,如需在你的系统上使用,还需要对应的运行时包,这里是Windows系统,因此还需下载 OpenCvSharp4.runtime.win

5db056eb618d345ec6bc0238c4a790cc.jpeg

三、 使用

在项目中引入OpenCvSharp

using OpenCvSharp;

由于OpenCVSharp4没有直接提供封装SSIM算法的接口,因此需要自行写这部分代码。完整代码如下

public Scalar Compare_SSIM(string imgFile1, string imgFile2)
{
    var image1 = Cv2.ImRead(imgFile1);
    var image2Tmp = Cv2.ImRead(imgFile2);
    // 将两个图片处理成同样大小,否则会有错误:The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array'
    var image2 = new Mat();
    Cv2.Resize(image2Tmp, image2, new OpenCvSharp.Size(image1.Size().Width, image1.Size().Height));
    double C1 = 6.5025, C2 = 58.5225;
    var validImage1 = new Mat();
    var validImage2 = new Mat();
    image1.ConvertTo(validImage1, MatType.CV_32F); //数据类型转换为 float,防止后续计算出现错误
    image2.ConvertTo(validImage2, MatType.CV_32F);


    Mat image1_1 = validImage1.Mul(validImage1); //图像乘积
    Mat image2_2 = validImage2.Mul(validImage2);
    Mat image1_2 = validImage1.Mul(validImage2);

    Mat gausBlur1 = new Mat(), gausBlur2 = new Mat(), gausBlur12 = new Mat();
    Cv2.GaussianBlur(validImage1, gausBlur1, new OpenCvSharp.Size(11, 11), 1.5); //高斯卷积核计算图像均值
    Cv2.GaussianBlur(validImage2, gausBlur2, new OpenCvSharp.Size(11, 11), 1.5);
    Cv2.GaussianBlur(image1_2, gausBlur12, new OpenCvSharp.Size(11, 11), 1.5);

    Mat imageAvgProduct = gausBlur1.Mul(gausBlur2); //均值乘积
    Mat u1Squre = gausBlur1.Mul(gausBlur1); //各自均值的平方
    Mat u2Squre = gausBlur2.Mul(gausBlur2);

    Mat imageConvariance = new Mat(), imageVariance1 = new Mat(), imageVariance2 = new Mat();
    Mat squreAvg1 = new Mat(), squreAvg2 = new Mat();
    Cv2.GaussianBlur(image1_1, squreAvg1, new OpenCvSharp.Size(11, 11), 1.5); //图像平方的均值
    Cv2.GaussianBlur(image2_2, squreAvg2, new OpenCvSharp.Size(11, 11), 1.5);

    imageConvariance = gausBlur12 - gausBlur1.Mul(gausBlur2);// 计算协方差
    imageVariance1 = squreAvg1 - gausBlur1.Mul(gausBlur1); //计算方差
    imageVariance2 = squreAvg2 - gausBlur2.Mul(gausBlur2);

    var member = ((2 * gausBlur1.Mul(gausBlur2) + C1).Mul(2 * imageConvariance + C2));
    var denominator = ((u1Squre + u2Squre + C1).Mul(imageVariance1 + imageVariance2 + C2));

    Mat ssim = new Mat();
    Cv2.Divide(member, denominator, ssim);

    var sclar = Cv2.Mean(ssim);

    return sclar;  // 变化率,即差异

}

实际检测效果如下

c7847e1ae9dcf5d515d32c49138f579f.jpeg

这两幅图的相似度大约是92.21%,基本符合预期

5b8fa1f03bc56e6cd6181709c08cdec8.jpeg

这两幅图居然还有约18%的相似度,根据SSIM算法特性,这应该是图片大小的相似。

虽然也是拿来主义,毕竟我不是研究算法的大佬,需要站在巨人肩膀上干活~

转自:宣君

链接:cnblogs.com/ycit/p/17688625.html

- EOF -

技术群:添加小编微信dotnet999

公众号:Dotnet讲堂

### 使用 OpenCvSharp 进行图像相似度检测 #### 方法概述 为了实现图像相似度检测,可以采用多种方法。其中一种常见的方式是利用直方图比较来评估两幅图像间的相似程度[^1]。 #### 直方图比较的具体实施步骤如下: - **读取并转换图像** 需要先加载待比较的两张图片,并将其颜色空间从 BGR 转换到 HSV 或 Lab 等更适合做统计分析的空间。 - **计算各通道的直方图** 对每张图片的不同色彩分量分别求解其灰度分布情况,即得到各个通道上的直方图数据。 - **应用合适的距离测度函数** 接下来就是选取恰当的距离测量方式(如巴氏距离、卡方距离等),以此为基础量化两个直方图之间的差异大小。 下面是具体的 C# 示例代码片段展示了上述流程的操作细节: ```csharp using System; using Cv = OpenCvSharp; class Program { static void Main() { string pathImgA = "path_to_image_A"; string pathImgB = "path_to_image_B"; // 加载原始图像文件 var imgA = Cv.Cv2.ImRead(pathImgA); var imgB = Cv.Cv2.ImRead(pathImgB); // 如果任意一张图片为空,则终止程序执行 if (imgA.Empty || imgB.Empty){ Console.WriteLine("无法打开指定路径下的图片!"); return ; } // 将输入图像的颜色模式由默认的BGR转为HSV形式 var hsvA = new Mat(); var hsvB = new Mat(); Cv.Cv2.CvtColor(imgA, hsvA, ColorConversionCodes.BGR2HSV); Cv.Cv2.CvtColor(imgB, hsvB, ColorConversionCodes.BGR2HSV); // 计算Hue,Saturation,Brightness三个维度各自的直方图 int[] histSize = { 50 }; float[][] ranges = { new float[]{ 0f, 180f } }; DenseHistogram hHistA = CalcHist(hsvA, 0, histSize, ranges); DenseHistogram sHistA = CalcHist(hsvA, 1, histSize, null); DenseHistogram vHistA = CalcHist(hsvA, 2, histSize, null); DenseHistogram hHistB = CalcHist(hsvB, 0, histSize, ranges); DenseHistogram sHistB = CalcHist(hsvB, 1, histSize, null); DenseHistogram vHistB = CalcHist(hsvB, 2, histSize, null); // 应用对比度受限自适应直方图均衡化CLAHE算法提升局部对比度 ClAhe clahe = Cv2.CreateCLAHE(clipLimit: 4.0, tileGridSize: new Size(8, 8)); Mat dstA = clahe.Apply(vHistA.ToMat()); Mat dstB = clahe.Apply(vHistB.ToMat()); // 比较V亮度分量经过处理后的直方图以获得最终得分 double similarityScore = Cv.Cv2.CompareHist(dstA, dstB, HistCompMethods.Correlation); Console.WriteLine($"The Similarity Score between two images is :{similarityScore}"); // 显示结果窗口 Cv.Cv2.NamedWindow("Image A", WindowMode.AutoSize); Cv.Cv2.NamedWindow("Image B", WindowMode.AutoSize); Cv.Cv2.ImShow("Image A", imgA); Cv.Cv2.ImShow("Image B", imgB); Cv.Cv2.WaitKey(); // 清除资源释放内存 Cv.Cv2.DestroyAllWindows(); } } ``` 此段代码实现了基于HSV模型下三通道独立直方图匹配的过程,并引入了 CLAHE 技术进一步增强了 V 组件内的纹理特性表达力,从而提高了不同光照条件下同源物体间识别准确性。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值