1. 反向投影
反向投影就是一种记录给定图像中像素店如何适应直方图模型像素分布方式的一种方法。简单来说就是,反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征的方法
2. 工作原理
- 对测试图像中的每个像素p(i,j) p ( i , j ) ,获取色调数据并找到该色调(hi,j,si,j) ( h i , j , s i , j ) 在直方图的bin的位置
- 查询模型直方图中对应bin的数值
- 将此数值存储在新的反射投影图像中。也可以先归一化直方图数值到0∼255 0 ∼ 255 范围,这样可以直接显示反射投影图像(单通道图像)
- 通过对测试图像中的每个像素采用以上步骤,可以得到最终的反射投影图像
- 使用统计学语言进行分析,反向投影中存储的数值代表了测试图像中该像素属于皮肤区域的概率。
假设你已经通过下图得到肤色直方图,下面的直方图就是模型直方图
得到效果图
3. 反向投影的作用
反向投影用于在输入图像中查找与特定图像(通常较小获取仅1个像素,以下将其称为模板图像)最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置
4. 反向投影的结果
反向投影的结果包含了以每个输入图像像素点为起点的直方图对比结果。可以把它看成是一个二维的浮点型数组,二维矩阵或者单通道的浮点型图像。
5. 计算反向投影:calcBackProject()函数
函数原型
void calcBackProject(const Mat * iamges,int nimages,const int * channels, InputArray hist,OutputArray backProject,const float ** ranges, double scale = 1,bool uniform = true)
- 第五个参数:OutputArray类型的backProject,目标反向投影阵列,必须为单通道,并且和image[0]有相同的大小和深度
- 第七个参数:double 类型的scale。有默认值为1,输出方向投影可选缩放因子
6. 通道复制:mixChannels()函数
函数原型:
void mixChannels(cosnt Mat * src,size_t nsrcs, Mat *dst, size_t ndsts, const int * formTo, size_t npairs)
void mixChannels(const vector<Mat>& src, vector<Mat>&dst,const int * fromTo,size_t npairs)
函数为重排图像通道提供了比较先进的机制,我们之前接触到的split()和merge(),以及cvtColor()的某些形式,都是mixChannels()的一部分
7.综合程序:反向投影
#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);
}