【45】【OpenCv】直方图 *** 作 反向投影之基础的反向投影 cv::calcBackProject()

【45】【OpenCv】直方图 *** 作 反向投影之基础的反向投影 cv::calcBackProject(),第1张

反向投影是计算像素和直方图模型种像素吻合度的一种方法。

例如有肤色的直方图,可以使用反向投影在图像中寻找肤色区域,用来做这种寻找 *** 作的函数有两种形式,一个是为稠密数组而设计的,另一个为稀疏数组设计的。

和cv::calcHist()类似,反向投影从输入图像的指定通道种计算出一个向量。不同之处在于cv::calcHist()在向直方图种记录累计值,反向投影从输入的直方图种读取当前像素对应的计数值作为结果。

从统计学的视角来看,如果将输入的直方图视为某个物体上特定的向量的一个概率分布,那么反向投影就是计算图片上某个特定部分来自该先验分布的概率。

函数声明:

void cv::calcBackProject(
	const cv::Mat* images,  // C-Style of images ,8U or 32F
	int nimages,  // number of images in 'images' array
	const int* channels,  // C-style list,ints indentifying channels
	cv::InputArray hist,  // input histogram array
	cv::OutputArray bacProject,  // output single channel array
	const float** ranges,  // C-style array, 'dims' pairs of bin sizes
	double scale = 1,  // optional scale factor for output
	bool uniform = true  // true for uniform binning
);

void cv::calcBackProject(
	const cv::Mat* images,  // C-style array of images, 8U or 32F
	int nimages,  // number of images in 'images' array
	const int* channels,  // C-style list, ints indentifyinf channels
	const cv::SparseMat& hist,  // input(sparse) histogram array
	cv::OutputArray backProject,  // output single channel array
	const float** ranges,  // C-style array, 'dims' pairs of bin sizes
	double scale = 1,  // optional scale factor for output
	bool uniform = true  // true for uniform binning
);

void cv::calcBackProject(
	cv::InputArrayOfArrays images,  // STL-vector of images,8U or 32F
	const vector& channels,  // STL-vector,channels indices
	cv::InputArray hist,  // input histogram array
	cv::OutputArray backProject,  // output single channel array
	const vector& ranges,  // STL-style vector range boundaries
	double scale = 1,  // optional scale factor for output
	bool uniform = true  // true for uniform binning
);

可以看到有三种版本的cv::calcBackProject(),前两个使用C风格数组作为输入,分别支持稠密直方图和稀疏直方图,第三个使用基于模板的输入。

不管是哪种情况,都应以单通道或是多通道数组集合的形式提供图像,同时以cv::calcHist()输出的直方图的格式传入直方图。

单通道数组集合恰和调用cv::calcHist()时所传入的第一个参数具有想用的形式,只是此时表示要和直方图做比较的图片几个。如果参数images是一个C风格数组,需要传递nimages指明images数组中元素的个数。

参数channel是通道的列表,该参数的形式和调用cv::calcHist()时对用的参数形式相同。虽然channels元素的个数等于直方图hist的维数,但该数组并不要求等于images中的数组数(或者说images中通道的总数。

反向计算的结果保存在backProject中,大小类型和images[0]相同,只有一个通道。

参数ranges与cv::calcHist()计算直方图时传入的区间信息ranges一致。

参数scale是一个可选的应用于backProject的缩放因子(需要结果可视化时有用)。

参数uniform表示输入的直方图是不是一个均匀的直方图,和cv::calcHist()中的意义相同。默认=true表示传入的直方图是均匀的,在传入的直方图是非均匀时需要设置为false。

该函数使用与cv::calcHist()极其类似,使用参考如下:

通过滑动条控制直方图的区间个数,读取另一张图4.jpg,计算出它的反向投影,并计算该反向投影的直方图,并与argv[1]图片的直方图比较。

#include 
#include 
#include 

using namespace std;
using namespace cv;

#define WINDOW_NAME "原始图"

void on_trackbar(int pos,void *param);


int main(int argc, char* argv[])
{
	int nPos = 30;
	int nMaxPos = 180;
	cv::Mat srcImg = cv::imread(argv[1],cv::IMREAD_COLOR);
	if(!srcImg.data)
	{
		printf("Load image fail,%s\r\n",argv[1]);
		return -1;
	}
	cv::Mat hsv;
	cv::cvtColor(srcImg,hsv,cv::COLOR_BGR2HSV);

	//calcTwoDims(hsv,argv);

	int ch[] = {0,0};
	cv::Mat hueImg, histImg;
	hueImg.create(hsv.size(),hsv.depth());
	cv::mixChannels(&hsv,1,&hueImg,1,ch,1);
	cv::namedWindow(WINDOW_NAME);

	cv::Mat imgs[] = {hueImg,histImg};
	cv::createTrackbar("hue",WINDOW_NAME,&nPos,nMaxPos,on_trackbar,(void*)imgs);

	cv::imshow(WINDOW_NAME,srcImg);

	cv::waitKey(0);
	return 0;
}

void on_trackbar(int pos,void *param)
{
	cv::Mat imgs[3] = {*(cv::Mat*)param};
	cv::Mat hueImg = imgs[0];
	cv::Mat hist;
	cv::Mat backPro = imgs[1];


	// 计算直方图
	int histSize = max(pos,2);  // 区间个数
	float h_range[] = {0,180};
	const float *histRange[] = {h_range};
	cv::calcHist(&hueImg,1,0,cv::noArray(),hist,1,&histSize,histRange);
	cv::normalize(hist,hist,0,255,cv::NORM_MINMAX);

	// 计算反向投影
	
	cv::Mat srcImg = cv::imread("4.jpg",cv::IMREAD_COLOR);
	if(!srcImg.data)
	{
		printf("Load image fail,%s\r\n","4.jpg");
		return;
	}
	cv::Mat hsv;
	cv::cvtColor(srcImg,hsv,cv::COLOR_BGR2HSV);

	int ch[] = {0,0};
	cv::Mat hueImg1;
	hueImg1.create(hsv.size(),hsv.depth());
	cv::mixChannels(&hsv,1,&hueImg1,1,ch,1);
	

	cv::calcBackProject(&hueImg1,1,0,hist,backPro,histRange);

	cv::Mat backHist;
	cv::calcHist(&backPro,1,0,cv::noArray(),backHist,1,&histSize,histRange);
	cv::normalize(backHist,backHist,0,255,cv::NORM_MINMAX);

	printf("\nhue_%d:",pos);
	for(int i=0;i<4;i++)
	{
		printf("method[%d] = %f\t",i,cv::compareHist(hist,backHist,i));
	}
	vector sigv;
	for(int i=0;i(i);
		if(hval != 0)
			sigv.push_back(cv::Vec3f(hval,(float)i,0));
	}
	cv::Mat sig0 = cv::Mat(sigv).clone().reshape(1);
	sigv.clear();
	for(int i=0;i(i);
		if(hval != 0)
			sigv.push_back(cv::Vec3f(hval,(float)i,0));
	}

	cv::Mat sig = cv::Mat(sigv).clone().reshape(1);
	printf("EMD = %f",cv::EMD(sig0,sig,CV_DIST_L2));

	// 绘制直方图
	int h=400;
	int w=400;
	int bin_w = cvRound((double)w/histSize);
	cv::Mat histImg = cv::Mat::zeros(h,w,CV_8UC3);

	for(int i=1;i(i)*h/255.0)),
			cv::Scalar(100,133,255),
			-1
			);
	}

	cv::imshow("反射投影",backPro);
	cv::imshow("直方图",histImg);
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1498725.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-25
下一篇 2022-06-25

发表评论

登录后才能评论

评论列表(0条)

保存