图像处理过程中,比较常见的灰化处理,将彩色图像处理为黑白图像,以便后续的其他处理工作。
在面对大量的图片或者像素尺寸比较大的图片的时候,处理速度和性能就显得非常重要,下面分别用3种方式来处理图像数据,得到不同的处理速度差异:
处理效果对比如下:
第一种方式,直接用.net提供的接口来处理,具有较好的兼容性,但是速度较慢:
/// <summary>
/// 用提取像素方法将图像灰化,有最好的兼容性
/// </summary>
/// <param name="bitmap"></param>
/// <returns></returns>
private Bitmap CovertPicturePixels(Bitmap bitmap)
{
try
{
Bitmap newbitmap = bitmap.Clone() as Bitmap;
Color pixel;
int ret;
for (int y = 0; y < newbitmap.Height; y++)
{
for (int x = 0; x < newbitmap.Width; x++)
{
pixel = newbitmap.GetPixel(x, y);
ret = (int)(pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114);
newbitmap.SetPixel(x, y, Color.FromArgb(ret, ret, ret));
}
}
return newbitmap;
}
catch { return null; }
}
第二种方法,使用托管内存来直接操作图像数据,速度速度较第一种方法快约30倍,非常明显,但是要根据不同的图片像素格式来处理数据,相对比较麻烦一些,兼容性不好。
/// <summary>
/// 用托管内存方式处理灰度图像,处理速度比CovertPicturePixels快约30倍,要处理不同的位深
/// </summary>
/// <param name="bitmapSrc">源图像</param>
/// <returns></returns>
private Bitmap CovertPictureGrayManagedMemory(Bitmap bitmapSrc)
{
try
{
Bitmap bitmap = bitmapSrc.Clone() as Bitmap;
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
BitmapData bmpdata = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat); //锁定内存
IntPtr ptr = bmpdata.Scan0;
int bytes = bitmap.Width * bitmap.Height * 4;
byte[] rgbvalues = new byte[bytes];
Marshal.Copy(ptr, rgbvalues, 0, bytes); //图像数据拷贝到内存
int factor = 4;
if (bmpdata.PixelFormat == PixelFormat.Format32bppRgb) //暂时只支持常见的格式
{
factor = 4;
}
else if (bmpdata.PixelFormat == PixelFormat.Format24bppRgb)
{
factor = 3;
}
else
{
return null;
}
double colortemp = 0;
for (int i = 0; i < rgbvalues.Length; i += factor)
{
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;
}
Marshal.Copy(rgbvalues, 0, ptr, bytes); //转换后的数据保存回源图像
bitmap.UnlockBits(bmpdata);
return bitmap;
}
catch { return null; }
}
第三种方式,直接使用指针来操作内存,得到最快的速度(相比托管内存操作方式略快)。
/// <summary>
/// 用非托管内存方式处理灰度图像,处理速度比CovertPictureGrayManagedMemory略快,要处理不同的位深
/// </summary>
/// <param name="bitmapSrc"></param>
/// <returns></returns>
private Bitmap CovertPictureGrayUnManagedMemory(Bitmap bitmapSrc)
{
Bitmap newbitmap = bitmapSrc.Clone() as Bitmap;
Rectangle rect = new Rectangle(0, 0, newbitmap.Width, newbitmap.Height);
BitmapData bmpdata = newbitmap.LockBits(rect, ImageLockMode.ReadWrite, newbitmap.PixelFormat);
byte temp;
unsafe
{
byte* ptr = (byte*)(bmpdata.Scan0);
int factor = 4;
if(bmpdata.PixelFormat == PixelFormat.Format32bppRgb) //暂时只支持常见的格式
{
factor = 4;
}
else if(bmpdata.PixelFormat == PixelFormat.Format24bppRgb)
{
factor = 3;
}
else
{
return null;
}
for (int x = 0; x < bmpdata.Width; x++)
{
for (int y = 0; y < bmpdata.Height; y++)
{
temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
ptr[0] = ptr[1] = ptr[2] = temp;
ptr += factor;
}
ptr += bmpdata.Stride - bmpdata.Width * factor; //bmpdata.Stride:一个扫描行的字节数,bmp的一行数据是4的整数倍
}
}
newbitmap.UnlockBits(bmpdata);
return newbitmap;
}
由于是非安全的内存操作,要在工程启用相关配置:
文章和代码均为原创,欢迎转载,请注明出处!