惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog
T
The Blog of Author Tim Ferriss
J
Java Code Geeks
腾讯CDC
D
Docker
G
Google Developers Blog
D
DataBreaches.Net
雷峰网
雷峰网
Blog — PlanetScale
Blog — PlanetScale
S
SegmentFault 最新的问题
The Cloudflare Blog
有赞技术团队
有赞技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Stack Overflow Blog
Stack Overflow Blog
大猫的无限游戏
大猫的无限游戏
量子位
美团技术团队
aimingoo的专栏
aimingoo的专栏
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Engineering at Meta
Engineering at Meta
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 东风125

.NET Actor Model Implementations Differ in Approach WCF 数据服务 4.5 XML 文档和数据 Why GUID primary keys are a database’s worst nightmare Conway's Game of Life: An Exercise in WPF, MVVM and C# A CIRCULAR PROGRESSBAR STYLE USING AN ATTACHED VIEWMODEL First MarkDown Blog Folder Recursion with C# 39. Volume Rendering Techniques Service Station - An Introduction To RESTful Services With WCF WPF Wonders: Transformations (and Robots!) Flipping elements with WPF FoLlow 的技术博客 利用索引降低并发事务引起的锁【转】 企业级应用架构模型-并发,事务,锁 Web service standards: SOAP, REST, OData, and more A Simple MVVM Example[Forward] The Truth About .NET Objects And Sharing Them Between AppDomains Three Sources of a Solid Object-Oriented Design
加快Bitmap的访问速度
东风125 · 2015-06-28 · via 博客园 - 东风125

引言

在对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[i];
                    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[i];
                    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[i];
                    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[i] = 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[i] = 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[i] = 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类似

资料

http://www.codeproject.com/Tips/240428/Work-with-bitmap-faster-with-Csharp