C#数字图像处理有3种典型方法:提取像素法、内存法、指针法。其中提取像素法使用的是GDI+中的Bitmap.GetPixel和Bitmap.SetPixel方法;内存法是通过LockBits方法来获取位图的首地址,从而把图像数据直接复制到内存中进行处理;指针法与内存法相似,但该方法直接应用指针对位图进行操作,由于在默认情况下,C#不支持指针运算,所以该方法只能在unsafe关键字所标记的代码块中使用。以一幅真彩色图像的灰度化为例,下面代码分别展现了这3种方法的使用,方便大家学习图像处理的基本技巧。
(1) 像素提取法
(2) 内存法
(3) 指针法
(1) 像素提取法
if (curBitmap != null)
{
Color curColor;
int gray;
for (int i = 0; i < curBitmap.Width; i++)
{
for (int j = 0; j < curBitmap.Height; j++)
{
curColor = curBitmap.GetPixel(i, j);
gray = (int)(0.3 * curColor.R + 0.59 * curColor.G * 0.11 * curColor.B);
curBitmap.SetPixel(i, j, curColor);
}
}
}
(2) 内存法
if (curBitmap != null)
{
int width = curBitmap.Width;
int height = curBitmap.Height;
int length = height * 3 * width;
RGB = new byte[length];
BitmapData data = curBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
System.IntPtr Scan0 = data.Scan0;
System.Runtime.InteropServices.Marshal.Copy(Scan0, RGB, 0, length);
double gray = 0;
for (int i = 0; i < RGB.Length; i=i+3)
{
gray = RGB[i + 2] * 0.3 + RGB[i + 1] * 0.59 + RGB[i] * 0.11;
RGB[i + 2] = RGB[i + 1] = RGB[i] = (byte)gray;
}
System.Runtime.InteropServices.Marshal.Copy(RGB, 0, Scan0, length);
curBitmap.UnlockBits(data);
}
(3) 指针法
if (curBitmap != null)
{
int width = curBitmap.Width;
int height = curBitmap.Height;
BitmapData data = curBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
System.IntPtr Scan0 = data.Scan0;
int stride = data.Stride;
System.Runtime.InteropServices.Marshal.Copy(Scan0, RGB, 0, length);
unsafe
{
byte* p = (byte*)Scan0;
int offset = stride - width * 3;
double gray = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
gray = 0.3 * p[2] + 0.59 * p[1] + 0.11 * p[0];
p[2] = p[1] = p[0] = (byte)gray;
p += 3;
}
p += offset;
}
}
curBitmap.UnlockBits(data);
}
在以上3种方法中,提取像素法能直观的展示图像处理过程,可读性很好,但效率最低,并不适合做图像处理方面的工程应用;内存法把图像直接复制到内存中,直接对内存中的数据进行处理,速度明显提高,程序难度也不大;指针法直接应用指针来对图像进行处理,所以速度最快。