C#結(jié)合OpenCVSharp4實(shí)現(xiàn)圖片相似度識(shí)別
OpenCVSharp4圖片相似度識(shí)別
需求背景:需要計(jì)算兩個(gè)圖片的相似度,然后將相似的圖片進(jìn)行歸納
1. 圖片相似度算法
由于我是CRUD后端仔,對(duì)圖像處理沒(méi)什么概念。因此網(wǎng)上調(diào)研了幾種相似度算法分析其適用場(chǎng)景。
直方圖算法
獲取要比較的2個(gè)圖片的直方圖數(shù)據(jù),然后再將直方圖數(shù)據(jù)歸一化比較,最終得到一個(gè)相似指數(shù),通過(guò)設(shè)定相似指數(shù)的邊界,以此判斷是否相同圖片。
平均值哈希算法 aHash
轉(zhuǎn)灰度壓縮之后計(jì)算均值,最終通過(guò)像素比較得出哈希值,速度很快,但敏感度很高,稍有變化就會(huì)極大影響判定結(jié)果,精準(zhǔn)度較差。因此比較適用于縮略圖比較,最常用的就是以圖搜圖
感知哈希算法 pHash
在均值哈?;A(chǔ)上加入DCT(離散余弦變化),兩次DCT就可以很好的將圖像按照頻度分開(kāi),取左上角高能低頻信息做均值哈希,因此,精確度很高,但是速度方面較差一些。相比較aHash,pHash更加適合用于縮略圖比較,也非常適合比較兩個(gè)近似圖片是否相等。
差異值哈希算法 dHash
灰度壓縮之后,比較相鄰像素之間差異。假設(shè)有10×10的圖像,每行10個(gè)像素,就會(huì)產(chǎn)生9個(gè)差異值,一共10行,就一共有9×10=90個(gè)差異值。最終生成哈希值即指紋。速度上來(lái)說(shuō),介于aHash和pHash之間,精準(zhǔn)度同樣也介于aHash和pHash之間。
結(jié)構(gòu)相似性算法 SSIM
SSIM(structural similarity),結(jié)構(gòu)相似性,是一種衡量?jī)煞鶊D像相似度的指標(biāo)。SSIM算法主要用于檢測(cè)兩張相同尺寸的圖像的相似度、或者檢測(cè)圖像的失真程度。原論文中,SSIM算法主要通過(guò)分別比較兩個(gè)圖像的亮度,對(duì)比度,結(jié)構(gòu),然后對(duì)這三個(gè)要素加權(quán)并用乘積表示。
SSIM算法在設(shè)計(jì)上考慮了人眼的視覺(jué)特性,它能夠考慮到圖像的結(jié)構(gòu)信息在人的感知上的模糊變化,該模型還引入了一些與感知上的變化有關(guān)的感知現(xiàn)象,包含亮度mask和對(duì)比mask,結(jié)構(gòu)信息指的是像素之間有著內(nèi)部的依賴性,尤其是空間上靠近的像素點(diǎn)。這些依賴性攜帶著目標(biāo)對(duì)象視覺(jué)感知上的重要信息。
經(jīng)過(guò)調(diào)研對(duì)比,這里就選擇SSIM算法。
2. 下載OpenCVSharp4
通過(guò)NuGet包管理器進(jìn)行下載。搜索OpenCVSharp4下載。
請(qǐng)注意其描述信息:OpenCV wrapper for .NET. Since this package includes only core managed libraries, another package of native bindings for your OS is required (OpenCvSharp4.runtime.*).
這是說(shuō):OpenCV 包只是一個(gè)核心庫(kù),如需在你的系統(tǒng)上使用,還需要對(duì)應(yīng)的運(yùn)行時(shí)包,這里是Windows系統(tǒng),因此還需下載 OpenCvSharp4.runtime.win

3. 使用
在項(xiàng)目中引入OpenCvSharp
using OpenCvSharp;
由于OpenCVSharp4沒(méi)有直接提供封裝SSIM算法的接口,因此需要自行寫(xiě)這部分代碼。完整代碼如下
public Scalar Compare_SSIM(string imgFile1, string imgFile2)
{
var image1 = Cv2.ImRead(imgFile1);
var image2Tmp = Cv2.ImRead(imgFile2);
// 將兩個(gè)圖片處理成同樣大小,否則會(huì)有錯(cuò)誤: 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); //數(shù)據(jù)類型轉(zhuǎn)換為 float,防止后續(xù)計(jì)算出現(xiàn)錯(cuò)誤
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); //高斯卷積核計(jì)算圖像均值
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);// 計(jì)算協(xié)方差
imageVariance1 = squreAvg1 - gausBlur1.Mul(gausBlur1); //計(jì)算方差
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; // 變化率,即差異
}實(shí)際檢測(cè)效果如下

這兩幅圖的相似度大約是92.21%,基本符合預(yù)期

這兩幅圖居然還有約18%的相似度,根據(jù)SSIM算法特性,這應(yīng)該是圖片大小的相似。
以上就是C#結(jié)合OpenCVSharp4實(shí)現(xiàn)圖片相似度識(shí)別的詳細(xì)內(nèi)容,更多關(guān)于C# OpenCVSharp4的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#高級(jí)靜態(tài)語(yǔ)言效率利器之泛型詳解
所謂泛型,就是創(chuàng)建一個(gè)函數(shù),對(duì)所有數(shù)據(jù)類型都生效。這篇文章就來(lái)帶大家深入了解一下C#中高級(jí)靜態(tài)語(yǔ)言效率利器——泛型的使用,需要的可以參考一下2023-02-02
如何在UpdatePanel中調(diào)用JS客戶端腳本
本文將介紹如何在UpdatePanel中調(diào)用JS客戶端腳本,需要了解的朋友可以參考下2012-12-12
c#操作sqlserver數(shù)據(jù)庫(kù)的簡(jiǎn)單示例
這篇文章主要介紹了c#操作sqlserver數(shù)據(jù)庫(kù)的簡(jiǎn)單示例,需要的朋友可以參考下2014-04-04
C# 通過(guò) inline-asm 解決嵌入x86匯編
此篇文章通過(guò)C#語(yǔ)言解決嵌入x86匯編,主要通過(guò)INline-asm方法來(lái)實(shí)現(xiàn),下面我通過(guò)圖片和代碼的形式給大家分享下,需要的朋友可以參考下2015-07-07
C# WinForm控件對(duì)透明圖片重疊時(shí)出現(xiàn)圖片不透明的簡(jiǎn)單解決方法
這篇文章主要介紹了C# WinForm控件對(duì)透明圖片重疊時(shí)出現(xiàn)圖片不透明的簡(jiǎn)單解決方法,結(jié)合實(shí)例形式分析了WinForm圖片重疊后造成圖片不透明的原因與相應(yīng)的解決方法,需要的朋友可以參考下2016-06-06

