本文共 6905 字,大约阅读时间需要 23 分钟。
写在前面的话:
本文针对GDI+下Bitmap操作(Get/SetPixel)进行测试,而非寻求最快速的位图处理方式。如果你需要速度上的提升,请使用GDI+以外的技术,如并行计算、调用MMX/SSE指令、CUDA等。
这是一个古老的技巧:
使用Bitmap类时经常会用到GetPixel和SetPixel,但是这两个方法直接使用都比较慢,所以一般都会使用LockBits/UnlockBits将位图在内存中锁定,以加快操作速度。 MSDN上的标准参考是这样的:private void LockUnlockBitsExample(PaintEventArgs e) { // Create a new bitmap.创建位图 Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg"); // Lock the bitmap's bits. 锁定位图 Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); // Get the address of the first line.获取首行地址 IntPtr ptr = bmpData.Scan0; // Declare an array to hold the bytes of the bitmap.定义数组保存位图 int bytes = Math.Abs(bmpData.Stride) * bmp.Height; byte[] rgbValues = new byte[bytes]; // Copy the RGB values into the array.复制RGB值到数组 System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); // Set every third value to 255. A 24bpp bitmap will look red. 把每像素第3个值设为255.24bpp的位图将变红 for (int counter = 2; counter < rgbValues.Length; counter += 3) rgbValues[counter] = 255; // Copy the RGB values back to the bitmap 把RGB值拷回位图 System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes); // Unlock the bits.解锁 bmp.UnlockBits(bmpData); // Draw the modified image.绘制更新了的位图 e.Graphics.DrawImage(bmp, 0, 150); }因为我比较闲,所以我在想这样的问题:加快之后到底有多快? 为此,我稍微调整了下之前用过的BitmapEx类(记得应该是人脸识别还是什么代码里用过),改成FastBitmap,然后创建了测试程序,搜集了一系列测试用例。(点击左上图片框打开图片文件,无异常处理)
发个帖子然后蒸馒头吃 ![]()
![]() ![]() ![]() for (int y = 0; y < h; y++){ for (int x = 0; x < w; x++) { tmp = bmp.GetPixel(x, y); }}其中bmp分别为Bitmap和FastBitmap。 为了专注于对比结果,虽然逐像素遍历图像非常耗费时间,但并没有刻意使用并行计算,使用单个CPU内核完成。所以如果你打算用这个程序对特别巨大的图片(10000×10000数量级以上)进行测试,还请慎重。 ![]() ![]() 后记 有朋友指出:
尽管本文的目的并非追求速度,仅仅是「测试」速度,我还是尝试着优化了一下代码,就用上述「反色」操作为例进行了测试。 测试用例选择#7(4096x4096 @ 24bpp),用时299ms,截图如下: 随后再次改进算法,得到了52ms的速度提升(约17%)。 这个结果,尽管较一般操作方式快了不少,但和「一般的语言100ms左右」比起来,还是「右」得多了一点(笑)。和汇编的「20ms」(无实验数据)比,差得更远了。 优化代码似乎比较有趣,我就继续试着优化一下。通过调整调用结构,改进算法,使用多线程并行计算,总算是进入50ms了。 仍旧基于Bitmap类的LockBits/UnlockBits。 语言:C#、C#指针 测试机:i3 380M @2.53GHz,2.92G DDR3-1333,Windows 7 32位 速度:约50ms 网友测试结果对比 以下是部分热心网友给出的测试结果数据,加以对比,供诸君参考。 测试项目统一为对规格为4096x4096x24bpp的位图图像进行反色处理。 测试1: ImageWizard(作者:laviewpbt) 实现:汇编+VB.NET 配置:i3 380M @2.53GHz,2.92G DDR3-1333,Windows 7 32位 用时:25ms 测试2: 临时测试(作者:兰征鹏) 实现:VC++.NET调用SSE指令 配置:i7 860@2.93GHz,12G PC1333内存,Windows7 64位 用时:12~19ms 测试3: GebImage(作者:xiaotie) 实现:C#重写全部图像库、unsafe指针 配置:优于测试1 用时:33ms 测试4: 本文(作者:野比) 实现:GDI+、unsafe指针 配置:同测试1 用时:46ms (完) |
转载地址:http://txdhb.baihongyu.com/