SIFT影象拼接入門教程
程式大概流程就是輸入兩幅影象,轉化成灰度圖,提取特徵點,對特徵點進行描述,描述後的特徵點進行匹配,選取幾個最優的來獲取投影對映矩陣,影象配準顯示影象。
從提取特徵點開始。計算機先是構造了尺度空間,尺度空間就是計算機在不同尺度下看某一個物體。差不都就是在模擬人觀察一個物體,從模糊到清晰到內部結構那種感覺。從第0層塔的最底層你的原始灰度圖開始,first Octave(0層塔)中從第二層到頂層為止,每一層是對下一層進行Laplacian變換,影象越來越模糊。然後next Octave(1層塔)第底層就是first Octave(0層塔)最底層長寬取一半,面積為它的四分之一。塔中各層間只是越來越模糊,它的解析度沒有變,而塔間的解析度確實越來越低。右邊相減就構成了左邊的高斯差分尺度空間。上中下三層找絕對值極值
然後是對特徵點進行描述。就是給他加方向,匹配的時候要用。如圖每個特徵點都有三個描述資訊(尺度空間,模長,方向)。然後是進行匹配我們採用關鍵點特徵向量的歐式距離來作為兩幅影象中關鍵點的相似性判定度量。先找出影象1中的某個關鍵點,再找出其與影象2中歐式距離最近的前兩個關鍵點,在這兩個關鍵點中,如果最近的距離除以次近的距離少於某個比例閾值,則接受這一對匹配點。然後是求單應型矩陣,可以這樣理解。兩架相機拍同一空間上得到兩幅影象AB,其中一幅A在另一幅B存在一種變換而且是一一對應的關係,他們之間可以用矩陣表示 這個矩陣用單應矩陣。最後按照這個單應型矩陣進行配準就可以了。
#include <highgui.h> #include <nonfree\nonfree.hpp> #include <cv.h> #include "opencv2/legacy/legacy.hpp" #include <iostream> using namespace std; using namespace cv; Point2f getTransformPoint(const Point2f originalPoint, const Mat &transformMaxtri); int main(int argc,char** argv){ Mat ima1=imread(argv[1]); Mat ima2=imread(argv[2]); if(ima1.empty()||ima2.empty()){ return 0; } Mat ima01,ima02; cvtColor(ima1,ima01,CV_RGB2GRAY); cvtColor(ima2,ima02,CV_RGB2GRAY); //提取特徵點 SiftFeatureDetector siftdetector(800); vector<KeyPoint> keypoint1,keypoint2; siftdetector.detect(ima01,keypoint1); siftdetector.detect(ima02,keypoint2); //找到特徵點後就進行描述 SiftDescriptorExtractor siftextractor; Mat imadesc1,imadesc2; siftextractor.compute(ima01,keypoint1,imadesc1); siftextractor.compute(ima02,keypoint2,imadesc2); //對特徵點進行匹配 FlannBasedMatcher matcher; vector<DMatch> matchpoints;//兩個函式queryIdx表示輸入影象的特徵描述子,trainIdx表示訓練影象的特徵描述子 matcher.match(imadesc1,imadesc2,matchpoints,Mat()); //選取前面幾個最優匹配點 sort(matchpoints.begin(),matchpoints.end()); vector<Point2f> imagepoints1,imagepoints2;//point2f浮點數x,y。point2d單精度x,y for(int i=0;i<10;i++){ imagepoints1.push_back(keypoint1[matchpoints[i].queryIdx].pt);//push_back在vector類尾部加一個數據 imagepoints2.push_back(keypoint2[matchpoints[i].trainIdx].pt); } //獲取投影對映矩陣 Mat homo=findHomography(imagepoints1,imagepoints2,CV_RANSAC);//求單應型矩陣 理解在兩視幾何中,可以這樣理解,兩架相機拍同一空間上得到兩幅影象AB,其中一幅A在另一幅B存在一種變換而且是一一對應的關係,他們之間可以用矩陣表示 這個矩陣用單應矩陣 Mat adjustMat=(Mat_<double>(3,3)<<1.0,0,ima01.cols,0,1.0,0,0,0,1.0); Mat adjustHomo=adjustMat*homo; //獲取最強匹配點在原圖,矩陣變換後的圖的位置 Point2f originalLinkePoint,targetLinkPoint,basedImagePoint; originalLinkePoint=keypoint1[matchpoints[0].queryIdx].pt; targetLinkPoint=getTransformPoint(originalLinkePoint,adjustHomo); basedImagePoint=keypoint2[matchpoints[0].trainIdx].pt; //影象配準 Mat imageTransform1; warpPerspective(ima1,imageTransform1,adjustHomo,Size(ima2.cols+ima01.cols+10,ima2.rows)); namedWindow("拼接結果"); imshow("拼接結果",imageTransform1); waitKey(0); destroyAllWindows(); return 0; } Point2f getTransformPoint(const Point2f originalPoint, const Mat &transformMaxtri) { Mat originelP, targetP; originelP = (Mat_<double>(3, 1) << originalPoint.x, originalPoint.y, 1.0); targetP = transformMaxtri*originelP; float x = targetP.at<double>(0, 0) / targetP.at<double>(2, 0); float y = targetP.at<double>(1, 0) / targetP.at<double>(2, 0); return Point2f(x, y); }
借鑑了
http://blog.csdn.net/abcjennifer/article/details/7639681
http://blog.csdn.net/jinshengtao/article/details/50043797?locationNum=3&fps=1
http://blog.csdn.net/dcrmg/article/details/52578732
請批評指教。另外不懂不同塔不同層的特徵點他怎麼彙總到原始影象的?