2013-07-18 79 views
2

我已經編寫了下一個算法(用於Android/NDK)將位數應用於位圖。問題是,真的非常慢,在像SGSIII這樣的快速設備上,對於800萬像素的圖像可能需要4秒鐘的時間。在配備ARMv6的設備上需要很長時間(超過10秒)。有什麼辦法可以優化它嗎?優化C++位圖處理算法

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

對於每個R/G/B值,您應該除去'/ 255.0'和'* 255.0',並使用255.0而不是1.0作爲最大值。這將消除昂貴的分工操作。你可能也想看看使用NEON,因爲這是SIMD的明顯候選者。 –

+5

這個問題似乎是脫離主題,因爲它是關於codereview。你可以在http://codereview.stackexchange.com/上發帖。 – TemplateRex

+0

試着不用浮動,看看普通整數數學是否足夠精確。畢竟,無論如何,你都以8位整數開始和結束。 –

回答

1

您正在將基於快速int的RGB值減小到較慢的浮點數,然後使用大量的浮點乘法進行調整。最好將你的調整(亮度,飽和度等)乘以256,並將它們存儲爲整數,並且不要在內部循環中使用任何浮點。

0

(1.0f - saturation)在任何地方都一樣,因此您可以將其分配給一個變量。

而不是>> 16)/255.0f>> 8)/255.0f您可以將它們轉換爲單個乘法。或者,您可以通過256,而不是255 >> 10>> 8分別將它們劃分:

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

幾個點,以優化代碼

  1. 青睞整數計算,這意味着,而不是改變你的RGB數據從[0,255]到[0,1]進行反轉並將所有對比度,亮度等轉換爲0和255之間的值。

  2. 剪切操作通常可以通過剪切表來簡化爲rem ove if-else語句。

    R = clip [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是否可以解決您的性能問題。

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個字節桌遊戲曝光和constrast處理的結果的表
  • tsat1tsat2是飽和處理256頁字節的表
  • brtab是用於亮度處理的512字節表格

請注意,如果沒有進行飽和處理,則只需要在256字節的表中查找每個組件。

一個巨大的速度問題可能是因爲您在沒有專用硬件的情況下使用浮點計算。浮點的軟件實現非常慢。