引言
在常規的ISP調試中,AE(atuo exposure)是其中很重要的環節,一個必不可少的內容。AE的好壞直接給人的感覺是這顆攝像頭ISP調節是否正常。本文將從以下幾點進行總結歸納:如何避免工頻干擾,TI DSP中H3A中關于AE的簡要說明,AE算法。
工頻干擾
cmos sensor的曝光方式是按行進行的,而在日關燈下,日光燈是交流電下工作。在每一刻輸出的能量并不相同。從而導致可能導致曝光接受的能量不同產生了flicker。 如下圖所示,AC表示交流電,(我國為50Hz)。Light表示工作電壓,Exposure表示理想曝光情況。在Exposure上的方框是實際設置的曝光。不同的寬度表示曝光的行數(基本上以行數為單位加上一些固定開銷),而Exposure與方框的交線表示實際Pixels獲取的能量。所以但左邊兩個大小設置不是理想曝光的倍數的時候由于曝光起始行的關系導致flicker。右側倆個方框則不會出現該情況。從而避免flicker的產生。
所以自動曝光時間設定最好是n/100或者n/120(針對60HZ)。 下面來計算下曝光時間設定。 去除50Hz工頻干擾: One Line Exposure time = (1/ PCLK)*(OneLinePixelNumber + DummyPixelNumber) Exposure Line = (1/100)/(One Line Exposure time)
去除60Hz工頻干擾: One Line Exposure time = (1/ PCLK)*(OneLinePixelNumber + DummyPixelNumber) Exposure Line = (1/120)/(One Line Exposure time)
Camera寄存器中主要調整的就是Exposure Line的值,按整數倍設定可以去除曝光。這個是理論上算出的值。可以按實際中Camera輸出圖像的情況略有偏差,如果偏差過大就要考慮哪里算錯了。
H3A
H3A模塊是通過收集圖像數據輸出統計信息用于自動對焦,自動曝光,以及自動白平衡。主要分為:
Auto focus engine(AF) Auto exposure and auto white balance engine(AE/AWB)
AF engine 主要通過圖像數據提取red,green,bule信息,并提供累加值和峰值信息。指定的區域由“Paxel”組成。 AE/AWB engine 在抽樣區間統計累加值預計飽和值。類似AF中的“Paxel”。“window”則是一個二維采樣的累加區域。AE/AWB engine 將單幀的圖像數據分成幾個“window”。在“window”中進一步分成2*2的blocks。若2*2block均大于或者等于閾值,那么該block不會統計為未飽和。而所有大于閾值的像素會用閾值代替像素值再進行累加。
window0 data Sub Sample Accum[1] Sub Sample Accum[0] Sub Sample Accum[3] Sub Sample Accum[2] Saturator Accum[1] Saturator Accum[0] Saturator Accum[3] Saturator Accum[2]
具體需要閱讀 H3A NDA手冊獲取。上述的統計值對應位置,并不對應顏色。 關于手冊獲取的TI解答
AE算法
算法的主要思想是根據H3A統計值,調整曝光至目標亮度,若達到目標亮度后,除非統計值超過閾值后才會重新調整曝光。 下面為AE的基本思想。當前亮度與目標亮度做比較,然后調整至藍色區域內為穩定狀態,但當前亮度變化超過最外面的兩個閾值后重新開始調整AE。 在調試過程主要是對兩個統計值的理解與應用。 如下為參考代碼:
#define AEWindowNum 8
#define AEINDEX_MIN 10
#define AEINDEX_MAX 120 #define TARGET_LUMA 140
#define UNSAT_PERCENT 10
#define AVE_LIMIT 225 #define AE_Unstable_CNT 0
#define AE_Unstable_CNT2 1 #define AE_Stable_CNT 2 #define AEStep_Thrd1 50
#define AEStep_Thrd2 30
#define AEStep_Thrd3 20 #define AEStep_MIN 1 #define AEStop_Thrd 8 #define AEStop_Thrd2 15 extern int AEStep;
#define Luma_Delta_Thrd 10
#define LumaPercent_Delta_Thrd 10
#define AE_NoOK_CNT 2 #define MIN(X, Y) ((X)<(Y)?(X):(Y))
#define MAX(X, Y) ((X)>(Y)?(X):(Y)) typedef
struct {Uint16 target_luma;Uint16 max_unsat_percent;
}H3aTargetLuma_Value;typedef
struct {Uint16 current_luma;Uint16 current_unsat_percent;
}H3aCurrentLuma_Value;typedef
enum {AE_Init,AE_Start,AE_Finish,AE_Pending,AE_IDLE
}AE_STATUS;
extern AE_STATUS H3A_AE_Status;
void H3A_AE_init()
{H3A_AEindex_Set(
30 );H3a_TargetValue_Set(TARGET_LUMA, UNSAT_PERCENT,AVE_LIMIT);convert_init();H3A_AE_Status = AE_Init;
}
void H3A_AEindex_Set(Uint8 Index)
{Index = MAX(Index, AEINDEX_MIN);Index = MIN(Index, AEINDEX_MAX);ae_index = Index;
}
void H3a_Ae_Process()
{Uint32 ae_int_num = AE_Unstable_CNT; Int32 AE_Direction = -
1 ; Int32 prev_AE_Direction;Uint32 ae_no_ok_num =
0 ;Int32 ABS_DeltaLuma;
if (ae_int_num >
0 ){ae_int_num--;
return ;}
#if 1 ABS_DeltaLuma = abs(CurrentLuma_Value.current_luma - ae_stable_luma);
if (ABS_DeltaLuma > AEStep_Thrd1){AEStep =
8 ;}
else if (ABS_DeltaLuma > AEStep_Thrd2){AEStep =
4 ;}
else if (ABS_DeltaLuma > AEStep_Thrd3){AEStep =
2 ;}
else {AEStep = AEStep_MIN;}ABS_DeltaLuma = abs(CurrentLuma_Value.current_luma - TargetLuma_Value.target_luma);
if (ABS_DeltaLuma < AEStep_Thrd3){AEStep = AEStep_MIN;ae_int_num = AE_Unstable_CNT2;}
#endif #if 1 switch (H3A_AE_Status){
case AE_Init:{AE_Direction = -
1 ;ae_int_num = AE_Unstable_CNT;ae_no_ok_num =
0 ;H3A_AE_Status = AE_Start;checkcnt =
0 ;
break ;}
case AE_Start:{prev_AE_Direction = AE_Direction;
if (CurrentLuma_Value.current_luma <= TargetLuma_Value.target_luma){
if ((prev_AE_Direction ==
1 ) && \((fabs(CurrentLuma_Value.current_luma - TargetLuma_Value.target_luma) < AEStop_Thrd) || checkcnt >=
1 )){ae_stable_luma = TargetLuma_Value.target_luma;ae_stable_lumaPercent = TargetLuma_Value.max_unsat_percent;H3A_AE_Status = AE_Finish;}
if ((prev_AE_Direction ==
1 ) && \(fabs(CurrentLuma_Value.current_luma - TargetLuma_Value.target_luma) < AEStop_Thrd2)){checkcnt ++;}AE_Direction =
0 ;
if ((ae_index + AEStep ) > AEINDEX_MAX){ae_stable_luma = CurrentLuma_Value.current_luma;ae_stable_lumaPercent = CurrentLuma_Value.current_unsat_percent;H3A_AE_Status = AE_Finish;}
else {H3A_AEindex_Set(ae_index + AEStep);}}
else {AE_Direction =
1 ;
if ((ae_index - AEStep ) < AEINDEX_MIN){ae_stable_luma = CurrentLuma_Value.current_luma;ae_stable_lumaPercent = CurrentLuma_Value.current_unsat_percent;H3A_AE_Status = AE_Finish;}
else {H3A_AEindex_Set(ae_index - AEStep);}}
break ;}
case AE_Pending:{
if ((fabs(CurrentLuma_Value.current_luma-ae_stable_luma) > Luma_Delta_Thrd ) \|| (fabs(CurrentLuma_Value.current_unsat_percent-ae_stable_lumaPercent) > LumaPercent_Delta_Thrd )){ae_no_ok_num++;ae_int_num = AE_Unstable_CNT;}
else if (CurrentLuma_Value.current_unsat_percent > (TargetLuma_Value.max_unsat_percent +
20 )){ae_no_ok_num++;ae_int_num = AE_Unstable_CNT;}
else {ae_no_ok_num =
0 ;ae_int_num = AE_Stable_CNT;}
if (ae_no_ok_num >= AE_NoOK_CNT){ae_no_ok_num =
0 ;H3A_AE_Status = AE_Init;}
break ;}
case AE_Finish:{ae_int_num = AE_Stable_CNT;H3A_AE_Status = AE_Pending;
break ;}
case AE_IDLE:{
break ;}
default :
break ;}
}
總結
以上是生活随笔 為你收集整理的ISP-AE 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。