反向投影就是一种记录给定图像中像素店如何适应直方图模型像素分布方式的一种方法。简单来说就是,反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征的方法
假设你已经通过下图得到肤色直方图,下面的直方图就是模型直方图
反向投影用于在输入图像中查找与特定图像(通常较小获取仅1个像素,以下将其称为模板图像)最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置
反向投影的结果包含了以每个输入图像像素点为起点的直方图对比结果。可以把它看成是一个二维的浮点型数组,二维矩阵或者单通道的浮点型图像。
函数原型
void calcBackProject(const Mat * iamges,int nimages,const int * channels, InputArray hist,OutputArray backProject,const float ** ranges, double scale = 1,bool uniform = true)
函数原型:
void mixChannels(cosnt Mat * src,size_t nsrcs, Mat *dst, size_t ndsts, const int * formTo, size_t npairs)
void mixChannels(const vector & src, vector &dst,const int * fromTo,size_t npairs)
函数为重排图像通道提供了比较先进的机制,我们之前接触到的split()和merge(),以及cvtColor()的某些形式,都是mixChannels()的一部分
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace cv;
//宏定义部分
#define WINDOW_NAME1 "【原始图】"
//全局变量声明部分
Mat g_srcImage;
Mat g_hsvImage;
Mat g_hueImage;
int g_bins = 30; //直方图组距
//全局函数声明部分
void on_BinChange(int, void *);
//main()函数
int main()
{
//读入源图像
g_srcImage = imread("1.jpg", 1);
if (!g_srcImage.data)
{
printf("读取图片错误~!\n");
return false;
}
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);
createTrackbar("色调组距:", WINDOW_NAME1, &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;
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());
//计算反向投影
MatND backproj;
calcBackProject(&g_hueImage, 1, 0, hist, backproj, &ranges, 1, true);
//显示反向投影
imshow("反向投影图", backproj);
//绘制直方图的参数准备
int w = 400;
int h = 400;
int bin_w = cvRound((double)w / histSize);
Mat histImg = Mat::zeros(w, h, CV_8UC3);
//绘制直方图
for (int i = 0; i < g_bins; i++)
{
rectangle(histImg, Point(i*bin_w, h),Point((i + 1)*bin_w, h - cvRound(hist.at<float>(i)*h / 255.0)), Scalar(100, 123, 255), -1);
}
imshow("直方图", histImg);
}