C++ 优化c++;位图处理算法

C++ 优化c++;位图处理算法,c++,c,optimization,image-processing,bitmap,C++,C,Optimization,Image Processing,Bitmap,我已经编写了下一个算法(适用于Android/NDK)来将级别应用于位图。问题是速度非常慢,在像SGSIII这样的高速设备上,8MP图像可能需要4秒钟。而在配备ARMv6的设备上,则需要很长时间(超过10秒)。有没有办法优化它 void applyLevels(unsigned int *rgb, const unsigned int width, const unsigned int height, const float exposure, const float brightness, c

我已经编写了下一个算法(适用于Android/NDK)来将级别应用于位图。问题是速度非常慢,在像SGSIII这样的高速设备上,8MP图像可能需要4秒钟。而在配备ARMv6的设备上,则需要很长时间(超过10秒)。有没有办法优化它

void applyLevels(unsigned int *rgb, const unsigned int width, const unsigned int height, const float exposure, const float brightness, const float contrast, const float saturation)
{
    float R, G, B;

    unsigned int pixelIndex = 0;

    float exposureFactor   = powf(2.0f, exposure);
    float brightnessFactor = brightness / 10.0f;
    float contrastFactor   = contrast > 0.0f ? contrast : 0.0f;

    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            const int pixelValue = buffer[pixelIndex];

            R = ((pixelValue & 0xff0000) >> 16) / 255.0f;
            G = ((pixelValue & 0xff00) >> 8) / 255.0f;
            B = (pixelValue & 0xff) / 255.0f;

            // Clamp values

            R = R > 1.0f ? 1.0f : R < 0.0f ? 0.0f : R;
            G = G > 1.0f ? 1.0f : G < 0.0f ? 0.0f : G;
            B = B > 1.0f ? 1.0f : B < 0.0f ? 0.0f : B;

            // Exposure

            R *= exposureFactor;
            G *= exposureFactor;
            B *= exposureFactor;

            // Contrast

            R = (((R - 0.5f) * contrastFactor) + 0.5f);
            G = (((G - 0.5f) * contrastFactor) + 0.5f);
            B = (((B - 0.5f) * contrastFactor) + 0.5f);

            // Saturation

            float gray = (R * 0.3f) + (G * 0.59f) + (B * 0.11f);
            R = gray * (1.0f - saturation) + R * saturation;
            G = gray * (1.0f - saturation) + G * saturation;
            B = gray * (1.0f - saturation) + B * saturation;

            // Brightness

            R += brightnessFactor;
            G += brightnessFactor;
            B += brightnessFactor;

            // Clamp values

            R = R > 1.0f ? 1.0f : R < 0.0f ? 0.0f : R;
            G = G > 1.0f ? 1.0f : G < 0.0f ? 0.0f : G;
            B = B > 1.0f ? 1.0f : B < 0.0f ? 0.0f : B;

            // Store new pixel value

            R *= 255.0f;
            G *= 255.0f;
            B *= 255.0f;

            buffer[pixelIndex] = ((int)R << 16) | ((int)G << 8) | (int)B;

            pixelIndex++;
        }
    }
}
void applyLevels(无符号整数*rgb、常量无符号整数宽度、常量无符号整数高度、常量浮点曝光、常量浮点亮度、常量浮点对比度、常量浮点饱和度)
{
浮子R,G,B;
无符号整数像素索引=0;
浮动曝光系数=功率因数(2.0f,曝光);
浮动亮度系数=亮度/10.0f;
浮动对比系数=对比度>0.0f?对比度:0.0f;
对于(int y=0;y>16)/255.0f;
G=((像素值&0xff00)>>8)/255.0f;
B=(像素值&0xff)/255.0f;
//钳位值
R=R>1.0f?1.0f:R<0.0f?0.0f:R;
G=G>1.0f?1.0f:G<0.0f?0.0f:G;
B=B>1.0f?1.0f:B<0.0f?0.0f:B;
//曝光
R*=暴露系数;
G*=暴露系数;
B*=暴露系数;
//对比度
R=((R-0.5f)*对比系数)+0.5f);
G=((G-0.5f)*对比系数)+0.5f);
B=((B-0.5f)*对比系数)+0.5f);
//饱和
浮动灰色=(R*0.3f)+(G*0.59f)+(B*0.11f);
R=灰色*(1.0f-饱和度)+R*饱和度;
G=灰色*(1.0f-饱和度)+G*饱和度;
B=灰色*(1.0f-饱和度)+B*饱和度;
//亮度
R+=亮度系数;
G+=亮度系数;
B+=亮度系数;
//钳位值
R=R>1.0f?1.0f:R<0.0f?0.0f:R;
G=G>1.0f?1.0f:G<0.0f?0.0f:G;
B=B>1.0f?1.0f:B<0.0f?0.0f:B;
//存储新的像素值
R*=255.0f;
G*=255.0f;
B*=255.0f;

缓冲区[pixelIndex]=((int)R您正在将基于int的快速RGB值减少为较慢的浮点值,然后使用大量浮点乘法进行调整。最好将调整值(亮度、饱和度等)乘以256,并将其存储为int,并且不要在内部循环中使用任何浮点。

(1.0f-饱和)
在任何地方都是相同的,因此您可以将其分配给变量

您可以将它们转换为单次乘法,而不是
>16)/255.0f
>8)/255.0f
。或者,您可以分别使用
>10
>8
将它们除以256,而不是255:

 R = ((pixelValue & 0xff0000) >> 10);
 G = ((pixelValue & 0xff00) >> 2);

优化代码的几个要点

  • 支持整数计算,这意味着不必将RGB数据从[0,255]转换为[0,1],而是将所有对比度、亮度等转换为0到255之间

  • 剪裁操作通常可以通过剪裁表来简化,以删除if-else语句

    R=剪辑[R']

  • 我注意到一个奇怪的剪辑部分

        // Clamp values
    
        R = R > 255.0f ? 255.0f : R < 0.0f ? 0.0f : R;
        G = G > 255.0f ? 255.0f : G < 0.0f ? 0.0f : G;
        B = B > 255.0f ? 255.0f : B < 0.0f ? 0.0f : B;
    
    //钳位值
    R=R>255.0f?255.0f:R<0.0f?0.0f:R;
    G=G>255.0f?255.0f:G<0.0f?0.0f:G;
    B=B>255.0f?255.0f:B<0.0f?0.0f:B;
    
  • 在这里,看起来您的帐户仍在[0,1]范围内,因此它没有用

  • 最后回顾一下你的公式,因为曝光和亮度似乎可以用来去除一些op

  • 最后,该代码是SIMD和MIMD的良好候选代码,因此,请查看MMX/SSE或OpenMP是否可以解决您的性能问题。

    您的大多数计算都可以简单地提交到表格中……整个处理过程都可以简化

    for (int i=0; i<n; i++) {
        int px = buffer[i];
        int r = tab1[(px >> 16) & 255];
        int g = tab1[(px >> 8) & 255];
        int b = tab1[px & 255];
        gray = (kr*r + kg*g + kb*b) >> 16;
        grayval = tsat1[gray];
        r = brtab[tsat2[r] + grayval];
        g = brtab[tsat2[g] + grayval];
        b = brtab[tsat2[b] + grayval];
        buffer[i] = (r << 16) | (g << 16) | b;
    }
    
    for(inti=0;i>16)&255];
    int g=tab1[(px>>8)和255];
    intb=tab1[px&255];
    灰色=(kr*r+kg*g+kb*b)>>16;
    grayval=tsat1[灰色];
    r=brtab[tsat2[r]+grayval];
    g=brtab[tsat2[g]+grayval];
    b=brtab[tsat2[b]+grayval];
    
    缓冲区[i]=(r对于每个r/G/B值,您应该去掉
    /255.0
    *255.0
    ,并使用255.0而不是1.0作为最大值。这将消除昂贵的除法运算。您可能还希望考虑使用NEON,因为这是SIMD的一个明显候选。这个问题似乎与主题无关,因为它与codereview有关。您可以尝试在没有浮点数的情况下进行操作,看看纯整数数学是否足够精确。毕竟,你的开始和结束都是8位整数。当然,开始时的
    钳制值
    是完全无用的,因为该值被屏蔽为255并除以255.0-不可能是负数或大于1。当然,我们使用定点数学是一个更好的选择。第二个“钳制值”似乎位于错误的位置(当然,这是必需的,因为乘法/加法可能会将其推到范围之外)