Opencv 实现 Surf 特征点和 Homography 匹配物体

发布于 2024-08-25 04:06:51 字数 5563 浏览 7 评论 0

另一篇博客已经初步了解单映性的原理和计算,这篇就借助 Opencv 库来实战。

目的:在一张背景图中寻找目标物体,并标注出来。

思路

  • 1.通过 SurfFeatureDetector 分别提取出 Object 图片和 Scene 图片各自的特征点(Surf 特征点)。
  • 2.通过 SurfDescriptorExtractor 分别计算出 Object 图片和 Scene 图片对特征点的描述。
  • 3.采用 FlannBasedMatcher 匹配器将 Object 和 Scene 各自的特征点匹配起来。(FLANN - Fast Library for Approximate Nearest Neighbors)
  • 4.提取出一定条件下的 Good_Matches,比如小于(3 * 最小匹配距离)的 Matches。
  • 5.通过 findHomography 函数来计算出 Object 的特征点(Good_Matches) 和 Scene 的特征点(Good_Matches) 之间的单映性矩阵H
  • 6.通过 perspectiveTransform (对二维或者三维矢量进行透射变换,也就是对输入二维坐标点或者三维坐标点进行投射变换) 函数对 Object 图像的四个交点进行投影映射到 Scene 图像上,并且用线段标识出来。

源码如下:

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/calib3d/calib3d.hpp>
using namespace cv;
using namespace std;

int main()
{
Mat img_object = imread("./res/box.png", CV_LOAD_IMAGE_GRAYSCALE);
Mat img_scene = imread("./res/box_in_scene.png", CV_LOAD_IMAGE_GRAYSCALE);

int minHessian = 400;

SurfFeatureDetector detector(minHessian);
vector<KeyPoint> kp_object, kp_scene;

detector.detect(img_object,kp_object);
detector.detect(img_scene, kp_scene);

SurfDescriptorExtractor extractor;
Mat descriptor_object, descriptor_scene;
extractor.compute(img_object, kp_object, descriptor_object);
extractor.compute(img_scene, kp_scene, descriptor_scene);

FlannBasedMatcher matcher;
vector<DMatch> matches;
matcher.match(descriptor_object, descriptor_scene, matches);

double min_dist = 100, max_dist = img_object.rows > img_object.cols ? img_object.rows:img_object.cols;
for (int i = 0; i < descriptor_object.rows;i++)
{
double dist = matches[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}

vector<DMatch> good_matchs;

for (int i = 0; i < descriptor_object.rows;i++)
{
if (matches[i].distance < 3 * min_dist )
{
good_matchs.push_back(matches[i]);
}
}

Mat img_matches;
drawMatches(img_object, kp_object, img_scene, kp_scene,
good_matchs,img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

//-- Localize the object
vector<Point2f> obj;
vector<Point2f> scene;
for (int i = 0; i < good_matchs.size();i++)
{
obj.push_back(kp_object[good_matchs[i].queryIdx].pt);
scene.push_back(kp_scene[good_matchs[i].trainIdx].pt);
}

Mat H = findHomography(obj, scene, CV_RANSAC);
vector<Point2f> obj_corners(4);
obj_corners[0] = Point(0, 0);
obj_corners[1] = Point(img_object.cols, 0);
obj_corners[2] = Point(img_object.cols, img_object.rows);
obj_corners[3] = Point(0, img_object.rows);
vector<Point2f> scene_corners(4);
perspectiveTransform(obj_corners, scene_corners, H);

line(img_matches, scene_corners[0] + Point2f(img_object.cols, 0), scene_corners[1] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 2);
line(img_matches, scene_corners[1] + Point2f(img_object.cols, 0), scene_corners[2] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 2);
line(img_matches, scene_corners[2] + Point2f(img_object.cols, 0), scene_corners[3] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 2);
line(img_matches, scene_corners[3] + Point2f(img_object.cols, 0), scene_corners[0] + Point2f(img_object.cols, 0), Scalar(0, 255, 0), 2);

imwrite("./res/Img_matches.jpg", img_matches);
imshow("Img_Matches", img_matches);
waitKey();
return 0;
}

效果图:

DetectObject

这里也同时贴出计算出来的 H(Homography 矩阵):

DetectObject

贴出 Opencv 中 Homography 相关的函数 Api 及功能:

  • estimateRigidTransform():计算多个二维点对或者图像之间的最优仿射变换矩阵 (2 行 x3 列),H 可以是部分自由度,比如各向一致的切变。
  • getAffineTransform():计算 3 个二维点对之间的仿射变换矩阵 H(2 行 x3 列),自由度为 6.
  • warpAffine():对输入图像进行仿射变换
  • findHomography: 计算多个二维点对之间的最优单映射变换矩阵 H(3 行 x3 列) ,使用最小均方误差或者 RANSAC 方法 。
  • getPerspectiveTransform():计算 4 个二维点对之间的透射变换矩阵 H(3 行 x3 列)
  • warpPerspective(): 对输入图像进行透射变换
  • perspectiveTransform():对二维或者三维矢量进行透射变换,也就是对输入二维坐标点或者三维坐标点进行投射变换。
  • estimateAffine3D:计算多个三维点对之间的最优三维仿射变换矩阵 H (3 行 x4 列)
  • transform():对输入的 N 维矢量进行变换,可用于进行仿射变换、图像色彩变换.
  • findFundamentalMat:计算多个点对之间的基矩阵 H
  • 如何计算 3 个二维点对之间的仿射变换矩阵?
    使用 getAffineTransform()。
  • 如何计算多个二维点对之间的仿射变换矩阵(使用误差最小准则 )?
    使用 estimateRigidTransform() 或者 findHomography。
  • 如何计算 4 个二维点对之间的透射变换?
    使用 getPerspectiveTransform()。
  • 如何计算多个三维点对之间的仿射变换?
    使用 estimateAffine3D。
  • 如何对输入图像进行仿射变换?
    使用 warpAffine()。
  • 如何对输入图像进行透射变换?
    使用 perspectiveTransform()。
  • 如何对输入的二维点对进行仿射变换?
    使用 transform()。
  • 如何对输入的三维点对进行投射变换?
    使用 perspectiveTransform()。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

傾旎

暂无简介

0 文章
0 评论
21 人气
更多

推荐作者

内心激荡

文章 0 评论 0

JSmiles

文章 0 评论 0

左秋

文章 0 评论 0

迪街小绵羊

文章 0 评论 0

瞳孔里扚悲伤

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文