opencv 基於sift的多張圖片全景圖拼接
阿新 • • 發佈:2019-01-10
這裡是基於sift來尋找特徵點經行影象的匹配的原理來進行影象拼接的,具體步驟如下:
1、利用sift特徵探測器來檢測出兩幅圖片的sift特徵點
2、根據上一步提取到的特徵點來提取特徵向量,使用SiftDescriptorExtractor對完成特徵向量提取的工作,通過他對關鍵點周圍鄰域內的畫素分塊進行梯度運算,得到128維的特徵向量
3、進行特徵向量臨近匹配,找到兩幅圖之間相互匹配的特徵點
匹配之後的結果如下圖:(2張圖片的)
4、在第一次匹配的基礎上再進行篩選,算出匹配的特徵向量之間的距離,然後只去向量距離小於2倍的最小距離的特徵點
這樣得到的結果為:
6、判斷兩幅圖在結果圖中的左邊還是右邊,這裡是根據特徵點在影象的位置來判斷的,求出影象上特徵點的x座標大於影象寬的一半的特徵點數量與總的特徵點數量的比值,比值大的就是在結果圖的右邊
部分拼接結果:
原始碼為:(為了方便測試我把影象都命名為1.jpg 2.jpg .......)
#include <opencv2/opencv.hpp> #include<opencv2/nonfree/nonfree.hpp> #include<opencv2/legacy/legacy.hpp> #include<vector> #include<iostream> #include<sstream> #include<string> #include<time.h> using namespace std; using namespace cv; Mat Stitched(Mat img1, Mat img2) { Mat g1(img1, Rect(0, 0, img1.cols, img1.rows)); Mat g2(img2, Rect(0, 0, img2.cols, img2.rows)); cvtColor(g1, g1, CV_BGR2GRAY); cvtColor(g2, g2, CV_BGR2GRAY); SiftFeatureDetector siftdet; vector<KeyPoint>kp1, kp2; //SIFT sift; SiftDescriptorExtractor extractor; Mat descriptor1, descriptor2; FlannBasedMatcher matcher; vector<DMatch> matches, goodmatches; /*進行特徵點提取*/ siftdet.detect(g1, kp1); siftdet.detect(g2, kp2); /* 進行特徵向量提取 */ extractor.compute(g1, kp1, descriptor1); extractor.compute(g2, kp2, descriptor2); /* 進行特徵向量臨近匹配 */ matcher.match(descriptor1, descriptor2, matches); Mat firstmatches; /*畫出第一次匹配的結果*/ drawMatches(img1, kp1, img2, kp2, matches, firstmatches, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); imshow("first_matches", firstmatches); /* 下面計算向量距離的最大值與最小值 */ double max_dist = 0; double min_dist = 1000; for (int i = 0; i < descriptor1.rows; i++) { if (matches[i].distance > max_dist) { max_dist = matches[i].distance; } if (matches[i].distance < min_dist) { min_dist = matches[i].distance; } } cout << "The max distance is: " << max_dist << endl; cout << "The min distance is: " << min_dist << endl; for (int i = 0; i < descriptor1.rows; i++) { if (matches[i].distance < 2 * min_dist) { goodmatches.push_back(matches[i]); } } Mat img_matches; /*第二次篩選後的結果*/ drawMatches(img1, kp1, img2, kp2, goodmatches, img_matches, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); imshow("good_matches", img_matches); vector<Point2f> keypoints1, keypoints2; for (int i = 0; i < goodmatches.size(); i++) { keypoints1.push_back(kp1[goodmatches[i].queryIdx].pt); keypoints2.push_back(kp2[goodmatches[i].trainIdx].pt); } /*計算單應矩陣*/ Mat H = findHomography(keypoints1, keypoints2, CV_RANSAC); Mat stitchedImage; int mRows = img2.rows; if (img1.rows> img2.rows) { mRows = img1.rows; } /*判斷影象在左邊還是在右邊*/ int propimg1 = 0, propimg2 = 0; for (int i = 0; i < goodmatches.size(); i++) { if (kp1[goodmatches[i].queryIdx].pt.x > img1.cols / 2) { propimg1++; } if (kp2[goodmatches[i].trainIdx].pt.x > img2.cols / 2) { propimg2++; } } bool flag = false; Mat imgright; Mat imgleft; if ((propimg1 / (goodmatches.size() + 0.0)) > (propimg2 / (goodmatches.size() + 0.0))) { imgleft = img1.clone(); flag = true; } else { imgleft = img2.clone(); flag = false; } if (flag) { imgright = img2.clone(); flag = false; } else { imgright = img1.clone(); } /*把上邊求得的右邊的影象經過矩陣H轉換到stitchedImage中對應的位置*/ warpPerspective(imgright, stitchedImage, H, Size(img2.cols + img1.cols, mRows)); /*把左邊的影象放進來*/ Mat half(stitchedImage, Rect(0, 0, imgleft.cols, imgleft.rows)); imgleft.copyTo(half); return stitchedImage; } int main() { Mat img1 = imread("1.jpg"); Mat stitchedImage; int n; cout << "Dataset2" << endl; cout << "請輸入想拼接的圖片數量(大於1小於18)" << endl; cin >> n; cout << "輸入成功,開始計時" << endl; clock_t start,finish; double totaltime; start=clock(); resize(img1, img1, Size(img1.cols / 4, img1.rows / 4)); for (int k = 2; k <= n; k++) { stringstream stream; string str; stream << k; stream >> str; string filename = str + ".jpg"; cout << "正在拼接......." << filename << endl; Mat img = imread(filename); resize(img, img, Size(img.cols / 4, img.rows / 4)); stitchedImage = Stitched(img1, img); img1 = stitchedImage; } finish = clock(); totaltime = (double)(finish - start) / CLOCKS_PER_SEC; cout << "拼接成功" << endl; cout << "拼接花費總時間為:" << totaltime << "秒!" << endl; imshow("ResultImage", stitchedImage); imwrite("ResultImage.jpg", stitchedImage); waitKey(0); return 0; }