特征点检测和匹配

来源:互联网 发布:java 多租户 编辑:程序博客网 时间:2024/05/16 13:44

兴趣点(interest points),或称作关键点(keypoints)、特征点(feature points) 被大量用于解决物体识别,图像识别、图像匹配、视觉跟踪、三维重建等一系列的问题。不再观察整幅图,而是选择某些特殊的点,然后对他们进行局部有的放矢的分析。如果能检测到足够多的这种点,同时他们的区分度很高,并且可以精确定位稳定的特征,那么这个方法就有使用价值。

特征点检测

  1. Harris 角点检测
  2. FAST 特征检测
  3. SURF 检测
  4. SIFT 检测
  5. MSER 检测

Harris 角点检测

OpenCv 中的 cornerHarris 函数可实现 Harris 角点检测,输出结果为浮点数类型的图像,其中每一项为对应位置的角点强度。然后使用阈值函数(threshold)进行阈值化处理,得到一组检测到的角点。

缺点:

  1. 需要多个参数,难以调优
  2. 获取的角点图形包含很多角点群,很难精确定位

Harris 算子提出了角点(特征点)的正式数学定义,它是基于两个正交方向上的强度变化率;然而,计算变化率需要计算图像的导数,计算复杂度比较高,效率较低,不适合实时处理。

OpenCV 特征检测器接口

OpenCV 2 中的通用特征检测器引入了一种新的通用接口用于不同的检测器。该接口定义了一个 KeyPoint 类以封装每个特征点的属性。对于 Harris 角点,只有位置是有用的。

  1. FastFeatureDetector:Fast 特征检测
  2. StarFeatureDetector:Star 特征检测
  3. SIFTFeatureDetector:SIFT 特征检测(nonfree中)
  4. SURFFeatureDetector:SURF 特征检测(nonfree中)
  5. ORBFeatureDetector:ORB 特征检测
  6. BRISKFeatureDetector:BRISK 特征检测
  7. MSERFeatureDetector:MSER 特征检测
  8. DenseFeatureDetector:Dense 特征检测

其他:

  1. GoodFeaturesToTrackDetector
  2. SimpleBlobDetector
  3. GridAdaptedFeatureDetector
  4. PyramidAdaptedFeatureDetector
  5. DynamicAdaptedFeatureDetector

使用示例:

Mat image = imread("...");vector<KeyPoint> keypoints;FastFeatureDetector fast(40);fast.detect(image, keypoints);

另外,OpenCV 同时提供了一个通用的特征点绘制函数:

drawKeypoints(image,        // 原始图像    keypoints,                  // 关键点容器    image,                      // 结果图像    Scalar(255, 255, 255),  // 关键点颜色    DrawMatchesFlags::DRAW_OVER_OUTIMG); // 绘制标志

FAST 特征点检测

角点:假定特征点周围的图像强度,通过检测候选像素周围一圈像素来决定是否接手一个特征点。与中心点差异较大的像素如果组成连续的圆弧,并且弧长大于圆周长的3/4,那么认为找到一个特征点。

优点:该算法可以获得非常快速的特征点检测,在需要考虑运行速度时可以选用,如在高帧率的视频序列中进行视觉跟踪。(如果是相机阵列,需要多个相机同时检测特征点,就要考虑速度的问题)

SURF 特征点检测

当尝试在不同图像之间匹配特征时,通常面临尺度变化的难题,也就是说,需要分析的图像在拍摄时与目标物体的距离时不同的,导致目标物体在图像中有不同的尺寸。如果尝试使用固定尺寸的相邻尺寸来匹配不同图像中的相同特征,那么由于尺度的变化,他们的强度模板并不会匹配。

SURF(Speeded Up Robust Features)特征——加速鲁棒特征。具有尺度不变性,主要思想是:每个检测到的特征点都伴随着对应的尺度因子。

使用示例:

Mat image = imread("...");vector<KeyPoint> keypoints;SurfFeatureDetector surf(40);surf.detect(image, keypoints);drawKeypoints(image,        // 原始图像    keypoints,                  // 关键点容器    image,                      // 结果图像    Scalar(255, 255, 255),  // 关键点颜色    DrawMatchesFlags::DRAW_OVER_OUTIMG); // 绘制标志

SURF 算法还将方向与每个特征联系使得他们具有旋转无关性,方向在圆圈中以放射线的形式绘出。

SURF 的实现如下:首先对每个像素计算 Hessian 矩阵以得到特征,该矩阵测量一个函数的局部曲率,给出曲率的强度,定义角点为具有较高局部曲率的图像点(即有多个方向具有高曲率),当 Hessian 值同时在空间域和尺度域上达到局部极大值时,认为找到了尺度不变的特征。

SIFT 特征点检测

SURF 算法是著名的尺度不变特征检测器 SIFT 的高效变种,但 SIFT 使用的是 Laplacian 滤波器响应而不是 Hessian 矩阵。

OpenCV 特征点描述子提取接口

OpenCV 2 中引入了一个通用类,用于提取不同的特征点描述子。

  1. SIFTDescriptorExtractor:对应 SIFT 特征点
  2. SURFDescriptorExtractor:对应 SURF 特征点
  3. BriefDescriptorExtractor:对应 Brief 特征点
  4. BRISKDescriptorExtractor:对应 BRISK 特征点
  5. ORBDescriptorExtractor:对应 ORB 特征点
  6. FREAKDescriptorExtractor:对应 FREAK 特征点

使用示例:

Mat image = imread("...");vector<KeyPoint> keypoints;SurfFeatureDetector surf(40);surf.detect(image, keypoints);// 构造surf描述子提取器SurfDescriptorExtractor surfDesc;// 提取surf描述子Mat descriptors;surfDesc.compute(image, keypoints, descriptors);

匹配

要想匹配同一场景的两幅图像:

  1. 检测每幅图像的特征点
  2. 提取每幅图像的特征点描述子
  3. 第一幅图的每个特征点描述子向量与第二幅图的每个特征点描述子向量比较,得分最高的一对描述子(两个向量距离最近)视为那个特征的最佳匹配。
  4. 重复所有的特征点

上述过程可以用 BruteForceMatcher 实现。

// 构造匹配器BruteForceMatcher<L2<float>> matcher;// 匹配两幅图像的描述子vector<DMatch> matches;matcher.match(descriptors1, descriptors2, matches);

输出结果是一个 DMatch 向量,Dmatch 是 OpenCV 定义的一个结构体,用于表示一对匹配的描述子。

为了让匹配操作可视化,OpenCV 也提供了一个函数以产生由两幅输入图像拼接成的图像,匹配的点由直线相连。

Mat imageMatches;drawMatches(image1, keypoints1,  // 第一幅图像及其特征点                image2, keypoints2,  // 第二幅图像及其特征点                matches,            // 匹配结果                imageMatches,       // 生成的图像                Scalar(255, 255, 255)); // 直线的颜色

当然,有些时候匹配的特征点较多,为了清晰的显示结果,我们往往只显示最好的一部分匹配点。通过下述方法实现:

// 第n个元素放在第n个位置,之前都是小于第n个元素,之后都大于nth_element(matches.begin(),    // 初始位置                 matches.begin() + 24, // 排序元素的位置                 matches.end());     // 终止位置

问题:由于场景中物体的对称性,一些局部匹配会产生歧义。

参考

参考《OpenCV 2 计算机视觉编程手册》

参考《The OpenCV Reference Manual-2.4.9.0》

代码

GitHub

0 0
原创粉丝点击