本文代码来自赵春江编著的《c#数字图像处理算法》
图像灰度化
24位彩色图像每个像素用三个字节表示,每个字节对应着R G B 分量的亮度(红黄蓝)
当R G B 分量值不同时,表现为彩色图像,当三个值相同时,表现为灰度图像
第一种转换公式
Gray(i,j) = [R(i,j) + G(i,j) + B(i,j)]/3
适应人的视觉感应的转换公式
Gray(i,j) = 0.299*R(i,j) + 0.587*G(i,j) + 0.114*B(i,j)
//简单的利用C#位图对象处理图片算法
private void getPixelBtn_Click(object sender, EventArgs e)
{
if (curBitmap != null)
{
Color curColor;
int ret;
//二维图像数组循环
for (int i = 0; i < curBitmap.Width; i++)
{
for (int j = 0; j < curBitmap.Height; j++)
{
//获取该点的像素的RGB的颜色值
curColor = curBitmap.GetPixel(i, j);
//利用公式计算灰度值
ret = (int)(curColor.R * 0.229 + curColor.G * 0.587 + curColor.B * 0.114);
//设置该点的灰度值,R = G = B = ret
curBitmap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));
}
}
this.Invalidate();
}
}
内存法,将图像数据读入内存,存在数组中,在进行灰度化处理,算法速度明显高于前一种,对于图像
处理的软件,读入内存进行处理,无疑是提高处理速度的优先考虑
private void memoryOperateBtn_Click(object sender, EventArgs e)
{
if (curBitmap != null)
{
//位图矩形
Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
//以可读写的方式锁定全部位图像素,将数据输入到内存
System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect,
System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);
//得到首地址
System.IntPtr ptr = bmpData.Scan0;
//24位Bmp位图字节数
//int bytes = curBitmap.Width * curBitmap.Height * 3;
int bytes = bmpData.Stride * bmpData.Height;
//定义位图数组
byte[] rgbValues = new byte[bytes];
//复制被锁定的位图像素值到该数组内
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
//灰度化
double colorTemp = 0;
/*
//由于图像实际大小,并不一定与其实际所占内存大小相等,因为为了提高效率
//系统要确定每行字节数必须是4的倍数,因此不是4的倍数的图像,将附加一些未用空间
//注释掉的代码只适用于,未有未用空间的图像处理
for (int i = 0; i < rgbValues.Length; i += 3)
{
//利用公式计算灰度值
colorTemp = rgbValues[i + 2] * 0.299 + rgbValues[i + 1] * 0.587 + rgbValues[i] * 0.114;
//G = R = B
rgbValues[i] = rgbValues[i + 1] = rgbValues[i + 2] = (byte)colorTemp;
}
*/
for (int i = 0; i < bmpData.Height; i++)
{
for (int j = 0; j < bmpData.Width * 3; j += 3)
{
//Stride是每行字节数,每一行像素行数乘以行字节数,保证未用空间略去不被处理
colorTemp = rgbValues[i * bmpData.Stride + j + 2] * 0.299 +
rgbValues[i * bmpData.Stride + j + 1] * 0.587 +
rgbValues[i * bmpData.Stride + j] * 0.114;
rgbValues[i * bmpData.Stride + j] = rgbValues[i * bmpData.Stride + j + 1] =
rgbValues[i * bmpData.Stride + j + 2] = (byte)colorTemp;
}
}
//把数组复制到位图
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
//解锁位图像素
curBitmap.UnlockBits(bmpData);
//对窗口进行重绘,这将导致强制执行paint事件处理程序
Invalidate();
}
指针法,与内存法类似只是,在处理数据时是利用指针来操作
private void ptrOperateBtn_Click(object sender, EventArgs e)
{
if (curBitmap != null)
{
//位图矩形
Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
//以读写方式锁定全部位图
System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect,
System.Drawing.Imaging.ImageLockMode.ReadWrite,
curBitmap.PixelFormat);
byte temp = 0;
//启动不安全模式
unsafe
{
//得到首地址
byte* ptr = (byte*)(bmpData.Scan0);//强制类型转换
//二维图像循环
for (int i = 0; i < bmpData.Height; i++)
{
for (int j = 0; j < bmpData.Width; j++)
{
//利用公式进行灰度值计算
temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
//G = R = B
ptr[0] = ptr[1] = ptr[2] = temp;
//指向下一个像素
ptr += 3;
}
//指向下一行数组的首个字节
ptr += bmpData.Stride - bmpData.Width * 3;
}
}
//解锁位图像素
curBitmap.UnlockBits(bmpData);
//对窗口体进行重绘
Invalidate();
}
}