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讲堂

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C是一门广泛应用于计算机科学、统计学、物理学、化学、金融等领域的编程语言。它是由AT&T贝尔实验室的Dennis Ritchie于1972年设计出来的。C语言是一种高效、可移植和灵活的语言,除了提供底层访问硬件的能力,同时也是高级程序设计的首选语言之一。 C语言最初用于UNIX操作系统的开发,但随着时间的推移,C语言被广泛应用于各个领域,例如嵌入式系统、游戏开发、框架开发、编译器的开发等。C语言具有灵活性,使得程序员可以方便地通过底层的算法解决问题。它还提供了丰富的库函数和语法特性,适合用于底层的编程,使得程序员可以更好地掌控内存和CPU的使用情况,提高程序的效率。C语言的语法简洁,使得学习和使用C语言变得更加容易,即使是初学者也可以很快掌握它。 作为一门编程语言,C语言有一些缺点。首先,它没有内置的对象模型(Object Model),这意味着开发者需要自己处理内存分配和释放,指针操作也需要谨慎,这在初学者中很容易犯错;其次,C语言的性能很高,但这也意味着如果程序员出现差错,可能会导致程序崩溃或者产生很严重的安全问题。因此,需要开发者具备较高的编程经验和严谨的态度才能开发出稳定可靠的程序。 总之,虽然C语言并不是最新的编程语言,但它在编程领域中仍然有着重要的地位。通过学习C语言,人们不仅可以了解底层的编程方式,还可以提高代码的效率和可移植性,为今后的编程打下坚实的基础。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值