编程实现直方图均衡化
一、实验目的
掌握直方图均衡化的原理,和其步骤,了解直方图均衡化的作用、效果。
二、实验要求
实现对任意图像进行直方图均衡化。
三、实验原理
1.直方图均衡化:对原始图像的像素灰度做某种映射变换,使变换后图像直方图的概率密度呈均匀分布,即变换后图像的灰度级均匀分布。
2. 步骤:
(1).统计原图像每一灰度级的像素数和累积像素数。
(2).计算每一灰度级xa均衡化后对应的新值,并对其四舍五入取整,得
到新灰度级xb。
(3).以新值替代原灰度值,形成均衡化后的新图像。
(4).根据原图像像素统计值对应找到新图像像素统计值,作出新直方图。
四、实验思路
五、 实验步骤
1.新建项目文件:本实验选用的语言是C#,开发工具是VisualStudio2010,通
过“文件—新建—项目—C#—Windows 窗体应用程序”,命名“直方图均衡化”即可;
2.编写代码:由实验思路中的思维导图可得知,本实验步骤与“绘制直方图实
验非常类似”,只是中间加了对原始图像灰度值统计数据进行了均衡化处理这一步骤,因此,只需在它的基础上进行改动和添加部分代码即可,具体如下:
(1).编写头文件读取代码:由于以前的实验已有该代码,那么只需,导入其所在的“.cs ”类文件即可;
(2).编写读取图像灰度值代码:将“绘制任意图像灰度值”实验该部分功能“.cs ”类文件导入即可;
(3).编写统计灰度值代码:载入该功能所在“.cs ”类文件即可;
(4).编写直方图均衡化代码:由实验原理里的直方图均衡化步骤可知它对应的代码部分应该有:统计像素累计数,这个只需利用已有的灰度值及其频数所在的
Hashtable 哈希表数据即可;将原始灰度级映射到新的值,只需编写一个 对应方法,再对新的灰度级频数进行统计即可,具体代码将后文;
(5).编写绘制直方图代码:导入已有的代码所在“.cs ”类文件即可。
3.编译与调试:通过VS2010断点等调试工具,可查看、排除程序错误,无语法、逻辑错误后,编译生成程序文件即可;
4.运行程序查看结果:运行程序,加载实验数据,查看绘制出的直方图,然后
再通过ENVI 的“Enhance-Interactive Stretching ”工具选择
“SretchType ”为“Equalization ”执行后显示的直方图对比,看是否准确;
六、 结果与分析
1. 结果
程序界面
()01k
j
a a j L h x N =-
∑
2.分析
在对灰度级进行映射转换时一定要进行四舍五入运算,否则会有误差。
七、 源代码
1.将原灰度级映射到新值: /// <summary>
/// 均衡化 /// </summary>
/// <param name="pixcount"></param>像素总数 /// <param name="levelcount"></param>灰度级别总数 /// <param name="totalpixcount"></param>累计像素统计值 /// <returns></returns>转化后新灰度级
public static int Equalization(int pixcount,int levelcount, int totalpixcou nt)
{
double dvalue = 0; int value = 0;
dvalue = ((levelcount - 1.0) / pixcount) * totalpixcount;///(L-1)/N*TotalCount 映射公式
if (dvalue * 10 % 10 >= 5) { //进行4舍五入 dvalue += 1; }
value =(int ) dvalue; return
value;
}
2.统计转换后的灰度值频率数据:
///<summary>
///获取DN值
///</summary>
///<returns></returns>
public Boolean GetDNCount()
{
htInputDNCount.Clear();
htOutputDNCount.Clear();//清除原来数据
if (file==null)
{
return false;
}
if(strInterLeave=="bsq")
{//通过
GetDNCountByBSQ();
}
else if (strInterLeave=="bip")
{
GetDNCountByBIP();
}
else if (strInterLeave == "bil")
{
GetDNCountByBIL();
}
double fmax = Double.MinValue, fmin = Double.MaxValue;//最小值赋最大值,最大值赋最小值
foreach (var item in htInputDNCount.Keys)
{//获取最大最小值
if (fmax<(double)item)
{//获取最大值
fmax = (double)item;
}
if (fmin >(double)item)
{//获取最小值
fmin =(double)item;
}
}
dMinValue = fmin;
dMaxValue = fmax;
// System.Console.WriteLine("max:"+dMaxValue.ToString()+" min:"+dMi nValue);
foreach (var item in htInputDNCount.Keys)
{//计算加入值
double value = (int)(ImageStretch.Linear(0,255,fmin,fmax,Convert.To Double(item)));//线性拉伸
if (htOutputDNCount.Contains(value))
{ //当存在该值时
int dncount = (int)htOutputDNCount[value];
dncount += (int)htInputDNCount[item]; //数量加1
htOutputDNCount[value] = dncount;
}
else
{//不存在该值时,直接加入
htOutputDNCount.Add(value,(int)htInputDNCount[item] );
}
}
if (this.stretchway == "均衡化(equalization)")
{
Hashtable ht = new Hashtable();
foreach (var item in htOutputDNCount.Keys)
{//计算加入值
int totalpixcount = (int)htOutputDNCount[item];
foreach (var key in htOutputDNCount.Keys)
{
if ((double)key<(double)item)
{
totalpixcount+= (int)htOutputDNCount[key];
}
}
double value = (int)(ImageStretch.Equalization(this.TotalCount, 256,totalpixcount));//均衡化
if (ht.Contains(value))
{ //当存在该值时
int dncount = (int)ht[value];
dncount += (int)htOutputDNCount[item]; //数量相加
ht[value] = dncount;
System.Console.WriteLine(value.ToString()+":"+dncount.ToStr ing());
}
else
{//不存在该值时,直接加入
ht.Add(value, (int)htOutputDNCount[item]); }
}
htOutputDNCount.Clear();
htOutputDNCount = ht;
}
return true;
}。