zoukankan      html  css  js  c++  java
  • 【转】【WPF】wpf 图片指针处理

    我一直用GDI+做Winform 的基于指针的图片处理,这次下决心全部移到wpf上(主要是显示布局很方便)
    采用的图片是
    2512*3307 的大图 830万像素
    类库基于WritableBitmapEx 的wpf版本
    函数是我自己写的扩展方法,只是利用了 writableBitmapEx提供的环境 ,我懒得从头到尾自己写了
     
    1.标准int32数组遍历计算 release
    0.28s

    public unsafe static void TestGray1(WriteableBitmap bmp)
           {
                using (var context = bmp.GetBitmapContext())
                {
                    int height = context.Height;
                    int width = context.Width;
                    for (int y = 0; y < height; y++)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            int pos = y * context.Width + x;
                            var c = context.Pixels[pos];
                            var r = (byte)(c >> 16);
                            var g = (byte)(c >> 8);
                            var b = (byte)(c);
    
                            var gray = ((r * 38 + g * 75 + b * 15) >> 7);
    
                            var color = (255 << 24) | (gray << 16) | (gray << 8) | gray;
                            context.Pixels[pos] = color;
                        }
                    }
                }
            }

    2.标准int32指针遍历计算 release

    0.04s

    public unsafe static void TestGray2(WriteableBitmap bmp)
            {
                using (var context = bmp.GetBitmapContext())
                {
                    var ptr = context.Pixels;
                    int height = context.Height;
                    int width = context.Width;
                    for (int y = 0; y < height; y++)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            var c = *ptr;
                            var r = (byte)(c >> 16);
                            var g = (byte)(c >> 8);
                            var b = (byte)(c);
    
                            var gray = ((r * 38 + g * 75 + b * 15) >> 7);
    
                            var color = (255 << 24) | (gray << 16) | (gray << 8) | gray;
                            *ptr = color;
    
                            ptr++;
                        }
                    }
                }
            }

    3.colorstruct指针 遍历计算

    0.02 s

    应该是已经到极限速度了[除了后面的并行方式],我已经想不出还有什么方法可以提高处理速度

    而且这种方式是最直观的,最容易理解的处理方式,也便于以后维护

    [StructLayout(LayoutKind.Sequential)]
        public struct PixelColor
        {
            public byte Blue;
            public byte Green;
            public byte Red;
            public byte Alpha;
        }
    public unsafe static void TestGray3(WriteableBitmap bmp)
            {
                using (var context = bmp.GetBitmapContext())
                {
                    var ptr = (PixelColor*)context.Pixels;
    
                    int height = context.Height;
                    int width = context.Width;
                    for (int y = 0; y < height; y++)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            var c = *ptr;
                            var gray = ((c.Red * 38 + c.Green * 75 + c.Blue * 15) >> 7);
                            (*ptr).Green=(*ptr).Red=(*ptr).Blue = (byte)gray;
    
                            ptr++;
                        }
                    }
                }
            }

    4.作为对比,我又测试了一下 GDI+的 指针处理图片的速度

    0.06s

    public static unsafe Bitmap ToGray(Bitmap img)
            {
                var rect = new System.Drawing.Rectangle(0, 0, img.Width, img.Height);
                var data = img.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                var ptr = (ColorType*)data.Scan0.ToPointer();
                var bytes = new Int32[img.Width * img.Height];
                var height = img.Height;
                var width = img.Width;
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        var color = *ptr;
                        var gray = ((color.R * 38 + color.G * 75 + color.B * 15) >> 7);
    
                        (*ptr).R = (*ptr).G = (*ptr).B = (byte)gray;
    
                        ptr++;
                    }
                }
                img.UnlockBits(data);
                return img;
            }

    5.重头戏来了。我一直对Parallel.For 很迷惑,为什么他的消耗时间是普通for的好几倍。今天仔细研究了一下,发现原来是用错了

    0.01秒   release

     笔记本i5cpu,如果台式机的I7会更加强悍,速度会成半成半降低。

    主要是利用了微软的任务并行库的循环并行化的方法。

    注意:默认的并行循环对于函数体很小的情况是很慢的,这种情况必须用Partitioner 创建循环体,这在MSDN有介绍,是关键之中的关键

    public  unsafe static void TestGray5(WriteableBitmap bmp)
            { 
                using (var context = bmp.GetBitmapContext())
                {
                    int height = context.Height;
                    int width = context.Width;
    
                    Parallel.ForEach(Partitioner.Create(0, height), (h) =>
                    {
                        var ptr = (PixelColor*)context.Pixels;
                        ptr += h.Item1 * width;
    
                        for (int y = h.Item1; y < h.Item2; y++)
                        {
                            for (int x = 0; x < width; x++)
                            {
                                var c = *ptr;
                                var gray = ((c.Red * 38 + c.Green * 75 + c.Blue * 15) >> 7);
                                (*ptr).Green = (*ptr).Red = (*ptr).Blue = (byte)gray;
    
                                ptr++;
                            }
                        }
    
                    });
    
                }
            }

    感想

    1.绝对不要在循环体内使用属性或函数,很有可能会降低数倍计算速度。

    因为属性本质上是个函数,而在循环体内最好不要再调用函数,如果确实需要用内联代码的方式,c#没有inline,那么copy代码吧,反正为了速度。

    2. 用指针移位操作 似乎比 直接数组访问要快10倍啊

    我感觉要么是cache命中的原因,要么是 数组本身存取被属性封装了。相当于又调用了函数。

    3.TPL 任务并行库果真好用,看来微软早已考虑过大量数据并行的循环优化问题09年,只是我一直用错了方法,才觉得很慢。

    摘自 苦力熊

    原文地址:http://www.2cto.com/kf/201204/129454.html

  • 相关阅读:
    leetcode108 Convert Sorted Array to Binary Search Tree
    leetcode98 Validate Binary Search Tree
    leetcode103 Binary Tree Zigzag Level Order Traversal
    leetcode116 Populating Next Right Pointers in Each Node
    Python全栈之路Day15
    Python全栈之路Day11
    集群监控
    Python全栈之路Day10
    自动部署反向代理、web、nfs
    5.Scss的插值
  • 原文地址:https://www.cnblogs.com/mqxs/p/3770249.html
Copyright © 2011-2022 走看看