直方图均衡化算法原理与实现

来源:互联网 发布:淘宝鹦鹉 编辑:程序博客网 时间:2024/05/21 03:58

工作后,对原来学习的一些基本图像处理算法有了一些新的认识,比如Canny 算法,直方图均衡化算法等,今天就来说说直方图均衡化算法。

直方图均衡化原理

我们知道提高图像对比度的变换函数f(x)需要满足一下条件:

  1. f(x)0<=x<=L1上单调递增(不要求严格单调递增),其中L表示灰度级(L=256)
  2. f(x)的范围是[0,L1]

我们知道当图像直方图完全均匀分布的时候,此时图像的熵是最大的(随机变量每个值的概率都相同时,概率最大),图像对比度是最大的。所以,理想情况下,图像经过变换函数f(x)变换后,直方图能够均匀分布,此时对比度是最大的。

那问题来了?怎样的变换函数具有如此神奇的功能呢?[1]P74中给出了答案。 
在图像处理中,有一个重要的函数,能够满足上面的条件: 

y=f(x)=(L1)x0px(t)dt

英文原版中P145中的表述为: 
这里写图片描述
其中px(x)表示概率密度函数,在离散的图像中,表示直方图的每个灰度级的概率(在图像中,灰度级就可以看成是一个随机变量,而直方图就是该随机变量的概率密度函数),由概率论的知识,我们可以知道,变换函数f(x)其实就是连续型随机变量x的分布函数,表示的是函数下方的面积。

这里写图片描述

分布函数的两个性质:1.单调不减 2.值域为[0,1],我们可以知道f(x)满足条件1和2

有人可能会有这个疑问?图像是离散的,为什么可以用连续的来表示呢?从数学角度来看,离散是连续的一种特例(图像就是一个很好的例子)。

下面我们证明变换后的直方图是均匀的。 
由概率论知识,变换后的概率密度: 

py(y)=px(x)|(f1(y))|

由变上限函数求导法则可知
f(x)=(L1)px(x)

反函数的导数等于原函数导数的倒数,所以 
(f1(y))=1(L1)px(x)

所以 
py(y)=1L1

看到了吧,变换后的概率密度函数是一个均匀分布,对于图像来说,就是每个灰度级概率都是相等的,达到了我们的目的。 
下面我们需要将这个变换函数转换为图像中的表达,图像中,我们可以知道,可以使用求和代替积分,差分代替微分,所以上述的变换函数就是: 

y=f(x)=(L1)0xih(xi)w×h

其中h(xi)表示直方图中每个灰度级像素的个数, w和 h分别表示图像的宽和高。

直方图均衡化算法实现


void GetHistogram(const Mat &image, int *histogram){memset(histogram, 0, 256 * sizeof(int));//开辟内存空间//计算直方图int pixelCount = image.cols*image.rows;uchar *imageData = image.data;for (int i = 0; i <= pixelCount - 1; ++i){int gray = imageData[i];histogram[gray]++;}}void EqualizeHistogram(const Mat &srcImage, Mat &dstImage){CV_Assert(srcImage.type() == CV_8UC1);dstImage.create(srcImage.size(), srcImage.type());// 计算直方图int histogram[256];GetHistogram(srcImage, histogram);// 计算分布函数(也就是变换函数f(x))int numberOfPixel = srcImage.rows*srcImage.cols;int LUT[256];LUT[0] = 1.0*histogram[0] / numberOfPixel * 255;int sum = histogram[0];for (int i = 1; i <= 255; ++i){sum += histogram[i];LUT[i] = 1.0*sum / numberOfPixel * 255;}// 灰度变换uchar *dataOfSrc = srcImage.data;uchar *dataOfDst = dstImage.data;for (int i = 0; i <= numberOfPixel - 1; ++i)dataOfDst[i] = LUT[dataOfSrc[i]];}