OpenCV学习二十五:calcBackProject 直方图反射函数

版权声明:共享知识,欢迎转载 https://blog.csdn.net/kakiebu/article/details/79522547

如果一幅图像的区域中显示的是一种结构纹理或者一个独特的物体,那么这个区域的直方图可以看作一个概率函数,他给的是某个像素属于该纹理或物体的概率。所谓反向投影就是首先计算某一特征的直方图模型,然后使用模型去寻找测试图像中存在的该特征。

void cv::calcBackProject 
(
const Mat * images, 
int nimages,
const int * channels,
InputArray hist,
OutputArray backProject,
const float ** ranges, 
double scale = 1,
bool uniform = true
)

const Mat* images:输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数 
int nimages:输入图像的数量 
const int* channels:用于计算反向投影的通道列表,通道数必须与直方图维度相匹配,第一个数组的通道是从0到image[0].channels()-1,第二个数组通道从图像image[0].channels()到image[0].channels()+image[1].channels()-1计数 
InputArray hist:输入的直方图,直方图的bin可以是密集(dense)或稀疏(sparse) 
OutputArray backProject:目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度 
const float ranges**:直方图中每个维度bin的取值范围 
double scale=1:可选输出反向投影的比例因子 

bool uniform=true:直方图是否均匀分布(uniform)的标识符,有默认值true

#include <opencv2/opencv.hpp>  
#include <stdio.h>  
#include <stdlib.h>  
#include <iostream>

using namespace cv;  
using namespace std;  

char file[] = "10.jpg";
char file2[] = "11.jpg";
string convertToString(double d);
int main(int argc, char** argv)  
{  
	Mat img = imread(file, -1);
	pyrDown(img, img, Size(img.cols/2, img.rows/2));
	pyrDown(img, img, Size(img.cols/2, img.rows/2));
	pyrDown(img, img, Size(img.cols/2, img.rows/2));
	imshow("1",img);imwrite("img.jpg", img);

	//对比阀值前后的效果差异
	///////////////////////////////////////////////////
	Mat hsv, hue;
	int nChannels[] = {0, 0};
	cvtColor(img, hsv, CV_BGR2HSV);
	hue.create(hsv.size(), hsv.depth());
	mixChannels(&hsv, 1, &hue, 1, nChannels, 1);//复制特定通道的图像
	imshow("hue_before_threshold",hue);imwrite("hue_before_threshold.jpg", hue);

	Mat h_hist;
	int n = 15;
	float range[] = {0, 180};
	const float *ranges = {range};
	calcHist(&hue, 1, 0, Mat(), h_hist, 1, &n, &ranges, true, false);
	normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());

	int img_h = 700;//图片的高(行数)  
	int img_w = 512;//图片的宽(列数)  
	int line_w = 30;//线宽  
	Mat histImage_before_threshold(img_h, img_w, CV_8UC3, Scalar(0,0,0));//图片(画布)大小  
	for (int i=1; i<n; i++)  
	{   
		line(histImage_before_threshold, Point((i-1)*line_w, img_h - cvRound(h_hist.at<float>(i-1)) - 200),  
			Point(i*line_w, img_h - cvRound(h_hist.at<float>(i)) - 200),Scalar(0,0,255), 2);  		
	}  
	imshow("histImage_before_threshold", histImage_before_threshold);imwrite("histImage_before_threshold.jpg", histImage_before_threshold);

	Mat backPrjImage;
	calcBackProject(&hue, 1, 0, h_hist, backPrjImage, &ranges, 1, true);
	imshow("backPrjImage_before_threshold", backPrjImage);imwrite("backPrjImage_before_threshold.jpg", backPrjImage);

	//阀值后
	threshold(hue, hue, 80, 180, THRESH_BINARY);
	imshow("hue",hue);imwrite("hue.jpg", hue);

	calcHist(&hue, 1, 0, Mat(), h_hist, 1, &n, &ranges, true, false);
	normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());

	Mat histImage(img_h, img_w, CV_8UC3, Scalar(0,0,0));//图片(画布)大小  
	for (int i=1; i<n; i++)  
	{   
		line(histImage, Point((i-1)*line_w, img_h - cvRound(h_hist.at<float>(i-1)) - 200),  
			Point(i*line_w, img_h - cvRound(h_hist.at<float>(i)) - 200),Scalar(0,0,255), 2);  		
	}  
	imshow("histImage", histImage);imwrite("histImage.jpg", histImage);

	calcBackProject(&hue, 1, 0, h_hist, backPrjImage, &ranges, 1, true);
	imshow("backPrjImage", backPrjImage);imwrite("backPrjImage.jpg", backPrjImage);


	//这里测试下同一个物体在两个图片里的效果
	//注意,虽然是两个图片,这里我取得是同一相机拍摄的图片
	////////////////////////////////////////////////////////////
	Mat img2 = imread(file2, -1);
	pyrDown(img2, img2, Size(img2.cols/2, img2.rows/2));
	pyrDown(img2, img2, Size(img2.cols/2, img2.rows/2));
	pyrDown(img2, img2, Size(img2.cols/2, img2.rows/2));
	imshow("2",img2);imwrite("img2.jpg", img2);

	Mat hsv2, hue2;
	int nChannels2[] = {0, 0};
	cvtColor(img2, hsv2, CV_BGR2HSV);
	hue2.create(hsv2.size(), hsv2.depth());
	mixChannels(&hsv2, 1, &hue2, 1, nChannels2, 1);
	threshold(hue2, hue2, 70, 180, THRESH_BINARY);//注意,两个图片的预处理是不一样的
	imshow("hue2",hue2);imwrite("hue2.jpg", hue2);

	Mat backPrjImage2;
	calcBackProject(&hue2, 1, 0, h_hist, backPrjImage2, &ranges, 1, true);
	imshow("backPrjImage2", backPrjImage2);imwrite("backPrjImage2.jpg", backPrjImage2);

	waitKey();
	return 1;
} 

总结:calcBackProject 函数是基于概率的一个反射函数,因此必须要求图片的概率特征明显,所以光源以及一定的预处理是必须的。其次可以通过预定良好的模板对物体进行识别,反射后得到的图片非常利于特征的抓取以及物体识别。

img.jpg

hue_before_threshold.jpg

histImage_before_threshold.jpg

backPrjImage_before_threshold.jpg

hue.jpg

histImage.jpg

backPrjImage.jpg

img2.jpg

hue2.jpg

backPrjImage2.jpg

猜你喜欢

转载自blog.csdn.net/kakiebu/article/details/79522547
今日推荐