xref: /OK3568_Linux_fs/external/camera_engine_rkaiq/rkaiq/algos/alsc/rk_aiq_alsc_convert_otp.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <xcam_std.h>
5 #include "xcam_log.h"
6 #include "rk_aiq_alsc_convert_otp.h"
7 
8 // #define WRITE_OTP_TABLE 1
9 
convertLscTableParameter(resolution_t * cur_res,alsc_otp_grad_t * otpGrad,RkAiqBayerPattern_t bayerPattern)10 void convertLscTableParameter(resolution_t *cur_res, alsc_otp_grad_t *otpGrad,
11                               RkAiqBayerPattern_t bayerPattern)
12 {
13     XCAM_STATIC_PROFILING_START(convertLscTable);
14 
15     int32_t bayer 			= bayerPattern;
16     int32_t srcLscWidth     = otpGrad->width;
17     int32_t srcLscHeight    = otpGrad->height;
18     int32_t dstWidth 		= cur_res->width;
19     int32_t dstHeight 		= cur_res->height;
20 
21     LOGD_ALSC("input params: src %dx%d, dst %dx%d, bayer: %d\n",
22             srcLscWidth, srcLscHeight, dstWidth,
23             dstHeight, bayer);
24 
25     if (dstWidth == srcLscWidth && dstHeight == srcLscHeight) {
26         return;
27     }
28 
29     if (dstWidth > srcLscWidth && dstHeight > srcLscHeight)
30     {
31         if ((dstWidth / 2 <= srcLscWidth) && (dstHeight / 2 <= srcLscHeight))
32         {
33             dstWidth = dstWidth / 2;
34             dstHeight = dstHeight / 2;
35         } else {
36             LOGE_ALSC("Failed to handle: src %dx%d, dst %dx%x, return!\n",
37                     srcLscWidth, srcLscHeight, dstWidth, dstHeight);
38             return;
39         }
40     } else if (dstWidth < srcLscWidth && dstHeight < srcLscHeight) {
41         if ((dstWidth <= srcLscWidth / 2) && (dstHeight <= srcLscHeight / 2))
42         {
43             srcLscWidth = srcLscWidth / 2;
44             srcLscHeight = srcLscHeight / 2;
45         }
46     }
47 
48     uint32_t maxSize        = srcLscWidth > srcLscHeight ? srcLscWidth : srcLscHeight;
49     uint32_t ratio          = maxSize > 3200 ? 8 : (maxSize > 1600 ? 4 : (maxSize > 800 ? 2 : 1));
50     srcLscWidth             = 2 * (int32_t)(srcLscWidth / (ratio * 2));
51     srcLscHeight            = 2 * (int32_t)(srcLscHeight / (ratio * 2));
52     dstWidth                = 2 * (int32_t)(dstWidth / (ratio * 2));
53     dstHeight               = 2 * (int32_t)(dstHeight / (ratio * 2));
54 
55     uint16_t *rTable = new uint16_t[srcLscWidth * srcLscHeight];
56     uint16_t *grTable = new uint16_t[srcLscWidth * srcLscHeight];
57     uint16_t *gbTable = new uint16_t[srcLscWidth * srcLscHeight];
58     uint16_t *bTable = new uint16_t[srcLscWidth * srcLscHeight];
59     uint16_t *corTable = new uint16_t[srcLscWidth * srcLscHeight];
60     uint16_t *corTable_crop = new uint16_t[dstWidth * dstHeight];
61 
62 #if WRITE_OTP_TABLE
63     char fileName[32] = {0};
64     snprintf(fileName, sizeof(fileName) - 1, "/tmp/otp_lsc_r.bin");
65     writeFile(fileName, otpGrad->lsc_r);
66     snprintf(fileName, sizeof(fileName) - 1, "/tmp/otp_lsc_b.bin");
67     writeFile(fileName, otpGrad->lsc_b);
68     snprintf(fileName, sizeof(fileName) - 1, "/tmp/otp_lsc_gr.bin");
69     writeFile(fileName, otpGrad->lsc_gr);
70     snprintf(fileName, sizeof(fileName) - 1, "/tmp/otp_lsc_gb.bin");
71     writeFile(fileName, otpGrad->lsc_gb);
72 #endif
73 
74     // Interpolate gain table back to full size
75     int sizeX[16];
76     int sizeY[16];
77     computeSamplingInterval(srcLscWidth, srcLscHeight, sizeX, sizeY);
78     calculateCorrectFactor(otpGrad->lsc_r, rTable, srcLscWidth, srcLscHeight, sizeX, sizeY);
79     calculateCorrectFactor(otpGrad->lsc_gr, grTable, srcLscWidth, srcLscHeight, sizeX, sizeY);
80     calculateCorrectFactor(otpGrad->lsc_gb, gbTable, srcLscWidth, srcLscHeight, sizeX, sizeY);
81     calculateCorrectFactor(otpGrad->lsc_b, bTable, srcLscWidth, srcLscHeight, sizeX, sizeY);
82     getLscParameter(rTable, grTable, gbTable, bTable, corTable, srcLscWidth, srcLscHeight, bayer);
83 
84     // Clipping a Gain table is centered by default
85     int cropoffsetx = srcLscWidth / 2 - dstWidth / 2;
86     int cropoffsety = srcLscHeight / 2 - dstHeight / 2;
87 
88     if (cropoffsetx % 2 != 0)
89         cropoffsetx = cropoffsetx - 1;
90     if (cropoffsety % 2 != 0)
91         cropoffsety = cropoffsety -1;
92 
93     for (int i = 0; i < dstHeight; i++)
94     {
95 
96         memcpy(corTable_crop + i * dstWidth, corTable + (cropoffsety + i)*srcLscWidth + cropoffsetx, dstWidth * 2);
97         //*(corTable_crop + i*dstWidth + j) = *(corTable + (cropoffsety + i)*srcLscWidth + j + cropoffsetx);
98     }
99 
100     delete[] rTable;
101     delete[] grTable;
102     delete[] gbTable;
103     delete[] bTable;
104     delete[] corTable;
105 
106 
107     // down-sampling again according to crop size
108     uint16_t *plscdataR = new uint16_t[dstWidth / 2 * dstHeight / 2];
109     uint16_t *plscdataGr = new uint16_t[dstWidth / 2 * dstHeight / 2];
110     uint16_t *plscdataGb = new uint16_t[dstWidth / 2 * dstHeight / 2];
111     uint16_t *plscdataB = new uint16_t[dstWidth / 2 * dstHeight / 2];
112 
113     memset(plscdataR, 0, sizeof(uint16_t)*dstWidth / 2 * dstHeight / 2);
114     memset(plscdataGr, 0, sizeof(uint16_t)*dstWidth / 2 * dstHeight / 2);
115     memset(plscdataGb, 0, sizeof(uint16_t)*dstWidth / 2 * dstHeight / 2);
116     memset(plscdataB, 0, sizeof(uint16_t)*dstWidth / 2 * dstHeight / 2);
117 
118     separateBayerChannel(corTable_crop, plscdataR, plscdataGr, plscdataGb, plscdataB, dstWidth, dstHeight, bayer);
119 
120 
121     int cPos[17];       // col sampling
122     int rPos[17];       // row sampling
123     computeSamplingPoint(dstWidth / 2, cPos);
124     computeSamplingPoint(dstHeight / 2, rPos);
125     int r, c;
126     for (int i = 0; i < 17; i++)
127     {
128         for (int j = 0; j < 17; j++)
129         {
130             r = rPos[i];
131             c = cPos[j];
132 
133             *(otpGrad->lsc_r + i * 17 + j) = plscdataR[r * dstWidth / 2 + c];
134             *(otpGrad->lsc_gr + i * 17 + j) = plscdataGr[r * dstWidth / 2 + c];
135             *(otpGrad->lsc_gb + i * 17 + j) = plscdataGb[r * dstWidth / 2 + c];
136             *(otpGrad->lsc_b + i * 17 + j) = plscdataB[r * dstWidth / 2 + c];
137         }
138     }
139 
140 #if WRITE_OTP_TABLE
141     snprintf(fileName, sizeof(fileName) - 1, "/tmp/converted_otp_lsc_r.bin");
142     writeFile(fileName, otpGrad->lsc_r);
143     snprintf(fileName, sizeof(fileName) - 1, "/tmp/converted_otp_lsc_b.bin");
144     writeFile(fileName, otpGrad->lsc_b);
145     snprintf(fileName, sizeof(fileName) - 1, "/tmp/converted_otp_lsc_gr.bin");
146     writeFile(fileName, otpGrad->lsc_gr);
147     snprintf(fileName, sizeof(fileName) - 1, "/tmp/converted_otp_lsc_gb.bin");
148     writeFile(fileName, otpGrad->lsc_gb);
149 #endif
150 
151     delete[] plscdataR;
152     delete[] plscdataGr;
153     delete[] plscdataGb;
154     delete[] plscdataB;
155     delete[] corTable_crop;
156 
157     LOGD_ALSC("crop otp LscMatrix r[0:3]:%d,%d,%d,%d, gr[0:3]:%d,%d,%d,%d, gb[0:3]:%d,%d,%d,%d, b[0:3]:%d,%d,%d,%d\n",
158             otpGrad->lsc_r[0],
159             otpGrad->lsc_r[1],
160             otpGrad->lsc_r[2],
161             otpGrad->lsc_r[3],
162             otpGrad->lsc_gr[0],
163             otpGrad->lsc_gr[1],
164             otpGrad->lsc_gr[2],
165             otpGrad->lsc_gr[3],
166             otpGrad->lsc_gb[0],
167             otpGrad->lsc_gb[1],
168             otpGrad->lsc_gb[2],
169             otpGrad->lsc_gb[3],
170             otpGrad->lsc_b[0],
171             otpGrad->lsc_b[1],
172             otpGrad->lsc_b[2],
173             otpGrad->lsc_b[3]);
174 
175     XCAM_STATIC_PROFILING_END(convertLscTable, 0);
176 }
177 
computeSamplingPoint(int size,int * pos)178 void computeSamplingPoint(int size, int *pos)
179 {
180     float sampPos[17] = { 0.0, 6.25, 12.5, 18.75, 25.0, 31.25, 37.5, 43.75, 50.0,
181                           56.25, 62.5, 68.75, 75.0, 81.25, 87.5, 93.75, 100.0
182                         };
183     float tmpVal;
184 
185     pos[0] = 0;
186     for (int i = 1; i < 17; i++)
187     {
188         tmpVal = sampPos[i] / 100;
189         pos[i] = (int)(tmpVal * size) - 1;
190     }
191 
192 }
193 
computeSamplingInterval(int width,int height,int * xInterval,int * yInterval)194 void computeSamplingInterval(int width, int height, int *xInterval, int *yInterval)
195 {
196     int xpos[17];
197     int ypos[17];
198 
199     computeSamplingPoint(width, xpos);
200     computeSamplingPoint(height, ypos);
201 
202     for (int i = 0; i < 16; i++)
203     {
204         xInterval[i] = xpos[i + 1] - xpos[i];
205         yInterval[i] = ypos[i + 1] - ypos[i];
206     }
207 
208     xInterval[0] = xInterval[0] + 1;
209     yInterval[0] = yInterval[0] + 1;
210 }
211 
calculateCorrectFactor(uint16_t * table,uint16_t * correctTable,int width,int height,int * xInterval,int * yInterval)212 void calculateCorrectFactor(uint16_t *table, uint16_t *correctTable, int width, int height, int *xInterval, int *yInterval)
213 {
214     int xGrad[16], yGrad[16];
215     int xblk, yblk;
216     uint16_t xbase, ybase, xoffset, yoffset;
217     uint16_t curSizeX, curSizeY, curGradX, curGradY;
218     uint16_t luCoeff, ldCoeff, ruCoeff, rdCoeff;
219     uint32_t lCoeff, rCoeff, coeff;
220     uint32_t tmp, tmp2;
221 
222     computeGradient(xInterval, yInterval, xGrad, yGrad);
223 
224     for (ybase = 0, yblk = 0; yblk < 16; yblk++)
225     {
226         curSizeY = yInterval[yblk];
227         curGradY = yGrad[yblk];
228         for (xbase = 0, xblk = 0; xblk < 16; xblk++)
229         {
230             curSizeX = xInterval[xblk];
231             curGradX = xGrad[xblk];
232             luCoeff = table[yblk * 17 + xblk];
233             ldCoeff = table[(yblk + 1) * 17 + xblk];
234             ruCoeff = table[yblk * 17 + xblk + 1];
235             rdCoeff = table[(yblk + 1) * 17 + xblk + 1];
236             for (yoffset = 0; yoffset < curSizeY; yoffset++)
237             {
238                 tmp = abs(luCoeff - ldCoeff);
239                 tmp = tmp * curGradY;
240                 tmp = (tmp + c_dy_round) >> c_dy_shift;
241                 tmp = tmp * yoffset;
242                 tmp = (tmp + c_extend_round) >> c_lsc_corr_extend;
243                 tmp = (tmp << (32 - c_lsc_corr_bw)) >> (32 - c_lsc_corr_bw);
244                 lCoeff = luCoeff << c_corr_diff;
245                 lCoeff = (luCoeff > ldCoeff) ? (lCoeff - tmp) : (lCoeff + tmp);
246 
247                 tmp = abs(ruCoeff - rdCoeff);
248                 tmp = tmp * curGradY;
249                 tmp = (tmp + c_dy_round) >> c_dy_shift;
250                 tmp = tmp * yoffset;
251                 tmp = (tmp + c_extend_round) >> c_lsc_corr_extend;
252                 tmp = (tmp << (32 - c_lsc_corr_bw)) >> (32 - c_lsc_corr_bw);
253                 rCoeff = ruCoeff << c_corr_diff;
254                 rCoeff = (ruCoeff > rdCoeff) ? (rCoeff - tmp) : (rCoeff + tmp);
255 
256                 coeff = lCoeff << c_lsc_corr_extend;
257                 tmp = abs((int)(rCoeff - lCoeff));
258                 tmp = tmp * curGradX;
259                 tmp = (tmp + c_dx_round) >> c_dx_shift;
260                 for (xoffset = 0; xoffset < curSizeX; xoffset++)
261                 {
262                     tmp2 = (coeff + c_extend_round) >> c_lsc_corr_extend;
263                     tmp2 = (tmp2 > ((1 << c_lsc_corr_bw) - 1)) ? ((1 << c_lsc_corr_bw) - 1) : tmp2;
264                     *(correctTable + (ybase + yoffset) * width + (xbase + xoffset)) = (uint16_t)tmp2 >> c_corr_diff;
265                     coeff = (lCoeff > rCoeff) ? (coeff - tmp) : (coeff + tmp);
266                 }
267             }
268             xbase += curSizeX;
269         }
270         ybase += curSizeY;
271     }
272 }
273 
getLscParameter(uint16_t * r,uint16_t * gr,uint16_t * gb,uint16_t * b,uint16_t * table,int width,int height,int bayer)274 void getLscParameter(uint16_t *r, uint16_t *gr, uint16_t *gb, uint16_t *b, uint16_t *table, int width, int height, int bayer)
275 {
276     int bayerIdx;
277     int idx;
278 
279     for (int i = 0; i < height; i++)
280     {
281         for (int j = 0; j < width; j++)
282         {
283             idx = i * width + j;
284             bayerIdx = getBayerIndex(bayer, i, j);
285             switch (bayerIdx)
286             {
287             case 0:
288                 table[idx] = r[idx];
289                 break;
290             case 1:
291                 table[idx] = gr[idx];
292                 break;
293             case 2:
294                 table[idx] = gb[idx];
295                 break;
296             case 3:
297                 table[idx] = b[idx];
298                 break;
299             default:
300                 break;
301             }
302         }
303     }
304 }
305 
separateBayerChannel(uint16_t * src,uint16_t * disR,uint16_t * disGr,uint16_t * disGb,uint16_t * disB,int width,int height,int bayer)306 void separateBayerChannel(uint16_t* src, uint16_t* disR, uint16_t* disGr, uint16_t* disGb, uint16_t* disB, int width, int height, int bayer)
307 {
308     int index = 0;
309     int bayerIdx = 0;
310 
311     for (int i = 0; i < height; i++)
312     {
313         for (int j = 0; j < width; j++)
314         {
315             index = i * width + j;
316             bayerIdx = getBayerIndex(bayer, i, j);
317             switch (bayerIdx)
318             {
319             case 0:
320                 *(disR++) = *(src + index);
321                 break;
322             case 1:
323                 *(disGr++) = *(src + index);
324                 break;
325             case 2:
326                 *(disGb++) = *(src + index);
327                 break;
328             case 3:
329                 *(disB++) = *(src + index);
330                 break;
331             default:
332                 break;
333             }
334         }
335     }
336 }
computeGradient(int * xInterval,int * yInterval,int * xGradient,int * yGradient)337 void computeGradient(int *xInterval, int *yInterval, int *xGradient, int *yGradient)
338 {
339     // gradient N = INT(2^15 / SizeN + 0.5)
340     for (int i = 0; i < 16; i++)
341     {
342         xGradient[i] = (int)(32768.0 / (double)xInterval[i] + 0.5);
343         if (xGradient[i] > 8191)
344         {
345             xGradient[i] = 8191;
346         }
347 
348         yGradient[i] = (int)(32768.0 / (double)yInterval[i] + 0.5);
349         if (yGradient[i] > 8191)
350         {
351             yGradient[i] = 8191;
352         }
353     }
354 }
getBayerIndex(int pattern,int row,int col)355 int getBayerIndex(int pattern, int row, int col)
356 {
357     int index = 0;
358     int x, y;
359     int tmp = 0;
360 
361     x = row % 2;
362     y = col % 2;
363 
364     if (x == 0 && y == 0)
365     {
366         tmp = 0;
367     }
368     else if (x == 0 && y == 1)
369     {
370         tmp = 1;
371     }
372     else if (x == 1 && y == 0)
373     {
374         tmp = 2;
375     }
376     else if (x == 1 && y == 1)
377     {
378         tmp = 3;
379     }
380 
381     if (pattern == BAYER_BGGR)
382     {
383         switch (tmp)
384         {
385         case 0:
386             index = B_INDEX;
387             break;
388         case 1:
389             index = GB_INDEX;
390             break;
391         case 2:
392             index = GR_INDEX;
393             break;
394         case 3:
395             index = R_INDEX;
396             break;
397         }
398     }
399     else if (pattern == BAYER_GBRG)
400     {
401         switch (tmp)
402         {
403         case 0:
404             index = GB_INDEX;
405             break;
406         case 1:
407             index = B_INDEX;
408             break;
409         case 2:
410             index = R_INDEX;
411             break;
412         case 3:
413             index = GR_INDEX;
414             break;
415         }
416     }
417     else if (pattern == BAYER_GRBG)
418     {
419         switch (tmp)
420         {
421         case 0:
422             index = GR_INDEX;
423             break;
424         case 1:
425             index = R_INDEX;
426             break;
427         case 2:
428             index = B_INDEX;
429             break;
430         case 3:
431             index = GB_INDEX;
432             break;
433         }
434     }
435     else if (pattern == BAYER_RGGB)
436     {
437         switch (tmp)
438         {
439         case 0:
440             index = R_INDEX;
441             break;
442         case 1:
443             index = GR_INDEX;
444             break;
445         case 2:
446             index = GB_INDEX;
447             break;
448         case 3:
449             index = B_INDEX;
450             break;
451         }
452     }
453 
454     return index;
455 }
456 
writeFile(char * fileName,uint16_t * buf)457 void writeFile(char *fileName, uint16_t *buf)
458 {
459     FILE *fd = fopen(fileName, "wb");
460     if (fd == NULL)
461         printf("%s: open failed: %s\n", __func__, fileName);
462     else {
463         fwrite(buf, 1, LSCDATA_LEN * sizeof(uint16_t), fd);
464         fclose(fd);
465     }
466 }
467 
468 
lightFallOff(uint16_t * table,float * percenttable,float percent,int width,int height)469 void lightFallOff(uint16_t *table, float *percenttable, float percent, int width, int height)
470 {
471     float ratio = (float)width / (float)height;
472     float rMax = sqrt(pow((float)(16 / 2 * ratio), 2) + pow((float)(16 / 2), 2));
473     float r = 0.0, alpha = 0.0, falloff = 0.0, halfPi = 3.1415926 / 2;
474 
475     percent = percent / 100.0;
476 
477     uint16_t tmpTable[17 * 17];
478     memcpy(tmpTable, table, sizeof(uint16_t) * 17 * 17);
479 
480     for (int i = 0; i < 17; i++)
481     {
482         for (int j = 0; j < 17; j++)
483         {
484             table[i * 17 + j] = (float)(table[i * 17 + j] - 1024) * percent + 1024.0;
485             percenttable[i * 17 + j] = (float)table[i * 17 + j] / (float)tmpTable[i * 17 + j];
486         }
487     }
488 }
489 
adjustVignettingForLscOTP(uint16_t * tableB,uint16_t * tableGb,uint16_t * tableGr,uint16_t * tableR,float newVig,int width,int height)490 void adjustVignettingForLscOTP(uint16_t *tableB, uint16_t *tableGb, uint16_t *tableGr, uint16_t *tableR, float newVig, int width, int height)
491 {
492     const float falloffRevert70[17 * 17] = {
493         1.42857, 1.3392, 1.27634, 1.22754, 1.18984, 1.16169, 1.14214, 1.13063, 1.12683, 1.13063, 1.14214, 1.16169, 1.18984, 1.22754, 1.27634, 1.3392, 1.42857,
494         1.37424, 1.29764, 1.23862, 1.19214, 1.15602, 1.12897, 1.11015, 1.09905, 1.09539, 1.09905, 1.11015, 1.12897, 1.15602, 1.19214, 1.23862, 1.29764, 1.37424,
495         1.33537, 1.26382, 1.20742, 1.16268, 1.12778, 1.10158, 1.08335, 1.07259, 1.06904, 1.07259, 1.08335, 1.10158, 1.12778, 1.16268, 1.20742, 1.26382, 1.33537,
496         1.30481, 1.23644, 1.18195, 1.13853, 1.10458, 1.07908, 1.06131, 1.05082, 1.04735, 1.05082, 1.06131, 1.07908, 1.10458, 1.13853, 1.18195, 1.23644, 1.30481,
497         1.28095, 1.21477, 1.16169, 1.11927, 1.08606, 1.06109, 1.04368, 1.0334, 1.03, 1.0334, 1.04368, 1.06109, 1.08606, 1.11927, 1.16169, 1.21477, 1.28095,
498         1.26297, 1.19832, 1.14626, 1.10458, 1.07193, 1.04735, 1.03021, 1.02009, 1.01675, 1.02009, 1.03021, 1.04735, 1.07193, 1.10458, 1.14626, 1.19832, 1.26297,
499         1.25042, 1.18678, 1.13541, 1.09425, 1.06197, 1.03767, 1.02072, 1.01071, 1.0074, 1.01071, 1.02072, 1.03767, 1.06197, 1.09425, 1.13541, 1.18678, 1.25042,
500         1.24299, 1.17993, 1.12897, 1.0881, 1.05605, 1.03191, 1.01508, 1.00513, 1.00184, 1.00513, 1.01508, 1.03191, 1.05605, 1.0881, 1.12897, 1.17993, 1.24299,
501         1.24053, 1.17766, 1.12683, 1.08606, 1.05408, 1.03, 1.0132, 1.00328, 1, 1.00328, 1.0132, 1.03, 1.05408, 1.08606, 1.12683, 1.17766, 1.24053,
502         1.24299, 1.17993, 1.12897, 1.0881, 1.05605, 1.03191, 1.01508, 1.00513, 1.00184, 1.00513, 1.01508, 1.03191, 1.05605, 1.0881, 1.12897, 1.17993, 1.24299,
503         1.25042, 1.18678, 1.13541, 1.09425, 1.06197, 1.03767, 1.02072, 1.01071, 1.0074, 1.01071, 1.02072, 1.03767, 1.06197, 1.09425, 1.13541, 1.18678, 1.25042,
504         1.26297, 1.19832, 1.14626, 1.10458, 1.07193, 1.04735, 1.03021, 1.02009, 1.01675, 1.02009, 1.03021, 1.04735, 1.07193, 1.10458, 1.14626, 1.19832, 1.26297,
505         1.28095, 1.21477, 1.16169, 1.11927, 1.08606, 1.06109, 1.04368, 1.0334, 1.03, 1.0334, 1.04368, 1.06109, 1.08606, 1.11927, 1.16169, 1.21477, 1.28095,
506         1.30481, 1.23644, 1.18195, 1.13853, 1.10458, 1.07908, 1.06131, 1.05082, 1.04735, 1.05082, 1.06131, 1.07908, 1.10458, 1.13853, 1.18195, 1.23644, 1.30481,
507         1.33537, 1.26382, 1.20742, 1.16268, 1.12778, 1.10158, 1.08335, 1.07259, 1.06904, 1.07259, 1.08335, 1.10158, 1.12778, 1.16268, 1.20742, 1.26382, 1.33537,
508         1.37424, 1.29764, 1.23862, 1.19214, 1.15602, 1.12897, 1.11015, 1.09905, 1.09539, 1.09905, 1.11015, 1.12897, 1.15602, 1.19214, 1.23862, 1.29764, 1.37424,
509         1.42857, 1.3392, 1.27634, 1.22754, 1.18984, 1.16169, 1.14214, 1.13063, 1.12683, 1.13063, 1.14214, 1.16169, 1.18984, 1.22754, 1.27634, 1.3392, 1.42857 };
510 
511 	for (int i = 0; i < 17 * 17; i++)
512 	{
513 		tableB[i] = tableB[i] < 1024 ? 1024 : tableB[i];
514 		tableGb[i] = tableGb[i] < 1024 ? 1024 : tableGb[i];
515 		tableGr[i] = tableGr[i] < 1024 ? 1024 : tableGr[i];
516 		tableR[i] = tableR[i] < 1024 ? 1024 : tableR[i];
517 	}
518 
519     // revert to 100 vig
520     for (int i = 0; i < 17 * 17; i++)
521     {
522         tableB[i] = (float)(tableB[i] - 1024) * falloffRevert70[i] + 1024.0 +0.5;
523         tableGb[i] = (float)(tableGb[i] - 1024)  * falloffRevert70[i] + 1024.0 + 0.5;
524         tableGr[i] = (float)(tableGr[i] - 1024)  * falloffRevert70[i] + 1024.0 + 0.5;
525         tableR[i] = (float)(tableR[i] - 1024)  * falloffRevert70[i] + 1024.0 + 0.5;
526     }
527 
528     // calculate new falloff table
529     float newFalloffTable[17 * 17];
530     lightFallOff(tableGb, newFalloffTable, newVig, width, height);
531 
532     // apply to other channel
533     for (int i = 0; i < 17 * 17; i++)
534     {
535         tableB[i] = (float)tableB[i] * newFalloffTable[i] + 0.5;
536         tableGr[i] = (float)tableGr[i] * newFalloffTable[i] + 0.5;
537         tableR[i] = (float)tableR[i] * newFalloffTable[i] + 0.5;
538     }
539 }
540