Opencv 实现 Surf 特征点和 Homography 匹配物体
另一篇博客已经初步了解单映性的原理和计算,这篇就借助 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;
}
效果图:
这里也同时贴出计算出来的 H(Homography 矩阵):
贴出 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 技术交流群。
上一篇: 矢量的叉积
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论