当前位置:首页 > 技术文章 > 正文内容

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

zonemu1周前 (08-18)技术文章11


OpenCVSharp4图片相似度识别


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

一、图片相似度算法

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

直方图算法

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

平均值哈希算法 aHash

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

感知哈希算法 pHash

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

差异值哈希算法 dHash

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

结构相似性算法 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

三、 使用

在项目中引入 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; // 变化率,即差异

}

实际检测效果如下

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

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

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

转自:宣君

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

- EOF -

相关文章

Linux之父:Linux内核5.8是“我们有史以来最大的发行版之一”

Linux内核负责人Linus Torvalds对Linux内核版本5.8的第一个候选发布版本(rc1)看得出来还是挺满意的,该版本包含80万行新代码行和超过14,000个更改的文件,占内核文件检修的...

2023 年 10 个最佳 Linux 桌面发行版

Linux 操作系统在桌面领域的发展已经不再被忽视,越来越多的用户正在考虑切换到 Linux 上。在 2023 年,我们可以期待更多的 Linux 桌面发行版的推出和发展。这里列举了 10 个最佳的...

2024前端面试真题之—VUE篇(前端面试题vuex)

添加图片注释,不超过 140 字(可选)1.vue的生命周期有哪些及每个生命周期做了什么? beforeCreate是new Vue()之后触发的第一个钩子,在当前阶段data、methods、com...

Vue3开发极简入门(16):祖孙组件间通信之provide&inject

前文说了Vue的组件间关系,有父子、爷孙、其他关系。例如之前的Father、Son是父子关系,App与Son就是爷孙关系。而props的Son,与emits的Son,就是其他关系。前文的props是父...

jenkins2.107+tomcat8+jdk1.8的安装和发布代码3种方式

jenkins2.107+tomcat8+jdk1.8的安装和发布代码3种方式如果对运维课程感兴趣,可以在b站上或csdn上搜索我的账号: 运维实战课程,可以关注我,学习更多免费的运维实战技术视频1....

100行Html5+CSS3+JS代码实现元旦倒计时界面

一、前言2022年到了,祝大家虎年大吉喜气临,昂首摆尾迎春来。双眼圆睁看世界,万水千山尽开颜。胡须翘翘美姿态,人人开心祝平安。巨大身躯摇摆摆,坎坷困境当笑谈。愿你虎年万事顺,吉星高照旺旺旺!二、202...