书中的解释有些晦涩难懂,下面利用摘自 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.特殊情况怎么样?
如果输入图像和模板图像一样大,那么反向投影相当于直方图对比。如果输入图像比模板图像还小,直接罢工~~。
#include
#include
#include
#include
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(i)*h / 255.0)),
Scalar(0, 0, 255), -1);
}
//显示反向投影图像
imshow("BackProj", backproj);
waitKey(0);
return 0;
}
实现效果: (HSV空间下有点难明白,建议初学者如我直接看下面的例子)
#include
#include
#include
#include
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(i)*h / 255.0)),
Scalar(0, 0, 255), -1);
}
//显示反向投影图像
imshow("BackProj", backproj);
waitKey(0);
return 0;
}
原图像:
匹配部分:
效果: (图中最亮的部分,就是匹配部分截取的地方)