繁体   English   中英

C ++ GDI +位图操作需要加快字节操作的速度

[英]C++ GDI+ bitmap manipulation needs speed up on byte operations

我在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
        }
    }

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

提前致谢!

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

代替:

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缓存大,因此我没有给它带来更高的速度效率。

  • 如建议的那样,您可以使用整数进行数学运算,但也可以尝试使用浮点数而不是双精度数(.114f而不是.114),通常更快,并且不需要精度。

  • 像这样进行循环,以节省指针数学。 创建这样的临时指针不会花费任何费用,因为编译器会理解您的工作。

    for(UINT x = 0; x <12000; x + = 3){字节* pVal =&oRow [x]; ....}

  • 该代码也易于线程化-编译器可以通过各种方式自动为您完成代码; 这是一个并行使用的示例: https : //msdn.microsoft.com/zh-cn/library/dd728073.aspx如果您有4个内核,那大约是4倍的加速。

  • 另外,请确保检查发布与调试版本-在以发布/优化模式运行它之前,您不了解性能。

您可以将值预乘: oRow[x * 3] * .114并将它们放入数组中。 oRow[x*3]具有256个值,因此您可以轻松创建0-> 255之间的256个值的数组aMul1,并将其乘以.144。 然后使用aMul1[oRow[x * 3]]查找相乘的值。 与其他组件相同。

实际上,您甚至可以为RGB值创建这样的数组,即。 您的像素为888,因此您将需要一个256 * 256 * 256大小的数组,即16777216 =〜16MB。这是否会加快您的处理速度,您必须使用Profiler进行检查。

总的来说,我发现更直接的指针管理,中间指令,更少的指令(在当今大多数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为您很好地解决了这一问题,并提供了内置的矢量操作和点积。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM