百張影象拼接2
阿新 • • 發佈:2018-12-18
60s執行100張532*300的圖片。 之前的方法只是適合相機不旋轉的情況,這個就沒有特殊要求了。 但是我們注意到,由於影象從最後一張開始拼接,在拼接的過程中,不斷變得模糊,因為經過多次處理,而圖片的左側,就保持最初的解析度,比較清晰。
#include "opencv2/core/core.hpp" #include "highgui.h" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/features2d/features2d.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/nonfree/nonfree.hpp" #include "opencv2/legacy/legacy.hpp" #include <iostream> #include <fstream> #include <string> #include<vector> #include "opencv2/opencv_modules.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/stitching/detail/autocalib.hpp" #include "opencv2/stitching/detail/blenders.hpp" #include "opencv2/stitching/detail/camera.hpp" #include "opencv2/stitching/detail/exposure_compensate.hpp" #include "opencv2/stitching/detail/matchers.hpp" #include "opencv2/stitching/detail/motion_estimators.hpp" #include "opencv2/stitching/detail/seam_finders.hpp" #include "opencv2/stitching/detail/util.hpp" #include "opencv2/stitching/detail/warpers.hpp" #include "opencv2/stitching/warpers.hpp" #include "opencv2/calib3d/calib3d.hpp" using namespace std; using namespace cv; using namespace cv::detail; //如果影象太大縮小一半 Mat mynarrow(Mat img) { Mat dst;//讀出一個圖 if (img.rows*img.cols > 2400 * 1200) resize(img, dst, Size(), 0.5, 0.5); else dst = img.clone(); return dst; } //利用findHomography函式利用匹配的關鍵點找出相應的變換: Mat myfindHomography(std::vector< DMatch > & good_matches, std::vector<KeyPoint>& keypoints_1, std::vector<KeyPoint> & keypoints_2) { //-- Localize the object from img_1 in img_2 //在img_2中定位來自img_1的物件 std::vector<Point2f> obj; std::vector<Point2f> scene; for (unsigned 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); return H; } //用單應性過濾匹配 bool refineMatchesWithHomography(const std::vector<cv::KeyPoint>& queryKeypoints, const std::vector<cv::KeyPoint>& trainKeypoints, float reprojectionThreshold, std::vector<cv::DMatch>& matches//, //cv::Mat& homography ) { cv::Mat homography; const int minNumberMatchesAllowed = 4; if (matches.size() < minNumberMatchesAllowed) return false; // 為 cv::findHomography 準備資料 std::vector<cv::Point2f> queryPoints(matches.size()); std::vector<cv::Point2f> trainPoints(matches.size()); for (size_t i = 0; i < matches.size(); i++) { queryPoints[i] = queryKeypoints[matches[i].queryIdx].pt; trainPoints[i] = trainKeypoints[matches[i].trainIdx].pt; } // 查詢單應矩陣並獲取內點掩碼 std::vector<unsigned char> inliersMask(matches.size()); homography = findHomography(queryPoints, trainPoints, CV_FM_RANSAC, reprojectionThreshold, inliersMask); std::vector<cv::DMatch> inliers; for (size_t i = 0; i < inliersMask.size(); i++) { if (inliersMask[i]) inliers.push_back(matches[i]); } matches.swap(inliers); //Mat homoShow; //drawMatches(src,queryKeypoints,frameImg,trainKeypoints,matches,homoShow,Scalar::all(-1),CV_RGB(255,255,255),Mat(),2); //imshow("homoShow",homoShow); return matches.size() > minNumberMatchesAllowed; } //獲得匹配點座標函式 Point2f get_match_points(vector<KeyPoint>& keypoints1,vector<KeyPoint>& keypoints2, vector< DMatch > & matches, vector<Point2f>& points1,vector< Point2f>& points2) { for (int i = 0; i < matches.size(); i++) { int index1 = matches.at(i).queryIdx; int index2 = matches.at(i).trainIdx; points1.push_back(keypoints1.at(index1).pt); points2.push_back(keypoints2.at(index2).pt); } } int main() { /* 特徵點的提取與匹配 */ int num_images = 100; //影象數量,可修改 vector<string> image_names; // image_names[i]表示第i個影象的名稱 string name; ifstream f("D:\\list低解析度.txt"); assert(f.is_open()); for(int i=0;i<num_images;i++) { getline(f, name); name = "D:\\低解析度截圖\\" + name; cout << name; image_names.push_back(name); } vector<vector<DMatch> > image_matches; // image_matches[i]表示第i幅影象和第i+1幅影象特徵點匹配的結果 // 提取特徵點 vector<ImageFeatures> features(num_images); //表示影象特徵 char temp[100]; double ge[100];//100張圖的特徵點個數 Point2f point; KeyPoint kp; float temp1 = 0, temp2 = 0; char ptsname[100]; char descname[100]; ifstream g("D:\\特徵\\特徵點個數.txt");//將100張圖的特徵點個數匯入陣列 assert(g.is_open()); for (int i = 1; i <= num_images; i++) { g >> ge[i - 1]; } g.close(); for (int i = 1; i <= num_images; i++) { sprintf(ptsname, "D:\\特徵\\pts%d.txt", i); //格式化輸出檔名 ifstream infile(ptsname); assert(infile.is_open()); //若失敗,則輸出錯誤訊息,並終止程式執行 for (int a = 0; !infile.eof(); a++) { infile >> temp1 >> temp2; point.x = temp1; point.y = temp2; kp = KeyPoint(point, 1.f); features[i - 1].keypoints.push_back(kp); } infile.close(); //infile.clear(); sprintf(descname, "D:\\特徵\\desc%d.txt", i); //格式化輸出檔名 ifstream des(descname); assert(des.is_open()); //若失敗,則輸出錯誤訊息,並終止程式執行 cout << ge[i - 1]; features[i - 1].descriptors= Mat::zeros(ge[i - 1], 256, CV_32FC1);//同理features[0].descriptors for (int k = 0; k < ge[i - 1]; k++) { for (int j = 0; j < 256; j++) { des >> features[i - 1].descriptors.at<float>(k, j); } } des.close(); //des.clear(); } //match_features2(features.descriptor, image_matches); // 特徵點匹配 //gms_match_features(image_keypoints,img0.size(),image_matches); for (unsigned int i = 0; i < num_images - 1; i++) { cout << "正在匹配 " << i << " - " << i + 1 << endl; vector<DMatch> matches; //match_features1 (image_descriptor[i], image_descriptor[i + 1], matches); //使用暴力匹配器進行暴力匹配——BruteForceMatcher類的match()方法 //opencv3.4使用 //Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce"); //matcher->match(features[i].descriptors, features[i + 1].descriptors, matches); BruteForceMatcher<L2<float> > matcher;//例項化暴力匹配器 matcher.match(features[i].descriptors, features[i+1].descriptors, matches); cout << "有 " << matches.size() << " 個匹配點" << endl; image_matches.push_back(matches); } cout<<"單應性過濾特徵點"<<endl; //單應性過濾特徵點 for (unsigned int i = 0; i < image_matches.size(); i++) { refineMatchesWithHomography(features[i].keypoints, features[i+1].keypoints, 1.0, image_matches[i]); } //image_descriptor.swap(vector<Mat>());//匹配完清除記憶體 cout<<"narrow"; Mat img0 = imread(image_names[0]);//讀出一個圖 img0 = mynarrow(img0);//如果太大縮小一點。(>2400*1200的) //查詢嚮應矩陣 vector<Mat> im_Homography; // im_Homography[i]表示第i+1-->i的單應矩陣 for (unsigned int i=0;i<image_matches.size ();i++) { //單應矩陣 Mat h12 = myfindHomography(image_matches[i], features[i].keypoints, features[i+1].keypoints ); Mat h21; invert(h12, h21, DECOMP_LU); im_Homography.push_back(h21); } Mat canvas; int canvasSize=image_names.size()*1.5; unsigned int j=image_names.size(); j--; Mat img2 = imread(image_names[j]);//讀出最後的哪個圖 for (unsigned int i=0;i<image_matches.size ();i++) { //從後到前 Mat img1; Mat h21; j--; if(j==image_matches.size ()-1){//最右圖 h21=im_Homography[j]; //使用透視變換 warpPerspective(img2, canvas, h21, Size(img0.cols*canvasSize, img0.rows)); img1 = imread(image_names[j]);//讀出最後的哪個圖 //拼接 img1.copyTo(canvas(Range::all(), Range(0, img0.cols))); } else{//其它 h21=im_Homography[j]; Mat temp2=canvas.clone(); //儲存拷貝 warpPerspective(temp2, canvas, h21, Size(img0.cols*canvasSize, img0.rows));//一起透視變換 img1 = imread(image_names[j]);//讀出當前的哪個圖 img1.copyTo(canvas(Range::all(), Range(0, img0.cols)));//加當前(拼接) } /*這個是從右到左,也就是從最後一張圖到第一張圖逐漸拼接的一個動態結果 imshow("拼接圖",canvas); char wname[255]; sprintf(wname,"can%d.jpg",i); imwrite(String(wname),canvas); waitKey(1); */ if(i==image_matches.size ()-1)//儲存最後一張拼接圖 { imshow("1",canvas); waitKey(); imwrite("result.png",canvas); } } return 0; }