【问题标题】:C++ GDI+ bitmap manipulation needs speed up on byte operationsC++ GDI+ 位图操作需要加快字节操作
【发布时间】:2015-04-24 08:20:44
【问题描述】:

我在 C++ 中使用 GDI+ 来处理一些位图图像、更改颜色和调整图像大小。我的代码在某个特定点非常慢,我正在寻找一些潜在的方法来加快 VS2013 Profiler 中突出显示的行

for (UINT y = 0; y < 3000; ++y)
    {
        //one scanline at a time because bitmaps are stored wrong way up
        byte* oRow = (byte*)bitmapData1.Scan0 + (y * bitmapData1.Stride);
        for (UINT x = 0; x < 4000; ++x)
        {
            //get grey value from 0.114*Blue + 0.299*Red + 0.587*Green
            byte grey = (oRow[x * 3] * .114) + (oRow[x * 3 + 1] * .587) + (oRow[x * 3 + 2] * .299); //THIS LINE IS THE HIGHLIGHTED ONE

            //rest of manipulation code
        }
    }

关于如何更好地处理这条算术线的任何方便提示?这导致我的代码大幅减速

提前致谢!

【问题讨论】:

  • 处理 120 万像素永远不会非常快。将您的浮点数乘以 1000,并在整个过程中使用整数算术。您还可以通过常量加法来更改乘以 3。
  • 请务必选择答案并点赞,以便我们将其标记为已完成

标签: c++ performance bitmap gdi+


【解决方案1】:

优化很大程度上取决于使用的编译器和目标系统。但是有一些提示可能有用。避免乘法:

代替:

byte grey = (oRow[x * 3] * .114) + (oRow[x * 3 + 1] * .587) + (oRow[x * 3 + 2] * .299); //THIS LINE IS THE HIGHLIGHTED ONE

使用...

 //get grey value from 0.114*Blue + 0.299*Red + 0.587*Green
 byte grey = (*oRow) * .114;
 oRow++;
 grey += (*oRow) * .587;
 oRow++;
 grey += (*oRow) * .299;
 oRow++;

您可以将指针的罪名放在同一行。为了更好地理解,我将其放在单独的一行中。

此外,您可以使用表格来代替浮点数的乘法,这比算术要快。这取决于 CPU 和表大小,但您可以试一试:

// somwhere global or class attributes
byte tred[256];
byte tgreen[256];
byte tblue[256];

...启动时...

// Only init once at startup
// I am ignoring the warnings, you should not :-)
for(int i=0;i<255;i++)
{
  tred[i]=i*.114;
  tgreen[i]=i*.587;
  tblue[i]=i*.229;
}

...在循环中...

 byte grey = tred[*oRow];
 oRow++;
 grey += tgreen[*oRow];
 oRow++;
 grey += tblue[*oRow];
 oRow++;

还有。 255*255*255 不是那么大的尺寸。你可以建一张大桌子。由于这个表会比通常的 CPU 缓存大,我给它的速度效率不会那么高。

【讨论】:

    【解决方案2】:
    • 按照建议,您可以使用整数进行数学运算,但您也可以尝试使用浮点数而不是双精度数(.114f 而不是 .114),这通常更快,而且您不需要精度。

    • 改为这样循环,以节省指针数学。创建这样的临时指针不会花费任何成本,因为编译器会理解你在做什么。

      for(UINT x = 0; x

    • 这段代码也很容易线程化——编译器可以通过各种方式自动为您完成;这是一个,使用并行: https://msdn.microsoft.com/en-us/library/dd728073.aspx 如果您有 4 个内核,则速度提高了 4 倍,差不多。

    • 还要确保检查发布与调试构建 - 在发布/优化模式下运行之前,您不知道性能。

    【讨论】:

      【解决方案3】:

      您可以预乘以下值:oRow[x * 3] * .114 并将它们放入数组中。 oRow[x*3] 有 256 个值,因此您可以轻松地创建从 0->255 的 256 个值的数组 aMul1,并将其乘以 0.144。然后使用aMul1[oRow[x * 3]] 找到相乘值。其他组件也是如此。

      实际上,您甚至可以为 RGB 值创建这样的数组,即。您的像素为 888,因此您需要一个大小为 256*256*256 的数组,即 16777216 = ~16MB。这是否会加快您的流程,您必须使用分析器检查自己。

      【讨论】:

        【解决方案4】:

        总的来说,我发现更直接的指针管理、中间指令、更少的指令(在大多数 CPU 上,它们现在的成本都相同)和更少的内存获取 - 例如表格不是比它们更常见的答案 - 通常是最佳选择,无需直接组装。矢量化,尤其是显式化也很有帮助,因为转储函数的程序集并确认内部位符合您的期望。试试这个:

        for (UINT y = 0; y < 3000; ++y)
        {
            //one scanline at a time because bitmaps are stored wrong way up
            byte* oRow = (byte*)bitmapData1.Scan0 + (y * bitmapData1.Stride);
            byte *p = oRow;
            byte *pend = p + 4000 * 3;
            for(; p != pend; p+=3){
                const float grey = p[0] * .114f + p[1] * .587f + p[2] * .299f;
            }
            //alternatively with an autovectorizing compiler
            for(; p != pend; p+=3){
                #pragma unroll //or use a compiler option to unroll loops
                //make sure vectorization and relevant instruction sets are enabled - this is effectively a dot product so the following intrinsic fits the bill:
                //https://msdn.microsoft.com/en-us/library/bb514054.aspx
                //vector types or compiler intrinsics are more reliable often too... but get compiler specific or architecture dependent respectively.
                float grey = 0;
                const float w[3] = {.114f, .587f, .299f};
                for(int c = 0; c < 3; ++c){
                    grey += w[c] * p[c];
                }
            }
        }
        

        考虑使用 OpenCL 并以您的 CPU 为目标,看看您可以通过 CPU 特定的优化和轻松多核来解决问题的速度 - OpenCL 很好地为您解决了这个问题,并提供了内置的矢量运算和点积。

        【讨论】:

          猜你喜欢
          • 2011-10-14
          • 2020-05-22
          • 2018-04-06
          • 2015-11-08
          • 2021-04-25
          • 2011-02-23
          • 1970-01-01
          • 2020-08-11
          相关资源
          最近更新 更多