Opencv2.4学习::根据直方图匹配原图像-----直方图反向投影

书中的解释有些晦涩难懂,下面利用摘自 https://blog.csdn.net/marshwb/article/details/21329063  进行通俗解释:

1.反向投影的作用是什么?
    反向投影用于在输入图像(通常较大)中查找特定图像(通常较小或者仅1个像素,以下将其称为模板图像)最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。
2.反向投影如何查找(工作)?
    查找的方式就是不断的在输入图像中切割跟模板图像大小一致的图像块,并用直方图对比的方式与模板图像进行比较。

假设我们有一张100x100的输入图像,有一张10x10的模板图像,查找的过程是这样的:
(1)从输入图像的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;
(2)生成临时图像的直方图;
(3)用临时图像的直方图和模板图像的直方图对比,对比结果记为c;
(4)直方图对比结果c,就是结果图像(0,0)处的像素值;
(5)切割输入图像从(0,1)至(10,11)的临时图像,对比直方图,并记录到结果图像;
(6)重复(1)~(5)步直到输入图像的右下角。

3.反向投影的结果是什么?
    反向投影的结果包含了:以每个输入图像像素点为起点的直方图对比结果。可以把它看成是一个二维的浮点型数组,二维矩阵,或者单通道的浮点型图像。
4.特殊情况怎么样?
    如果输入图像和模板图像一样大,那么反向投影相当于直方图对比。如果输入图像比模板图像还小,直接罢工~~。

 

关键函数: void calcBackProject

实现代码: 

(1)利用原图像的HSV空间通道进行匹配

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace std;
using namespace cv;

int main()
{
	//原图像
	Mat srcImage = imread("F:\\opencv_re_learn\\2.jpg");
	if (!srcImage.data){
		cout << "failed to read" << endl;
		system("pause");
		return -1;
	}
	imshow("srcImage", srcImage);

	//转换到hsv空间
	Mat hsvImage;
	cvtColor(srcImage, hsvImage, CV_BGR2HSV);
	//hue通道分离 
	Mat hueImage;
	hueImage.create(hsvImage.size(), hsvImage.depth());
	int ch[] = { 0, 0 };
	mixChannels(&hsvImage,1, &hueImage, 1, ch, 1);
	//初始化直方图计算参数
	int bins = 25;//区间数
	MatND hist;
	int histSize =MAX(bins, 2);//分成25个区间
	float hue_range[] = { 0,100};//每个区间值域范围
	const float *ranges = { hue_range };
	//计算直方图并归一化
	calcHist(&hueImage, 1, 0, Mat(),
		hist, 1, &histSize, &ranges, true, false);
	normalize(hist, hist, 0,255, NORM_MINMAX,
		-1, Mat());//又归一化到0-255
	//计算反向投影
	MatND backproj;
	calcBackProject(&hueImage, 1, 0, hist, backproj,
		&ranges, 1, true);
	//定义输出图像
	int w = 320; int h = 360;
	int bin_w = cvRound((double)w / histSize);
	Mat histImg = Mat::zeros(w, h, CV_8UC3);
	for (int i = 0; i < bins; i++){
		//绘制直方图
		rectangle(histImg, Point(i*bin_w, h),
			Point((i + 1)*bin_w,
			h - cvRound(hist.at<float>(i)*h / 255.0)),
			Scalar(0, 0, 255), -1);
	}
	//显示反向投影图像
	imshow("BackProj", backproj);

	waitKey(0);
	return 0;
}

实现效果: (HSV空间下有点难明白,建议初学者如我直接看下面的例子)

(2)利用某部分的灰度直方图进行匹配 

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace std;
using namespace cv;

int main()
{
	//原图像
	Mat srcImage = imread("F:\\opencv_re_learn\\2.jpg");
	//直方图匹配部分
	Mat matchImage = imread("F:\\opencv_re_learn\\4.jpg");
	if (!srcImage.data){
		cout << "failed to read" << endl;
		system("pause");
		return -1;
	}
	imshow("srcImage", srcImage);
	//匹配部分转换为灰度图
	Mat matchgray;
	cvtColor(matchImage, matchgray, CV_BGR2GRAY);
	Mat srcGray;
	cvtColor(srcImage, srcGray, CV_BGR2GRAY);
	//初始化直方图计算参数
	int bins = 5;
	MatND hist;
	int histSize = MAX(bins, 2);//分成25个区间
	float hue_range[] = { 0, 255 };//每个区间值域
	const float *ranges = { hue_range };
	//计算直方图并归一化
	calcHist(&matchgray, 1, 0, Mat(),
		hist, 1, &histSize, &ranges, true, false);
	normalize(hist, hist, 0, 255, NORM_MINMAX,
		-1, Mat());//又归一化到0-255
	//△△实际上,计算完的hist就是匹配部分的特征了
	
	//计算反向投影
	//即根据特征在原图像上进行匹配
	MatND backproj;
	calcBackProject(&srcGray, 1, 0, hist, backproj,
		&ranges, 1, true);
	//定义输出图像
	int w = 320; int h = 360;
	int bin_w = cvRound((double)w / histSize);
	Mat histImg = Mat::zeros(w, h, CV_8UC3);
	for (int i = 0; i < bins; i++){
		//绘制直方图
		rectangle(histImg, Point(i*bin_w, h),
			Point((i + 1)*bin_w,
			h - cvRound(hist.at<float>(i)*h / 255.0)),
			Scalar(0, 0, 255), -1);
	}
	//显示反向投影图像
	imshow("BackProj", backproj);

	waitKey(0);
	return 0;
}

 原图像:

匹配部分:

效果: (图中最亮的部分,就是匹配部分截取的地方)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值