问题描述
发个帖子然后蒸馒头吃--------这是一个古老的技巧:使用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.
解决方案:
关注,前些时间也在做这一块,不过没有这么快