文章目录

  • 对比度增强
  • 一、对比度增强的方法?
  • 二、各方法的原理
  • 1.线性变换
  • 2.直方图正规化
  • 3.伽马变换
  • 4.全局直方图均衡化
  • 5.限制对比度的自适应直方图均衡化
  • 总结



对比度增强

在图像处理中,由于获取的图像质量不好,需要通过对比度增强来提升图片质量,主要解决的是由于图像灰度级范围较小造成的对比度较低的问题,作用是使图像的灰度级范围放大,从而让图像更加清晰。

本文所总结的内容出自张平的《opencv算法精讲》

一、对比度增强的方法?

对比度提升的几种常用方法:

线性变换、直方图正规化、伽马变换、全局直方图均衡化、限制对比度的自适应直方图均衡化等。

二、各方法的原理

1.线性变换

我们知道简单的线性方程公式是 y = a*x+b,对于图像亮度提升来说,此时的x,y都是二维矩阵,通过系数a来调整原始图像中的图像灰度级的范围(指的是图像转换为灰度图后的范围 [最小灰度值,最大灰度值] )

当0<a<1时,图像灰度级方位缩小,当a>0时,图像灰度级范围扩大。
当b>0时,亮度增加,当b<0时,亮度减小。

代码如下:

/*
线性变换
变换后的矩阵B = a*原矩阵A+b
image:原图像
rtype:输出矩阵的数据类型,CV_8U等
a:上述公式中的a
b:上述公式中的b
*/
Mat LinearTransform(const Mat& image, int rtype, double a, double b) {
	Mat Out;
	image.convertTo(Out, rtype, a, b);
	return Out;
}

2.直方图正规化

直方图正规化其实是一种自动选取a和b的线性变换的方法。
假设输入矩阵 I,高为H、宽为W,I(r,c)代表第r行第c列的灰度值,将 I 中的最小灰度值记为 I min,最大值记为 I max,即 I(r,c)∈[ I min, I max],为使输出矩阵 ***O***的灰度级范围为[ O min, O max],则 I(r,c)和 O(r,c)的映射关系如下:
提高图片对比度 python opencv 提升图像对比度_c++
其中提高图片对比度 python opencv 提升图像对比度_opencv_02提高图片对比度 python opencv 提升图像对比度_计算机视觉_03提高图片对比度 python opencv 提升图像对比度_c++_04代表第r行第c列的灰度值。这个过程就是直方图正规化。因为提高图片对比度 python opencv 提升图像对比度_灰度值_05,所以提高图片对比度 python opencv 提升图像对比度_opencv_06,一般令提高图片对比度 python opencv 提升图像对比度_线性变换_07,提高图片对比度 python opencv 提升图像对比度_线性变换_08。我们将上面的公式展开后花间,可达到线性变换的a和b,
提高图片对比度 python opencv 提升图像对比度_计算机视觉_09

代码如下:

Mat HistgramNormalization(Mat gray_image)
{	
	//获取输入矩阵的最大值和最小值
	double Imax, Imin;
	minMaxLoc(gray_image, &Imin, &Imax, NULL, NULL);

	// 定义输出矩阵的最大值和最小值
	double Omin = 0, Omax = 255;
	// 确定映射关系函数中的系数,其实就是确定线性变换中的系数a和b
	double a = (Omax - Omin) / (Imax - Imin);
	double b = Omin - a * Imin;
	Mat Out;//输出矩阵
	convertScaleAbs(gray_image, Out, a, b);//进行线性变换
	return Out;
}

3.伽马变换

伽马变换的第一步是将灰度值归一化带提高图片对比度 python opencv 提升图像对比度_线性变换_10的范围。归一化后的图像矩阵记为提高图片对比度 python opencv 提升图像对比度_计算机视觉_11,高为H,宽为W,第r行第c列的值记为提高图片对比度 python opencv 提升图像对比度_线性变换_12,输出矩阵击为提高图片对比度 python opencv 提升图像对比度_opencv_13,伽马变换就是:

提高图片对比度 python opencv 提升图像对比度_计算机视觉_14

提高图片对比度 python opencv 提升图像对比度_opencv_15时,图像不变,当提高图片对比度 python opencv 提升图像对比度_计算机视觉_16时,可以增加对比度,当 提高图片对比度 python opencv 提升图像对比度_计算机视觉_17 时,可以降低对比度,接下来我们在看一下Gamma变换的的图示,这样理解起来容易点。下图中从左上角到右下角的曲线为提高图片对比度 python opencv 提升图像对比度_计算机视觉_18,a∈[0.125,0.25,0.5,1,2,4,8],其实就是高中的幂函数,只是定义域在[0,1]之间,

提高图片对比度 python opencv 提升图像对比度_灰度值_19

代码如下:

Mat GammaTransform(Mat gray_image, double gamma)
{
	//1.归一化
	Mat fI;
	gray_image.convertTo(fI, CV_64F, 1 / 255, 0);
	//2.伽马变换,其实就是幂运算,gamma的区间为(0,1)
	Mat Out;
	pow(fI, gamma, Out);
	//3.再次进行线性变换,转换为0,255之间的像素值
	Out.convertTo(Out, CV_8U, 255, 0);
	return Out;
}

4.全局直方图均衡化

假设输入的图像为 提高图片对比度 python opencv 提升图像对比度_计算机视觉_11,高为提高图片对比度 python opencv 提升图像对比度_计算机视觉_21,宽为提高图片对比度 python opencv 提升图像对比度_线性变换_22提高图片对比度 python opencv 提升图像对比度_opencv_23代表提高图片对比度 python opencv 提升图像对比度_计算机视觉_11的灰度直方图,提高图片对比度 python opencv 提升图像对比度_c++_25代表灰度值等于k的像素点的个数,其中提高图片对比度 python opencv 提升图像对比度_灰度值_26。全局直方图均衡化的操作就是对图像提高图片对比度 python opencv 提升图像对比度_计算机视觉_11进行改变,使得输出图像提高图片对比度 python opencv 提升图像对比度_opencv_13的灰度直方图提高图片对比度 python opencv 提升图像对比度_计算机视觉_29是‘平的’,即每一个像素值的个数是‘相等’的。这里的相等不是严格意义上的相等,而是‘约等于’,即提高图片对比度 python opencv 提升图像对比度_c++_30,那么对于任意灰度级p,提高图片对比度 python opencv 提升图像对比度_opencv_31,总能找到q,提高图片对比度 python opencv 提升图像对比度_线性变换_32,使得
提高图片对比度 python opencv 提升图像对比度_灰度值_33
其中 提高图片对比度 python opencv 提升图像对比度_opencv_34提高图片对比度 python opencv 提升图像对比度_c++_35称为提高图片对比度 python opencv 提升图像对比度_计算机视觉_11提高图片对比度 python opencv 提升图像对比度_opencv_13的累加直方图,又因为提高图片对比度 python opencv 提升图像对比度_灰度值_38,所以
提高图片对比度 python opencv 提升图像对比度_线性变换_39
化简上式得
提高图片对比度 python opencv 提升图像对比度_c++_40
上式给出了一个从亮度级为p的输入像素到亮度级为q的输出像素的映射关系,p代表的是I(r,c),是原矩阵第r行第c列的像素值,此时令p=I(r,c);q代表的是O(r,c),是输出矩阵的第r行第c列的像素值,将两个进行替换得到最终的映射关系
提高图片对比度 python opencv 提升图像对比度_灰度值_41
代码如下:

Mat equalHist(Mat image)
{
	//检查图像数据类型是否符合要求,如不符合,则抛出异常
	// CV_Assert的官方简要说明如下
	// Checks a condition at runtime and throws exception if it fails
	CV_Assert(image.type() == CV_8UC1);
	// 灰度图像的宽和高
	int rows = image.rows;
	int cols = image.cols;
	//第一步:计算图像的灰度直方图
	Mat gray_hist = CalcGrayHist(image);
	//第二步:计算累加灰度直方图
	Mat zero_comu_moment = Mat::zeros(Size(256, 1), CV_32SC1); //生成一行256列的零矩阵

	for (int p = 0; p < 256; p++)
	{
		if (p==0)
		{
			zero_comu_moment.at<int>(0, p) = gray_hist.at<int>(0, 0);
		}
		else
		{
			zero_comu_moment.at<int>(0, p) = zero_comu_moment.at<int>(0, p - 1) + gray_hist.at<int>(0, p);
		}
	}

	//第三步:根据累加直方图得到输入灰度级和输出灰度级直方图的映射关系
	Mat output_q = Mat::zeros(Size(256, 1), CV_8UC1);

	float cofficient = 256.0 / (rows * cols);

	for (int p = 0; p < 256; p++)
	{
		float q = cofficient * zero_comu_moment.at<int>(0, p) - 1;
		if (q>=0)
		{
			output_q.at<uchar>(0, p) = uchar(floor(q));
		}
		else
		{
			output_q.at<uchar>(0, p) = 0;
		}
	}
	//第四步:得到直方图均衡化后的图像
	Mat equal_hist_image = Mat::zeros(image.size(), CV_8UC1);

	for (int r = 0; r < rows; r++)
	{
		for (int c = 0; c < cols; c++)
		{
			int	p = image.at<uchar>(r, c);
			//根据原像素值p获得新的像素值q重新赋值给对应位置
			equal_hist_image.at<uchar>(r, c) = output_q.at<uchar>(0, p);
		}
	}
	return equal_hist_image;
}

5.限制对比度的自适应直方图均衡化

自适应直方图均衡化首先将图像划分为不重叠的区域块,然后对每一个快进行直方图均衡化,同时为了避免噪声被放大,提出了“限制对比度”,即如果某个像素点的统计数据超过某个界限,便将多余的数量平均分配到每一个像素点上。

由此我们可以大致总结其流程:
1.将图像分割成不重叠的区域块;
2.对每个区域块进行直方图均衡化;
3.为避免噪声的出现,设置一个像素点出现的最高数量,如果超过这个数量,将多出来的平均分配到每个像素点上。
代码如下:

Mat AdaptEqualHist(Mat gray_image)
{
	//构建CLAHE对象,其默认设置“限制对比度”为40,块的大小为8*8
	Ptr<CLAHE> clahe = createCLAHE(2.0, Size(8, 8));
	Mat dst;
	//限制对比度的自适应直方图均衡化
	clahe->apply(gray_image, dst);
	return dst;

}

总结

以上为亮度提升的一些基础算法,个人认为亮度提升的关键是要提升图像像素级的范围和亮度值,最基础的就是一个的线性变换。