C#数字图像处理主要用到Bitmap类、BitmapData类和Graphics类。
1、彩色图像的灰度化
(1)彩色图
彩色图像,每个像素通常是由红(R)、绿(G)、蓝(B)三个分量来表示的,分量介于(0,255)。M、N分别表示图像的行列数,三个M x N的二维矩阵分别表示各个像素的R、G、B三个颜色分量。RGB图像的数据类型一般为8位无符号整形,通常用于表示和存放真彩色图像,当然也可以存放灰度图像。
(2)灰度图
将彩色图像转化成为灰度图像的过程成为图像的灰度化处理。彩色图像中的每个像素的颜色有R、G、B三个分量决定,而每个分量有255中值可取,这样一个像素点可以有1600多万(255*255*255)的颜色的变化范围。而灰度图像是R、G、B三个分量相同的一种特殊的彩色图像,其一个像素点的变化范围为255种,所以在数字图像处理种一般先将各种格式的图像转变成灰度图像以使后续的图像的计算量变得少一些。灰度图像的描述与彩色图像一样仍然反映了整幅图像的整体和局部的色度和亮度等级的分布和特征。图像的灰度化处理可用两种方法来实现。
2、C#图像处理有三种方法
(1)提取像素法
使用Bitmap.GetPixel类读取当前像素的颜色,在计算灰度值,最后使用Bitmap.SetPixel类应用计算后的新颜色。
速度分析:先提取像素的颜色值,在进行灰度值的计算,然后绘图速度较慢。
//提取像素法会获取灰度图
private void pixel_Click(object sender, EventArgs e)
{
if(curBitmap != null)
{
myTimer.ClearTimer();
myTimer.Start();
Color curColor;
int ret;
//二维图像数组循环
for (int i = 0; i < curBitmap.Width; i++)
{
for (int j = 0; j < curBitmap.Height ; j++)
{
curColor = curBitmap.GetPixel(i,j);//获取该像素点的RGB颜色值
ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);//利用公式计算灰度值
curBitmap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));//设置该像素的灰度值 R=G=B=ret
}
}
myTimer.Stop();
timeBox.Text = myTimer.Duration.ToString("####.##") + " 毫秒";
Invalidate();//对窗体重新绘制
}
}
(2)内存法
把图像的数据复制到内存中,进行处理,程序的运行速度大大提高。
private void memory_Click(object sender, EventArgs e)
{
if (curBitmap != null)
{
myTimer.ClearTimer();
myTimer.Start();
//位图矩形
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);
//得到首地址
IntPtr ptr = bmpData.Scan0;
//24位BMP位图字节数
int bytes = curBitmap.Width * curBitmap.Height * 3;
//定义位图数组
byte[] rgbValues = new byte[bytes];
//复制被锁定的位图像素值到该数组内
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
//灰度化
double colorTemp = 0;
for (int i = 0; i < rgbValues.Length; i += 3)
{
colorTemp = rgbValues[i + 2] * 0.299 + rgbValues[i + 1] * 0.587 + rgbValues[i] * 0.114;
rgbValues[i] = rgbValues[i + 1] = rgbValues[i + 2] = (byte)colorTemp;
}
//把数组复制回位图
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
//解锁位图像素
curBitmap.UnlockBits(bmpData);
myTimer.Stop();
timeBox.Text = myTimer.Duration.ToString("####.##") + " 毫秒";
Invalidate();
}
}
(3)指针法
private void pointer_Click(object sender, EventArgs e)
{
if (curBitmap != null)
{
myTimer.ClearTimer();
myTimer.Start();
//位图矩形
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]);
ptr[0] = ptr[1] = ptr[2] = temp;
ptr += 3;
}
//指向下一行数组的首个地址
ptr += bmpData.Stride - bmpData.Width * 3;
}
}
//解锁位图像素
curBitmap.UnlockBits(bmpData); //对窗体重新绘制
myTimer.Stop();
timeBox.Text = myTimer.Duration.ToString("####.##") + " 毫秒";
Invalidate();
}
}
三种方法比较:
提取像素法:方法简单,但是运算速度慢、效率低。
内存法:将图像复制到内存中,直接对内存的数据进行处理,速度明显提高。
指针法:速度最快,但是难以编写和调试。