「玩一玩」量化GDI+:快速Bitmap读写像素——到底有多快?

问题描述

发个帖子然后蒸馒头吃--------这是一个古老的技巧:使用Bitmap类时经常会用到GetPixel和SetPixel,但是这两个方法直接使用都比较慢,所以一般都会使用LockBits/UnlockBits将位图在内存中锁定,以加快操作速度。MSDN上的标准参考是这样的:privatevoidLockUnlockBitsExample(PaintEventArgse){//Createanewbitmap.创建位图Bitmapbmp=newBitmap("c:\fakePhoto.jpg");//Lockthebitmap'sbits.锁定位图Rectanglerect=newRectangle(0,0,bmp.Width,bmp.Height);System.Drawing.Imaging.BitmapDatabmpData=bmp.LockBits(rect,System.Drawing.Imaging.ImageLockMode.ReadWrite,bmp.PixelFormat);//Gettheaddressofthefirstline.获取首行地址IntPtrptr=bmpData.Scan0;//Declareanarraytoholdthebytesofthebitmap.定义数组保存位图intbytes=Math.Abs(bmpData.Stride)*bmp.Height;byte[]rgbValues=newbyte[bytes];//CopytheRGBvaluesintothearray.复制RGB值到数组System.Runtime.InteropServices.Marshal.Copy(ptr,rgbValues,0,bytes);//Seteverythirdvalueto255.A24bppbitmapwilllookred.把每像素第3个值设为255.24bpp的位图将变红for(intcounter=2;counter<rgbValues.Length;counter+=3)rgbValues[counter]=255;//CopytheRGBvaluesbacktothebitmap把RGB值拷回位图System.Runtime.InteropServices.Marshal.Copy(rgbValues,0,ptr,bytes);//Unlockthebits.解锁bmp.UnlockBits(bmpData);//Drawthemodifiedimage.绘制更新了的位图e.Graphics.DrawImage(bmp,0,150);}

因为我比较闲,所以我在想这样的问题:加快之后到底有多快?为此,我稍微调整了下之前用过的BitmapEx类(记得应该是人脸识别还是什么代码里用过),改成FastBitmap,然后创建了测试程序,搜集了一系列测试用例。(点击左上图片框打开图片文件,无异常处理)测试用例如下:为了保证不受文件格式影响,统一使用24bpp的bmp格式。(感谢科技发展,内存白菜价,不然单个文件将近200MB可真要让我麻烦一番。)考察分为GetPixel和SetPixel两个部分,把读写分开。测试代码(以GetPixel为例)非常简单,如下:for(inty=0;y<h;y++){for(intx=0;x<w;x++){tmp=bmp.GetPixel(x,y);}}

其中bmp分别为Bitmap和FastBitmap。为了专注于对比结果,虽然逐像素遍历图像非常耗费时间,但并没有刻意使用并行计算,使用单个CPU内核完成。所以如果你打算用这个程序对特别巨大的图片(10000×10000数量级以上)进行测试,还请慎重。经过测试,得到了这样的测试结果:从测试结果来看,号称「Fast」果然有两把刷子,平均提升效率在90%~95%,也就说性能提高了10~20倍。这个结果,虽然还不算很快,但我觉得基本到了GDI+的极限了(剩下的就是机器性能的提升了),如果再要提升,可以试试并行计算、C++native、直接调用MMX/SSE指令、CUDA之类的技术。我不知道现在技术发展下还有多少用到Bitmap的场合,只是觉得:追求开发效率和性能平衡的时候,Bitmap也能成为一个不错的选择。测试程序下载:--------------顺便求解答:1.C++Native/Managed的测试结果2.葱油饼/状元饼的做法3.怎样揉面能让馒头更好吃

解决方案

解决方案二:
该回复于2012-07-10 13:11:51被版主删除
解决方案三:
没进行过类似处理,关注。
解决方案四:
该回复于2012-07-10 13:18:52被版主删除
解决方案五:
学习C#,收藏。
解决方案六:
该回复于2012-07-10 13:46:53被版主删除
解决方案七:
野比就是野人牛比。
解决方案八:
不错,mark
解决方案九:
学习。。
解决方案十:
不错,学习!
解决方案十一:
直接内存操作确实快。。。
解决方案十二:
微软的那个例子(见连接)可能有问题http://msdn.microsoft.com/zh-cn/library/system.drawing.imaging.bitmapdata.aspx原因是跨距(Stride)可以是负数,这种情况下bmpData.Scan0将指向图像最后一行的开头。直接Marshal.Copy会出问题。BmpData.Stride见:http://msdn.microsoft.com/zh-cn/library/system.drawing.imaging.bitmapdata.stride.aspx
解决方案十三:
该回复于2012-07-10 14:19:39被版主删除
解决方案十四:
引用11楼的回复:

微软的那个例子(见连接)可能有问题http://msdn.microsoft.com/zh-cn/library/system.drawing.imaging.bitmapdata.aspx原因是跨距(Stride)可以是负数,这种情况下bmpData.Scan0将指向图像最后一行的开头。直接Marshal.Copy会出问题。BmpData.Stride见:http://msdn.……

感谢。各位请参考11楼。
解决方案十五:
你这出产速度也太快了啊
解决方案:
前段时间试过Cimage里面的GetPixel,直接内存操作,当时效率提升20倍。想来也差不多了。感谢内存白菜价。
解决方案:
在实际的程序里如果出现这样的东西,还是慢。publicunsafeColorGetPixel(intx,inty){if(this.bmpData.PixelFormat==PixelFormat.Format32bppArgb){byte*numPtr=(byte*)((((void*)this.bmpData.Scan0)+(y*this.bmpData.Stride))+(x*4));returnColor.FromArgb(numPtr[3],numPtr[2],numPtr[1],numPtr[0]);}if(this.bmpData.PixelFormat==PixelFormat.Format24bppRgb){byte*numPtr2=(byte*)((((void*)this.bmpData.Scan0)+(y*this.bmpData.Stride))+(x*3));returnColor.FromArgb(numPtr2[2],numPtr2[1],numPtr2[0]);}returnColor.Empty;}

大量属性的调用,会耗时。实际算法里这只是优化的第一步。
解决方案:
引用4楼的回复:

学习C#,收藏。

学习了。。。。。
解决方案:
引用16楼的回复:

在实际的程序里如果出现这样的东西,还是慢。C#codepublicunsafeColorGetPixel(intx,inty){if(this.bmpData.PixelFormat==PixelFormat.Format32bppArgb){byte*numPtr=(byte*)((((void*)this.……

我能保证你发的这段代码效率远比你想象中高。至于算法中其他优化那是具体的设计,我也没办法考虑。
解决方案:
一直是听说,直接Pixel操作速度会很慢,一直都没接触过,现在感觉速度还能接受啊
解决方案:
类时经常会用到GetPixel和SetPixel,但是这两个方法直接使用都比较慢,所以一般都会使用LockBits/UnlockBits将位图在内存中锁定,以加快操作速
解决方案:
野比兄,下次发帖前,可否先贴一张个人清晰大头照哇
解决方案:
不错啊
解决方案:
学习了,野哥速度太快了!
解决方案:
内存法也慢,用指针法吧,至少比内存法快10倍!
解决方案:
该回复于2012-07-11 11:35:44被版主删除
解决方案:
C#图像处理有三种方法,1是GetPixel,SetPixel方法,这种方法最慢,简直就是看幻灯片;2是内存法,就是你介绍的那个方法,这个方法比方法1快了N倍;3是指针法,虽然C#中指针属于不安全因素,但是,这种方法的速度确实是内存法的10倍以上!建议如果做大型图像处理操作,还是用指针法好!
解决方案:
引用24楼的回复:

内存法也慢,用指针法吧,至少比内存法快10倍!

求实验数据。
解决方案:
我一般是用unsafe的,回头试试Marshal~
解决方案:
没积分了啊郁闷
解决方案:
该回复于2012-07-11 12:29:31被版主删除
解决方案:
顶起,还看不懂
解决方案:
1024
解决方案:
不错,谢谢
解决方案:
该回复于2012-07-11 16:15:37被版主删除
解决方案:
不就是个buffer吧,直接定位到那里写就行了,没这么多事!
解决方案:
野比就是野人牛比引用6楼的回复:

野比就是野人牛比。

解决方案:
该回复于2012-07-11 15:10:56被版主删除
解决方案:
引用27楼的回复:

引用24楼的回复:内存法也慢,用指针法吧,至少比内存法快10倍!求实验数据。

这个不需要实验,把两个copy去掉,它不但浪费了两次copy的时间,还付出了空间的代价。在下面的代码中for(intcounter=2;counter<rgbValues.Length;counter+=3)rgbValues[counter]=255;替换为指针操作,或者不用指针操作,直接用Marshal.WriteByte
解决方案:
顺便再讨论下将图片输出到屏幕的高效的方法呗
解决方案:
该回复于2012-07-11 15:32:15被版主删除
解决方案:
引用6楼的回复:

野比就是野人牛比。

牛比
解决方案:
引用38楼的回复:

引用27楼的回复:引用24楼的回复:内存法也慢,用指针法吧,至少比内存法快10倍!求实验数据。这个不需要实验,把两个copy去掉,它不但浪费了两次copy的时间,还付出了空间的代价。在下面的代码中for(intcounter=2;counter<rgbValues.Length;counter+=3)rgb……

我明白你说的「内存法」就是指Copy了。。从来不用。。其实,MSDN那段我只是用来说明下Lock/Unlock的用法,和测试代码无关。测试是用指针逐像素读写的。。参考16楼。。
解决方案:
珍爱生命远离gdi+
解决方案:
GDIPLUS这种LockBits是临时性的把图像的数据读到内存,是不适合于做专业的图像处理软件的,专业做的话一个图像加载后在内存呢中的格式应该是固定的,这样做算法也就是直接访问这段内存的数据。LockBits的存在有点类似于GDI的GetDibits,他能够简单的把图像数据在不同格式之间进行转换。GetPixel之类的函数的存在也不是为了专业的图像处理的,而是对类似于屏幕取色或DC取色这样小批量数据时方便处理。要玩速度,图像处理方面的算法先是用普通语言写出来,对算法的核心尽心优化,如果速度还不行,考虑用汇编进一步优化,越简单的算法,用汇编优化的速度能提高的倍数越高,比如,最简单的反色算法,3000*4000*24的图像,一般的语言要100ms左右的处理时间,用汇编的话20ms够了,不过复杂的算法,一般汇编能提升的档次不会有这么明显。
解决方案:
引用42楼的回复:

引用38楼的回复:引用27楼的回复:引用24楼的回复:内存法也慢,用指针法吧,至少比内存法快10倍!求实验数据。这个不需要实验,把两个copy去掉,它不但浪费了两次copy的时间,还付出了空间的代价。在下面的代码中for(intcounter=2;counter<rgbValues.Length;counte……

我没说“内存法”,那是另一个人。不过我还是测试了一下指针和copy的速度比较,比如那段代码改为byte*p=(byte*)ptr;byte*q=p+rgbValues.Length;for(byte*counter=p+2;counter<q;counter+=3)*counter=255;把两个copy去掉测试一下时间,除了时间之外还有空间的优势。Marshal.WriteByte我说的有误,速度不快,特此更正,不好意思,哈哈。
解决方案:
葱油饼做法关键还是面粉跟发酵
解决方案:
引用44楼的回复:

GDIPLUS这种LockBits是临时性的把图像的数据读到内存,是不适合于做专业的图像处理软件的,专业做的话一个图像加载后在内存呢中的格式应该是固定的,这样做算法也就是直接访问这段内存的数据。LockBits的存在有点类似于GDI的GetDibits,他能够简单的把图像数据在不同格式之间进行转换。GetPixel之类的函数的存在也不是为了专业的图像处理的,而……

是的。GDI+做点简单图像做界面,真正处理还是需要更精简的方式。刚优化了下,反色4096x4096@24bpp的图像,用时299ms,我已经黔驴技穷了,大家继续。PS:3000x4000@24bpp的图像用时213msSize:3000x4000ProcessingFastBitmap...Processedfastinvertin213ms.ProcessedFastBitmapin213ms.
解决方案:
tolizhibin11:收到。tolaviewpbt&all:最新优化,时间缩短52mstoKarasCanvas:正点!我都是用的自发粉。先试试吧,不行再买酵母。
解决方案:
3000x4000@24bpp的图像用时176msSize:3000x4000ProcessingFastBitmap...Processedfastinvertin176ms.ProcessedFastBitmapin176ms.
解决方案:
关注,前些时间也在做这一块,不过没有这么快

时间: 2024-08-20 00:36:03

「玩一玩」量化GDI+:快速Bitmap读写像素——到底有多快?的相关文章

「玩一玩」功能强大 纯GDI+渲染的语法高亮编辑器控件 支持折叠、书签和代码缩略图等各种高级功能

问题描述 这个控件是纯GDI+绘图的,适用于.NET/.NETCF2.0,高版本.NET也是可以兼容的.代码缩略图(类似SublimeText)这些powerful的高级特性需要额外写一些代码,在DEMO里面已经有了,伸手党有福了.WPF党欢迎参与改良.但是如果你拿不出东西只是要秀优越,请有多远滚多远.lambda党同上.当然,蠢笨如我这文章是翻译乌克兰人PavelTorgashov的.之前翻译过他的,这两个控件可以完美兼容.先放出下载链接,满足下只要源码不要原理的码农们..至于不看这里回帖留邮

拇指玩」制作的「谷歌安装器」app

作者:匿名用户链接:https://www.zhihu.com/question/57468448/answer/153000587来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 先说Google 服务框架Google 服务框架全称 Google Mobile Service,其中包括了应用包,也就是我们希望用到的各种 Google 应用.Android 虽然开源且自由,但 Google 的应用程序并不包含其中,它们都属于 Google 的知识产权.所以厂家们预装

30万、70万和1000万,AI行业的第一仗是「挖人大战」

AI行业的第一仗是「挖人大战」 在今年春季招聘黄金档,对AI(人工智能)人才的抢夺"不计代价".抢不到人,就什么都别谈了.春节前的一天,闵万里突然有些好奇,想看看邮箱里自2016年1月以来收到过多少份职位邀约.最终的数字吓了他一跳--700多封,相当于一天收两封来自各路猎头的邮件.挖他的短信.电话.邮件,"有时候一天收到好几个,刚开始我还认真回复,后来实在烦了." 闵万里是阿里云的人工智能科学家,像他这样,从事人工智能研究的科学家如今奇货可居.连他手下团队里的中层和

《Java特种兵》1.3 简单数字游戏玩一玩

1.3 简单数字游戏玩一玩 数字游戏没错就是玩数字游戏 Java怎么玩马上见证下 玩数字有什么用途呢我们不是虚拟数据给别人看而是通过玩数字转换让我们更了解计算机的数字运算也许数字运算可以有一些神奇的地方有些变态的问题也不是我们想的那么简单. 这里不讲基本的"四则运算"胖哥会讲一些运算符然后再讲讲"大数字"是如何处理的. 1.3.1 变量A.B交换有几种方式 胖哥认为有3种方法来实现变量交换其中一种最简单的方法就是定义一个变量C作为中间量来实现代码例子如下 int C

报名|「OneAPM x DaoCloud」技术公开课:Docker性能监控!

如今,越来越多的公司开始 Docker 了,「三分之二的公司在尝试了 Docker 后最终使用了它」,也就是说 Docker 的转化率达到了 67%,同时转化时长也控制在 60 天内. 既然 Docker 这么火,Docker 监控是不是也该提上日程?或许具体问题要具体分析,但是似乎大家都在寻找新一代 Docker 监控的工具. 本次技术公开课将会给大家带来全方位的 Docker 实践,从监控之道到监控方案,让你了解到 Docker 实时性能状况,精准定位到性能薄弱的环节,从而优化应用,让监控之

3.15 晚会—「饿了么」之殇

一.开题有随想 3 月 15 号晚上的 315 晚会,相信很多人都记忆深刻,「饿了么」.「淘宝」等多家知名互联网厂商都被报出了负面的消息,BAT 中的百度也因为群众对其积攒的「怨气」又一次在微博形成热搜. 其实我们稳下心来想一想,拿饿了么举例,315 所报出的一些问题并没有我们想的那么严重:门店环境良好自然是大家心里期望的,可是当我们用低廉的价格在外卖平台上购餐的时候,谁心里都明白,这不可能是五星级酒店做出来的:而且,除非是在比较高端的餐厅或者酒店中,否则,尝菜这种做法并不少见. 那么真正让大众

钉钉「中国酷公司」发布会图文全纪录(首发)

「中国酷公司」发布会 "关于初心,和一切的开始" 今天我们先不发产品,先发布一个思想.这个思想的起源,来自于我曾经做过的来往. 没有来往就没有钉钉--因为我们现在这个团队以前就是做"来往"的,这是一款阿里巴巴推出的移动社交软件.你们可能很好奇,好好的做着To C的移动社交?怎么跑去做To B的企业软件?其实我们一开始都没想到会是这样的情况,就连阿里巴巴集团CEO逍遥子对我们的评价都是:我们本来打算生一只鸡,但却孵化出一只鸭,其实也挺好的. 2013年,"来

用大数据把医疗行业「熊彼特化」

20世纪中期,著名奥地利经济学家约瑟夫·熊彼特(Joseph Schumpeter)提出了「创造性破坏」的理论,以此表示伴随根本性创新而发生的转型.近些年来,我们的世界已经「熊彼特化」了.数字化设备大规模高强度的渗透我们的日常生活,我们也因此根本性.一次性的改变了彼此之间,以及与我们整个社交网络的沟通方式.我们可以在任何时间轻松的诉诸我们的假体大脑--搜索引擎,以寻找信息或弥补大脑短时间的失忆.无论我们走到哪里,都会用手机拍摄照片和视频,而手机这部宝贵的物件,一直都与我们形影不离. 我们还能想起

互联网时代应给用户「归属和爱」

基础设施的完善,上层应用的繁荣,社会日新月异,全球的移动互联网已称霸多年.茶余饭后,人们的谈资都以扯上互联网三个字为荣,这俨然以成为一种时尚.似乎无论说什么.做什么.想什么,跟互联网搭边,就会显得高大上. 然而很少有人看到现实,做产品.提供服务,不管形式如何,用户需求永远是一切行动的出发点.做好用户肚子里的蛔虫,结合当前时代下工具的能力水平,就已经成功了一半.对于用户需求,我们已经开始懂得区分用户的表面需求与内在需求(比如买车与炫耀),也能够明白在实现需求的过程中手段与目的的微妙关系(比如打井与