c#_灰度图,二值化,腐蚀算法等具体实现
这几天在折腾我们学校的教务管理系统,我想写一个程序不用输入密码和用户名and那个磨人的验证码就可以直接登陆的玩具出来,后来看到了网上的一些介绍,发现验证码就是专门阻止我这样的家伙的,呵呵了,我不服,一个小小的验证码就能挡得住我么?我就要破掉你!
于是开始有了下面的乱七八糟的代码,各位看官且看~
获取灰度图
在计算机领域中,灰度(Gray scale)数字图像是每个像素只有一个采样颜色的图像。什么意思呢?也就是说,每一种颜色其实都是有亮度的,亮度不同给人的视觉感受也是不同的,灰度图通常显示的是从最暗的黑色到最亮的白色之间不同亮度的图片。
下面请看代码:
Bitmap GetGrayImage(Bitmap image)
{
// 如果直接赋值的话,会改变原来的图片。
Bitmap result = image.Clone() as Bitmap;
Color c = new Color();
int ret;
for (int i = 0; i < image.Width; i++)
{
for (int j = 0; j < image.Height; j++)
{
c = result.GetPixel(i, j);
// 计算点i,j的灰度值
ret = (int)(c.R * 0.299 + c.G * 0.587 + c.B * 0.114);
result.SetPixel(i, j, Color.FromArgb(ret, ret, ret));
}
}
return result;
}
实现思路就是,通过遍历每一个点,获取这个点的颜色值,然后按照RGB一定的比例计算出每个点的灰度值然后赋值。
二值化
一幅图像包括目标物体、背景还有噪声,要想从多值的数字图像中直接提取出目标物体,最常用的方法就是设定一个全局的阈值T,用T将图像的数据分成两部分:大于T的像素群和小于T的像素群。将大于T的像素群的像素值设定为白色(或者黑色),小于T的像素群的像素值设定为黑色(或者白色)。
在这里通过计算图片的平均灰度值作为全局的阈值T,遍历图片中的每一个点,计算每个点的 value = (R+G+B)/3 如果value > 127,则设置该像素为白色,即R = G = B = 255,否则设置为黑色 R = G = B = 0;
/// <summary>
/// 平均值法获取二值化的阈值
/// </summary>
/// <param name="image">灰度图像</param>
/// <returns></returns>
private Bitmap GetBinaryzationImage1(Bitmap image)
{
Bitmap result = image.Clone() as Bitmap;
// 计算灰度平均值
List<int> tempList = new List<int>();
for (int i = 0; i < result.Width; i++)
{
for (int j = 0; j < result.Height; j++)
{
tempList.Add(result.GetPixel(i, j).R);
}
}
double average = tempList.Average();
Color color = new Color();
for (int i = 0; i < result.Width; i++)
{
for (int j = 0; j < result.Height; j++)
{
color = result.GetPixel(i, j);
if ((color.R + color.G + color.B) / 3 > average)
{
result.SetPixel(i, j, Color.White);
}
else
{
result.SetPixel(i, j, Color.Black);
}
}
}
return result;
}
腐蚀算法
腐蚀是一种消除边界点,使边界向内部收缩的过程。可以用来消除小且无意义的物体。
以下是我自己实现的一个腐蚀算法,当然,是针对特定的情况,比如说我们学校的教务系统的验证码,对于边界没有仔细处理。
基本思路是这样的
以B中指出的origin点为指定点,如果这个点是黑色and正上方和左方的点都是黑色的就将这个点保留位黑色,否则设置为白色。这样我们就将原来的黑色区域缩小了一圈了,这个就叫做腐蚀。
/// <summary>
/// 腐蚀(来消除小且无意义的物体)
/// </summary>
/// <param name="image">二值化图片</param>
/// <returns></returns>
private Bitmap GetFuShiImage(Bitmap image)
{
List<Point> setList = new List<Point>();
Bitmap result = image.Clone() as Bitmap;
for (int i = 0; i < result.Width; i++)
{
for (int j = 0; j < result.Height; j++)
{
// 如果是应该设置为黑色的点,将其添加到我们要设的list中
if (SetPixelFuShi(result, i, j))
{
setList.Add(new Point(i, j));
}
}
}
// 遍历,设置相应的值
foreach (var item in setList)
{
result.SetPixel(item.X, item.Y, Color.White);
}
return result;
}
// 判断一个点是不是应该设置为白颜色
protected bool SetPixelFuShi(Bitmap image, int i, int j)
{
int origion;
int upPoint;
int leftPoint;
if (i != 0 && j != 0)
{
origion = image.GetPixel(i, j).ToArgb();
upPoint = image.GetPixel(i, j - 1).ToArgb();
leftPoint = image.GetPixel(i - 1, j).ToArgb();
// image.GetPixel(i,j) == Color.Black
// 这样写居然没用,我还调试了老半天,也不报错!!!
if (origion == Color.Black.ToArgb() &&
upPoint == Color.Black.ToArgb() &&
leftPoint == Color.Black.ToArgb())
{
return false;
}
else
{
return true;
}
}
else return true;
}
膨胀算法
思路和腐蚀算法极为相似,就是腐蚀算法的逆运算。
如果指定的点是黑色的,那么就把它正上方和左边的像素点设置为黑色。
/// <summary>
/// 膨胀算法
/// </summary>
/// <param name="image"></param>
/// <returns></returns>
private Bitmap GetPengZhangImage(Bitmap image)
{
List<Point> setList = new List<Point>();
Bitmap result = image.Clone() as Bitmap;
for (int i = 0; i < result.Width; i++)
{
for (int j = 0; j < result.Height; j++)
{
// 如果应该设置为黑色的
if (SetPixelPengZhang(result, i, j))
{
setList.Add(new Point(i, j));
}
}
}
int x, y;
foreach (var item in setList)
{
x = item.X;
y = item.Y;
result.SetPixel(x - 1, y, Color.Black);
result.SetPixel(x, y - 1, Color.Black);
}
return result;
}
// 判断这个点应不应该设置为黑色
protected bool SetPixelPengZhang(Bitmap image, int i, int j)
{
Color c = image.GetPixel(i, j);
if (i != 0 && j != 0)
{
if (image.GetPixel(i, j).ToArgb() == Color.Black.ToArgb())
{
return true;
}
else return false;
}
else return false;
}