【短道速滑二】古老的基於亮度平均值的自動Gamma校訂算法。

  在github上搜索代碼Auto Gamma Correction,找到一個比較古老的代碼,詳見:https://github.com/PedramBabakhani/Automatic-Gamma-Correction,配套的代碼使用VHDL語言寫的,看了半天一個for循環沒有,是在看不懂,幸虧裏面有篇算法對應的論文下載,論文名字叫《ASIC implementation of automatic gamma correction based on average of brightness 》,下載看了下,大概搞明白了他的大概意思。git

  文章的核心思想很簡單,就是他假定一幅合理的圖像應該全部像素的平均值應該是0.5左右(歸一化後的),因此那麼自動伽馬校訂的伽馬值就要使得目標圖像向這個目標前進。github

  假定X是圖像的平均值,那麼自動伽馬需符合下述要求:算法

      

   一步一步的往下推導,有:ide

        -----》       --------》spa

   就是這麼簡單哪,若是寫個代碼也就是幾分鐘的事情。3d

int IM_AutoGammaCorrection(unsigned char *Src, unsigned char *Dest, int Width, int Height, int Stride) { int Channel = Stride / Width; if ((Src == NULL) || (Dest == NULL))                    return IM_STATUS_NULLREFRENCE; if ((Width <= 0) || (Height <= 0))                        return IM_STATUS_INVALIDPARAMETER; if ((Channel != 1) && (Channel != 3) && (Channel != 4))    return IM_STATUS_NOTSUPPORTED; int AvgB, AvgG, AvgR, AvgA; int Status = IM_GetAverageValue(Src, Width, Height, Stride, AvgB, AvgG, AvgR, AvgA); if (Status != IM_STATUS_OK)    return Status; if (Channel == 1) { float Gamma = -0.3 / (log10(AvgB / 256.0f)); unsigned char Table[256]; for (int Y = 0; Y < 256; Y++)        // 另一種方式是:pow(Y / 255.0, 1.0 / Gamma)
 { Table[Y] = IM_ClampToByte((int)(pow(Y / 255.0f, Gamma) * 255.0f)); } return IM_Curve(Src, Dest, Width, Height, Stride, Table, Table, Table); } else { float GammaB = -0.3 / (log10(AvgB / 256.0f)); float GammaG = -0.3 / (log10(AvgG / 256.0f)); float GammaR = -0.3 / (log10(AvgR / 256.0f)); unsigned char TableB[256], TableG[256], TableR[256]; for (int Y = 0; Y < 256; Y++)        // 另一種方式是:pow(Y / 255.0, 1.0 / Gamma)
 { TableB[Y] = IM_ClampToByte((int)(pow(Y / 255.0f, GammaB) * 255.0f)); TableG[Y] = IM_ClampToByte((int)(pow(Y / 255.0f, GammaG) * 255.0f)); TableR[Y] = IM_ClampToByte((int)(pow(Y / 255.0f, GammaR) * 255.0f)); } return IM_Curve(Src, Dest, Width, Height, Stride, TableB, TableG, TableR); } }

  效果彷佛仍是很不錯的。 code

       

  對於正常的圖像,基本上沒有啥變化,這也是必需要有的特性。blog

          

  論文裏提出了另一種更適合於硬件實現的方式。get

  他把圖像分紅不少個16*16的小塊,好比N*M個(文章中固定死了,也是16*16個),而後對16*16的小塊,每次提取對應位置的一個像素,共計N*M個像素,計算這N*M像素的平均值,而後依據這個平均值計算出伽馬值,這樣就能計算出16*16個Gamma值,這些Gamma值確定不會是徹底相同的,文章中也統計了他們的差別大小,最後用這個256個gamma的平均值做爲最後的正副圖像的平均值。it

   

  這代碼寫的有點狗屎 ......

  注意上面的取樣是所有平均取樣,不是某一個塊集中取樣。

  這樣寫的結果和全圖取平均仍是有必定區別的,不過效果基本上差很少。

  整個過程就這麼簡單,不過對於彩色圖像,若是直接分通道實現,彷佛會出現必定的偏色現象,我想這個不該該是Gamma調整該出現的做用,應該予以消除,以下所示:

       

  解決方法有把三通道求得的Gamma值再求平均值,做爲每一個通道的Gamma值,也能夠對亮度通道作Gamma,而後在返回到RGB空間等等。

       

  如上所示,基本沒有這個現象。

  固然,這種全局的Gamma校訂仍是有不少問題,好比容易出現塊狀,容易加強噪音等等,須要和某些局部算法結合在一塊兒來實現更好的結果。

       本文Demo下載地址:  http://files.cnblogs.com/files/Imageshop/SSE_Optimization_Demo.rar,見其中的Adjust-> Auto Gamma Correction菜單。

相關文章
相關標籤/搜索