在github上搜索代碼Auto Gamma Correction,找到一個比較古老的代碼,詳見:https://github.com/PedramBabakhani/Automatic-Gamma-Correction,配套的代碼使用VHDL語言寫的,看了半天一個for回圈沒有,是在看不懂,幸好里面有篇演算法對應的論文下載,論文名字叫《ASIC implementation of automatic gamma correction based on average of brightness 》,下載看了下,大概搞明白了他的大概意思,
文章的核心思想很簡單,就是他假定一幅合理的影像應該所有像素的平均值應該是0.5左右(歸一化后的),所以那么自動伽馬校正的伽馬值就要使得目標影像向這個目標前進,
假定X是影像的平均值,那么自動伽馬需符合下述要求:

一步一步的往下推導,有:
-----》
--------》
就是這么簡單哪,如果寫個代碼也就是幾分鐘的事情,
int IM_AutoGammaCorrection(unsigned char *Src, unsigned char *Dest, int Width, int Height, int Stride)
{
int Channel = Stride / Width;
if ((Src =https://www.cnblogs.com/Imageshop/p/= 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);
}
}
效果似憾訓是很不錯的,

對于正常的影像,基本上沒有啥變化,這也是必須要有的特性,

論文里提出了另外一種更適合于硬體實作的方式,
他把影像分成很多個16*16的小塊,比如N*M個(文章中固定死了,也是16*16個),然后對16*16的小塊,每次提取對應位置的一個像素,共計N*M個像素,計算這N*M像素的平均值,然后依據這個平均值計算出伽馬值,這樣就能計算出16*16個Gamma值,這些Gamma值肯定不會是完全相同的,文章中也統計了他們的差異大小,最后用這個256個gamma的平均值作為最后的正副影像的平均值,

這代碼寫的有點狗屎 ......
注意上面的取樣是全部平均取樣,不是某一個塊集中取樣,
這樣寫的結果和全圖取平均還是有一定區別的,不過效果基本上差不多,
整個程序就這么簡單,不過對于彩色影像,如果直接分通道實作,似憾訓出現一定的偏色現象,我想這個不應該是Gamma調整該出現的作用,應該予以消除,如下所示:

解決方法有把三通道求得的Gamma值再求平均值,作為每個通道的Gamma值,也可以對亮度通道做Gamma,然后在回傳到RGB空間等等,

如上所示,基本沒有這個現象,
當然,這種全域的Gamma校正還是有很多問題,比如容易出現塊狀,容易增強噪音等等,需要和某些區域演算法結合在一起來實作更好的結果,
本文Demo下載地址: http://files.cnblogs.com/files/Imageshop/SSE_Optimization_Demo.rar,見其中的Adjust-> Auto Gamma Correction選單,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/552.html
標籤:其他
