C#结合OpenCVSharp4图片相似度识别
<h1 id="opencvsharp4图片相似度识别">OpenCVSharp4图片相似度识别</h1><p>需求背景:需要计算两个图片的相似度,然后将相似的图片进行归纳</p>
<h2 id="1-图片相似度算法">1. 图片相似度算法</h2>
<p>由于我是CRUD后端仔,对图像处理没什么概念。因此网上调研了几种相似度算法分析其适用场景。</p>
<p><strong>直方图算法</strong></p>
<p>获取要比较的2个图片的直方图数据,然后再将直方图数据归一化比较,最终得到一个相似指数,通过设定相似指数的边界,以此判断是否相同图片。</p>
<p><strong>平均值哈希算法 aHash</strong></p>
<p>转灰度压缩之后计算均值,最终通过像素比较得出哈希值,速度很快,但敏感度很高,稍有变化就会极大影响判定结果,精准度较差。因此比较适用于缩略图比较,最常用的就是以图搜图</p>
<p><strong>感知哈希算法 pHash</strong></p>
<p>在均值哈希基础上加入<code>DCT</code>(离散余弦变化),两次<code>DCT</code>就可以很好的将图像按照频度分开,取左上角高能低频信息做均值哈希,因此,精确度很高,但是速度方面较差一些。相比较<code>aHash</code>,<code>pHash</code>更加适合用于缩略图比较,也非常适合比较两个近似图片是否相等。</p>
<p><strong>差异值哈希算法 dHash</strong></p>
<p>灰度压缩之后,比较相邻像素之间差异。假设有10×10的图像,每行10个像素,就会产生9个差异值,一共10行,就一共有9×10=90个差异值。最终生成哈希值即指纹。速度上来说,介于<code>aHash</code>和<code>pHash</code>之间,精准度同样也介于<code>aHash</code>和<code>pHash</code>之间。</p>
<p><strong>结构相似性算法 SSIM</strong></p>
<p><code>SSIM(structural similarity)</code>,结构相似性,是一种衡量两幅图像相似度的指标。<code>SSIM</code>算法主要用于检测两张相同尺寸的图像的相似度、或者检测图像的失真程度。原论文中,<code>SSIM</code>算法主要通过分别比较两个图像的亮度,对比度,结构,然后对这三个要素加权并用乘积表示。</p>
<p><code>SSIM</code>算法在设计上考虑了人眼的视觉特性,它能够考虑到图像的结构信息在人的感知上的模糊变化,该模型还引入了一些与感知上的变化有关的感知现象,包含亮度mask和对比mask,结构信息指的是像素之间有着内部的依赖性,尤其是空间上靠近的像素点。这些依赖性携带着目标对象视觉感知上的重要信息。</p>
<p>经过调研对比,这里就选择<code>SSIM</code>算法。</p>
<h2 id="2-下载opencvsharp4">2. 下载OpenCVSharp4</h2>
<p>通过NuGet包管理器进行下载。搜索<code>OpenCVSharp4</code>下载。</p>
<blockquote>
<p>请注意其描述信息:OpenCV wrapper for .NET. Since this package includes only core managed libraries, another package of native bindings for your OS is required (OpenCvSharp4.runtime.*).</p>
<p>这是说:OpenCV 包只是一个核心库,如需在你的系统上使用,还需要对应的运行时包,这里是Windows系统,因此还需下载 OpenCvSharp4.runtime.win</p>
</blockquote>
<p><img src="https://jsd.cdn.zzko.cn/gh/YuanjunXu/Images@main/src/image.16h5utdraaww.webp" alt="image" loading="lazy"></p>
<hr>
<h2 id="3-使用">3. 使用</h2>
<p>在项目中引入<code>OpenCvSharp</code></p>
<pre><code class="language-c">using OpenCvSharp;
</code></pre>
<p>由于<code>OpenCVSharp4</code>没有直接提供封装<code>SSIM</code>算法的接口,因此需要自行写这部分代码。完整代码如下</p>
<pre><code class="language-c">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;// 变化率,即差异
}
</code></pre>
<p>实际检测效果如下</p>
<p><img src="https://jsd.cdn.zzko.cn/gh/YuanjunXu/Images@main/src/image.6z5o5cmie4k0.webp" alt="image" loading="lazy"></p>
<p>这两幅图的相似度大约是92.21%,基本符合预期</p>
<p><img src="https://jsd.cdn.zzko.cn/gh/YuanjunXu/Images@main/src/image.5zcz26nzvm80.webp" alt="image" loading="lazy"></p>
<p>这两幅图居然还有约18%的相似度,根据<code>SSIM</code>算法特性,这应该是图片大小的相似。</p>
<p>虽然也是拿来主义,毕竟我不是研究算法的大佬,需要站在巨人肩膀上干活~</p>
<p>做个笔记。</p>
</div>
<div id="MySignature" role="contentinfo">
<p>本文来自博客园,作者:宣君{https://www.nhit.icu/},转载请注明原文链接:https://www.cnblogs.com/ycit/p/17688625.html</p><br><br>
来源:https://www.cnblogs.com/ycit/p/17688625.html
頁:
[1]