1 引言
反向投影就是一种记录给定图像中的像素点适应直方图模型像素分布方式的一种方法。也就是计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征的方法
2 反向投影的工作原理
- 建立直方图模型
- 计算待测图像直方图并映射到模型中
- 从模型中反向计算生成图像
3 反向投影的作用
反向投影用于输入图像中查找与特定图像最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。
4 反向投影的结果
反向投影的结果包含了以输入图像像素点为起点的的直方图对比结果。可以看作一个二维的浮点型数组、二维矩阵,或者单通道的浮点型图像。
5 计算反向投影:calcBackProject()函数
void calcBackProject(const Mat * images,int nimages,const int* channels,InputArray hist,OutputArray backProject,const float** ranges,double scale=1,bool uniform=true)
第一个参数:输入的数组
第二个参数:输入数组的个数,也就是有多少张图片,通常为1
第三个参数:通道数目
第四个参数:输入的直方图
第五个参数:目标反向投影阵列,单通道,与image[0]有相同的大小和深度
第六个参数:表示每一个维度数组的每一维的边界矩阵,每一个维度的取值范围
第七个参数:默认值1,输出的方向投影可选的缩放因子
第八个参数:直方图是否均匀的标识符,默认值True
6 通道复制:mixChannels()函数
说明:此函数由输入参数复制某通道到输出参数特定的通道中。该函数是为重排图像通道提供比较先进的机制。之前接触的split()和merge()以及cvtColor()都是mixChannels()函数一部分
void mixChannels(const Mat * src,size_t nsrcs,Mat * dst,size_t ndsts,const int * fromTo,size_t npairs)
第一个参数:输入的数组(hsv),所有的矩阵必须有相同的尺寸和深度
第二个参数:第一个参数src输入的矩阵数
第三个参数:输出数组(hue),所有矩阵必须初始化,大小和深度必须与src[0]相同
hue.create(hsv.szie(),hsv.depth())
- 第四个参数:第三个参数dst的输出矩阵数
- 第五个参数:对指定的通道进行复制的数组索引
- 第六个参数:第五个参数fromTo的索引数
示例说明:将一个4通道的RGBA图像转化为3通道BGR和一个单独的Alpha通道图像
Mat rgba(100,100,CV_8UC4,Scalar(1,2,3,4)); Mat bgr(rgba.rows,rgba.cols,CV_8UC3); Mat alpha(rgba.rows,rgba.cols,CV_8UC1); //组成矩阵数组来进行操作 Mat out[]={bgr,alpha}; //将rgba[0]->bgr[2] //将rgba[1]->bgr[1] //将rgba[2]->bgr[1] //将rgba[3]->alpha[0] int fromTo[]={0,2,1,1,2,0,3,3}; mixChannels(&rgba,1,out,2,fromTo,4);
7 综合示例:反向投影
#include<opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv; #define WINDOW_NAME1 "【原始图】" #define WINDOW_NAME2 "【反射投影图】" Mat g_srcImage; Mat g_hsvImage; Mat g_hueImage; int g_bins = 30;//直方图组距 void on_BinChange(int, void *); int main() { g_srcImage = imread("E:\\Pec\\手.jpg", 1); cvtColor(g_srcImage, g_hsvImage, COLOR_BGR2HSV); //分离Hue色调通道 g_hueImage.create(g_hsvImage.size(), g_hsvImage.depth()); int ch[] = { 0,0 }; mixChannels(&g_hsvImage, 1, &g_hueImage, 1, ch, 1); //创建Trackbar来输入bin数目 namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE); namedWindow(WINDOW_NAME2, WINDOW_AUTOSIZE); createTrackbar("色调组距:", WINDOW_NAME2, &g_bins, 180, on_BinChange); on_BinChange(0, 0); imshow(WINDOW_NAME1, g_srcImage); waitKey(0); return 0; } void on_BinChange(int, void *) { //参数准备 MatND hist;//Mat表示二维数组,MatND表示三维或者以上 int histSize = MAX(g_bins, 2); float hue_range[] = { 0,180 }; const float * ranges = { hue_range }; //计算直方图并归一化 calcHist(&g_hueImage, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false); normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat()); //计算反射投影 Mat backproj; calcBackProject(&g_hueImage, 1, 0, hist, backproj, &ranges, 1, true); imshow(WINDOW_NAME2, backproj); //绘制直方图 int hist_w = 400, hist_h = 400; //cvRound:对double类型的数四舍五入并返回一个整型 int bin_w = cvRound((double)hist_w / histSize); Mat histImage = Mat::zeros(hist_w, hist_h, CV_8UC3); for (int i = 0; i < g_bins; i++) { //pt1 -- 矩形的一个顶点。pt2 -- 矩形对角线上的另一个顶点 rectangle(histImage, Point(i*bin_w, hist_h), Point((i + 1)*bin_w, hist_h - cvRound(hist.at<float>(i)*hist_h / 255.0)), Scalar(100, 123, 255),-1); } imshow("直方图", histImage); }
(1)原图展示
(2)组距bin为 6 的反向投影
(3)组距bin为 30 的反向投影