基于C#的简单图像处理与分析
1. 图像的直方图及直方图的均衡化
图像的直方图是图像处理中一种十分重要的图像分析工具,它描述了一幅图像的灰度级内容,任何一幅图像的直方图都包含了丰富的信息,它主要用在图象分割,图像灰度变换等处理过程中。从数学上来说图像直方图是图像各灰度值统计特性与图像灰度值的函数,它统计一幅图像中各个灰度级出现的次数或概率;从图形上来说,它是一个二维图,(一般)横坐标表示图像中各个像素点的灰度级,纵坐标为各个灰度级上图像各个像素点出现的次数或概率,它是图像最基本的统计特征。
直方图有以下性质:
(1)直方图是一幅图像中各像素灰度出现频次的统计结果,它只反映图像中不同灰度值出现的次数,而没反映某一灰度所在的位置。也就是说,它只包含了该图像的某一灰度像素出现的概率,而丢失了其所在的位置信息。
(2)任一幅图像,都有惟一 确定一幅与它对应的直方图,但不同的图像可能有相同的直方图。即图像与直方图之间是多对一的映射关系。
(3)由于直方图是对具有相同灰度值的像素统计得到的,因此,一幅图像各子区的直方图之和就等于该图像全图的直方图。
直方图均衡化是灰度变换的一个重要应用,广泛应用在图像增强处理中,它是以累计分布函数变换为基础的直方图修正法,可以产生一幅灰度级分布具有均匀概率密度的图像,扩展了像素的取值动态范围。许多图像的灰度值是非均匀分布的,其中灰度值集中在一个小区间内的图像是很常见的.直方图均衡化是一种通过重新均匀地分布各灰度值来增强图像对比度的方法.经过直方图均衡化的图像对二值化阈值选取十分有利.一般来说,直方图修正能提高图像的主观质量,因此在处理艺术图像时非常有用.直方图均衡化处理的中心思想是把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。直方图均衡化是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。
对图像空间域点的增强过程是通过增强函数t=EH(s)来完成的,t、s分别为目标图像和原始图像上的像素点,在进行均衡化处理时,增强函数EH需要满足两个条件:增强函数EH(s)在0≤s≤L-1的范围内是一个单调递增函数,这个条件保证了在增强处理时没有打乱原始图像的灰度排列次序; 另一个需要满足的条件是对于0≤s≤L-1应当有0≤EH(s)≤L-1,它保证了变换过程中灰度值的动态范围的一致性。同样的,对于反变换过程s=EH-1(t),在0≤t≤1时也必须满足上述两个条件。累计分布函数(cumulative distribution function,CDF)就是满足上述条件的一种,通过该函数可以完成s到t的均匀分布转换。此时的增强转换方程为:
tk = EH(sk)=∑(ni/n)=∑ps(si),(k=0,1,2……L-1)
上述求和区间为0到k,根据该方程可以由原图像的各像素灰度值直接得到直方图均衡化后各像素的灰度值。在实际处理变换时,一般先对原始图像的灰度情况进行统计分析,计算出原始直方图分布,然后计算累计直方图分布tk,按式tk=tk-1+ sk得出源灰度sk到tk的灰度映射关系,其中k为灰度的级数。重复上述步骤,得到所有的源图像各灰度级到目标图像各灰度级的映射关系,再按照新的映射关系对源图像各点像素进行灰度转换,即可完成对源图的直方图均衡化。
2. 图像滤波
图像信息在采集过程中往往受到各种噪声源的干扰,这些噪声在图像上的常常表现为一些孤立像素点,这可理解为像素的灰度分布是空间相关的,即噪声点像素灰度与它们临近像素的灰度有着显著不同。这种干扰或孤立像素点如不经过滤波处理,会对以后的图像区域分割、分析和判断带来影响。
图像增强的方法分为两大类:空间域图像增强和频域图像增强,而程序中的均值滤波,高斯滤波等就是空间域图像增强的重要内容。使用空域模板进行图像处理,被称为空域滤波。模板本身被称为空域滤波器。空域滤波的原理就是在待处理的图像中逐点地移动模板,滤波器在该点地响应通过事先定义的滤波器系数与滤波模板扫过区域的相应像素值的关系来计算。
⑴ 从数学形态上可以把空域滤波器分为线性滤波器和非线性滤波器:
线性滤波器是线性系统和频域滤波在空域的自然延伸。其特征是结果像素值的计算由下列公式定义:
R = w1z1 + w2z2 + … + wnzn
其中:wi,i = 1, 2, … ,n 是模板的系数;zi,i = 1,2, … ,n 是被计算像素及其邻域像素的值
线性滤波器又可以分为高通,低通和带通滤波器。
非线性滤波器使用模板进行结果像素值的计算,结果值直接取决于像素邻域的值,而不与线性乘积和无关,它包括中值滤波,最大最小值滤波器等等。
⑵ 从处理效果上可以把空域滤波器分为平滑空间滤波器和锐化空间滤波器:
平滑空间滤波器用于模糊处理和减小噪声,经常在图像的预处理中使用。
锐化空间滤波器主要用于突出图像中的细节或者增强被模糊了的细节。
3. 程序设计
程序采用Visual Studio 2008 作为开发平台,C#作为开发语言,以.NET framework 2.0作为底层支持框架。
程序主要代码如下:
//以下是三个主要算法:
Code
Code
/**//**//**//// <summary>
/// 画直方图
/// </summary>
/// <param name="use">要处理的图像</param>
/// <param name="box">画直方图的位置</param>
/// <param name="g">使用的图形对象</param>
private void DrawZhifang(Bitmap use, GroupBox box, Graphics g)
{
int r, c, tmp = 0;
float[] Pixel = new float[256];
float[] Prob = new float[256];
//统计同一灰度级的像素个数 Calculating the number of pixel of same type
for (r = 0; r < use.Height; r++)
{
for (c = 0; c < use.Width; c++)
{
Color cr = use.GetPixel(r, c);
tmp = Convert.ToInt32((cr.R+cr.G+cr.B)/3);
Pixel[tmp] += 1;
}
}
//计算总像素 Total Number of Pixels
int tot = use.Height * use.Width;
//计算像素的概率 Calculating the probability
for (r = 0; r < 256; r++)
{
Pixel[r] = Pixel[r] / tot;
}
//Graphics g = box.CreateGraphics();
Pen redpen = new Pen(Color.Red, 1);//新建画笔 宽度为1
for (int i = 0; i < 256; i++)
{
Point[] pointArray = { new Point(15 + i, 170), new Point(15 + i,170-(int)(10000*Pixel[i])) };//定义直线起点和终点 Y轴
g.DrawLines(redpen, pointArray);//画直线
}
}
/**//**//**//// <summary>
/// 直方图均衡化
/// </summary>
/// <param name="use">要处理的源图像</param>
/// <returns>处理后的图像</returns>
public static Bitmap Histogram(Bitmap use)
{
int r, c, tmp = 0;
float[] Pixel = new float[256];
float[] Prob = new float[256];
//统计同一灰度级的像素个数 Calculating the number of pixel of same type
for (r = 0; r < use.Height; r++)
{
for (c = 0; c < use.Width; c++)
{
Color cr = use.GetPixel(r, c);
tmp = Convert.ToInt32(cr.R);
Pixel[tmp]+=1;
}
}
//计算总像素 Total Number of Pixels
int tot = use.Height * use.Width;
//计算像素的概率 Calculating the probability
for (r = 0; r < 256; r++)
{
Pixel[r] = Pixel[r] / tot;
}
//计算累积概率 Calculating the cumulative probability
Prob[0] = Pixel[0];
for (r = 1; r < 256; r++)
{
Prob[r] = Prob[r - 1] + Pixel[r];
}
// 生成新的灰度值 Generating New Graylevel Values
for (r = 0; r < 256; r++)
{
Prob[r] = Prob[r] * 255;
}
Bitmap target = new Bitmap(use.Height, use.Width);
for (r = 0; r < use.Height; r++)
{
for (c = 0; c < use.Width; c++)
{
Color cr = use.GetPixel(r, c);
tmp = Convert.ToInt32((cr.R + cr.G + cr.B) / 3);
target.SetPixel(r, c, Color.FromArgb(255, Convert.ToInt32(Prob[tmp]), Convert.ToInt32(Prob[tmp]), Convert.ToInt32(Prob[tmp])));
}
}
return (target);
}
/**//**//**//// <summary>
/// 滤波函数
/// </summary>
/// <param name="img">原始图像</param>
/// <returns>滤波后的图像</returns>
public static Bitmap filter(Bitmap img,int[] template)
{
int Rows = img.Height;
int Cols = img.Width;
Bitmap newImg = new Bitmap(Rows, Cols); //实例一个与原图像一样大小的对象
Color color = new Color();
int r, g, b; //存放图像颜色点的R、G、B值
int rSum=0, gSum=0, bSum=0;
int rAvg, gAvg, bAvg; //存放某一点与相邻点平均值后的R、G、B值
//循环得到图像的每一个像素点
for (int i = 1; i < Rows - 1; i++)
{
for (int j = 1; j < Cols - 1; j++)
{
int index = 0; //模板数组的索引
for (int row = -1; row <= 1; row++)
{
for (int col = -1; col <= 1; col++)
{
color = img.GetPixel(i + row, j + col);
r = color.R;
g = color.G;
b = color.B;
rSum += r * template[index];
gSum += g * template[index];
bSum += b * template[index];
index++;
}
}
rAvg = Math.Abs(rSum/template[9]);
gAvg = Math.Abs(gSum/template[9]);
bAvg = Math.Abs(bSum/template[9]);
rSum = 0;
gSum = 0;
bSum = 0;
//处理颜色值的溢出
rAvg = rAvg > 255 ? 255 : rAvg;
gAvg = gAvg > 255 ? 255 : gAvg;
bAvg = bAvg > 255 ? 255 : bAvg;
//设置新对象的每一点的颜色值
newImg.SetPixel(i, j, Color.FromArgb(255,rAvg, gAvg, bAvg));
}
}
return (newImg);
}
4. 运行效果
程序运行后的效果图如下:
直方图及其均衡化:
从上述效果图可以看出,经过直方图均衡化处理后,图像变的清晰了,从直方图来看,处理后的Lena的图像直方图分布更均匀了,在每个灰度级上图像都有像素点。但是直方图均衡化存在着两个缺点:
(1)变换后图像的灰度级减少,某些细节消失;
(2)某些图像,如直方图有高峰,经处理后对比度不自然的过分增强。
图像滤波:
从上述的效果图可以看出,平滑滤波(上图中的均值滤波)使图像看起来更加柔和,而锐化滤波使得图像的对比度加强了,但同时又会产生了一些不和谐的像素点。
5. 实习总结
学习了图像处理与分析这门课,我觉得我学到了一些东西。虽然不敢说老师讲的每一堂课我都听懂了,但是至少我了解到了这门学科大概的轮廓,尤其是学到了很多有用的图像处理算法思想,这对我以后的编程学习有很大的帮助。特别是老师对Image Board这个MFC程序的讲解,使我对Visual C++有了更多的了解。做这个C#小程序,花费了我不少的时间,虽然其中的一些算法我参考了网络上的一些代码,但程序中绝大部分的代码都是自己手工完成的。最后非常感谢童老师能够给我们讲述这样一门精彩的课程!