翼度科技»论坛 编程开发 .net 查看内容

OpenCV+OpenCvSharp实现图片特征向量提取与相似度计算

8

主题

8

帖子

24

积分

新手上路

Rank: 1

积分
24
图片特征向量是一种用于描述图片内容的数学表示,它可以反映图片的颜色、纹理、形状等信息。图片特征向量可以用于做很多事情,比如图片检索、分类、识别等。
本文将介绍图片特征向量的提取以及相似度的计算,并使用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方法从图片中提取特征点和描述符。下面是代码示例:
  1. // 加载图片
  2. Mat image1 = Cv2.ImRead("image1.jpg", ImreadModes.Grayscale);
  3. Mat image2 = Cv2.ImRead("image2.jpg", ImreadModes.Grayscale);
  4. // 创建SIFT对象
  5. SIFT sift = SIFT.Create();
  6. // 提取特征点和描述符
  7. Mat descriptors1 = new Mat();
  8. Mat descriptors2 = new Mat();
  9. sift.DetectAndCompute(image1, null, out _, descriptors1);
  10. 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方法从图片中提取特征点和描述符。下面是代码示例:
  1. // 加载图片
  2. Mat image1 = Cv2.ImRead("image1.jpg", ImreadModes.Grayscale);
  3. Mat image2 = Cv2.ImRead("image2.jpg", ImreadModes.Grayscale);
  4. // 创建SURF对象
  5. SURF surf = SURF.Create(500); // 500是阈值参数,表示特征点的最小响应值
  6. // 提取特征点和描述符
  7. Mat descriptors1 = new Mat();
  8. Mat descriptors2 = new Mat();
  9. surf.DetectAndCompute(image1, null, out _, descriptors1);
  10. surf.DetectAndCompute(image2, null, out _, descriptors2);
复制代码
图片相似度计算

提取了图片的特征向量后,我们就可以计算图片的相似度了。图片相似度的计算方法有很多,本文将介绍两种常用的方法:BFMatcher 和 FlannBasedMatcher,它们都是基于特征点匹配的方法,但是有一些区别。
BFMatcher

BFMatcher 是一种暴力匹配方法,它的原理是对于第一张图片中的每个特征点,都遍历第二张图片中的所有特征点,找出最接近的一个或多个特征点作为匹配结果。BFMatcher 的优点是简单直观,缺点是效率低,时间复杂度为 O(n^2),其中n是特征点的数量。
使用 OpenCvSharp4 实现 BFMatcher 也非常简单,只需要调用BFMatcher类的构造函数创建一个BFMatcher对象,然后调用Match方法进行匹配。下面是代码示例:
  1. // 创建BFMatcher对象
  2. BFMatcher bfMatcher = new BFMatcher(NormTypes.L2, false); // NormTypes.L2表示使用欧式距离作为相似度度量,false表示不交叉匹配
  3. // 进行匹配
  4. DMatch[] bfMatches = bfMatcher.Match(descriptors1, descriptors2); // bfMatches是一个数组,每个元素是一个DMatch对象,表示一对匹配结果
复制代码
FlannBasedMatcher

FlannBasedMatcher 是一种近似最近邻匹配方法,它的原理是使用一种快速的索引结构来加速特征点的查找,从而降低时间复杂度。FlannBasedMatcher 的优点是效率高,缺点是精度略低,可能会出现一些错误的匹配。
使用 OpenCvSharp4 实现 FlannBasedMatcher 也非常简单,只需要调用FlannBasedMatcher类的构造函数创建一个FlannBasedMatcher对象,然后调用Match方法进行匹配。下面是代码示例:
  1. // 创建FlannBasedMatcher对象
  2. FlannBasedMatcher flannMatcher = new FlannBasedMatcher();
  3. // 进行匹配
  4. DMatch[] flannMatches = flannMatcher.Match(descriptors1, descriptors2); // flannMatches是一个数组,每个元素是一个DMatch对象,表示一对匹配结果
复制代码
相似度得分

相似度得分的计算方法有很多,这里使用一种简单的方法:首先计算出每个匹配对的距离。然后对所有的距离求平均值,得到一个相似度得分,得分越小表示越相似。
我们对 BFMatcher 和 FlannBasedMatcher 的匹配结果都做了这个计算。
  1. // 计算并显示BFMatcher和FlannBasedMatcher的相似度得分,得分越低越相似
  2. Console.WriteLine("The score using BFMatcher is {0}", bfMatches.Average(m => m.Distance));
  3. Console.WriteLine("The score using FlannBasedMatcher is {0}", flannMatches.Average(m => m.Distance));
复制代码
这样,图片特征向量提取和相似度计算就实现了。完整代码可在公众号查看。
结果对比

接下来我们运行程序,从四种情况去查看结果。
1、两张完全不同的图片对比

这种情况下,我们可以预期得到很高的相似度得分,表示两张图片几乎没有相似之处。如图所示:
  1. SURF算法
  2. The score using BFMatcher is 0.77414566
  3. The score using FlannBasedMatcher is 0.77414566
  4. SIFT算法
  5. The score using BFMatcher is 366.84616
  6. The score using FlannBasedMatcher is 372.25107
复制代码
2、两张完全相同的图片对比

这种情况下,我们可以预期得到很低的相似度得分,表示两张图片完全一致。如图所示:
  1. SURF算法
  2. The score using BFMatcher is 0
  3. The score using FlannBasedMatcher is 0
  4. SIFT算法
  5. The score using BFMatcher is 0
  6. The score using FlannBasedMatcher is 0
复制代码
3、某一张图片和它的部分截图进行对比

这种情况下,我们可以预期得到中等的相似度得分,表示两张图片有部分重合。如图所示:
  1. SURF算法
  2. The score using BFMatcher is 0.22462595
  3. The score using FlannBasedMatcher is 0.23025486
  4. SIFT算法
  5. The score using BFMatcher is 105.93032
  6. The score using FlannBasedMatcher is 108.3307
复制代码
4、两张相似的图片进行对比

这种情况下,我们可以预期得到较低的相似度得分,表示两张图片有很多共同的特征。例如,我们可以使用两张不同角度拍摄的同一物体的图片进行对比。如图所示:

 
  1. SURF算法
  2. The score using BFMatcher is 0.37855583
  3. The score using FlannBasedMatcher is 0.38878053
  4. SIFT算法
  5. The score using BFMatcher is 239.1525
  6. The score using FlannBasedMatcher is 248.43388
复制代码
从上面的结果可以看出,SURF 和 SIFT 算法都可以提取图片特征向量,同时,BFMatcher 和 FlannBasedMatcher 也有区别。因此,在选算法时,需要根据具体的应用场景和需求进行权衡。
如果你对此感兴趣,还可以进一步探究,将图片特征向量存储到向量数据库中,实现更多的功能需求。比如,你可以使用 Redis 或  Elasticsearch,它们都支持对向量数据进行增、删、改、查等操作。
以下是相关推荐阅读:
1、ChatGPT Embeddings与Redis强强结合实现文本相似度分析与搜索
2、利用Redis实现向量相似度搜索:解决文本、图像和音频之间的相似度匹配问题
3、C#+Redis Search:如何用Redis实现高性能全文搜索
写作不易,转载请注明博文地址,否则禁转!!!

来源:https://www.cnblogs.com/anech/archive/2023/10/27/17792133.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具