opencv入门(14)--直方图

14.1 引言

       直方图是对数据进行统计的一种方式。其实就是对值进行范围分段,统计每个值出现的频率情况。

       图像直方图可以用来表示数字图像灰度的分布情况,是指对整个图像在灰度范围内的像素值出现频次的统计。此外,对图像的梯度、每个像素的角度等一切图像的属性值我们都可以建立直方图。可以直观地看出图像的灰度特征、梯度、方向等。如下图所示:

直方图最常见的几个属性:

  1. dims--表示维度,对灰度图像来说只有一个通道值dims=1
  2. bins--表示在维度中子区域大小的划分,bins=256,划分为256个级别
  3. range--表示值的范围,灰度值范围是0~255之间

14.2 直方图计算

14.2.1 相关API

  • void cv::split(const Mat &src, Mat *mvbegin)
参数含义
作用将多通道图形分为多个单通道图像
输入src

输入图像

vbegin输出的多通道图像数组
返回值void
  • void cv::calcHist(const Mat *images, int nimages,const int* channels,InputArray mask,OutputArray hist, int dims,const int *histsize, const float* ranges,bool uniform, bool accumulate)
参数含义
作用将多通道图形分为多个单通道图像
输入images输入的图像的指针
nimages输入图像个数
channels需要统计直方图的第几通道
mask掩模,mask必须是一个8位(CV_8U)的数组并且和images的数组大小相同
hist直方图计算的输出值
dims输出直方图的维度(由channels指定);
histsize直方图中每个dims维度需要分成多少个区间(如果把直方图看作一个一个竖条的话,就是竖条的个数
ranges统计像素值的区间
uniform是否对得到的直方图数组进行归一化处理
accumulate在多个图像时,是否累积计算像素值的个数
返回值void

14.2.2 代码示例

int main(int argc, char** argv)
{
	Mat src = imread("D:\\testimg\\CSet12\\lena.png");
	if (src.empty())
	{
		printf("Could not load the image...\n");
		return -1;
	}
	else;
	char input_win[] = "srcImg";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	imshow(input_win, src);

	//分离多通道图像;
	vector<Mat> bgrImgs;
	split(src, bgrImgs);
	//imshow("B", bgrImgs[0]);

	//定义直方图参数
	int histsize = 256;
	float range[] = { 0,256 };
	const float *histrange = { range };
	Mat bHist, gHist, rHist;
	calcHist(&bgrImgs[0],1,0,Mat(),bHist,1,&histsize,&histrange,true,false);
	calcHist(&bgrImgs[1], 1, 0, Mat(), gHist, 1, &histsize, &histrange, true, false);
	calcHist(&bgrImgs[2], 1, 0, Mat(), rHist, 1, &histsize, &histrange, true, false);

	//绘制直方图
	int histh = 256;
	int histw = 512;
	int binw = histw / histsize;
	Mat histImg(histh, histw,CV_8UC3,Scalar(0,0,0));
    //灰度值归一化到画布高度
	normalize(bHist, bHist,0, histh,NORM_MINMAX,-1,Mat());
	normalize(gHist, gHist, 0, histh, NORM_MINMAX, -1, Mat());
	normalize(rHist, rHist, 0, histh, NORM_MINMAX, -1, Mat());
	for (int i = 1; i < histsize; i++)
	{
		line(histImg, Point((i - 1)*binw, histh - cvRound(bHist.at<float>(i - 1))), Point((i)*binw, histh - cvRound(bHist.at<float>(i))), Scalar(255, 0, 0), 2);
		line(histImg, Point((i - 1)*binw, histh - cvRound(gHist.at<float>(i - 1))), Point((i)*binw, histh - cvRound(gHist.at<float>(i))), Scalar(0, 255, 0), 2);
		line(histImg, Point((i - 1)*binw, histh - cvRound(rHist.at<float>(i - 1))), Point((i)*binw, histh - cvRound(rHist.at<float>(i))), Scalar(0, 0, 255), 2);
	}
	imshow("histImg", histImg);


	waitKey(0);
	return 0;
}

14.3直方图均衡化

       直方图均衡化是一种提高图像对比度的方法,拉伸图像灰度值范围。可以将较少像素的灰度分配到别的灰度中去,像素相对集中的,放大器灰度变化范围,是对比度变大,有效增强图像。

14.3.1 实现方式

 将图像的灰度分布映射到另一个分布上,得到映射后的像素值即可。

  1. 计算原图像的直方图H;
  2. 将柱状图归一化,是柱状图bin的总和为255;
  3. 计算直方图积分H^{'}(i)=\sum_{0\leq j< i}^{}H(j)
  4. 使用H'作为查找表的转换图像:equalized(x,y)=H^{'}(src(x,y))

14.3.2 相关API:equalizeHist

  • void cv::equalizeHist(InputArray src, OutputArray dst)
参数含义
作用直方图均衡化,用于提高图像的质量
输入src

原图,8位单通道的图像

dst输出图像,大小与输入图像一致
返回值void

14.3.3 代码示例

//绘制直方图
void ShowHist(Mat &Hist,string sName)
{	
	int histw = 513;
	int histh = 256;
	int width = 2;
	Mat histImage = Mat::zeros(histh, histw, CV_8UC3);   //准备histImage为全黑背景色,大小为512*256
	for (int i = 0; i < Hist.rows; i++)
	{
		rectangle(histImage, Point(width*(i), histh - 1), Point(width*(i + 1), histh - cvRound(Hist.at<float>(i) /4)),Scalar(255, 255, 255), -1);
	}
	namedWindow(sName, WINDOW_AUTOSIZE);
	imshow(sName, histImage);
	//waitKey(0);
}

int main(int argc, char** argv)
{
	Mat src = imread("D:\\testimg\\CSet12\\lena.png");
	if (src.empty())
	{
		printf("Could not load the image...\n");
		return -1;
	}
	else;
	char input_win[] = "srcImg";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	imshow(input_win, src);

	//转为灰度图
	Mat grayImg;
	cvtColor(src, grayImg,COLOR_BGR2GRAY);
	//namedWindow("grayImg", WINDOW_AUTOSIZE);
	imshow("grayImg", grayImg);

	//原灰度图的直方图
	const int channels[] = { 0 };
	Mat srcHist;//定义输出Mat类型
	int dims = 1;//设置直方图维度
	const int histSize[] = { 256 }; //直方图每一个维度划分的柱条的数目//每一个维度取值范围
	float pranges[] = { 0, 255 };//取值区间
	const float* ranges[] = { pranges };
	calcHist(&grayImg, 1, channels, Mat(), srcHist, dims, histSize, ranges, true,false);//计算直方图
	ShowHist(srcHist, "srcHist");

	//灰度均匀化
	Mat equalizeImg;
	equalizeHist(grayImg, equalizeImg);
	imshow("equalizeImg", equalizeImg);
	Mat equalizeHist;
	calcHist(&equalizeImg, 1, channels, Mat(), equalizeHist, dims, histSize, ranges, true, false);//计算直方图
	ShowHist(equalizeHist, "equalizeHist");


	waitKey(0);
	return 0;
}


14.4 直方图比较

14.4.1 直方图比较方法

对输入的两张图像计算得到直方图H1和H2,归一化到相同的尺度空间,然后可以通过计算H1、H2之间的距离得到两个直方图的相似程度,进而比较图像本身的相似程度。opencv提供了四种比较方法:

  1. Correlation--相关性比较
  2. Chi-Square--卡方比较
  3. Intersection--十字交叉性
  4. Bhattacharyya distance--巴氏距离

(1)相关性计算(CV_COMP_CORREL)

d(h_{1},h_{2})=\frac{\sum_{I}^{}(H_{1}(I)-\bar{H}_{1})(H_{2}(I)-\bar{H}_{2})}{\sqrt{\sum_{I}^{}(H_{1}(I)-\bar{H}_{1})^{2}\sum_{I}^{}(H_{2}(I)-\bar{H}_{2})^{2}}}   其中 :\bar{H}_{k}=\frac{1}{N}\sum_{j}^{}H_{k}(J)

其中N是直方图的bin的个数,\bar{H}是均值。

(2)卡方计算(CV_COMP_CHISQR)

d(h_{1},h_{2})=\sum_{I}^{}\frac{(H_{1}(I)-H_{2}(I))^{2}}{H_{1}(I)}

H1/H2分别表示两个图像的直方图数据。

(3)十字计算(CV_COMP_INTERSECT)

d(h_{1},h_{2})=\sum_{I}^{}min(H_{1}(I),H_{2}(I)),H1/H2分别表示两个图像的直方图数据。

(4)巴氏距离计算(CV_COMP_BHATTACHARYYA)

d(h_{1},h_{2})=\sqrt{1-\frac{1}{\sqrt{\bar{H_{1}}\bar{H_{2}}N^{2}}}\sum_{I}^{}\sqrt{H_{1}(I)*H_{2}(I)}};0-1相关性减小

14.4.2 图像直方图比较步骤

  1. 把图像从RGB色彩空间转换到HSV色彩空间(由于直方图对亮度和灰度图比较敏感,色彩空间转换就是突出这两个因素尽量去除其他因素)
  2. 计算图像直方图,然后归一化到[0~1]
  3. 进行直方图比较

14.4.3 相关API

  • double cv::compareHist(InputArray h1, InputArray h2,int method)
参数含义
作用直方图比较
输入h1

直方图1

h2直方图2
method

比较方法

返回值double相关性

14.4.4 代码示例

int main(int argc, char** argv)
{
	Mat src = imread("D:\\testimg\\CSet12\\lena.png");
	if (src.empty())
	{
		printf("Could not load the image...\n");
		return -1;
	}
	else;
	char input_win[] = "srcImg";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	imshow(input_win, src);

	//给原图加噪
	Mat GaussianImg,medianImg;
	GaussianBlur(src, GaussianImg,Size(3,3),0);
	medianBlur(src,medianImg,3);

	//转化到hsv空间;
	Mat hsvImg;
	cvtColor(src,hsvImg,COLOR_BGR2HSV);
	cvtColor(GaussianImg, GaussianImg, COLOR_BGR2HSV);
	cvtColor(medianImg, medianImg, COLOR_BGR2HSV);

	//计算H和S两通道直方图参数并归一化
	int hbins = 50; //H通道设置50
	int sbins = 50; //s通道设置50
	int histsize[] = { hbins ,sbins };
	//h:0~179,s:0~255	
	float hrange[] = { 0,180 };
	float srange[] = { 0,256 };
	const float *histrange[] = { hrange,srange };
	int channels[] = {0,1}; // 计算H和S两通道
	MatND histhsv;
	MatND histgaussian;
	MatND histmedian;

	calcHist(&hsvImg,1,channels,Mat(), histhsv,2,histsize,histrange,true,false);
	normalize(histhsv, histhsv,0,1,NORM_MINMAX,-1,Mat());
	calcHist(&GaussianImg, 1, channels, Mat(), histgaussian, 2, histsize, histrange, true, false);
	normalize(histgaussian, histgaussian, 0, 1, NORM_MINMAX, -1, Mat());
	calcHist(&medianImg, 1, channels, Mat(), histmedian, 2, histsize, histrange, true, false);
	normalize(histmedian, histmedian, 0, 1, NORM_MINMAX, -1, Mat());

	double compare1 = compareHist(histhsv, histhsv, 2);
	double compare2 = compareHist(histhsv, histgaussian, 2);
	double compare3 = compareHist(histhsv, histmedian, 2);
	printf("src compare with src correlation value :%f\n", compare1);
	printf("src compare with GaussianImg correlation value :%f\n", compare2);
	printf("src compare with medianImg correlation value :%f\n", compare3);

	waitKey(0);
	return 0;
}

method:0

method:1

method:2

method:3

14.5 直方图反向投影

14.5.1 概述

       反向投影是反映直方图模型在目标图像中的分布情况,简单点说计算某一特征的直方图模型,然后使用模型去寻找图像中存在的该特征的方法。通常用HSV色彩空间的HS两个通道直方图模型。

14.5.2 反向投影步骤

  1. 建立直方图模型;
  2. 计算待测图像直方图并映射到模型中;
  3. 从模型反向计算生成图像;

14.5.3 实现步骤和相关API

  1. 加载图像imread;
  2. 将图像从BGR色彩空间转换到HSV色彩空间cvtColor;
  3. 计算直方图并进行归一化处理calcHist、normalize;(Mat二维,MatND多维)
  4. 计算反向投影图像图像 calcBackProject
  • void cv::calcBackProject(const Mat *images,int nimages,const int *channels,InputArray hist,OutputArray backProject, const float **ranges,double scale=1,bool uniform=true)
参数含义
作用直方图比较
输入images输入图像指针,图像深度必须位CV_8U, CV_16U或CV_32F中的一种
nimages输入图像的数量
channels通道列表
hist输入的直方图
backProject目标反向投影输出图像,单通道图像,与原图像有相同的尺寸和深度
ranges直方图中每个维度bin的取值范围
scale可选输出反向投影的比例因子
uniform

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

返回值double相关性

14.5.4 代码示例

Mat src;
Mat hsv, hue;
int bins = 12;
void HistBackproject(int, void*)
{
	float range[] = {0,180};
	const float *histRange = {range};
	Mat h_hist;
	calcHist(&hue,1,0,Mat(),h_hist,1,&bins,&histRange,true,false);
	normalize(h_hist, h_hist,0,255,NORM_MINMAX,-1,Mat());

	Mat backProject;
	calcBackProject(&hue,1,0, h_hist, backProject, &histRange,1,true);
	imshow("backproject", backProject);
}

int main(int argc, char** argv)
{
	src = imread("D:\\testimg\\CSet12\\yingbi.png");
	if (src.empty())
	{
		printf("Could not load the image...\n");
		return -1;
	}
	else;
	char input_win[] = "srcImg";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	
	namedWindow("output_win", WINDOW_AUTOSIZE);

	//转化到hsv空间;
	cvtColor(src,hsv,COLOR_BGR2HSV);
	hue.create(hsv.size(),hsv.depth());
	int nchannels[] = {0,0};
	//从hsv中将0,0通道拷贝到hue中
	mixChannels(&hsv,1,&hue,1,nchannels,1);

	createTrackbar("hist bins:", input_win,&bins,180, HistBackproject);
	HistBackproject(0,0);

	imshow(input_win, src);

	waitKey(0);
	return 0;
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值