【问题标题】:Optimize c++ bitmap processing algorithm [closed]优化c++位图处理算法[关闭]
【发布时间】:2013-07-17 08:42:40
【问题描述】:

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

【问题讨论】:

  • 您应该去掉每个 R/G/B 值的 / 255.0* 255.0 并使用 255.0 而不是 1.0 作为最大值。这将消除昂贵的部门操作。您可能还想考虑使用 NEON,因为这显然是 SIMD 的候选者。
  • 这个问题似乎是题外话,因为它是关于代码审查的。你可以发帖codereview.stackexchange.com
  • 尝试不使用浮点数,看看普通整数数学是否足够精确。毕竟,无论如何,你都是以 8 位整数开始和结束的。
  • 当然,开头的 clamp values 完全没用,因为该值被屏蔽为 255 并除以 255.0 - 不可能为负数或大于 1。当然,使用定点数学会是更好的选择。第二个“钳位值”似乎在错误的位置(当然,这是必需的,因为乘法/加法可能会将其推到范围之外)

标签: c++ c optimization image-processing bitmap


【解决方案1】:

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

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 字节的表格,列出了曝光和对比处理的结果
  • tsat1tsat2 是用于饱和处理的 256 字节表
  • brtab 是一个 512 字节的亮度处理表

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      (1.0f - saturation) 在任何地方都是一样的,所以你可以把它赋值给一个变量。

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

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

      【讨论】:

        【解决方案4】:

        优化该代码的几点

        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 是否可以解决您的性能问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-04-28
          • 2020-08-13
          • 1970-01-01
          • 1970-01-01
          • 2019-04-07
          • 1970-01-01
          • 1970-01-01
          • 2011-02-28
          相关资源
          最近更新 更多