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


    图像处理过程中,比较常见的灰化处理,将彩色图像处理为黑白图像,以便后续的其他处理工作。
    在面对大量的图片或者像素尺寸比较大的图片的时候,处理速度和性能就显得非常重要,下面分别用3种方式来处理图像数据,得到不同的处理速度差异:
    处理效果对比如下:

    第一种方式,直接用.net提供的接口来处理,具有较好的兼容性,但是速度较慢:

           /// 
            /// 用提取像素方法将图像灰化,有最好的兼容性
            /// 
            /// 
            /// 
            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; }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    第二种方法,使用托管内存来直接操作图像数据,速度速度较第一种方法快约30倍,非常明显,但是要根据不同的图片像素格式来处理数据,相对比较麻烦一些,兼容性不好。

     /// 
            /// 用托管内存方式处理灰度图像,处理速度比CovertPicturePixels快约30倍,要处理不同的位深
            /// 
            /// 源图像
            /// 
            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; }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    第三种方式,直接使用指针来操作内存,得到最快的速度(相比托管内存操作方式略快)。

     /// 
            /// 用非托管内存方式处理灰度图像,处理速度比CovertPictureGrayManagedMemory略快,要处理不同的位深
            /// 
            /// 
            /// 
            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;
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

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

  • 相关阅读:
    华北理工大学计算机考研资料汇总
    医学图像分割利器:U-Net网络详解及实战
    Java版分布式微服务云开发架构 Spring Cloud+Spring Boot+Mybatis 电子招标采购系统功能清单
    模板的进阶
    Linux离线安装插件
    产品管理系统(MVC设计模式)——第一个Javaee项目
    STM32外设系列—MPU6050角度传感器
    WorkManager的学习二
    FLStudio21水果免费版本FL2023电音制作软件
    Android-宝宝相册(第四次作业)
  • 原文地址:https://blog.csdn.net/huangbinvip/article/details/133793096