opencv 浅谈反向投影

一、话说反向投影

首先,讲解下它的英文名,projection除了项目工程的意思外,还有投影的意思,数学中也用 表示投影。

反向投影其实是直方图运算的逆过程。直方图运算是统计每个灰度值对应的像素个数,而反向投影则是将像素个数回送到该像素个数对应灰度区间的像素位置。来看一个例子。

假设有下面这个图像矩阵:


然后计算直方图,将灰度值划分为如下四个区间:[0,2] [3,5] [6,7] [8,10]很容易得到这个图像矩阵的直方图hist= 4 4 6 2

最后计算反向投影,原图像中坐标为(0,0)的灰度值为1,1位于区间[0,2] 中,区间[0,2] 对应的直方图值为4,所以反向投影矩阵中中坐标为(0,0)的值记为4。以此类推,得到反向投影后的矩阵:


二、一般步骤

前面讲过,反向投影是基于直方图的逆运算,而直方图则反应了图像的色彩(亮度)特征,当两幅相似的图像仅发生位置的变化而色彩(光线)几乎不变时,对应的两幅直方图相似度肥肠高。

但直方图只是得到了特征,反向投影则是将特征“反映”到图像上,对于物体特征识别和分割有着很大的作用。

进行反向投影的一般步骤:

  • 获取直方图的源,比如我们要对手进行反向投影,那么直方图的源就是肤色的ROI
  • 获取需要反向投影的图像
  • 计算直方图,通常是在HSV模型中计算,毕竟反向投影的一大工作就是区分颜色
  • 反向投影
  • 显示

API:

dst=cv2.calcBackProject(images, channels, hist, ranges, scale[, dst])
  • dst:输出图像,与源图images有相同的尺寸
  • images:输入的图像集合,需要有相同的尺寸和深度,其中深度需为CV_8U、CV_16U或CV_32F
  • channels:要统计哪个通道的像素,彩色图像的话就有3个通道
  • hist:反向投影的计算源:直方图
  • ranges:统计量的取值范围,注意不是纵轴的取值范围,而是横轴的取值范围比如统计量是像素,那么通常就是像素值的取值范围
  • scale:缩放系数,默认值为1

三、实验

话不多说,上代码

Mat srcImage, hsvImage, hueImage;
const int hueBinMaxValue = 180;
int hueBinValue = 25;

//声明回调函数
void Hist_and_Backprojection(int, void*);

int main()
{
	srcImage = imread("D:\\cv_study\\随机练\\1.jpg");
	imshow("原图", srcImage);
	//判断图像是否加载成功
	if (srcImage.empty())
	{
		cout << "图像加载失败" << endl;
		return -1;
	}
	else
		cout << "图像加载成功..." << endl << endl;

	//将图像转化为HSV图像
	cvtColor(srcImage, hsvImage, CV_BGR2HSV);

	//只使用图像的H参数
	hueImage.create(hsvImage.size(), hsvImage.depth());
	int ch[] = { 0,0 };
	mixChannels(&hsvImage, 1, &hueImage, 1, ch, 1);

	//轨迹条参数设置

	namedWindow("SourceImage", WINDOW_AUTOSIZE);

	//创建轨迹条并调用回调函数
	createTrackbar("值", "SourceImage", &hueBinValue, hueBinMaxValue, Hist_and_Backprojection);
	Hist_and_Backprojection(hueBinValue, 0);

	imshow("SourceImage", srcImage);

	waitKey(0);

	return 0;
}

void Hist_and_Backprojection(int, void*)
{
	MatND hist;
	int histsize = MAX(hueBinValue, 2);
	float hue_range[] = { 0,180 };
	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());

	//获取反向投影
	MatND backProjection;
	calcBackProject(&hueImage, 1, 0, hist, backProjection, &ranges, 1, true);

	//输出反向投影
	imshow("BackProjection", backProjection);

	//绘制图像直方图
	int w = 400;
	int h = 400;
	int bin_w = cvRound((double)w / histsize);
	Mat histImage = Mat::zeros(w, h, CV_8UC3);
	for (int i = 0; i < hueBinValue; i++)
	{
		rectangle(histImage, Point(i*bin_w, h), Point((i + 1)*bin_w, h - cvRound(hist.at(i)*h / 255.0)), Scalar(0, 0, 255), -1);
	}
	imshow("HistImage", histImage);
}

结果如下:

opencv 浅谈反向投影_第1张图片


opencv 浅谈反向投影_第2张图片

opencv 浅谈反向投影_第3张图片

这里将反向投影的结果复现出来,那么反向投影有什么用呢,就我所知道的在目标跟踪算法mean-shift和camshift中都会用到,计算目标区域的反向投影,然后进行匹配,一系列的迭代和逼近,这里我就不多说了,有兴趣的可以搜索一下上面说的算法。知识有限,错误的地方请批评指正,谢谢

你可能感兴趣的:(opencv)