图像对比度增强的方法可以分成两类:一类是直接对比度增强方法;另一类是间接对比度增强方法。直方图拉伸和直方图均衡化是两种最常见的间接对比度增强方法。直方图拉伸是通过对比度拉伸对直方图进行调整,从而“扩大”前景和背景灰度的差别,以达到增强对比度的目的,这种方法可以利用线性或非线性的方法来实现;直方图均衡化则通过使用累积函数对灰度值进行“调整”以实现对比度的增强。
直方图均衡化的英文名称是Histogram Equalization.
直方图均衡化是图像处理领域中利用图像直方图对对比度进行调整的方法。这种方法通常用来增加许多图像的局部对比度,尤其是当图像的有用数据的对比度相当接近的时候。通过这种方法,亮度可以更好地在直方图上分布。这样就可以用于增强局部的对比度而不影响整体的对比度,直方图均衡化通过有效地扩展常用的亮度来实现这种功能。
基本思想
直方图均衡化处理的“中心思想”是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。直方图均衡化就是把给定图像的直方图分布改变成“均匀”分布直方图分布。
直方图均衡化的基本思想是把原始图的直方图变换为均匀分布的形式,这样就增加了象素灰度值的动态范围从而可达到增强图像整体对比度的效果。设原始图像在(x,y)处的灰度为f,而改变后的图像为g,则对图像增强的方法可表述为将在(x,y)处的灰度f映射为g。在灰度直方图均衡化处理中对图像的映射函数可定义为:g = EQ (f),这个映射函数EQ(f)必须满足两个条件(其中L为图像的灰度级数):
(1)EQ(f)在0≤f≤L-1范围内是一个单值单增函数。这是为了保证增强处理没有打乱原始图像的灰度排列次序,原图各灰度级在变换后仍保持从黑到白(或从白到黑)的排列。
(2)对于0≤f≤L-1有0≤g≤L-1,这个条件保证了变换前后灰度值动态范围的一致性。
累积分布函数(cumulative distribution function,CDF)即可以满足上述两个条件,并且通过该函数可以完成将原图像f的分布转换成g的均匀分布。此时的直方图均衡化映射函数为:
gk = EQ(fk) = (ni/n) = pf(fi) ,
(k=0,1,2,……,L-1)
上述求和区间为0到k,根据该方程可以由源图像的各像素灰度值直接得到直方图均衡化后各像素的灰度值。在实际处理变换时,一般先对原始图像的灰度情况进行统计分析,并计算出原始直方图分布,然后根据计算出的累计直方图分布求出fk到gk的灰度映射关系。在重复上述步骤得到源图像所有灰度级到目标图像灰度级的映射关系后,按照这个映射关系对源图像各点像素进行灰度转换,即可完成对源图的直方图均衡化。
图像直方图变换的基本原理:
设变量r代表图像中像素的灰度级,直方图变换就是假定一个变换式:
(1-1)
也就是,通过上述变换,每个原始图像的像素灰度级r都会产生一个s值。变换函数T(r)应满足以下条件:
(1) T(r)在区间中为单值且单调递增;
(2) 当 时,,即T(r)的取值范围与r相同。
2. 直方图均衡化:
对于离散值,我们处理其概率与求和,而不是概率密度函数与积分。一幅图像中灰度级rk出现的概率近似为
(1-2)
其中,n是图像中像素的总和, 是灰度级 的像素个数,L为图像中可能的灰度级总数。
(1-3)
上式中变换函数的离散形式为:
(1-4)
式(1-4)给出的变换(映射)称为直方图均衡化或直方图线性化。
优缺点
这种方法对于背景和前景都太亮或者太暗的图像非常有用,这种方法尤其是可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。这种方法的一个主要优势是它是一个相当直观的技术并且是可逆操作,如果已知均衡化函数,那么就可以恢复原始的直方图,并且计算量也不大。
这种方法的一个缺点是它对处理的数据不加选择,它可能会增加背景杂讯的对比度并且降低有用信号的对比度;变换后图像的灰度级减少,某些细节消失;某些图像,如直方图有高峰,经处理后对比度不自然的过分增强。
/*************************************************************************
*
* 函数名称:
* InteEqualize()
*
* 参数:
* LPSTR lpDIBBits - 指向源DIB图像指针
* LONG lWidth - 源图像宽度(象素数)
* LONG lHeight - 源图像高度(象素数)
*
* 返回值:
* BOOL - 成功返回TRUE,否则返回FALSE。
*
* 说明:
* 该函数用来对图像进行直方图均衡。
*
************************************************************************/
BOOL WINAPI InteEqualize(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
// 指向源图像的指针
unsigned char* lpSrc;
// 临时变量
LONG lTemp;
// 循环变量
LONG i; LONG j;
// 灰度映射表
BYTE bMap[256];
// 灰度映射表
LONG lCount[256];
// 图像每行的字节数
LONG lLineBytes;
// 计算图像每行的字节数
lLineBytes = WIDTHBYTES(lWidth * 8);
// 重置计数为0
for (i = 0; i < 256; i ++)
{
// 清零
lCount[i] = 0;
}
// 计算各个灰度值的计数
for (i = 0; i < lHeight; i ++)
{
for (j = 0; j < lWidth; j ++)
{
lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j;
// 计数加1 l
Count[*(lpSrc)]++;
}
}
/ / 计算灰度映射表
lTemp = 0;
for (i = 0; i < 256; i++)
{
lTemp += lCount[j];
// 计算对应的新灰度值
bMap[i] = (BYTE) (lTemp * 255 / lHeight / lWidth);
}
// 每行
for(i = 0; i < lHeight; i++)
{
// 每列
for(j = 0; j < lWidth; j++)
{
// 指向DIB第i行,第j个象素的指针
lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
// 计算新的灰度值
*lpSrc = bMap[*lpSrc];
}
}
// 返回
return TRUE;
}
Split |
opencv多通道融合:Merge |
Merge |
EqualizeHist
灰度图象直方图均衡化
void cvEqualizeHist( const CvArr* src, CvArr* dst );
src
输入的 8-比特 单信道图像
dst
输出的图像与输入图像大小与数据类型相同
函数 cvEqualizeHist 采用如下法则对输入图像进行直方图均衡化:
1.
2.
3.
4.
该方法归一化图像亮度和增强对比度。
#include <highgui.h>
#include <cv.h>
int main(int argc, char** argv)
{
int i;
IplImage* src = cvLoadImage( argv[1], 1 );
IplImage* imgChannel[4] = { 0, 0, 0, 0 };
IplImage* dst = cvCreateImage( cvGetSize( src ), IPL_DEPTH_8U, 3 );
if( src )
{
for( i = 0; i < src -> nChannels; i++ )
{
imgChannel[i] = cvCreateImage( cvGetSize( src ), IPL_DEPTH_8U, 1 ); //要求单通道图像才能直方图均衡化
}
//通道分离
cvSplit( src, imgChannel[0], imgChannel[1], imgChannel[2], imgChannel[3] );
for( i = 0; i < dst -> nChannels; i++ )
{
//直方图均衡化,原始图像和目标图像必须是单通道
cvEqualizeHist( imgChannel[i], imgChannel[i] );
}
//通道组合
cvMerge( imgChannel[0], imgChannel[1], imgChannel[2], imgChannel[3], dst );
cvNamedWindow( "src", 1 );
cvShowImage( "src", src );
cvNamedWindow( "Equalize", 1 );
cvShowImage( "Equalize", dst );
cvWaitKey(0);
//释放资源
for( i = 0; i < src -> nChannels; i++ )
{
if( imgChannel[i] )
{
cvReleaseImage( &imgChannel[i] );
//imgChannel[i] = 0;
}
}
cvReleaseImage( &dst );
}
return 0;
}