Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 810|回复: 0

解决 C# GetPixel 和 SetPixel 效率问题(转)

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-5-6 11:38:36 | 显示全部楼层 |阅读模式

    在对Bitmap图片操作的时候,有时需要用到获取或设置像素颜色方法:GetPixel 和 SetPixel,

    如果直接对这两个方法进行操作的话速度很慢,这里我们可以通过把数据提取出来操作,然后操作完在复制回去可以加快访问速度

    其实对Bitmap的访问还有两种方式,一种是内存法,一种是指针法

    1、内存法

      这里定义一个类LockBitmap,通过把Bitmap数据拷贝出来,在内存上直接操作,操作完成后在拷贝到Bitmap中

            public class LockBitmap
            {
                Bitmap source = null;
                IntPtr Iptr = IntPtr.Zero;
                BitmapData bitmapData = null;
    
                public byte[] Pixels { get; set; }
                public int Depth { get; private set; }
                public int Width { get; private set; }
                public int Height { get; private set; }
    
                public LockBitmap(Bitmap source)
                {
                    this.source = source;
                }
    
                /// <summary>
                /// Lock bitmap data
                /// </summary>
                public void LockBits()
                {
                    try
                    {
                        // Get width and height of bitmap
                        Width = source.Width;
                        Height = source.Height;
    
                        // get total locked pixels count
                        int PixelCount = Width * Height;
    
                        // Create rectangle to lock
                        Rectangle rect = new Rectangle(0, 0, Width, Height);
    
                        // get source bitmap pixel format size
                        Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);
    
                        // Check if bpp (Bits Per Pixel) is 8, 24, or 32
                        if (Depth != 8 && Depth != 24 && Depth != 32)
                        {
                            throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
                        }
    
                        // Lock bitmap and return bitmap data
                        bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite,
                                                     source.PixelFormat);
    
                        // create byte array to copy pixel values
                        int step = Depth / 8;
                        Pixels = new byte[PixelCount * step];
                        Iptr = bitmapData.Scan0;
    
                        // Copy data from pointer to array
                        Marshal.Copy(Iptr, Pixels, 0, Pixels.Length);
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
    
                /// <summary>
                /// Unlock bitmap data
                /// </summary>
                public void UnlockBits()
                {
                    try
                    {
                        // Copy data from byte array to pointer
                        Marshal.Copy(Pixels, 0, Iptr, Pixels.Length);
    
                        // Unlock bitmap data
                        source.UnlockBits(bitmapData);
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
    
                /// <summary>
                /// Get the color of the specified pixel
                /// </summary>
                /// <param name="x"></param>
                /// <param name="y"></param>
                /// <returns></returns>
                public Color GetPixel(int x, int y)
                {
                    Color clr = Color.Empty;
    
                    // Get color components count
                    int cCount = Depth / 8;
    
                    // Get start index of the specified pixel
                    int i = ((y * Width) + x) * cCount;
    
                    if (i > Pixels.Length - cCount)
                        throw new IndexOutOfRangeException();
    
                    if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha
                    {
                        byte b = Pixels;
                        byte g = Pixels[i + 1];
                        byte r = Pixels[i + 2];
                        byte a = Pixels[i + 3]; // a
                        clr = Color.FromArgb(a, r, g, b);
                    }
                    if (Depth == 24) // For 24 bpp get Red, Green and Blue
                    {
                        byte b = Pixels;
                        byte g = Pixels[i + 1];
                        byte r = Pixels[i + 2];
                        clr = Color.FromArgb(r, g, b);
                    }
                    if (Depth == 8)
                    // For 8 bpp get color value (Red, Green and Blue values are the same)
                    {
                        byte c = Pixels;
                        clr = Color.FromArgb(c, c, c);
                    }
                    return clr;
                }
    
                /// <summary>
                /// Set the color of the specified pixel
                /// </summary>
                /// <param name="x"></param>
                /// <param name="y"></param>
                /// <param name="color"></param>
                public void SetPixel(int x, int y, Color color)
                {
                    // Get color components count
                    int cCount = Depth / 8;
    
                    // Get start index of the specified pixel
                    int i = ((y * Width) + x) * cCount;
    
                    if (Depth == 32) // For 32 bpp set Red, Green, Blue and Alpha
                    {
                        Pixels = color.B;
                        Pixels[i + 1] = color.G;
                        Pixels[i + 2] = color.R;
                        Pixels[i + 3] = color.A;
                    }
                    if (Depth == 24) // For 24 bpp set Red, Green and Blue
                    {
                        Pixels = color.B;
                        Pixels[i + 1] = color.G;
                        Pixels[i + 2] = color.R;
                    }
                    if (Depth == 8)
                    // For 8 bpp set color value (Red, Green and Blue values are the same)
                    {
                        Pixels = color.B;
                    }
                }
            }
      使用:先锁定Bitmap,然后通过Pixels操作颜色对象,最后释放锁,把数据更新到Bitmap中
                string file = @"C:\test.jpg";
                Bitmap bmp = new Bitmap(Image.FromFile(file));
                
                LockBitmap lockbmp = new LockBitmap(bmp);
                //锁定Bitmap,通过Pixel访问颜色
                lockbmp.LockBits();
    
                //获取颜色
                Color color = lockbmp.GetPixel(10, 10);
    
                //从内存解锁Bitmap
                lockbmp.UnlockBits();        

     

     2、指针法
    
      这种方法访问速度比内存法更快,直接通过指针对内存进行操作,不需要进行拷贝,但是在C#中直接通过指针操作内存是不安全的,所以需要在代码中加入unsafe关键字,在生成选项中把允许不安全代码勾上,才能编译通过
    
      这里定义成PointerBitmap类
    public class PointBitmap
                {
                    Bitmap source = null;
                    IntPtr Iptr = IntPtr.Zero;
                    BitmapData bitmapData = null;
    
                    public int Depth { get; private set; }
                    public int Width { get; private set; }
                    public int Height { get; private set; }
    
                    public PointBitmap(Bitmap source)
                    {
                        this.source = source;
                    }
    
                    public void LockBits()
                    {
                        try
                        {
                            // Get width and height of bitmap
                            Width = source.Width;
                            Height = source.Height;
    
                            // get total locked pixels count
                            int PixelCount = Width * Height;
    
                            // Create rectangle to lock
                            Rectangle rect = new Rectangle(0, 0, Width, Height);
    
                            // get source bitmap pixel format size
                            Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);
    
                            // Check if bpp (Bits Per Pixel) is 8, 24, or 32
                            if (Depth != 8 && Depth != 24 && Depth != 32)
                            {
                                throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
                            }
    
                            // Lock bitmap and return bitmap data
                            bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite,
                                                         source.PixelFormat);
    
                            //得到首地址
                            unsafe
                            {
                                Iptr = bitmapData.Scan0;
                                //二维图像循环
                                
                            }
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    }
    
                    public void UnlockBits()
                    {
                        try
                        {
                            source.UnlockBits(bitmapData);
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    }
    
                    public Color GetPixel(int x, int y)
                    {
                        unsafe
                        {
                            byte* ptr = (byte*)Iptr;
                            ptr = ptr + bitmapData.Stride * y;
                            ptr += Depth * x / 8;
                            Color c = Color.Empty;
                            if (Depth == 32)
                            {
                                int a = ptr[3];
                                int r = ptr[2];
                                int g = ptr[1];
                                int b = ptr[0];
                                c = Color.FromArgb(a, r, g, b);
                            }
                            else if (Depth == 24)
                            {
                                int r = ptr[2];
                                int g = ptr[1];
                                int b = ptr[0];
                                c = Color.FromArgb(r, g, b);
                            }
                            else if (Depth == 8)
                            {
                                int r = ptr[0];
                                c = Color.FromArgb(r, r, r);
                            }
                            return c;
                        }
                    }
    
                    public void SetPixel(int x, int y, Color c)
                    {
                        unsafe
                        {
                            byte* ptr = (byte*)Iptr;
                            ptr = ptr + bitmapData.Stride * y;
                            ptr += Depth * x / 8;
                            if (Depth == 32)
                            {
                                ptr[3] = c.A;
                                ptr[2] = c.R;
                                ptr[1] = c.G;
                                ptr[0] = c.B;
                            }
                            else if (Depth == 24)
                            {
                                ptr[2] = c.R;
                                ptr[1] = c.G;
                                ptr[0] = c.B;
                            }
                            else if (Depth == 8)
                            {
                                ptr[2] = c.R;
                                ptr[1] = c.G;
                                ptr[0] = c.B;
                            }
                        }
                    }
                }    

     

     

     

     

     使用方法这里就不列出来了,跟上面的LockBitmap类似

     

    https://blog.csdn.net/yangyikun0428/article/details/53771596

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-23 02:10 , Processed in 0.126623 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表