Bootstrap

图像配准融合(二)——基于特征的图像配准方法(c++)

本文主要记录我在基于特征的图像配准方法方面的一点儿实验。

本文图像配准主要参考如下3个链接:

1.https://blog.csdn.net/qq_27737701/article/details/82289607

2.https://www.cnblogs.com/skyfsm/p/7411961.html

3.https://blog.csdn.net/czl389/article/details/65937864https://blog.csdn.net/czl389/article/details/60572159

一、总结1、2,基于特征的图像配准融合方法实现流程如下:

           步骤1:计算获得两幅图像的特征点;

           步骤2:根据特征对两幅图像进行匹配;

           步骤3:对步骤2中匹配的特征对进行筛选;

           步骤4:根据匹配关系得到单应性矩阵;

           步骤5:根据单应性矩阵使用warpPerspective调整两幅图像为相对应图像;

           步骤6:对应位置按比例融合。

二、代码部分

本代码使用sift特征,根据距离对匹配对儿筛选。对图像1、图像2进行配准融合。(图1、图2来自上述第三个链接)

               

            图像1                                                               图像2

正如链接3所述,实现两幅图像的拼接,主要是使用了单应矩阵和warpPerspective()这个库函数。

warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize)

这个函数不灵活。一方面,目标投影的图像不能选取感兴趣区域,使得每拼接两幅都会产生一个结果图像;另一方面,投影参考原点为图像左上角,如果投影后的图像在左方,就不能显示出,所以需要左侧的图像为参考图像。因此,下面拼接图1、图2将图像2作为参考图像。(在链接3中也给出了以右边图像作为参考时,将图像显示出来的方法,需要添加位移变换,具体可参考链接3)

#include <opencv2\highgui\highgui.hpp>
#include<opencv2\nonfree\nonfree.hpp>
#include<opencv2\legacy\legacy.hpp>

using namespace std;
using namespace cv;

void sift_Registration_fusion(Mat img1, Mat img2, Mat&fuseimage)
{
	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);

	vector<cv::KeyPoint> keypoints_roi, keypoints_img;
	Mat descriptor_roi, descriptor_img;

	BFMatcher matcher(NORM_L2);
	vector<cv::DMatch> matches, good_matches;

	SIFT sift;
	int i, dist = 80;

	sift(g1, Mat(), keypoints_roi, descriptor_roi);      /* get keypoints of ROI image */
	sift(g2, Mat(), keypoints_img, descriptor_img);         /* get keypoints of the image */

	matcher.match(descriptor_roi, descriptor_img, matches);

	double max_dist = 0; double min_dist = 1000;
	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]);
		}
	}

	vector<Point2f> keypoints1, keypoints2;
	for (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);
	}

	Mat Perspectiveimg;
	//计算单应矩阵
	Mat H = findHomography(keypoints1, keypoints2, CV_RANSAC);

	//将投影全部画出来,可以计算变换后的图大小,如链接2中计算方式,此处直接将其放在2倍原图的大小进行拼接
	warpPerspective(img2, Perspectiveimg, H, cv::Size(img1.cols*2, img1.rows), INTER_LINEAR);
	imwrite("Perspectiveimg.jpg", Perspectiveimg);
	
	img1.copyTo(Perspectiveimg(Rect(0, 0, img1.cols, img1.rows)));
        fuseimage=Perspectiveimg.clone();
	

}
int main()
{
        Mat img1 = cv::imread("img2.png");
	Mat img2 = cv::imread("img1.png");
	resize(img2, img2, Size(img1.cols, img1.rows));
	Mat imgfuse;
	sift_Registration_fusion(img1, img2, imgfuse);
	imwrite("result.jpg", imgfuse);
}

             上述示例,为了展示结果方便,在配准前将两幅图像变换为尺寸相同的图像,也可以不变换(如链接1、链接2需要提前计算结果图的大小),结果如下:

           

           img1在img2上的透视变换图                                                      拼接融合图                          

   此处融合只是简单的拼接,链接2中有去裂纹的融合方法,还有更多的融合方法尚未研究实验。。。。

   文中若有错误以及不妥之处,还望指出,以便共同学习。

 

 

 

 

;