C# 图像灰化处理方法及速度对比

图像处理过程中,比较常见的灰化处理,将彩色图像处理为黑白图像,以便后续的其他处理工作。
在面对大量的图片或者像素尺寸比较大的图片的时候,处理速度和性能就显得非常重要,下面分别用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;
        }

由于是非安全的内存操作,要在工程启用相关配置:
在这里插入图片描述
文章和代码均为原创,欢迎转载,请注明出处!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值