直方图反向投射(Back Projection)详解

openCV笔记——直方图反向投射(Back Projection)详解

备注:本人近期学习图像处理,一路遇到许多问题,多亏得到许多博主博客指点,感激不尽。现学习到直方图反向投射,花了半天时间终于搞懂了,故第一次写此博客记录,如有错误,请网友指正。

一、反向投影概念

反向投影是反应直方图模型在目标图像中的的分布情况,简单来说就是用直方图模型去目标图像中寻找相似的特征对象。

二、反向投影的作用

反向投影的作用是:在输入图像中寻找与模板图像最匹配的区域,也就是定位模板图像出现在输入图像的位置。

三、反向投影的原理

举例:
使用模型直方图(代表手掌的皮肤色调)来检测测试图像中的皮肤区域。以下是检测的步骤:

  1. 对测试图像中的每个像素P(i,j),获取色调数据并找到该色调h(i,j)在直方图中的bin的位置。
  2. 查询模型直方图中对应的bin-h(i,j)-并读取该bin的数值。
  3. 将此数值储存在新的图像中(BackProjection)。可以先归一化模型直方图,这样测试图像的输出就可以在屏慕显示了。
  4. 通过对测试图像中的每个像素采用以上步骤,就得到了BackProjection 结果图。

如:模板Hue像素为:
在这里插入图片描述
直方图的bin为:[0,3],[4,7],[8,11],[12,15]
模型直方图为:4 4 6 2
假设待测图片的Hue为:
在这里插入图片描述
(反向投影在某一位置的值就是原图对应位置像素值在在模型直方图中所属bin的值)
反向投影图为:
calcBackProject=
在这里插入图片描述
可看出与模型相同特征处较亮。

四、实现步骤与相关API

  • 加载图片imread
  • 将图像从RGB色彩空间转换到HSV色彩空间cvtColor
  • 分割出hue通道mixChannels
  • 计算直方图和归一化calcHist与normalize
  • Mat与MatND其中Mat表示二维数组,MatND表示三维或者多维数组,此处均可以用Mat表示。
  • 计算反向投影图像-calcBackProject

calceackProject
const Matimages,//输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数
int nimages,//输入图片数量
const int
channels,//用于计算反向投影的通道列表,通道数必须与直方图维度相匹配
InputArray hist,//输入的直方图
OutputArray backProject,//目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度
const float **ranges,//直方图中每个维度bin的取值范围(二维数组)
double scale=1,//可选输出反向投影的比例因子
bool uniform =true, //直方图是否均匀分布(uniform)的标识符,有默认值true

mixchannels( //通道图像分割
const Matsrc,//输入数组或向量矩阵,所有矩阵的大小和深度必须相同。(指针形式)
size_t nsrcs,//矩阵的数量
Mat
dst,//输出数组或矩阵向量,大小和深度必须与src[0]相同(指针形式)
size_t ndsts,//输出矩阵的数量
const int*fromTo,//指定被复制通道与要复制到的位置组成的索引对
size_t npairs //fromTo中索引对的数目

五、代码演示

/*直方图反向投射
利用图片hand.jpg的hue通道的直方图hist作为模板,去图片hand1.jpg中的hue通道寻找相似特征
*/

#include <iostream>
#include <opencv2/opencv.hpp>
#include<math.h>
using namespace std;
using namespace cv;
char inputTitle[]="input demo"char outputTitle[]="BackPro ject demo";
Mat model,test;
int bins=50/区间数(级数)
void Hist_And_BackPro ject(intvoid*);
int main(char argc,char**argv)
{
	model=imread("D:\\OpenCV\\VS_opencv\\images\\hand.jpg");
	if(!model.data)
	{
		cout<<"couldn't load image..."<<end1;
		return-1}
	imshow("model demo",model);
	test=imread("D:\\ OpenCV\\ VS_opencv\\ images\\ hand1. jpg"); 
	if (! test. data)
	{
		cout<<"couldn't load image..."<<end1; 
		return-1;
	}
	imshow("test demo", test); 
	namedWindow(outputTitle, WINDOW_AUTOSIZE); 
	createTrackbar("bins Value:", outputTitle,& bins,180, Hist_And_BackProject); 		 
	Hist_And_BackPro ject(0,0); 
	return 0;
}
void Hist_And_BackProject(intvoid*{
	//分离hue通道
	Mat hsv,hue,hsv1,hue1;
	//mode1:hand 
	cvtColor(model,hsv,COLOR_BGR2HSV);
	hue.create(hsv.size),hsv.depth());
	int nchannels[]={00}//索引对(hsv的0通道分离到hue的0通道)
	mixchannels(&hsv,1&hue,1,nchannels,1);
	//test:hand1
	cvtColor(test,hsvl,COLOR_BGR2HSV);
	huel.create(hsvl.size(),hsv.depth));//索引对(hsv的0通道分离到hue的0通道)
	mixChannels(&hsvl,1&huel,1,nchannels,1);
	//计算直方图
	Mat hist;/输出直方图矩阵
	int histsize=max(bins,2);//级数(至少2级)
	float range[]={0180}const float*Range[]={range}//取值范围
	calcHist(&hue,10,Mat(),hist,1&histsize,Range,truefalse);//直方图计算
	normalize(hist,hist,0255,NORM_MINMAX,-1,Mat());∥归一化
	//反向投影
 	Mat BackProject;
 	calcBackPro ject(&hue1,10,hist,BackProject,Range,1true);
 	imshow(outputTitle,BackProject);
	//绘制直方图
	int hist_w=512int hist h=512;
	Mat hist_draw(hist_w,hist_h,CV_8UC3,Scalar(000));//绘制画布
	int bin w=cvRound(hist w/bins);//每个区间的宽度
	for(size_ti=0;i<bins;i++/*矩形
	//Rect类:成员变量x、y、width、height,分别为左上角点的坐标和矩形的宽和高
	//因为图片的(0,0)点在左上角,所以纵坐标要用总高度减去算出的高度
	Rect rect=Rect(i*binw,hist_h-cvRound(hist.at<float>(i)*hist_h/255),bin_w,cvRound(hist.at<float>(i)*hist_h/255));
	rectangle(hist_draw,rect,Scalar(255,0,0),2,LINE_AA);
	*/
	
	//填充(fi11Poly)
	//因为图片的(0,0)点在左上角,所以纵坐标要用总高度减去算出的高度
	Point pts[1][5];
	pts[0][0]=Point(i*bin w,hist h-cvRound(hist.at<float>(i)*hist h/255));
	pts[0][1]=Point((i+1*bin_w,hist_h-cvRound(hist.at<float>(i)*hist_h/255));
	pts[0][2]=Point((i+1*bin w,hist_h);
	pts[0][3]=Point(i*bin w,hist h);
	pts[0][4]=Point(i*bin w,hist_h-cvRound(hist.at<float>(i)*hist_h/255));
	const Point*ppts[]={pts[0]}int npt[]={5};fil1Poly(hist_draw,ppts,npt,1,Scalar(00255),LINE_AA);
	imshow("Hist demo",hist_draw);
	waitKey(0);
	return}
	

结果

在这里插入图片描述

后记:学疏才浅,如有错误,忘指正!
感谢贾志刚老师的《opencv基础教程》视频教程。

  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
反向投影是一种用于图像分割的技术,它可以将图像中某个特定区域中的像素值与整个图像中的像素值进行比较,从而实现对该区域的分离。OpenCV中提供了多通道直方图算法来实现反向投影,以下是一些示例代码: ```c++ #include <opencv2/opencv.hpp> using namespace cv; int main() { Mat image, hsv; image = imread("image.jpg"); // 转换为HSV格式 cvtColor(image, hsv, COLOR_BGR2HSV); // 设置H、S通道的范围 float h_ranges[] = { 0, 180 }; float s_ranges[] = { 0, 256 }; const float* ranges[] = { h_ranges, s_ranges }; // 设置H、S通道的数量 int h_bins = 16, s_bins = 16; int hist_sizes[] = { h_bins, s_bins }; // 计算图像的直方图 MatND hist; int channels[] = { 0, 1 }; calcHist(&hsv, 1, channels, Mat(), hist, 2, hist_sizes, ranges, true, false); // 归一化直方图 normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat()); // 反向投影 Mat dst; calcBackProject(&hsv, 1, channels, hist, dst, ranges, 1, true); // 显示结果 imshow("image", image); imshow("back projection", dst); waitKey(0); return 0; } ``` 在这个示例中,我们首先将图像转换为HSV格式,然后计算出H、S通道的直方图,并将其归一化。接下来,我们使用`calcBackProject`函数来计算反向投影图像,并将结果显示出来。 注意,我们在调用`calcHist`和`calcBackProject`函数时,都需要指定通道数量和通道范围。在本例中,我们使用了两个通道(H、S),并将H通道的范围设置为0到180,S通道的范围设置为0到256。我们还指定了16个bin用于计算直方图,这个值可以根据实际需要进行调整。 希望这些代码可以对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值