surf特征+FLANN特征匹配+knn筛选匹配点+单应性矩阵映射
#include "stdafx.h" #include <stdio.h> #include <iostream> #include <opencv2/core/core.hpp> #include "opencv2/nonfree/features2d.hpp" #include<opencv2/legacy/legacy.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv; using namespace std; int main( ) { Mat img_1 = imread( "C:\\temp\\PyramidPattern.jpg", CV_LOAD_IMAGE_GRAYSCALE ); Mat img_2 = imread( "C:\\temp\\PyramidPatternTest.bmp", CV_LOAD_IMAGE_GRAYSCALE ); if( !img_1.data || !img_2.data ) { return -1; } //-- Step 1: Detect the keypoints using SURF Detector int minHessian = 400; SurfFeatureDetector detector( minHessian ); vector<KeyPoint> keypoints_1, keypoints_2; detector.detect( img_1, keypoints_1 ); detector.detect( img_2, keypoints_2 ); //-- Step 2: Calculate descriptors (feature vectors) SurfDescriptorExtractor extractor; Mat descriptors_1, descriptors_2; extractor.compute( img_1, keypoints_1, descriptors_1 ); extractor.compute( img_2, keypoints_2, descriptors_2 ); //-- Step 3: Matching descriptor vectors using FLANN matcher FlannBasedMatcher matcher; vector< DMatch > matches; vector<vector<DMatch>> m_knnMatches; matches.clear(); const float minRatio=1.f / 1.5f; matcher.knnMatch(descriptors_1,descriptors_2,m_knnMatches,2); for (int i=0; i<m_knnMatches.size(); i++) { const DMatch& bestMatch=m_knnMatches[i][0]; const DMatch& betterMatch=m_knnMatches[i][1]; float distanceRatio=bestMatch.distance/betterMatch.distance; if (distanceRatio<minRatio) { matches.push_back(bestMatch); } } vector< DMatch > good_matches; if(!matches.size()) { cout<<"matches is empty! "<<endl; return -1; } else if (matches.size()<4) { cout<<matches.size()<<" points matched is not enough "<<endl; } else //单应性矩阵的计算最少得使用4个点 { for( int i = 0; i < matches.size(); i++ ) { good_matches.push_back(matches[i]); } Mat img_matches; drawMatches( img_1, keypoints_1, img_2, keypoints_2, good_matches, img_matches, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); //☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★ //-- Localize the object from img_1 in img_2 vector<Point2f> obj; vector<Point2f> scene; for( int i = 0; i < good_matches.size(); i++ ) { //-- Get the keypoints from the good matches obj.push_back( keypoints_1[ good_matches[i].queryIdx ].pt ); scene.push_back( keypoints_2[ good_matches[i].trainIdx ].pt ); } Mat H = findHomography( obj, scene, CV_RANSAC ); //-- Get the corners from the image_1 ( the object to be "detected" ) vector<Point2f> obj_corners(4); obj_corners[0]=cvPoint(0,0); obj_corners[1]=cvPoint( img_1.cols, 0 ); obj_corners[2]=cvPoint(img_1.cols,img_1.rows); obj_corners[3]=cvPoint(0,img_1.rows); vector<Point2f> scene_corners(4); perspectiveTransform( obj_corners, scene_corners, H); for( int i = 0; i < 4; i++ ) { /* 作用和perspectiveTransform一样 double x = obj_corners[i].x; double y = obj_corners[i].y; double Z = 1./( H.at<double>(2,0)*x + H.at<double>(2,1)*y + H.at<double>(2,2) ); double X = ( H.at<double>(0,0)*x + H.at<double>(0,1)*y + H.at<double>(0,2) )*Z; double Y = ( H.at<double>(1,0)*x + H.at<double>(1,1)*y + H.at<double>(1,2) )*Z; scene_corners[i] = cvPoint( cvRound(X) + img_1.cols, cvRound(Y) );*/ scene_corners[i].x+=img_1.cols; } line( img_matches, scene_corners[0], scene_corners[1], Scalar(0, 255, 0), 2 ); line( img_matches, scene_corners[1], scene_corners[2], Scalar( 0, 255, 0), 2 ); line( img_matches, scene_corners[2], scene_corners[3], Scalar( 0, 255, 0), 2 ); line( img_matches, scene_corners[3], scene_corners[0], Scalar( 0, 255, 0), 2 ); imshow( "Good Matches & Object detection", img_matches ); } waitKey(0); return 0; }
1.边界
2.角点(兴趣点)
3.斑点(兴趣区域)
角点是图像的一个局部特征,常用的有harris角点,其算法是一种直接基于灰度图像的,稳定性高,尤其对L型角点检测精度高,但由于采用了高斯滤波,运算速度相对较慢,角点信息有丢失和位置偏移的现象,而且角点提取有聚簇现象。具体在OpenCV中的实现就是使用函数cornerHarris。
除了Harris角点检测,还有Shi-Tomasi角点检测,goodFeaturesToTrack角点检测,将找到的点再用FindCornerSubPix()来找出强特征点。也可以自己制作角点检测的函数,需要用到cornerMinEigenVal函数和minMaxLoc函数,最后的特征点选取,判断条件要根据自己的情况编辑。如果对特征点,角点的精度要求更高,可以用cornerSubPix函数将角点定位到子像素。
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。
cvStereoCalibrate():中T类型要求了3*1,对与其他形参float和double都支持
cvStereoRectigy():只支持double类型
cvStereoRectifyUncalibrated():立体校正算法Hartley算法效果和F矩阵及图像数量有关,
ps:
【如果用cvStereoCalibrate()函数计算处理的F矩阵效果和Bouguet算法(cvStereoRectigy())效果一样】
【如果用cvFindFundamentalMat()函数计算F矩阵,没有Bougut算法好】
【用Hartley算法(cvStereoRectifyUncalibrated())校正时,别忘了实现要用cvUndistortPoints()去除相机畸变,Bouguet算法(cvStereoRectigy())没有这个要求,实际上它在函数内部校正了相机的畸变。】
答:使用estimateRigidTransform()。
问题3:如何计算多个二维点对之间的投影变换矩阵(使用误差最小准则 )
答:findHomography()。
问题4:如何计算4个二维点对之间的透射变换?