当前位置:   article > 正文

c#-OpenCvSharp-SURF/SIFT特征匹配(附源码)_opencvsharp surf

opencvsharp surf

目录

前言:

核心函数:

SURF.Create() 创建SURF检测器

 detector.DetectAndCompute() 检测关键点并计算特征描述向量

Cv2.DrawMatches()  绘制特征匹配

KeyPoint 类:

 匹配思路:

代码流程:

 运行结果:


前言:

SURF(Speeded Up Robust Features)是一种用于特征检测和图像匹配的算法,其主要特点是在提供良好特征匹配性能的同时,具有高速性和对图像变换的鲁棒性

核心函数:

SURF.Create() 创建SURF检测器
SURF.Create(hessianThreshold, extended, upright)
  • hessianThreshold:Hessian阈值,用于控制关键点检测。通常,较大的值将导致更少但更重要的关键点。
  • extended:如果为 true,则使用扩展的SURF描述符。扩展的描述符具有更多信息,但也更大。
  • upright:如果为 true,则只检测正立(不旋转)的SURF特征。这在某些情况下可以提高性能。

 detector.DetectAndCompute() 检测关键点并计算特征描述向量
DetectAndCompute(Mat image, Mat mask, out KeyPoint[] keypoints, Mat descriptors)
  • DetectAndCompute(Mat image, Mat mask, out KeyPoint[] keypoints, Mat descriptors) 用于检测关键点并计算特征描述向量。
  • image:要检测关键点的图像。
  • mask:一个可选的掩膜,可用于限制关键点的检测区域。
  • keypoints:输出参数,存储检测到的关键点。
  • descriptors:输出参数,存储计算的特征描述向量。

Cv2.DrawMatches()  绘制特征匹配
  1. void Cv2.DrawMatches(
  2. Mat img1, KeyPoint[] keypoints1,
  3. Mat img2, KeyPoint[] keypoints2,
  4. DMatch[] matches1to2,
  5. Mat outImg,
  6. Scalar matchColor, Scalar singlePointColor,
  7. MatOfByte mask,
  8. DrawMatchesFlags flags = DrawMatchesFlags.Default );

  • img1img2: 两幅输入图像,用于绘制特征匹配。
  • keypoints1keypoints2: 分别是两幅图像的关键点数组。
  • matches1to2: 一个包含特征点匹配关系的数组,通常是使用特征匹配算法(如SIFT,SURF,ORB)得出的。
  • outImg: 存储输出结果的 Mat 对象,通常是一个空白图像,这个方法会在这个图像上绘制特征匹配。
  • matchColor: 用于绘制匹配线的颜色。
  • singlePointColor: 用于绘制单个特征点的颜色。
  • mask: 可选参数,一个指示哪些匹配有效的掩码图像。如果不使用掩码,可以传递 null
  • flags: 一个可选参数,控制绘制特征匹配的方式。可以是 DrawMatchesFlags.Default 或其他选项。
KeyPoint 类:
  • 用于表示检测到的关键点的类,包括位置、尺度、方向等信息。

 匹配思路:

1、创建检测器

2、检测关键点并计算特征描述向量

3、创建特征点匹配器并进行匹配

4、绘制两个图像匹配出得关键点

5、显示匹配图像

代码流程:

注释详细,仔细阅读。SURF匹配增加了筛选优秀匹配点的逻辑,SIFT匹配为主要流程的匹配

  1. using OpenCvSharp;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Data;
  6. using System.Drawing;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. using System.Windows.Forms;
  11. using Point = OpenCvSharp.Point;
  12. namespace SURF_and_SIFT特征匹配
  13. {
  14. public partial class Form1 : Form
  15. {
  16. public Form1()
  17. {
  18. InitializeComponent();
  19. }
  20. Mat srcImage1;
  21. Mat srcImage2;
  22. private void button1_Click(object sender, EventArgs e)
  23. {
  24. OpenFileDialog ofd = new OpenFileDialog();
  25. ofd.Filter = "Image Files(*.jpg;*.png*;*.bmp*)|*.jpg;*.png*;*.bmp";
  26. if (ofd.ShowDialog() != DialogResult.OK)
  27. return;
  28. string imagePath = ofd.FileName;
  29. srcImage1 = Cv2.ImRead(imagePath, ImreadModes.AnyColor);
  30. Cv2.ImShow("src image1", srcImage1);
  31. }
  32. private void button2_Click(object sender, EventArgs e)
  33. {
  34. OpenFileDialog ofd = new OpenFileDialog();
  35. ofd.Filter = "Image Files(*.jpg;*.png*;*.bmp*)|*.jpg;*.png*;*.bmp";
  36. if (ofd.ShowDialog() != DialogResult.OK)
  37. return;
  38. string imagePath = ofd.FileName;
  39. srcImage2 = Cv2.ImRead(imagePath, ImreadModes.AnyColor);
  40. Cv2.ImShow("src image2", srcImage2);
  41. }
  42. private void button3_Click(object sender, EventArgs e)
  43. {
  44. // 定义SURF中的hessian阈值特征点检测算子
  45. int minHessian = 400;
  46. // 定义一个特征检测类对象
  47. var MySurf = OpenCvSharp.XFeatures2D.SURF.Create(minHessian, 4, 3, true, true);
  48. Mat descriptors1 = new Mat();
  49. Mat descriptors2 = new Mat();
  50. // 模板类是能够存放任意类型的动态数组,能够增加和压缩数据
  51. // 方法1:计算描述符(特征向量),将Detect和Compute操作分开
  52. //KeyPoint[] keyPoint1 = MySurf.Detect(srcImage1);
  53. //KeyPoint[] keyPoint2 = MySurf.Detect(srcImage2);
  54. //MySurf.Compute(srcImage1, ref keyPoint1, descriptors1);
  55. //MySurf.Compute(srcImage2, ref keyPoint2, descriptors2);
  56. // 方法2:计算描述符(特征向量),将Detect和Compute操作合并
  57. KeyPoint[] keyPoint1, keyPoint2;
  58. MySurf.DetectAndCompute(srcImage1, null, out keyPoint1, descriptors1);
  59. MySurf.DetectAndCompute(srcImage2, null, out keyPoint2, descriptors2);
  60. // 使用BruteForce进行匹配 暴力匹配
  61. // 创建特征点匹配器
  62. BFMatcher matcher = new BFMatcher(NormTypes.L2, crossCheck: false);
  63. // 匹配两幅图中的描述子(descriptors)
  64. DMatch[] matches = matcher.Match(descriptors1, descriptors2);
  65. // 设置比率阈值
  66. double ratio_thresh = 0.2;
  67. List<DMatch> good_matches = new List<DMatch>();
  68. for (int i = 0; i < matches.Length; i++)
  69. {
  70. if (matches[i].Distance < ratio_thresh)
  71. {
  72. good_matches.Add(matches[i]);
  73. }
  74. }
  75. if (good_matches.Count <= 4)
  76. {
  77. // 匹配点不足,无法进行透视变换
  78. MessageBox.Show("合格匹配点数量不足" + good_matches.Count);
  79. }
  80. // 创建一个新的图像以绘制匹配结果
  81. Mat imgMatches = new Mat();
  82. // 绘制匹配关键点
  83. Cv2.DrawMatches(srcImage1, keyPoint1, srcImage2, keyPoint2, good_matches, imgMatches, null, null, null, DrawMatchesFlags.NotDrawSinglePoints);
  84. // -------锚定物体------------
  85. // 创建两个数组来存储匹配成功的特征点,一个用于物体图像(obj),另一个用于场景图像(scene)
  86. Point2d[] obj = new Point2d[good_matches.Count()], scene = new Point2d[good_matches.Count()];
  87. // 遍历匹配成功的特征点
  88. for (int i = 0; i < good_matches.Count(); i++)
  89. {
  90. // 获取查询图像中特征点的坐标,通过good_matches[i].QueryIdx找到对应特征点的索引
  91. obj[i] = keyPoint1[good_matches[i].QueryIdx].Pt.ToPoint();
  92. // 获取模板图像中对应的特征点坐标,通过good_matches[i].TrainIdx找到对应特征点的索引
  93. scene[i] = keyPoint2[good_matches[i].TrainIdx].Pt.ToPoint();
  94. }
  95. if (obj.Length < 4)
  96. {
  97. MessageBox.Show("obj优秀匹配点不足,数量为"+ obj.Length);
  98. }
  99. if (scene.Length < 4)
  100. {
  101. MessageBox.Show("匹配点不足,数量为"+ scene.Length);
  102. return;
  103. }
  104. // 使用Cv2.FindHomography方法计算透视变换矩阵H,它可以将物体图像映射到场景图像上
  105. // HomographyMethods.Ransac表示使用RANSAC算法来估计透视变换矩阵,3表示RANSAC算法的最大迭代次数,null表示不使用掩码
  106. Mat H = Cv2.FindHomography(obj, scene, HomographyMethods.Ransac, 3, null);
  107. // 创建两点,初始值设为最小和最大的浮点数,用于存储最左上角和最右下角的点
  108. Point2f topLeft = new Point2f(float.MaxValue, float.MaxValue);
  109. Point2f bottomRight = new Point2f(float.MinValue, float.MinValue);
  110. // 遍历所有匹配点
  111. foreach (DMatch match in good_matches)
  112. {
  113. // 获取当前匹配对中源图像和目标图像的点坐标
  114. Point2f srcPt = keyPoint1[match.QueryIdx].Pt;
  115. Point2f dstPt = keyPoint2[match.TrainIdx].Pt;
  116. // 寻找最左上角的点
  117. topLeft.X = Math.Min(topLeft.X, srcPt.X);
  118. topLeft.Y = Math.Min(topLeft.Y, srcPt.Y);
  119. // 寻找最右下角的点
  120. bottomRight.X = Math.Max(bottomRight.X, srcPt.X);
  121. bottomRight.Y = Math.Max(bottomRight.Y, srcPt.Y);
  122. }
  123. // 将浮点数坐标转换为整数坐标
  124. Point topLeftPoint = new Point((int)topLeft.X, (int)topLeft.Y);
  125. Point bottomRightPoint = new Point((int)bottomRight.X, (int)bottomRight.Y);
  126. // 绘制一个矩形框,框住匹配的区域
  127. Cv2.Rectangle(imgMatches, topLeftPoint, bottomRightPoint, new Scalar(0, 255, 0), 2);
  128. // 显示最终的匹配图像
  129. Cv2.ImShow("匹配图", imgMatches);
  130. }
  131. // SIFT特征匹配
  132. private void button4_Click(object sender, EventArgs e)
  133. {
  134. // 创建检测器
  135. int minHessian = 400;
  136. var MySift = OpenCvSharp.Features2D.SIFT.Create(minHessian);
  137. Mat descriptors1 = new Mat();
  138. Mat descriptors2 = new Mat();
  139. // 计算描述符(特征向量)
  140. KeyPoint[] keyPoint1, keyPoint2;
  141. MySift.DetectAndCompute(srcImage1, null, out keyPoint1, descriptors1);
  142. MySift.DetectAndCompute(srcImage2, null, out keyPoint2, descriptors2);
  143. // 使用BruteForce进行匹配
  144. // 创建特征点匹配器
  145. BFMatcher matcher = new BFMatcher();
  146. // 匹配两幅图中的描述子(descriptors)
  147. DMatch[] matches = matcher.Match(descriptors1, descriptors2);
  148. //【6】绘制从两个图像中匹配出的关键点
  149. Mat imgMatches = new Mat();
  150. Cv2.DrawMatches(srcImage1, keyPoint1, srcImage2, keyPoint2, matches, imgMatches);//进行绘制
  151. // 显示最终的匹配图像
  152. Cv2.ImShow("SIFT匹配", imgMatches);
  153. }
  154. }
  155. }

 运行结果:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/81218
推荐阅读
  

闽ICP备14008679号