从这篇博文开始,小生正式从一个毫不相干专业转投数字图像处理。废话不多说了,talk is cheap. show me the code.
- 直方图均衡化目的
由于一些图像灰度的分布过于集中,这样会导致图像的层次不够分明,直方图均衡化就是为了让图像的灰度分布更均匀,图像的层次感更强。
- 数学原理
基于连续灰度分布的结论推导
直方图均衡化属于数字图像处理中灰度变换(intensity transformation)的内容,灰度变换的目的就是找到一个合适的映射函数s=T(r).将原图像的灰度值映射到新的图像中,已达到优化图像的目的。
假设原图像的灰度统计直方图标准化后为pr(r).原图像灰度范围为(0~L-1)。那么直方图均衡化找到的就是这样一个映射函数:
设映射后的图像的灰度分布为ps(s),在由概率论相关理论(随机变量函数的概率密度与随机变量概率密度的关系)可知:
对映射函数两边进行求导
所以我们可以得到变换后的图像直方图分布为
我们可以看到,变换后的图像灰度直方图分布恒为1/(L-1),这就达到了上面的目的,使得图像的灰度分布更均匀,层次感更强。
注:在灰度变换中,变换函数T(r)需要满足下面的两点要求,
- 当0≤r≤L-1时,T(r)是一个严格递增函数。
- 当0≤r≤L-1时,0≤T(r)≤L-1。
第一点要求的原因是,对于变化前像素和变换后像素灰度的明暗顺序不能改变,之所以要严格递增,是为了确保变化前和变换后像素可以一一对应。
第二点要求的原因是,变换后的图像不能超过原先的灰度级数。
不难发现,其实直方图均衡化的过程并不一定满足条件1。所以该变换时不可逆的。
公式的离散化
设原图像灰度等级为0、1、2……L-1.离散化后的映射公式就是
在利用上面公式进行计算的时候,需要把计算的结果s(r),近似为最近的整数。
- 基于OpenCV的直方图均衡化
OpenCV中有专门的直方图均衡化函数,equalizeHist,定义的头文件在imaproc/imaproc.hpp中。
基于OpenCV的直方图均衡化代码段:
//load the original image and show
Mat src,dst_1;
src = imread("test.jpg",);
namedWindow("OriginalGrayImage");
imshow("OriginalGrayImage",src); //use the OpenCV measure do histogram equalization
equalizeHist(src,dst_1);
namedWindow("histogram equalization_opencv");
imshow("histogram equalization_opencv",dst_1);
仿真结果:
原图:
使用equalizeHist均衡化后的结果:
- 根据推导过程,自己编写的直方图均衡化
代码段如下:
//rewrite the histogram algorithm
//get some needed information
int nr = src.rows;
int nc = src.cols;
int n = nr*nc;
Mat dst_2(nr,nc,CV_8U); //get the histogram of original image
uchar *p_1 = NULL;
unsigned int hist[] = {};
for(int i=;i<nr;i++)
{
p_1 = src.ptr<uchar>(i);
for(int j=;j<nc;j++)
{
hist[p_1[j]] = hist[p_1[j]]+;
}
} //calculate the transform function
uchar transf_fun[] = {};
transf_fun[] = (uchar)(*hist[]/n);
for(int i=;i<;i++)
{
hist[i] = hist[i-]+hist[i];
transf_fun[i] = (uchar)(*hist[i]/n);
} //pad dst_2 the equalized values
uchar *p_2 = NULL;
for(int i=;i<nr;i++)
{
p_2 = dst_2.ptr<uchar>(i);
p_1 = src.ptr<uchar>(i);
for(int j=;j<nc;j++)
{
p_2[j] = transf_fun[p_1[j]];
}
} //show the results of our own histogram algorithm
namedWindow("histogram equalization_own");
imshow("histogram equalization_own",dst_2)
运行结果: