找回密码
 立即注册
首页 业界区 安全 OpenCVSharp:学习最佳匹配矩形检测

OpenCVSharp:学习最佳匹配矩形检测

甘子萱 2 小时前
前言

今天来学习一下OpenCVSharp中最佳匹配矩形检测的例子。其过程可以分为ORB特征检测、特征匹配、最佳匹配筛选、单应性计算与矩形绘制。
效果:
1.png

实践

ORB特征检测
进行ORB特征检测:
  1. using var img1 = new Mat(FirstImagePath, ImreadModes.Color);
  2. using var img2 = new Mat(SecondImagePath, ImreadModes.Color);
  3. using var orb = ORB.Create(1000);
  4. using var descriptors1 = new Mat();
  5. using var descriptors2 = new Mat();
  6. orb.DetectAndCompute(img1, null, out var keyPoints1, descriptors1);
  7. orb.DetectAndCompute(img2, null, out var keyPoints2, descriptors2);
复制代码
ORB(Oriented FAST and Rotated BRIEF)是一种快速高效的特征检测算法,它结合了FAST关键点检测器和BRIEF描述符,并添加了旋转不变性和尺度不变性,能够在保持较高匹配精度的同时提供极快的计算速度,特别适合实时应用和移动设备上的计算机视觉任务。
查看ORB.Create方法:
  1. public static ORB Create(int nFeatures = 500, float scaleFactor = 1.2f, int nLevels = 8, int edgeThreshold = 31, int firstLevel = 0, int wtaK = 2, ORBScoreType scoreType = ORBScoreType.Harris, int patchSize = 31, int fastThreshold = 20)
  2. {
  3.     NativeMethods.HandleException(NativeMethods.features2d_ORB_create(nFeatures, scaleFactor, nLevels, edgeThreshold, firstLevel, wtaK, (int)scoreType, patchSize, fastThreshold, out var returnValue));
  4.     return new ORB(returnValue);
  5. }
复制代码
ORB.Create() 方法是OpenCV中用于创建ORB特征检测器的静态工厂方法,它提供了多个参数来定制ORB检测器的行为:
参数名默认值含义说明nFeatures500要保留的最大特征点数量scaleFactor1.2f金字塔缩放比率,大于1。scaleFactor=2表示经典金字塔,每下一层比上一层少4倍像素nLevels8金字塔层数。最小层尺寸等于输入图像尺寸/pow(scaleFactor, nlevels-firstLevel)edgeThreshold31不检测特征的边界区域大小,应大致匹配patchSize参数firstLevel0放置源图像的金字塔层级,之前的层级用上采样的源图像填充wtaK2生成定向BRIEF描述符每个元素所需的点数。默认值2表示取随机点对比较亮度,输出0/1响应scoreTypeHarris特征点评分类型。Harris_SCORE表示使用Harris算法对特征排序,FAST_SCORE是稍快但不太稳定的替代方案patchSize31定向BRIEF描述符使用的补丁大小,在较小的金字塔层上特征覆盖的感知图像区域会更大fastThreshold20FAST角点检测的阈值再来看下DetectAndCompute方法:
  1. public virtual void DetectAndCompute(InputArray image, InputArray? mask, out KeyPoint[] keypoints, OutputArray descriptors, bool useProvidedKeypoints = false)
  2. {
  3.     ThrowIfDisposed();
  4.     if (image == null)
  5.     {
  6.         throw new ArgumentNullException("image");
  7.     }
  8.     if (descriptors == null)
  9.     {
  10.         throw new ArgumentNullException("descriptors");
  11.     }
  12.     image.ThrowIfDisposed();
  13.     mask?.ThrowIfDisposed();
  14.     using VectorOfKeyPoint vectorOfKeyPoint = new VectorOfKeyPoint();
  15.     NativeMethods.HandleException(NativeMethods.features2d_Feature2D_detectAndCompute(ptr, image.CvPtr, Cv2.ToPtr(mask), vectorOfKeyPoint.CvPtr, descriptors.CvPtr, useProvidedKeypoints ? 1 : 0));
  16.     keypoints = vectorOfKeyPoint.ToArray();
  17.     GC.KeepAlive(this);
  18.     GC.KeepAlive(image);
  19.     GC.KeepAlive(mask);
  20.     descriptors.Fix();
  21.     GC.KeepAlive(descriptors);
  22. }
复制代码
DetectAndCompute 是OpenCV中特征检测器类的核心方法,用于在图像中检测关键点(特征点)并计算这些点的描述符。这是计算机视觉中特征匹配、物体识别、图像拼接等应用的基础。
查看参数含义:
参数名类型含义imageInputArray输入的灰度图像,大多数特征检测器要求单通道灰度图像maskInputArray?可选的掩码,用于指定在图像的哪些区域检测特征keypointsout KeyPoint[]输出的关键点数组,包含检测到的关键点信息descriptorsOutputArray输出的描述符,包含每个关键点的描述符useProvidedKeypointsbool是否使用提供的关键点查看得到的关键点数组:
2.png

特征匹配
进行汉明特征匹配:
  1. using var bf = new BFMatcher(NormTypes.Hamming, crossCheck: true);
  2. var matches = bf.Match(descriptors1, descriptors2);
复制代码
汉明匹配是一种基于汉明距离的二进制特征描述符匹配方法,通过计算两个二进制字符串之间不同位的数量来衡量相似度,主要用于ORB、BRISK、FREAK等二进制特征描述符的快速匹配。相比传统的欧几里得距离匹配,汉明匹配具有计算速度快、内存占用小的优势,只需简单的位运算和计数操作,特别适合实时应用和移动设备场景。在OpenCV中,通常使用BFMatcher配合NormTypes.Hamming来实现,通过设置距离阈值(如ORB通常为30-70)来筛选最佳匹配,广泛应用于特征匹配、物体识别和图像拼接等计算机视觉任务中。
查看BFMatcher类的这个构造函数:
  1. public BFMatcher(NormTypes normType = NormTypes.L2, bool crossCheck = false)
  2. {
  3.     NativeMethods.HandleException(NativeMethods.features2d_BFMatcher_new((int)normType, crossCheck ? 1 : 0, out ptr));
  4.     detectorPtr = null;
  5. }
复制代码
BFMatcher(Brute-Force Matcher,暴力匹配器)是OpenCV中用于特征描述符匹配的基础类,它通过遍历所有可能的描述符对来找到最佳匹配。
参数名类型默认值含义normTypeNormTypesNormTypes.L2距离度量类型,用于计算描述符之间的相似度crossCheckboolfalse是否启用交叉验证,确保匹配的对称性再来看下Match方法:
  1. public DMatch[] Match(Mat queryDescriptors, Mat trainDescriptors, Mat? mask = null)
  2. {
  3.     ThrowIfDisposed();
  4.     if (queryDescriptors == null)
  5.     {
  6.         throw new ArgumentNullException("queryDescriptors");
  7.     }
  8.     if (trainDescriptors == null)
  9.     {
  10.         throw new ArgumentNullException("trainDescriptors");
  11.     }
  12.     using VectorOfDMatch vectorOfDMatch = new VectorOfDMatch();
  13.     NativeMethods.HandleException(NativeMethods.features2d_DescriptorMatcher_match1(ptr, queryDescriptors.CvPtr, trainDescriptors.CvPtr, vectorOfDMatch.CvPtr, Cv2.ToPtr(mask)));
  14.     GC.KeepAlive(this);
  15.     GC.KeepAlive(queryDescriptors);
  16.     GC.KeepAlive(trainDescriptors);
  17.     GC.KeepAlive(mask);
  18.     return vectorOfDMatch.ToArray();
  19. }
复制代码
Match 是OpenCV中描述符匹配器的核心方法,用于在两组描述符之间找到最佳匹配对。这是特征匹配流程中的关键步骤,将查询描述符与训练描述符进行一对一匹配。
参数名类型默认值含义queryDescriptorsMat-查询描述符集合,通常来自第一幅图像trainDescriptorsMat-训练描述符集合,通常来自第二幅图像maskMat?null可选掩码,用于指定哪些描述符对可以匹配返回的是DMatch结构体数组,查看这个结构体
3.png

属性名类型含义QueryIdxint查询描述符索引,指向查询描述符集合中的第几个描述符TrainIdxint训练描述符索引,指向训练描述符集合中的第几个描述符ImgIdxint训练图像索引,当有多个训练图像时指定匹配来自哪个图像Distancefloat两个描述符之间的距离,值越小表示匹配质量越好
4.png

选取最好的10个匹配:
  1. var goodMatches = matches
  2.     .OrderBy(x => x.Distance)
  3.     .Take(10)
  4.     .ToArray();
复制代码
提取这些关键点坐标:
  1. var srcPts = goodMatches.Select(m => keyPoints1[m.QueryIdx].Pt).Select(p => new Point2d(p.X, p.Y));
  2. var dstPts = goodMatches.Select(m => keyPoints2[m.TrainIdx].Pt).Select(p => new Point2d(p.X, p.Y));
复制代码
计算单应性矩阵
  1. using var homography = Cv2.FindHomography(srcPts, dstPts, HomographyMethods.Ransac, 5, null);
复制代码
查看FindHomography方法:
  1. public static Mat FindHomography(IEnumerable<Point2d> srcPoints, IEnumerable<Point2d> dstPoints, HomographyMethods method = HomographyMethods.None, double ransacReprojThreshold = 3.0, OutputArray? mask = null, int maxIters = 2000, double confidence = 0.995)
  2. {
  3.      if (srcPoints == null)
  4.      {
  5.          throw new ArgumentNullException("srcPoints");
  6.      }
  7.      if (dstPoints == null)
  8.      {
  9.          throw new ArgumentNullException("dstPoints");
  10.      }
  11.      Point2d[] obj = (srcPoints as Point2d[]) ?? srcPoints.ToArray();
  12.      Point2d[] array = (dstPoints as Point2d[]) ?? dstPoints.ToArray();
  13.      NativeMethods.HandleException(NativeMethods.calib3d_findHomography_vector(obj, obj.Length, array, array.Length, (int)method, ransacReprojThreshold, ToPtr(mask), maxIters, confidence, out var returnValue));
  14.      GC.KeepAlive(mask);
  15.      mask?.Fix();
  16.      return new Mat(returnValue);
  17. }
复制代码
FindHomography 是OpenCV中用于计算最佳透视变换矩阵的核心方法,它能够找到将源平面点映射到目标平面点的单应性矩阵。这是计算机视觉中图像配准、拼接和三维重建的基础算法。
参数名类型默认值含义srcPointsIEnumerable-原始平面中的点坐标集合dstPointsIEnumerable-目标平面中的点坐标集合methodHomographyMethodsHomographyMethods.None计算单应性矩阵的方法ransacReprojThresholddouble3.0RANSAC方法中允许的最大重投影误差maskOutputArray?null可选输出掩码,标记内点和外点maxItersint2000RANSAC最大迭代次数confidencedouble0.995置信水平,范围0-1HomographyMethods 选项:
方法值含义适用场景HomographyMethods.None普通最小二乘法数据质量好,无外点HomographyMethods.RansacRANSAC算法存在外点和噪声HomographyMethods.Lmeds最小中值法外点比例适中HomographyMethods.RhoRHO算法对外点鲁棒性强
  1. int h = img1.Height, w = img1.Width;
  2. var img2Bounds = new[]
  3. {
  4.       new Point2d(0, 0),
  5.       new Point2d(0, h-1),
  6.       new Point2d(w-1, h-1),
  7.       new Point2d(w-1, 0),
  8.   };
  9. var img2BoundsTransformed = Cv2.PerspectiveTransform(img2Bounds, homography);
复制代码
定义图像边界然后变换图像边界。
  1. public static Point2d[] PerspectiveTransform(IEnumerable<Point2d> src, Mat m)
  2. {
  3.   if (src == null)
  4.   {
  5.       throw new ArgumentNullException("src");
  6.   }
  7.   if (m == null)
  8.   {
  9.       throw new ArgumentNullException("m");
  10.   }
  11.   using Mat<Point2d> mat = Mat.FromArray(src);
  12.   using Mat<Point2d> mat2 = new Mat<Point2d>();
  13.   NativeMethods.HandleException(NativeMethods.core_perspectiveTransform_Mat(mat.CvPtr, mat2.CvPtr, m.CvPtr));
  14.   GC.KeepAlive(m);
  15.   return mat2.ToArray();
  16. }
复制代码
PerspectiveTransform 是OpenCV中用于执行透视变换的核心方法,它能够对二维或三维点集合应用透视变换矩阵,实现坐标系的转换。这是图像几何变换中的基础操作,广泛应用于图像校正、拼接和增强现实等领域。
矩形绘制
  1. using var view = img2.Clone();
  2. var drawingPoints = img2BoundsTransformed.Select(p => (Point)p).ToArray();
  3. Cv2.Polylines(view, new[] { drawingPoints }, true, Scalar.Red, 3);
复制代码
查看Polylines方法:
  1. public static void Polylines(
  2.    Mat img,
  3.    IEnumerable<IEnumerable<Point>> pts,
  4.    bool isClosed,
  5.    Scalar color,
  6.    int thickness = 1,
  7.    LineTypes lineType = LineTypes.Link8,
  8.    int shift = 0)
  9. {
  10.    if (img is null)
  11.        throw new ArgumentNullException(nameof(img));
  12.    if (pts is null)
  13.        throw new ArgumentNullException(nameof(pts));
  14.    img.ThrowIfDisposed();
  15.    var ptsList = new List<Point[]>();
  16.    var nptsList = new List<int>();
  17.    foreach (var pts1 in pts)
  18.    {
  19.        var pts1Arr = pts1.ToArray();
  20.        ptsList.Add(pts1Arr);
  21.        nptsList.Add(pts1Arr.Length);
  22.    }
  23.    var ptsArr = ptsList.ToArray();
  24.    var npts = nptsList.ToArray();
  25.    var ncontours = ptsArr.Length;
  26.    using var ptsPtr = new ArrayAddress2<Point>(ptsArr);
  27.    NativeMethods.HandleException(
  28.        NativeMethods.imgproc_polylines_Mat(
  29.            img.CvPtr, ptsPtr.GetPointer(), npts, ncontours, isClosed ? 1 : 0, color, thickness, (int) lineType, shift));
  30.    GC.KeepAlive(img);
  31. }
复制代码
Polylines 是OpenCV中用于绘制一个或多个多边形曲线的绘图函数。它可以在图像上绘制连续的线段,形成闭合或开放的多边形形状,是计算机视觉中可视化检测结果、标注区域和绘制轮廓的重要工具。
参数名类型默认值含义imgMat-目标图像,要在其上绘制多边形ptsIEnumerable-多边形点集合的集合,每个内层集合代表一个多边形isClosedbool-是否闭合多边形,true表示闭合,false表示开放colorScalar-绘制颜色,BGR格式thicknessint1线条粗细,正数表示粗细,负数表示填充lineTypeLineTypesLineTypes.Link8线条类型,抗锯齿算法shiftint0坐标点的小数位数
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册