博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【转】【WPF】wpf 图片指针处理
阅读量:6207 次
发布时间:2019-06-21

本文共 5210 字,大约阅读时间需要 17 分钟。

我一直用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.绝对不要在循环体内使用属性或函数,很有可能会降低数倍计算速度。

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

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

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

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

摘自 苦力熊

 

原文地址:

 

转载地址:http://upzja.baihongyu.com/

你可能感兴趣的文章
Python函数积累
查看>>
洛谷P1605:迷宫(DFS)
查看>>
jq挑战30天——打字机效果+小程序
查看>>
正则表达式怎样匹配 不包含特定字符串的字符串
查看>>
【SRX】折腾了半天终于我的那对SRX210 升级到了 12.1R1.9
查看>>
bzoj 2296: 【POJ Challenge】随机种子
查看>>
MPU和MCU的区别和选择
查看>>
js call
查看>>
es6
查看>>
apply和call用法
查看>>
学习笔记之-------UIScrollView 基本用法 代理使用
查看>>
如何理解运维
查看>>
Dom学习笔记
查看>>
JAVA流程控制学习总结
查看>>
配置yum,nc,telnet
查看>>
nib和xib的区别
查看>>
== 和 is 的区别
查看>>
OSPF RFC2740
查看>>
Apple Swift编程语言新手教程
查看>>
linux服务器加入windows域时报错Ticket expired
查看>>