2

我已经编写了下一个算法(用于 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++;
        }
    }
}
4

4 回答 4

2

您的大部分计算都可以简单地列出......整个处理可以变成

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;
}

在哪里

  • tab1是一张 256 字节的表格,列出了曝光和对比处理的结果
  • tsat1并且tsat2是用于饱和处理的 256 字节表
  • brtab是一个用于亮度处理的 512 字节表

请注意,如果没有饱和处理,您只需要在 256 字节表中查找每个组件。

一个巨大的速度问题可能是因为您正在使用没有专用硬件的浮点计算。浮点的软件实现真的很慢。

于 2013-07-18T12:47:01.877 回答
1

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

于 2013-07-18T12:03:40.600 回答
0

优化该代码的几点

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

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

    R = 剪辑[R'];

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

        // 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;
    

在这里看起来您仍在 [0, 1] 范围内,所以它没用!

  1. 最后检查您的公式,因为似乎曝光和亮度可以成为消除一些操作的事实奖励。

最后,该代码非常适合 SIMD 和 MIMD,因此请查看 MMX/SSE 或 OpenMP 是否可以解决您的性能问题。

于 2013-07-18T12:20:17.947 回答
0

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

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

 R = ((pixelValue & 0xff0000) >> 10);
 G = ((pixelValue & 0xff00) >> 2);
于 2013-07-18T12:07:42.253 回答