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

推荐订阅源

Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
Engineering at Meta
Engineering at Meta
博客园 - 司徒正美
T
Tailwind CSS Blog
F
Full Disclosure
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
小众软件
小众软件
IT之家
IT之家
J
Java Code Geeks
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog
B
Blog
V
V2EX
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Hugging Face - Blog
Hugging Face - Blog
美团技术团队
The Cloudflare Blog
Recent Announcements
Recent Announcements
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
罗磊的独立博客
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
酷 壳 – CoolShell
酷 壳 – CoolShell
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
S
Security @ Cisco Blogs
MyScale Blog
MyScale Blog
MongoDB | Blog
MongoDB | Blog
U
Unit 42
H
Heimdal Security Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
V2EX - 技术
V2EX - 技术
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google Online Security Blog
Google Online Security Blog
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
PCI Perspectives
PCI Perspectives
博客园 - 三生石上(FineUI控件)
I
InfoQ
SecWiki News
SecWiki News
N
News and Events Feed by Topic
D
DataBreaches.Net
Schneier on Security
Schneier on Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

博客园 - 东风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