1. 程式人生 > >百張影象拼接2

百張影象拼接2

在這裡插入圖片描述

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;
}