参考教程
依赖opencv扩展库,使用sifi匹配
保存配准信息
"./config/calibratedPara.yaml"
#include <iostream> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp> #include <opencv2/opencv.hpp> #include<opencv2/xfeatures2d.hpp> #include<opencv2/core/core.hpp> #define PATH_XMAL "./config/calibratedPara.yaml" #define IMG_WIDTH 2592//2592 #define IMG_HEIGHT 1944//2048 using namespace cv; using namespace std; using namespace cv::xfeatures2d;//只有加上这句命名空间,SiftFeatureDetector and SiftFeatureExtractor才可以使用 /****************************************************** *name :Rect CalcCorners(const Mat& H, const Mat& src) *function :通过H计算图片角点位置,返回左上和宽高 *time :2019-4-28 ********************************************************/ Rect CalcCorners(const Mat& H, const Mat& src) { double v1[3]; Mat _V1 = Mat(3, 1, CV_64FC1, v1); //左上角(0,0,1) Mat _V2 = (Mat_<double>(3, 1) << 0, 0, 1); _V1 = H * _V2; Point _left_top; _left_top.x = v1[0] / v1[2]; _left_top.y = v1[1] / v1[2]; //左下角(0,src.rows,1) _V2 = (Mat_<double>(3, 1) << 0, src.rows, 1); _V1 = H * _V2; Point _left_bottom; _left_bottom.x = v1[0] / v1[2]; _left_bottom.y = v1[1] / v1[2]; //右上角(src.cols,0,1) _V2 = (Mat_<double>(3, 1) << src.cols, 0, 1); _V1 = H * _V2; Point _right_top; _right_top.x = v1[0] / v1[2]; _right_top.y = v1[1] / v1[2]; //右下角(src.cols,src.rows,1) _V2 = (Mat_<double>(3, 1) << src.cols, src.rows, 1); _V1 = H * _V2; Point _right_bottom; _right_bottom.x = v1[0] / v1[2]; _right_bottom.y = v1[1] / v1[2]; int _x1 = (int)max(_left_bottom.x, _left_top.x); int _y1 = (int)max(_left_top.y, _right_top.y); int _x2 = (int)min(_right_top.x, _right_bottom.x); int _y2 = (int)min(_left_bottom.y, _right_bottom.y); cout << "point is " << _x1 << " " << _y1 << " " << _x2 << " " << _y2 << endl; if (_x2 > IMG_WIDTH) _x2 = IMG_WIDTH - 1; if (_y2 > IMG_HEIGHT) _y2 = IMG_HEIGHT - 1; if (_x1 < 0) _x1 = 0; if (_y1 < 0) _y1 = 0; cout << "point is " << _x1 << " " << _y1 << " " << _x2 << " " << _y2 << endl; return Rect(Point(_x1, _y1), Point(_x2, _y2)); //表示左上点和右下点 } Rect inscrRect; cv::Mat warpedPic; cv::Mat Homography; Mat compicCalibrate; int main() { //Create SIFT class pointer Ptr<Feature2D> f2d = xfeatures2d::SIFT::create(); //SiftFeatureDetector siftDetector; //Loading images Mat img_1 = imread("1.bmp"); Mat img_2 = imread("2.bmp"); if (!img_1.data || !img_2.data) { cout << "Reading picture error!" << endl; return false; } //Detect the keypoints double t0 = getTickCount();//当前 vector<KeyPoint> keypoints_1, keypoints_2; f2d->detect(img_1, keypoints_1); f2d->detect(img_2, keypoints_2); cout << "The keypoints number of img1 is:" << keypoints_1.size() << endl; cout << "The keypoints number of img2 is:" << keypoints_2.size() << endl; //Calculate descriptors (feature vectors) Mat descriptors_1, descriptors_2; f2d->compute(img_1, keypoints_1, descriptors_1); f2d->compute(img_2, keypoints_2, descriptors_2); double freq = getTickFrequency(); double tt = ((double)getTickCount() - t0) / freq; cout << "Extract SIFT Time:" << tt << "ms" << endl; //画关键点 Mat img_keypoints_1, img_keypoints_2; drawKeypoints(img_1, keypoints_1, img_keypoints_1, Scalar::all(-1), 0); drawKeypoints(img_2, keypoints_2, img_keypoints_2, Scalar::all(-1), 0); //imshow("img_keypoints_1",img_keypoints_1); //imshow("img_keypoints_2",img_keypoints_2); //Matching descriptor vector using BFMatcher BFMatcher matcher; vector<DMatch> matches; matcher.match(descriptors_1, descriptors_2, matches); cout << "The number of match:" << matches.size() << endl; //绘制匹配出的关键点 Mat img_matches; drawMatches(img_1, keypoints_1, img_2, keypoints_2, matches, img_matches); //imshow("Match image",img_matches); //计算匹配结果中距离最大和距离最小值 double min_dist = matches[0].distance, max_dist = matches[0].distance; for (int m = 0; m < matches.size(); m++) { if (matches[m].distance<min_dist) { min_dist = matches[m].distance; } if (matches[m].distance>max_dist) { max_dist = matches[m].distance; } } cout << "min dist=" << min_dist << endl; cout << "max dist=" << max_dist << endl; //筛选出较好的匹配点 vector<DMatch> goodMatches; for (int m = 0; m < matches.size(); m++) { if (matches[m].distance < 0.6*max_dist) { goodMatches.push_back(matches[m]); } } cout << "The number of good matches:" << goodMatches.size() << endl; //画出匹配结果 Mat img_out; //红色连接的是匹配的特征点数,绿色连接的是未匹配的特征点数 //matchColor – Color of matches (lines and connected keypoints). If matchColor==Scalar::all(-1) , the color is generated randomly. //singlePointColor – Color of single keypoints(circles), which means that keypoints do not have the matches.If singlePointColor == Scalar::all(-1), the color is generated randomly. //CV_RGB(0, 255, 0)存储顺序为R-G-B,表示绿色 drawMatches(img_1, keypoints_1, img_2, keypoints_2, goodMatches, img_out, Scalar::all(-1), CV_RGB(0, 0, 255), Mat(), 2); namedWindow("good Matches", 0); imshow("good Matches", img_out); //RANSAC匹配过程 vector<DMatch> m_Matches; m_Matches = goodMatches; int ptCount = goodMatches.size(); if (ptCount < 100) { cout << "Don't find enough match points" << endl; return 0; } //坐标转换为float类型 vector <KeyPoint> RAN_KP1, RAN_KP2; //size_t是标准C库中定义的,应为unsigned int,在64位系统中为long unsigned int,在C++中为了适应不同的平台,增加可移植性。 for (size_t i = 0; i < m_Matches.size(); i++) { RAN_KP1.push_back(keypoints_1[goodMatches[i].queryIdx]); RAN_KP2.push_back(keypoints_2[goodMatches[i].trainIdx]); //RAN_KP1是要存储img01中能与img02匹配的点 //goodMatches存储了这些匹配点对的img01和img02的索引值 } //坐标变换 vector <Point2f> p01, p02; for (size_t i = 0; i < m_Matches.size(); i++) { p01.push_back(RAN_KP1[i].pt); p02.push_back(RAN_KP2[i].pt); } /*vector <Point2f> img1_corners(4); img1_corners[0] = Point(0,0); img1_corners[1] = Point(img_1.cols,0); img1_corners[2] = Point(img_1.cols, img_1.rows); img1_corners[3] = Point(0, img_1.rows); vector <Point2f> img2_corners(4);*/ ////求转换矩阵 //Mat m_homography; //vector<uchar> m; //m_homography = findHomography(p01, p02, RANSAC);//寻找匹配图像 //求基础矩阵 Fundamental,3*3的基础矩阵 vector<uchar> RansacStatus; Mat Fundamental = findFundamentalMat(p01, p02, RansacStatus, FM_RANSAC); //重新定义关键点RR_KP和RR_matches来存储新的关键点和基础矩阵,通过RansacStatus来删除误匹配点 vector <KeyPoint> RR_KP1, RR_KP2; vector <DMatch> RR_matches; int index = 0; for (size_t i = 0; i < m_Matches.size(); i++) { if (RansacStatus[i] != 0) { RR_KP1.push_back(RAN_KP1[i]); RR_KP2.push_back(RAN_KP2[i]); m_Matches[i].queryIdx = index; m_Matches[i].trainIdx = index; RR_matches.push_back(m_Matches[i]); index++; } } cout << "RANSAC后匹配点数" << RR_matches.size() << endl; Mat img_RR_matches; drawMatches(img_1, RR_KP1, img_2, RR_KP2, RR_matches, img_RR_matches); namedWindow("After RANSAC", 0); imshow("After RANSAC", img_RR_matches); //等待任意按键按下 waitKey(1); vector<cv::Point2f> Pic1Point, Pic2Point; for (int i = 0; i < RR_matches.size(); i++) { Pic1Point.push_back(RR_KP1[RR_matches[i].queryIdx].pt); Pic2Point.push_back(RR_KP2[RR_matches[i].trainIdx].pt); } Homography = cv::findHomography(Pic1Point, Pic2Point, CV_RANSAC); //计算将p2投影到p1上的单映性矩阵 FileStorage fs(PATH_XMAL, FileStorage::WRITE); //单应矩阵保存 fs << "Homography" << Homography; warpPerspective(img_1, warpedPic, Homography, cv::Size(img_2.cols, img_2.rows));//第一路图像根据参数Homography变换映射到warpedPic图 inscrRect = CalcCorners(Homography, img_1);// 第一路图像根据参数Homography计算本土映射区域的起始点和宽高 fs << "inscrRect" << inscrRect;//保存在xml fs.release(); Rect cutRoi(inscrRect.x, inscrRect.y, inscrRect.width, inscrRect.height);// 定义一个抠图区域 Mat Pic1Roi = warpedPic(cutRoi).clone();//第一张变换图扣出对应区域 compicCalibrate.create(inscrRect.height, inscrRect.width * 2, CV_8UC3); // Mat Pic1Roi = warpedPic(inscrRect); Mat Pic2Roi = img_2(inscrRect); Pic1Roi.copyTo(compicCalibrate(Rect(0, 0, Pic1Roi.cols, Pic1Roi.rows))); Pic2Roi.copyTo(compicCalibrate(Rect(Pic1Roi.cols, 0, Pic2Roi.cols, Pic2Roi.rows))); namedWindow("martch", 0); imshow("martch", compicCalibrate); waitKey(0); }