述算法实现的部分关键
程序代码。
首先对原始图像的各像素点的灰度情况进行统计计算。对于24位BMP图像,图像阵列是从第54字节开始的,每像素按R、G、B的顺序占3个字节。
for (DWORD i=54; i
ns_r[m_cpBuffer[i]]++; //ns_r[k]为k灰度级像素数,m_cpBuffer[i]为当前的灰度值
i++;
ns_g[m_cpBuffer[i]]++;
//ns_g为G分量的统计计数
i++;
ns_b[m_cpBuffer[i]]++;
//ns_b为B分量的统计计数
}
for (i=0; i<256; i++)
//计算R、G、B三分量的直方图分布
{
ps_r[i]=ns_r[i]/((m_dwFileLen-54)/3.0f);
//ps_r[i]为R分量中i灰度级出现的概率
ps_g[i]=ns_g[i]/((m_dwFileLen-54)/3.0f);
//ps_b[i]为G分量中i灰度级出现的概率
ps_b[i]=ns_b[i]/((m_dwFileLen-54)/3.0f);
//ps_b[i]为B分量中i灰度级出现的概率
}
然后计算R、G、B三分量各灰度级的累计直方图分布,并对其进行取整以得出源和目标图像灰度之间的映射关系:
for (i=0; i<256; i++)
{
//计算累计直方图分布
temp_r[i]=temp_r[i-1]+ps_r[i];
temp_g[i]=temp_g[i-1]+ps_g[i];
temp_b[i]=temp_b[i-1]+ps_b[i];
//累计分布取整,ns_r、ns_g、ns_b保存有计算出来的灰度映射关系
ns_r[i]=(int)(255.0f*temp_r[i]+0.5f);
ns_g[i]=(int)(255.0f*temp_g[i]+0.5f);
ns_b[i]=(int)(255.0f*temp_b[i]+0.5f);
}
最后按照计算出来的映射关系,把原图的原始灰度值映射到经过均衡化的新灰度级上。图1、图2分别是原始图像和用本
程序得出的经过直方图均衡化处理后的目标图像,从实验结果可以看出原始图像太暗,根本看不清细节,而处理过的图像则比较清晰:
for (i=54; i
{
m_cpBuffer[i]=ns_r[m_cpBuffer[i]];
//对R分量进行灰度映射(均衡化)
i++;
m_cpBuffer[i]=ns_g[m_cpBuffer[i]];
//对G分量进行灰度映射(均衡化)
i++;
m_cpBuffer[i]=ns_b[m_cpBuffer[i]];
//对B分量进行灰度映射(均衡化)
}
单映射规则的直方图规定化处理
前面介绍的直方图均衡化处理方法从实验效果看还是很不错的,从实现算法上也可以看出其优点主要在于能自动增强整幅图像的对比度,但具体的增强效果也因此不易控制,只能得到全局均衡化处理的直方图。在科研和工程应用中往往要根据不同的要求得到特定形状的直方图分布以有选择的对某灰度范围进行局部的对比度增强,此时可以采用对直方图的规定化处理,通过选择合适的规定化函数取得期望的效果。对于灰度级数分别为M和N(满足M≥N)的原始图和规定图,一般仍先按均衡化对原始图进行处理:
tk =EHs(si)=∑ps(si),(k=0,1,2……M-1)
然后规定需要的直方图,并计算出能使规定的直方图均衡化的变换:
vl = EHu(uj)=∑pu(ui),(l=0,1,2……N-1)
最后将第一步得到的变换反转过去,即把原始直方图对应映射到规定的直方图,也就是把所有的ps(si)映射到pu(uj)中去。由于映射是在离散空间进行的,而且在取整时不可避免会引入误差,因此采取何种对应规则是一个很重要的
问题。比较常用的一种方法是Gonzalez在1987年提出的单映射规则(single mapping law,SML),首先寻找能满足|∑ps(si)-∑pu(uj)| 最小的k和l(ps()和pu()的求和上限),然后把ps(si)映射到pu(uj)中去。
本文针对原始图像比较暗的特点,采取如下的规定直方图,以使高亮度像素能得到充分的加强:
float a=1.0f/(32.0f*63.0f);
//64个灰度级,a为步长
for (int i=0; i<64; i++)
{
nu[i]=i*4;
pu[i]=a*i;
}
接下来对原始图和规定直方图计算累计直方图,在此不再赘述,重点是根据SML规则把ps(si)映射到pu(uj)中去:
for (i=0;i<256;i++)
{
……
for (int j=0; j<64; j++)
{
float now_value=0.0f;
//计算R分量的两累计直方图的绝对差值,并找到满足最小的灰度级
if (ps_r[i]-pu[j]>=0.0f)
now_