OpenCV:C++——直方图修正

一、直方图的概念

        一幅图像由不同灰度值的像素组成,图像中灰度的分布情况是该图像的一个重要特征。图像的灰度直方图描述了图像中灰度的分布情况,能够很直观地展示出图像中各个灰度级所占的比例。

        图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数。简单地说,就是把一辐图像中每一个像素出现的次数先统计出来,然后把每一个像素出现的次数除以总的像素个数,得到的就是这个像素出现的频率,再把像素与该像素出现的频率用图表示出来,就是灰度直方图。从图形上来说,灰度直方图是一个二维图,横坐标为图像中各个像素点的灰度值,纵坐标表
示具有各个灰度值的像素在图像中出现的次数。

        横坐标代表像素的灰度值的范围:[0,255],越接近0表示图像越黑,越接近255 表示图像越亮。纵坐标代表每一个灰度值在图像所有像素中出现的次数。曲线越高,表示该像素值在图像中出现的次数越多。除此之外,直方图的纵轴代表的是图像灰度概率密度,这种直方图称为归一化直方图,它可以直接反映不同灰度级出现的比率(或叫概率),此时会将纵坐标归一化到[0,1]区间内,也就是将灰度级出现的次数(频率或像素个数)除以图像中像素的总数。对于拥有256种灰度(灰度级是256)的图像,我们假设n为灰度值等于n的像素个数(灰度出现的次数),则该灰度出现的概率(灰度概率密度函数)可以用如下公式表示:

P(rk)=nk/n

其中,n表示图像像素的总个数,它可以用图像的宽度和高度相乘来获得;nk为灰度值为rk的像素个数(灰度出现的次数),比如m是所有像素中灰度出现的次数;L是图像的灰度级数;取表示第k级灰度值;p(rk)是各个出现的概率,反映了图像的灰度值的分布情况。

二、OpenCV实现灰度直方图

1、calcHist函数介绍

        直方图的计算很简单,无非是遍历图像的像素,统计每个灰度级的个数。在OpenCV 中封装了直方图的计算函数 calcHist,该函数能够同时计算多个图像、多个通道、不同灰度范围的灰度直方图。为了更为通用,该函数的参数有些复杂。该函数声明如下:

CV_EXPORTS void calcHist( const Mat* images, int nimages,
                          const int* channels, InputArray mask,
                          OutputArray hist, int dims, const int* histSize,
                          const float** ranges, bool uniform = true, bool accumulate = false );

/** @overload

this variant uses %SparseMat for output
*/
CV_EXPORTS void calcHist( const Mat* images, int nimages,
                          const int* channels, InputArray mask,
                          SparseMat& hist, int dims,
                          const int* histSize, const float** ranges,
                          bool uniform = true, bool accumulate = false );

/** @overload

this variant supports only uniform histograms.

ranges argument is either empty vector or a flattened vector of histSize.size()*2 elements
(histSize.size() element pairs). The first and second elements of each pair specify the lower and
upper boundaries.
*/
CV_EXPORTS_W void calcHist( InputArrayOfArrays images,
                            const std::vector<int>& channels,
                            InputArray mask, OutputArray hist,
                            const std::vector<int>& histSize,
                            const std::vector<float>& ranges,
                            bool accumulate = false );

 images: 表示图像矩阵数组,这些图像必须有相同的大小和相同的深度;

nimages: 表示数组 imagcs 的个数;

channels: 表示要计算的直方图的通道个数;

mask: 表示可选的掩码,不使用时可设为空,要和输入的图像具有相同的大小,在进行直方图

计算的时候,只会统计该掩码不为0的对应像素;

hist: 表示输出的直方图;

dims: 表示直方图的维度;

histSize 表示直方图每个维度的大小;

ranges:表示直方图每个维度要统计的灰度级的范围;

uniform:表示是否进行归一化,默认为true:

accumulate:表示累积标志,默认值为false。

2、实例

int main()
{
	Mat image_src, image_gray;
	image_src = imread("D:\\photo\\cat.jpg");//读取一张图片
	imshow("image_src", image_src);//显示出读取的图片

	cvtColor(image_src, image_gray, CV_RGB2GRAY);//将图片转换成灰度图
	
	int bins = 256;
	int hist_size[] = { bins };
	float range[] = { 0,256 };
	const float* ranges[] = { range };
	MatND hist;
	int channels[] = { 0 };
	calcHist(&image_gray, 1, channels, Mat(), hist, 1, hist_size, ranges, true, false);

	double max_val;
	minMaxLoc(hist, 0, &max_val, 0, 0);
	int scale = 2;
	int hist_height = 256;
	Mat image_hist = Mat::zeros(hist_height, bins * scale, CV_8UC3);
	for (int i = 0; i < bins; i++)
	{
		float bin_val = hist.at<float>(i);
		int intensity = cvRound(bin_val * hist_height / max_val);
		rectangle(image_hist, Point(i * scale, hist_height - 1), Point((i + 1) * scale - 1, hist_height - intensity), CV_RGB(255, 255, 255));
	}
	imshow("hist", image_hist);
	waitKey(0);
}

三、直方图均衡化

1、基本概念

        直方图均衡化是一种常见的增强图像对比度的方法,使用该方法可以增强局部图像的对比度,尤其在数据较为相似的图像中作用更加明显。直方图均衡化处理的“中心思想”是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。直方图均衡化就是把给定图像的直方图分布变成“均匀”分布的直方图分布。

        为什么要进行直方图均衡化?很多时候,我们的图片看起来不是那么清晰,这时可以对图像进行一些处理,来扩大图像像素值显示的范围。例如,有些图像整体像素值偏低,图像中的一些特征看得不是很清晰,只是隐约看到一些轮廓痕迹,这时可以通过图像直方图均衡化使得图像看起来亮一些,也便于后续的处理。直方图均衡化是灰度变换的一个重要应用,它高效且易于实现,广泛应用于图像增强处理中。图像的像素灰度变化是随机的,直方图的图形高低不齐,直方图均衡化就
是用一定的算法使直方图大致平和。

        直方图均衡化方法把原图像的直方图通过灰度变换函数修正为灰度均匀分布的直方图,然后按均衡直方图修正原图像。当图像的直方图均匀分布时,图像包含的信息量最大,图像看起来就很清晰。该方法以累计分布函数为基础,其变换函数取决于图像灰度直方图的累积分布函数。它对整幅图像进行同一个变换,也称为全局直方图均衡化。

        在均衡化过程中,必须保证两个条件:①像素无论怎么映射,一定要保证原来的大小关系不变,较亮的区域依旧较亮,较暗的区域依旧较暗,只是对比度增大,绝对不能明暗颠倒;②如果是

8位图像,那么像素映射函数的值域应在0和255之同,不能越界。综合以上两个条件,累积分布函数是一个好的选择,因为累积分布函数是单调增函数(控制大小关系),并且值域是0-1(控制越界问题)。

2、方法介绍

        下面我们实现直方图均衡化来改善图像质量。通常有两种方法可以实现,一种是不通过OpenCV 函数,另一种是通过 OpenCV 函数。通过 OpenCV 函数的方式比较简单,不懂原理也可以使用,只要把原图像输入,即可得到均衡化的图像输出,所用的函数是equalizeHist。该函数对图像进行直方图均衡化(归一化图像亮度和增强图像对比度),声明如下:

CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst );

src :表示输入图像,即源图像,填 Mat 类的对象即可,但需要为 8 位单通道的图像;

dst :表示输出结果,需要和源图像有一样的尺寸和类型。

3、实例

void test02()
{
	Mat image_src, image_gray, image_dst;
	image_src = imread("D:\\photo\\cat.jpg");//读取一张图片
	imshow("image_src", image_src);//显示出读取的图片

	cvtColor(image_src, image_gray, CV_RGB2GRAY);//将图片转换成灰度图

	imshow("image_gray", image_gray);//显示出图片

	equalizeHist(image_gray, image_dst);//均衡化

	imshow("image_dst", image_dst);//显示出图片
	waitKey(0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值