图像处理之模板匹配

模板匹配法

       模板匹配是一种用于在源图像S中寻找定位给定目标图像T(即模板图像)的技术。其原理很简单,就是通过一些相似度准则来衡量两个图像块之间的相似度Similarity(S,T)。

模板匹配的工作方式

       模板匹配的工作方式跟直方图的反向投影基本一样,大致过程是这样的:通过在输入图像上滑动图像块对实际的图像块和输入图像进行匹配。假设我们有一张100x100的输入图像,有一张10x10的模板图像,查找的过程是这样的:

 (1)从输入图像的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;

 (2)用临时图像和模板图像进行对比,对比结果记为c;

 (3)对比结果c,就是结果图像(0,0)处的像素值;

 (4)切割输入图像从(0,1)至(10,11)的临时图像,对比,并记录到结果图像;

 (5)重复(1)~(4)步直到输入图像的右下角。

模板匹配方法的优缺点:

       优点:简单、直接

       缺点:不具有旋转不变性、不具有尺度不变性

	代码如下:  
	int main()  
	{  
	    Mat img, templ, result;  
	    img = imread("match_dst.jpg");  
	    templ = imread("match_src.jpg");  
	    /*img = imread("1.jpg"); 
	    templ = imread("2.jpg");*/  
	
        int result_cols = img.cols - templ.cols + 1;  
	    int result_rows = img.rows - templ.rows + 1;  
	    result.create(result_cols, result_rows, CV_32FC1);  
	  
	    //进行匹配和标准化  
	    matchTemplate(img, templ, result, CV_TM_SQDIFF_NORMED);  
	    normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());  
	  
	    double minVal;  //匹配最小值  
	    double maxVal;  //匹配最大值  
	    Point maxLoc;  //匹配最大值的位置坐标  
        Point minLoc;   //匹配最小值的位置坐标  
	    Point matchLoc;    
	  
	    //通过函数minMaxLoc定位最匹配的位置  
	    minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());  
	  
	    cout << "匹配度:" << minVal << endl;  
	    cout << "匹配度最小值的坐标" << minLoc.x << "," << minLoc.y << endl;  
	  
	    /*Mat H = findHomography(templ,img, CV_RANSAC); 
	 
	    Mat trans1; 
	    perspectiveTransform(img, trans1, H); 
	    imshow("trans1", trans1);*/  
	  
	    matchLoc = minLoc;  
	    rectangle(img, matchLoc, Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows), Scalar(0, 255, 0), 2, 8, 0);  
	  
	    imshow("img", img);  
	    imshow("templ", templ);  
	    //imshow("result", result);  

	    waitKey(0);  	  
	    return 0;  
	}  

效果如下:

图像处理之模板匹配_第1张图片

       但是,在该方法中,最佳匹配点位于大图匹配位置的左上部分,且只能用矩形框选匹配位置。若小图视角变化,框选无效。

Surf之图像匹配

       利用Surf算法进行图像匹配其一般流程为:检测物体特征点->计算特征点描述子->使用BurteForceMatcher或FLANN进行特征点匹配->匹配到的特征点进行透视变换findHomography()->透视矩阵变换perspectiveTransform()->绘制匹配物体轮廓。

#include
#include
#include
#include 
#include
#include
#include

using namespace std;
using namespace cv;

int main()
{
	Mat image_object = imread("template.png", IMREAD_GRAYSCALE);
	Mat image_scene = imread("image.png", IMREAD_GRAYSCALE);
	
	//检测特征点
	const int minHessian = 400;
	SurfFeatureDetector detector(minHessian);
	vectorkeypoints_object, keypoints_scene;
	detector.detect(image_object, keypoints_object);
	detector.detect(image_scene, keypoints_scene);

	//计算特征点描述子
	SurfDescriptorExtractor extractor;
	Mat descriptors_object, descriptors_scene;
	extractor.compute(image_object, keypoints_object, descriptors_object);
	extractor.compute(image_scene, keypoints_scene, descriptors_scene);

	//使用FLANN进行特征点匹配
	FlannBasedMatcher matcher;
	vectormatches;
	matcher.match(descriptors_object, descriptors_scene, matches);

	//计算匹配点之间的最大和最小距离
	double max_dist = 0;
	double min_dist = 100;
	for (int i = 0; i < descriptors_object.rows; i++)
	{
		double dist = matches[i].distance;
		if (dist < min_dist)
		{
			min_dist = dist;
		}
		else if (dist > max_dist)
		{
			max_dist = dist;
		}
	}
	printf("Max dist: %f \n", max_dist);
	printf("Min dist: %f \n", min_dist);
   //绘制好的匹配点
	vectorgood_matches;
	for (int i = 0; i < descriptors_object.rows; i++)
	{
		if (matches[i].distance<2 * min_dist)
		{
			good_matches.push_back(matches[i]);
		}
	}
	Mat image_matches;
	drawMatches(image_object, keypoints_object, image_scene, keypoints_scene, good_matches, image_matches,
		Scalar::all(-1), Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

	//定位好的匹配点
	vector obj;
	vector scene;
	for (int i = 0; i < good_matches.size(); i++)
	{
		//DMathch类型中queryIdx是指match中第一个数组的索引,keyPoint类型中pt指的是当前点坐标
		obj.push_back(keypoints_object[good_matches[i].queryIdx].pt);
		scene.push_back(keypoints_scene[good_matches[i].trainIdx].pt);
	}

	Mat H = findHomography(obj, scene, CV_RANSAC);

	vector obj_corners(4), scene_corners(4);
	obj_corners[0] = cvPoint(0, 0);
	obj_corners[1] = cvPoint(image_object.cols, 0);
	obj_corners[2] = cvPoint(image_object.cols, image_object.rows);
	obj_corners[3] = cvPoint(0, image_object.rows);

	perspectiveTransform(obj_corners, scene_corners, H);

	//绘制角点之间的直线
	line(image_matches, scene_corners[0] + Point2f(image_object.cols, 0),
		scene_corners[1] + Point2f(image_object.cols, 0), Scalar(0, 0, 255), 2);
	line(image_matches, scene_corners[1] + Point2f(image_object.cols, 0),
		scene_corners[2] + Point2f(image_object.cols, 0), Scalar(0, 0, 255), 2);
	line(image_matches, scene_corners[2] + Point2f(image_object.cols, 0),
		scene_corners[3] + Point2f(image_object.cols, 0), Scalar(0, 0, 255), 2);
	line(image_matches, scene_corners[3] + Point2f(image_object.cols, 0),
		scene_corners[0] + Point2f(image_object.cols, 0), Scalar(0, 0, 255), 2);

	//输出图像
	namedWindow("匹配图像", WINDOW_AUTOSIZE);
	imshow("匹配图像", image_matches);
	waitKey(0);

	return 0;

}

程序说明:

       在定位匹配点中用到了DMatchqueryIdxtrainIdx成员变量和keyPoint的成员变量pt

cv::DMatch::DMatch(int  queryIdx,  //在对描述子匹配时,第一组特征点的索引  
int  trainIdx,  //在对描述子匹配时,第二组特征点的索引  
int  imgIdx,    //多个图像中图像的索引  
float   distance  //两个特征向量间的欧氏距离,越小表明匹配度越高 )  

       对于DrawMatch函数:

void drawMatches( const Mat& img1, const vector& keypoints1,  
	              const Mat& img2, const vector& keypoints2,  
	              const vector >& matches1to2, Mat& outImg,  
	              const Scalar& matchColor=Scalar::all -1), 
	              const Scalar& singlePointColor=Scalar::all(-1),  
	              const vector >& matchesMask=vector >(), 
                  int flags=DrawMatchesFlags::DEFAULT );  

/其中参数如下:  
img1 – 源图像1  
keypoints1 –源图像1的特征点.  
img2 – 源图像2.  
keypoints2 – 源图像2的特征点  
matches1to2 – 源图像1的特征点匹配源图像2的特征点[matches[i]] .  
outImg – 输出图像具体由flags决定.  
matchColor – 匹配的颜色(特征点和连线),若matchColor==Scalar::all(-1),颜色随机.  
singlePointColor – 单个点的颜色,即未配对的特征点,若matchColor==Scalar::all(-1),颜色随机.  
matchesMask – Mask决定哪些点将被画出,若为空,则画出所有匹配点.  
* flags – Fdefined by DrawMatchesFlags.  

效果图:

图像处理之模板匹配_第2张图片

 

FAsT-Match

        FAsT-Match是在2D仿射变换下用于近似模板匹配的快速算法,其最小化绝对差分和(SAD)误差测量。 通过图像平滑度的密度对其进行采样。 对于每个可能的变换,使用次线性算法来近似SAD误差, 同时使用分支定界法进一步加速算法。 由于已知图像是分段平滑的,因此结果是具有近似保证的实际仿射模板匹配算法。

算法流程:                                                                                                      

图像处理之模板匹配_第3张图片

图像处理之模板匹配_第4张图片

图像处理之模板匹配_第5张图片

代码地址

结果如下:

图像处理之模板匹配_第6张图片

 

你可能感兴趣的:(图像处理之模板匹配)