- ISP Pipeline中Lv实现方式探究之二
- ISP Pipeline中Lv实现方式探究之三--lv计算定点实现
- ISP Pipeline中Lv实现方式探究之四----正LV值定点实现
- ISP Pipeline中Lv实现方式探究之五--lv值计算框架优化
- ISP Pipeline中Lv实现方式探究之六--lv值计算再优化
一、Lv值的计算 公式
LV = log₂(1/(T·Gain)) + Lv_Offset
其中,T表示秒为单位的曝光时间,Gain为总的增益倍数,Lv_offset=8
二、Lv节点具体表现
前 7 段:T=1/512,1/256,1/128,1/64,1/32,1/16,1/8,1/4,Gain=1
后 10 段:T=1/4,Gain=2,4,8,16,32,64,128,256,512
三、下述类似Lv节点代码实现
代码实现:
#define LUT_SIZE_64 64 static const int16_t log2_table_q10_64[LUT_SIZE_64 + 1] = { 0, 23, 45, 68, 90, 111, 132, 153, 174, 194, 214, 234, 254, 273, 292, 311, 330, 348, 366, 384, 402, 419, 436, 454, 470, 487, 504, 520, 536, 552, 568, 584, 599, 614, 629, 644, 659, 674, 689, 703, 717, 731, 745, 759, 773, 787, 800, 813, 827, 840, 853, 866, 879, 891, 904, 916, 929, 941, 953, 965, 977, 989, 1001, 1012, 1024, }; int32_t q10_log2_64lut(uint32_t x) { uint32_t val = x; int32_t exp = 0; if (x <= 0) return 0; // 归一化到 [1024, 2047] while (val >= 2UL * Q10_SCALE) { val >>= 1; exp++; } while (val < Q10_SCALE) { val <<= 1; exp--; } uint32_t delta = val - Q10_SCALE; uint8_t idx = (uint8_t)(delta >> 4); // 64点:右移4位 uint8_t frac = (uint8_t)(delta & 0x0F); // 插值 0~15 int16_t y0 = log2_table_q10_64[idx]; int16_t y1 = log2_table_q10_64[idx + 1]; // 插值公式:y0 + (y1-y0)*frac/16 int32_t interp = y0 + (((int32_t)(y1 - y0) * frac) >> 4); int32_t res = (exp * Q10_SCALE) + interp; return res; } int32_t calc_log2_ev_q10( uint32_t again_q8, uint32_t dgain_q8, uint32_t ispd_q8, uint32_t exp) { int16_t la = q10_log2_64lut(again_q8*4); int16_t ld = q10_log2_64lut(dgain_q8*4); int16_t li = q10_log2_64lut(ispd_q8 * 4); int16_t le = q10_log2_64lut(exp * 1024); return le - (la + ld + li) + 8 * Q10_SCALE; // Q10 格式输出 } int main() { int i; int again = 6318; int dgain = 256; int ispdgain = 256; int exp_numerator = 1; int exp_denominator = 4; int lv = 0; int rand_gain,rand_exp; srand((unsigned int)time(NULL)); int couont = 500; int gain_min = 256; int gain_max = 131072; int exp_min = 4; int exp_max = 512; FILE *fp = fopen("lv_fixed_q10_LUT-new-rand-rand_gain_exp.txt", "w"); fprintf(fp, "Q8fixAgain ori_Again Dgain ispdgain exp_time exp_time(s) lv lv理论值\n"); for (i = 0; i <= couont; i++) { rand_gain = rand() % (gain_max - gain_min + 1) + gain_min; rand_exp = rand() % (exp_max - exp_min + 1) + exp_min; lv = calc_log2_ev_q10(rand_gain, dgain, ispdgain, rand_exp); fprintf(fp, "%6d %10f %4d %4d %d %.8f %4d %.8f\n", rand_gain, (float)rand_gain / 256.0, dgain, ispdgain, rand_exp, 1.0 / rand_exp, lv, lv / 1024.0); } return 0; }增益和曝光时间随机改变,代码计算最终的lv值和excel计算的lv值对比。误差非常小,完全可以在驱动块使用定点实现代码计算Lv值。数据比较如下: