这个程序是本人用于OpenCV项目学习而写的,其中很多代码都是从网上或cook book 中借鉴而来的。由于本人还是菜鸟,程序中难免会出现很多不合理的地方,希望各位高手能赐教或交流。
这个程序在linux 的ubuntu 中能运行,没试过其他平台,但应该是大同小异的。其中代码都是C++风格,用了surf算法寻找特征点,用flann算法匹配特征点,有简单拼接模式和加权平均匹配模式(加权匹配模式还有优化的空间,其中的遍历图像还可以用其他方法来提升速度,但由于代码还没调好,先发一下初始版)。
最后感谢你看了我的代码,希望如果你对算法或图像处理甚至对电子有研究或有兴趣的话,可以加我QQ交流。
QQ:448680688
//#include <stdio.h> #include "opencv2/highgui/highgui.hpp" #include "opencv2/core/core.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/features2d/features2d.hpp" #include "opencv2/nonfree/nonfree.hpp" #include "opencv2/calib3d/calib3d.hpp" //#include "opencv2/legacy/legacy.hpp" #include <QDebug> #include <iostream> #include <fstream> #include <QApplication> #include <QTextStream> #include <ImageMosaic.h> //#include <harrisDetector.h> using namespace cv; void ImageMosaic::computeSIFT(){ cv::Mat g1(img1,cv::Rect(0,0,img1.cols,img1.rows)); cv::Mat g2(img2,cv::Rect(0,0,img2.cols,img2.rows)); cv::cvtColor(g1,g1,CV_BGR2GRAY); cv::cvtColor(g2,g2,CV_BGR2GRAY); cv::SURF sift; sift(g1, cv::Mat(), keypoints_roi, descriptor_roi); /* get keypoints of ROI image */ sift(g2, cv::Mat(), keypoints_img, descriptor_img); /* get keypoints of the image */ } void ImageMosaic::matchKeypoint(){ cv::FlannBasedMatcher matcher; /* FLANN based matcher to match keypoints */ int i; double max_dist = 0; double min_dist = 1000; //int dist=80; std::vector<cv::DMatch> matches; matcher.match(descriptor_roi, descriptor_img, matches); //try to understand what it is! ! ! //-- Quick calculation of max and min distances between keypoints ;it's said that the distance must //less than 3*min,but i can't find the resource for( int i = 0; i < descriptor_roi.rows; i++ ) { double dist = matches[i].distance; if( dist < min_dist ) min_dist = dist; if( dist > max_dist ) max_dist = dist; } for (i=0; i < descriptor_roi.rows; i++) { if (matches[i].distance < 3*min_dist) { good_matches.push_back(matches[i]); } } //Mat img_matches; cv:: drawMatches(img1, keypoints_roi, img2, keypoints_img, good_matches, img_matches, cv::Scalar(200,200,200)); // , vector<char>(),DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); cv::namedWindow("Matches"); cv::imshow("Matches",img_matches); } void ImageMosaic::findH(){ std::vector<cv::Point2f> keypoints1, keypoints2; for (int i=0; i<good_matches.size(); i++) { keypoints1.push_back(keypoints_img[good_matches[i].trainIdx].pt); keypoints2.push_back(keypoints_roi[good_matches[i].queryIdx].pt); } H = cv::findHomography( keypoints1, keypoints2, CV_RANSAC ); // CalcFourCorner(H,img2); } void ImageMosaic::CalcFourCorner() { //计算图2的四个角经矩阵H变换后的坐标 double v2[]={0,0,1};//左上角 double v1[3];//变换后的坐标值 cv::Mat V2 = cv::Mat(3,1,CV_64FC1,v2); cv::Mat V1 = cv::Mat(3,1,CV_64FC1,v1);qDebug("p1"); cv::gemm(H,V2,1,1,0,V1);//矩阵乘法////the src3 can't be 0,so if you want to ignore the src3, //you should set the beater as 0 leftTop.x = cvRound(v1[0]/v1[2]); leftTop.y = cvRound(v1[1]/v1[2]); //cvCircle(xformed,leftTop,7,CV_RGB(255,0,0),2); //将v2中数据设为左下角坐标 v2[0] = 0; v2[1] = img2.rows; V2 = cv::Mat(3,1,CV_64FC1,v2); V1 = cv::Mat(3,1,CV_64FC1,v1); cv::gemm(H,V2,1,1,0,V1); leftBottom.x = cvRound(v1[0]/v1[2]); leftBottom.y = cvRound(v1[1]/v1[2]); //cvCircle(xformed,leftBottom,7,CV_RGB(255,0,0),2); //将v2中数据设为右上角坐标 v2[0] = img2.cols; v2[1] = 0; V2 = cv::Mat(3,1,CV_64FC1,v2); V1 = cv::Mat(3,1,CV_64FC1,v1); cv::gemm(H,V2,1,1,0,V1); rightTop.x = cvRound(v1[0]/v1[2]); rightTop.y = cvRound(v1[1]/v1[2]); //cvCircle(xformed,rightTop,7,CV_RGB(255,0,0),2); //将v2中数据设为右下角坐标 v2[0] = img2.cols; v2[1] = img2.rows; V2 = cv::Mat(3,1,CV_64FC1,v2); V1 = cv::Mat(3,1,CV_64FC1,v1); cv::gemm(H,V2,1,1,0,V1); rightBottom.x = cvRound(v1[0]/v1[2]); rightBottom.y = cvRound(v1[1]/v1[2]); //cvCircle(xformed,rightBottom,7,CV_RGB(255,0,0),2); } void ImageMosaic::showSimpleImg(){ // show stitchImage cv::Mat stitchedImage; int mRows = img2.rows; if (img1.rows> img2.rows) { mRows = img1.rows; } stitchedImage = cv::Mat::zeros(cv::min(rightTop.x,rightBottom.x), mRows, CV_8UC3); cv::warpPerspective(img2,stitchedImage,H,cv::Size(cv::min(rightTop.x,rightBottom.x),mRows)); cv::Mat half(stitchedImage,cv::Rect(0,0,img1.cols,img1.rows)); // cv::namedWindow("IMG1"); // cv::imshow("IMG1",stitchedImage); // cv::namedWindow("Test"); // cv::imshow("Test",half); img1.copyTo(half); // cv::Mat stitchedImage_simple=stitchedImage.clone(); cv::imshow("stitchedImage",stitchedImage);//(cv::Rect(0,0,img1.cols+stitchedImage.cols,img1.rows))); } void ImageMosaic::showAVImage(){ cv::Mat stitchedImage; int mRows = img2.rows; if (img1.rows> img2.rows) { mRows = img1.rows; } stitchedImage = cv::Mat::zeros(cv::min(rightTop.x,rightBottom.x), mRows, CV_8UC3); cv::warpPerspective(img2,stitchedImage,H,cv::Size(cv::min(rightTop.x,rightBottom.x),mRows)); cv::Mat xformed_proc=stitchedImage.clone(); cv::Mat xformed=stitchedImage.clone(); cv::Mat img1_ROI=img1(cv::Rect(0,0,cv::min(leftTop.x,leftBottom.x),xformed_proc.rows)); cv::Mat xformed_ROI=xformed_proc(cv::Rect(0,0,cv::min(leftTop.x,leftBottom.x),xformed_proc.rows)); cv::addWeighted(img1_ROI,1,xformed_ROI,0,0, xformed_proc(cv::Rect(0,0,cv::min(leftTop.x,leftBottom.x),xformed_proc.rows))); cv::namedWindow("Temp"); cv::imshow("Temp",xformed_proc); int nl=xformed_proc.rows; // int nc=xformed_proc.cols*xformed_proc.channels(); int nc1=img1.cols; int start=cv::min(leftTop.x,leftBottom.x); // double processWidth=img1.cols*img1.channels()-start; double processWidth=img1.cols-start; double alpha=1; // if(xformed_proc.isContinuous()){ // nc*=nl; // nl=1; // } for(int j=0;j<nl;j++){ uchar *data=xformed_proc.ptr<uchar>(j); uchar *data_img1=img1.ptr<uchar>(j); uchar *data_xformed=xformed_proc.ptr<uchar>(j); for(int i=start;i<nc1;i++){ if(data_xformed[i]<50 &&data_xformed[i+1]<50 &&data_xformed[i+2]<50){ alpha=1; } else{ alpha = (processWidth-(i-start)) / processWidth ; } data[i*3]=data_img1[i*3]*alpha+data_xformed[i*3]*(1-alpha); data[i*3+1]=data_img1[i*3+1]*alpha+data_xformed[i*3+1]*(1-alpha); data[i*3+2]=data_img1[i*3+2]*alpha+data_xformed[i*3+2]*(1-alpha); // data[i]=0; // data[i+1]=0; // data[i+2]=0; } } cv::namedWindow("Final"); cv::imshow("Final",xformed_proc); // cv::Mat xformedROI=stitchedImage(cv::Rect(0,0,cv::min(leftTop.x,leftBottom.x),xformed_proc.cols)); // cv::Mat xformed_procROI=img1(cv::Rect(0,0,cv::min(leftTop.x,leftBottom.x),xformed_proc.cols)); // cv::addWeighted(img1,1,stitchedImage,0,0,xformed_proc) ; // cv::imshow("xformed_proc",xformed_proc); }
另外,完整版在这里:点击打开链接