OpenCV+OpenCvSharp實現圖片特徵向量提取與相似度計算

圖片特徵向量是一種用於描述圖片內容的數學表示,它可以反映圖片的顏色、紋理、形狀等信息。圖片特徵向量可以用於做很多事情,比如圖片檢索、分類、識別等。

本文將介紹圖片特徵向量的提取以及相似度的計算,並使用C#來實現它們。

文章開始前,我們先來簡單瞭解一下 OpenCV 和 OpenCvSharp4,這兩個庫是本文的核心。

什麼是OpenCV

OpenCV(Open Source Computer Vision Library)是一個基於開源發行的跨平臺計算機視覺和機器學習軟件庫,它支持多種編程語言,包含了數百種圖像處理和計算機視覺算法。

什麼是OpenCvSharp4

OpenCvSharp4 是一個基於 OpenCV 開發的跨平臺圖像處理庫,它支持 .NET Framework 4.8+和 .NET Core 2.0+。它提供了豐富而易用的 API,可以實現各種圖像處理功能。OpenCvSharp4 只包含核心的託管庫,所以還需要另外安裝對應操作系統的原生綁定包(OpenCvSharp4.runtime.*)。

圖片特徵向量提取

提取圖片特徵向量的方法有很多,本文將採用 SIFT 和 SURF 兩種常用的算法。

SIFT算法

SIFT(Scale Invariant Feature Transform)算法是一種尺度不變的特徵提取方法,它能夠在不同的尺度空間中檢測出穩定的關鍵點,並生成具有唯一性和不變性的描述符。SIFT 算法的主要優點是:

  • 尺度不變性:SIFT 算法使用了高斯金字塔來構建不同尺度的圖像,並在每個尺度上進行極值點檢測,從而實現了對尺度變化的不敏感。
  • 旋轉不變性:SIFT 算法使用了梯度方向直方圖來生成描述符,並根據關鍵點的主方向進行旋轉歸一化,從而實現了對旋轉變化的不敏感。
  • 鑑別性強:SIFT 算法能夠生成具有高維度和高信息量的描述符,使得每個關鍵點都具有唯一性和區分性,提高了匹配的可靠性。

使用 OpenCvSharp4 實現 SIFT 算法很簡單,只需要調用SIFT.Create方法創建一個SIFT對象,然後調用DetectAndCompute方法從圖片中提取特徵點和描述符。下面是代碼示例:

// 加載圖片
Mat image1 = Cv2.ImRead("image1.jpg", ImreadModes.Grayscale);
Mat image2 = Cv2.ImRead("image2.jpg", ImreadModes.Grayscale);
​
// 創建SIFT對象
SIFT sift = SIFT.Create();
​
// 提取特徵點和描述符
Mat descriptors1 = new Mat();
Mat descriptors2 = new Mat();
sift.DetectAndCompute(image1, null, out _, descriptors1);
sift.DetectAndCompute(image2, null, out _, descriptors2);

SURF算法

SURF(Speeded Up Robust Features)算法是一種快速而穩健的特徵提取方法,它基於Harris角點檢測和尺度不變特徵變換(SIFT)算法改進而來。SURF 算法的主要優點是:

  • 速度快:SURF 算法使用了積分圖和哈爾小波來加速特徵點檢測和描述符生成,比SIFT算法快幾倍。
  • 穩健性高:SURF 算法對於旋轉、縮放、亮度變化等干擾具有較好的魯棒性,能夠在不同的場景中保持穩定的性能。
  • 精度高:SURF 算法能夠提取出高質量的特徵點和描述符,提高了匹配的準確率。

使用 OpenCvSharp4 實現 SURF 算法也非常簡單,只需要調用SURF.Create方法創建一個SURF對象,然後調用DetectAndCompute方法從圖片中提取特徵點和描述符。下面是代碼示例:

// 加載圖片
Mat image1 = Cv2.ImRead("image1.jpg", ImreadModes.Grayscale);
Mat image2 = Cv2.ImRead("image2.jpg", ImreadModes.Grayscale);
​
// 創建SURF對象
SURF surf = SURF.Create(500); // 500是閾值參數,表示特徵點的最小響應值
​
// 提取特徵點和描述符
Mat descriptors1 = new Mat();
Mat descriptors2 = new Mat();
surf.DetectAndCompute(image1, null, out _, descriptors1);
surf.DetectAndCompute(image2, null, out _, descriptors2);

圖片相似度計算

提取了圖片的特徵向量後,我們就可以計算圖片的相似度了。圖片相似度的計算方法有很多,本文將介紹兩種常用的方法:BFMatcher 和 FlannBasedMatcher,它們都是基於特徵點匹配的方法,但是有一些區別。

BFMatcher

BFMatcher 是一種暴力匹配方法,它的原理是對於第一張圖片中的每個特徵點,都遍歷第二張圖片中的所有特徵點,找出最接近的一個或多個特徵點作爲匹配結果。BFMatcher 的優點是簡單直觀,缺點是效率低,時間複雜度爲 O(n^2),其中n是特徵點的數量。

使用 OpenCvSharp4 實現 BFMatcher 也非常簡單,只需要調用BFMatcher類的構造函數創建一個BFMatcher對象,然後調用Match方法進行匹配。下面是代碼示例:

// 創建BFMatcher對象
BFMatcher bfMatcher = new BFMatcher(NormTypes.L2, false); // NormTypes.L2表示使用歐式距離作爲相似度度量,false表示不交叉匹配
​
// 進行匹配
DMatch[] bfMatches = bfMatcher.Match(descriptors1, descriptors2); // bfMatches是一個數組,每個元素是一個DMatch對象,表示一對匹配結果

FlannBasedMatcher

FlannBasedMatcher 是一種近似最近鄰匹配方法,它的原理是使用一種快速的索引結構來加速特徵點的查找,從而降低時間複雜度。FlannBasedMatcher 的優點是效率高,缺點是精度略低,可能會出現一些錯誤的匹配。

使用 OpenCvSharp4 實現 FlannBasedMatcher 也非常簡單,只需要調用FlannBasedMatcher類的構造函數創建一個FlannBasedMatcher對象,然後調用Match方法進行匹配。下面是代碼示例:

// 創建FlannBasedMatcher對象
FlannBasedMatcher flannMatcher = new FlannBasedMatcher();
​
// 進行匹配
DMatch[] flannMatches = flannMatcher.Match(descriptors1, descriptors2); // flannMatches是一個數組,每個元素是一個DMatch對象,表示一對匹配結果

相似度得分

相似度得分的計算方法有很多,這裏使用一種簡單的方法:首先計算出每個匹配對的距離。然後對所有的距離求平均值,得到一個相似度得分,得分越小表示越相似。

我們對 BFMatcher 和 FlannBasedMatcher 的匹配結果都做了這個計算。

// 計算並顯示BFMatcher和FlannBasedMatcher的相似度得分,得分越低越相似
Console.WriteLine("The score using BFMatcher is {0}", bfMatches.Average(m => m.Distance));
Console.WriteLine("The score using FlannBasedMatcher is {0}", flannMatches.Average(m => m.Distance));

這樣,圖片特徵向量提取和相似度計算就實現了。完整代碼可在公衆號查看。

結果對比

接下來我們運行程序,從四種情況去查看結果。

1、兩張完全不同的圖片對比

這種情況下,我們可以預期得到很高的相似度得分,表示兩張圖片幾乎沒有相似之處。如圖所示:

卡通人物

中度可信度描述已自動生成

SURF算法
The score using BFMatcher is 0.77414566
The score using FlannBasedMatcher is 0.77414566
SIFT算法
The score using BFMatcher is 366.84616
The score using FlannBasedMatcher is 372.25107

2、兩張完全相同的圖片對比

這種情況下,我們可以預期得到很低的相似度得分,表示兩張圖片完全一致。如圖所示:

SURF算法
The score using BFMatcher is 0
The score using FlannBasedMatcher is 0
SIFT算法
The score using BFMatcher is 0
The score using FlannBasedMatcher is 0

3、某一張圖片和它的部分截圖進行對比

這種情況下,我們可以預期得到中等的相似度得分,表示兩張圖片有部分重合。如圖所示:

SURF算法
The score using BFMatcher is 0.22462595
The score using FlannBasedMatcher is 0.23025486
SIFT算法
The score using BFMatcher is 105.93032
The score using FlannBasedMatcher is 108.3307

4、兩張相似的圖片進行對比

這種情況下,我們可以預期得到較低的相似度得分,表示兩張圖片有很多共同的特徵。例如,我們可以使用兩張不同角度拍攝的同一物體的圖片進行對比。如圖所示:

 

SURF算法
The score using BFMatcher is 0.37855583
The score using FlannBasedMatcher is 0.38878053
SIFT算法
The score using BFMatcher is 239.1525
The score using FlannBasedMatcher is 248.43388

從上面的結果可以看出,SURF 和 SIFT 算法都可以提取圖片特徵向量,同時,BFMatcher 和 FlannBasedMatcher 也有區別。因此,在選算法時,需要根據具體的應用場景和需求進行權衡。

如果你對此感興趣,還可以進一步探究,將圖片特徵向量存儲到向量數據庫中,實現更多的功能需求。比如,你可以使用 Redis 或  Elasticsearch,它們都支持對向量數據進行增、刪、改、查等操作。

以下是相關推薦閱讀:

1、ChatGPT Embeddings與Redis強強結合實現文本相似度分析與搜索

2、利用Redis實現向量相似度搜索:解決文本、圖像和音頻之間的相似度匹配問題

3、C#+Redis Search:如何用Redis實現高性能全文搜索

寫作不易,轉載請註明博文地址,否則禁轉!!!

👇感謝閱讀,點贊+分享+收藏+關注👇
文章出自猿惑豁微信公衆號
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章