xref: /OK3568_Linux_fs/external/camera_engine_rkaiq/rkaiq/algos/accm/rk_aiq_accm_algo_com.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2 * rk_aiq_accm_algo_com.cpp
3 
4 * for rockchip v2.0.0
5 *
6 *  Copyright (c) 2019 Rockchip Corporation
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */
21 /* for rockchip v2.0.0*/
22 
23 #include "accm/rk_aiq_accm_algo_com.h"
24 #include "xcam_log.h"
25 #include "interpolation.h"
26 
27 RKAIQ_BEGIN_DECLARE
28 
Swinfo_wbgain_init(float awbGain[2],const CalibDbV2_Ccm_Tuning_Para_t * pCalib,const char * illuName)29 XCamReturn Swinfo_wbgain_init(float awbGain[2], const CalibDbV2_Ccm_Tuning_Para_t *pCalib, const char* illuName)
30 {
31     XCamReturn ret = XCAM_RETURN_NO_ERROR;
32     LOG1_ACCM("%s(%d): (enter)\n", __FUNCTION__, __LINE__);
33 
34     if (pCalib == NULL) {
35         ret = XCAM_RETURN_ERROR_PARAM;
36         LOGE_ACCM("%s(%d): invalid input params\n", __FUNCTION__, __LINE__);
37         return ret;
38     }
39 
40     bool lsFound = false;
41 
42     for(int i = 0; i < pCalib->aCcmCof_len; i++) {
43         if(strcmp(pCalib->aCcmCof[i].name, illuName) == 0) {
44             awbGain[0] = pCalib->aCcmCof[i].awbGain[0];
45             awbGain[1] = pCalib->aCcmCof[i].awbGain[1];
46             lsFound = true;
47             LOGD_ACCM("%s: accm lsForFirstFrame:%s", __FUNCTION__, pCalib->aCcmCof[i].name);
48             break;
49         }
50     }
51     if(pCalib->aCcmCof_len> 0 && lsFound == false) {
52         awbGain[0] = pCalib->aCcmCof[0].awbGain[0];
53         awbGain[1] = pCalib->aCcmCof[0].awbGain[1];
54         LOGD_ACCM("%s: accm lsForFirstFrame:%s", __FUNCTION__, pCalib->aCcmCof[0].name);
55     }
56     LOGV_ACCM("%s: accm illunum:%d", __FUNCTION__, pCalib->aCcmCof_len);
57     LOG1_ACCM( "%s(%d): (exit)\n", __FUNCTION__, __LINE__);
58     return ret;
59 }
60 
illuminant_index_estimation_ccm(int light_num,const CalibDbV2_Ccm_Accm_Cof_Para_t illAll[],float awbGain[2],int * illuminant_index)61 XCamReturn illuminant_index_estimation_ccm(int light_num, const CalibDbV2_Ccm_Accm_Cof_Para_t illAll[], float awbGain[2], int* illuminant_index)
62 {
63 
64     LOG1_ACCM( "%s: (enter)\n", __FUNCTION__);
65     float minDist = 9999999;
66     float dist[8];
67     float nRG, nBG;
68     nRG = awbGain[0];
69     nBG = awbGain[1];
70     *illuminant_index = 0;
71     XCamReturn ret = XCAM_RETURN_ERROR_FAILED;
72     for(int i = 0; i < light_num; i++)
73     {
74         dist[i] = (nRG - illAll[i].awbGain[0]) * (nRG -  illAll[i].awbGain[0])
75                        + (nBG -  illAll[i].awbGain[1]) * (nBG -  illAll[i].awbGain[1]);
76         if(dist[i] < minDist)
77         {
78             minDist = dist[i];
79             *illuminant_index = i;
80             ret = XCAM_RETURN_NO_ERROR;
81         }
82     }
83     if(ret != XCAM_RETURN_NO_ERROR) {
84         LOGE_ACCM("fail to estimate illuminant!!!\n");
85     }
86 
87     LOGD_ACCM( "wbGain:%f,%f, estimation illuminant  is %s(%d) \n", awbGain[0], awbGain[1],
88                illAll[*illuminant_index].name, *illuminant_index);
89 
90     LOG1_ACCM( "%s: (exit)\n", __FUNCTION__);
91     return ret;
92 }
93 
illuminant_index_candidate_ccm(int light_num,const CalibDbV2_Ccm_Accm_Cof_Para_t illAll[],float awbGain[2],char * default_illu,float prob_limit,const float weight_rb[2],float * prob)94 XCamReturn illuminant_index_candidate_ccm(int light_num, const CalibDbV2_Ccm_Accm_Cof_Para_t illAll[], float awbGain[2], char* default_illu, float prob_limit, const float weight_rb[2], float* prob)
95 {
96     LOG1_ACCM( "%s: (enter)\n", __FUNCTION__);
97     float dist[8];
98     float nRG, nBG;
99     nRG = awbGain[0];
100     nBG = awbGain[1];
101     float wr = weight_rb[0];
102     float wb = weight_rb[1];
103     XCamReturn ret = XCAM_RETURN_ERROR_FAILED;
104     if (light_num == 0) {
105         LOGE_ACCM(" Illuminant Profile does not exit  !!!\n");
106         return ret;
107     }
108     LOGD_ACCM("wbGain: %f, %f \n", nRG, nBG);
109     memset(prob, 0, light_num*sizeof(float));
110     if (light_num == 1) {
111         prob[0] =1;
112         LOGD_ACCM(" Only one illuminant profile: %s\n", illAll[0].name);
113         ret = XCAM_RETURN_NO_ERROR;}
114     else {
115         float mean_dist = 0;
116         int idx = 0;
117         float minDist = 9999999;
118         int default_illu_idx = 0;
119         for(int i = 0; i < light_num; i++) {
120             dist[i] = sqrt((nRG - illAll[i].awbGain[0]) * (nRG -  illAll[i].awbGain[0])*wr + (nBG -  illAll[i].awbGain[1]) * (nBG -  illAll[i].awbGain[1])*wb);
121             if (strcmp( default_illu, illAll[i].name) == 0)
122                 default_illu_idx = i;
123             if(dist[i] < minDist)
124             {
125                 minDist = dist[i];
126                 idx = i;
127             }
128             mean_dist = mean_dist + dist[i];
129         }
130         if (minDist  < illAll[idx].minDist) {
131             prob[idx] = 1;
132             LOGD_ACCM(" pick Illu: %s, dist = %f, prob = %f \n", illAll[idx].name, dist[idx],
133                       prob[idx]);
134             ret = XCAM_RETURN_NO_ERROR;
135             LOG1_ACCM( "%s: (exit)\n", __FUNCTION__);
136             return ret;
137         }
138         float sigma = 0;
139         mean_dist = mean_dist/light_num;
140         for(int i = 0; i < light_num; i++)
141             sigma = sigma + (dist[i] - mean_dist)* (dist[i] - mean_dist);
142         sigma = sigma/light_num;
143 
144         if (fabs(sigma)>DIVMIN) {
145             float sum_prob = 0;
146             for(int i = 0; i < light_num; i++) {
147                 prob[i] = exp(-0.5*dist[i]*dist[i]/sigma);
148                 sum_prob = sum_prob + prob[i];
149             }
150             // normalize prob
151             float new_sum_prob = 0;
152             for(int i = 0; i < light_num; i++) {
153                 float prob_tmp;
154                 prob_tmp = prob[i]/sum_prob;
155                 LOGD_ACCM(" Illu Name: %s, dist = %f, ori prob = %f \n", illAll[i].name, dist[i],
156                           prob_tmp);
157                 if (prob_tmp < prob_limit ) {
158                     prob[i] = 0;
159                 }
160                 new_sum_prob += prob[i];
161             }
162             if (fabs(new_sum_prob)<DIVMIN) {
163                 LOGE_ACCM(" prob_limit is too large  !!!\n");
164                 float max_prob = DIVMIN;
165                 int maxprob_idx = 0;
166                 for (int i = 0; i < light_num; i++) {
167                     if (prob[i] > max_prob){
168                         max_prob = prob[i];
169                         maxprob_idx = i;
170                     }
171                 }
172                 memset(prob, 0, light_num*sizeof(float));
173                 prob[maxprob_idx] = 1;
174                 LOGD_ACCM(" pick max prob illu : %s \n", illAll[maxprob_idx].name);
175             } else {
176                 float *prob_test = (float*)malloc(light_num*sizeof(float));
177                 memset(prob_test, 0, light_num*sizeof(float));
178                 float fsum_prob = 0;
179                 for(int i = 0; i < light_num; i++) {
180                     prob_test[i] = prob[i]/new_sum_prob;
181                     if (prob_test[i]<0.333333)
182                         prob_test[i] = 0;
183                     fsum_prob += prob_test[i];
184                 }
185                 if (fabs(fsum_prob)<DIVMIN) {
186                     fsum_prob = new_sum_prob;
187                 } else {
188                     memcpy(prob,  prob_test, light_num*sizeof(float));
189                 }
190                 for(int i = 0; i < light_num; i++) {
191                     prob[i] = prob[i]/fsum_prob;
192                     LOGD_ACCM(" Illu Name: %s, prob = %f \n", illAll[i].name, prob[i]);
193                 }
194                 free(prob_test);
195                 prob_test = NULL;
196             }
197         }
198         else {
199             prob[default_illu_idx] = 1;
200             LOGD_ACCM(" All dist values are equal, pick Default Illu: %s\n",
201                       illAll[default_illu_idx].name);
202         }
203 
204         ret = XCAM_RETURN_NO_ERROR;
205     }
206     if(ret != XCAM_RETURN_NO_ERROR)
207             LOGE_ACCM(" Fail to get Illuminant Probability !!!\n");
208     LOG1_ACCM( "%s: (exit)\n", __FUNCTION__);
209     return ret;
210 }
211 
AwbOrderCcmProfilesBySaturation(const CalibDbV2_Ccm_Matrix_Para_t * pCcmProfiles[],const int32_t cnt)212 static XCamReturn AwbOrderCcmProfilesBySaturation
213 (
214     const CalibDbV2_Ccm_Matrix_Para_t* pCcmProfiles[],
215     const int32_t   cnt
216 ) {
217     int32_t i, j;
218 
219     for (i = 0; i < (cnt - 1); ++i) {
220         for (j = 0; j < (cnt - i - 1); ++j) {
221             if (pCcmProfiles[j]->saturation < pCcmProfiles[j + 1]->saturation) {
222                 const CalibDbV2_Ccm_Matrix_Para_t* temp   = pCcmProfiles[j];
223                 pCcmProfiles[j]         = pCcmProfiles[j + 1];
224                 pCcmProfiles[j + 1]       = temp;
225             }
226         }
227     }
228 
229     return (XCAM_RETURN_NO_ERROR);
230 }
231 
pCcmMatrixAll_init(accm_context_t * accm_context,const CalibDbV2_Ccm_Tuning_Para_t * pCalib)232 XCamReturn pCcmMatrixAll_init(accm_context_t* accm_context, const CalibDbV2_Ccm_Tuning_Para_t *pCalib)
233 {
234     XCamReturn ret = XCAM_RETURN_NO_ERROR;
235     LOG1_ACCM("%s(%d): (enter)\n", __FUNCTION__, __LINE__);
236 
237     if (pCalib == NULL) {
238         ret = XCAM_RETURN_ERROR_PARAM;
239         LOGE_ACCM("%s(%d): invalid input params\n", __FUNCTION__, __LINE__);
240         return ret;
241     }
242 
243     //Config  pCcmMatrixAll (normal and hdr)
244        // 1) get and reorder para
245     for(int i = 0; i < pCalib->aCcmCof_len; i++) {
246         for (int j = 0; j < pCalib->aCcmCof[i].matrixUsed_len; j++) {
247             char name[CCM_PROFILE_NAME];
248             sprintf(name, "%s", pCalib->aCcmCof[i].matrixUsed[j]);
249             const CalibDbV2_Ccm_Matrix_Para_t* pCcmMatrixProfile = NULL;
250             // get a ccm-profile from database
251             ret = CamCalibDbGetCcmProfileByName(pCalib, name, &pCcmMatrixProfile);
252             RETURN_RESULT_IF_DIFFERENT(ret, XCAM_RETURN_NO_ERROR);
253             // store ccm-profile in pointer array
254             accm_context->pCcmMatrixAll[i][j] = pCcmMatrixProfile;
255             LOGV_ACCM("CCM name  %s coef:%f,%f,%f  %f,%f,%f  %f,%f,%f  \n", name,
256                       accm_context->pCcmMatrixAll[i][j]->ccMatrix[0],
257                       accm_context->pCcmMatrixAll[i][j]->ccMatrix[1],
258                       accm_context->pCcmMatrixAll[i][j]->ccMatrix[2],
259                       accm_context->pCcmMatrixAll[i][j]->ccMatrix[3],
260                       accm_context->pCcmMatrixAll[i][j]->ccMatrix[4],
261                       accm_context->pCcmMatrixAll[i][j]->ccMatrix[5],
262                       accm_context->pCcmMatrixAll[i][j]->ccMatrix[6],
263                       accm_context->pCcmMatrixAll[i][j]->ccMatrix[7],
264                       accm_context->pCcmMatrixAll[i][j]->ccMatrix[8]);
265             LOGV_ACCM("off:%f,%f,%f  \n", accm_context->pCcmMatrixAll[i][j]->ccOffsets[0],
266                       accm_context->pCcmMatrixAll[i][j]->ccOffsets[1],
267                       accm_context->pCcmMatrixAll[i][j]->ccOffsets[2]);
268         }
269         // order ccm-profiles by saturation
270         ret = AwbOrderCcmProfilesBySaturation(accm_context->pCcmMatrixAll[i],
271                                               pCalib->aCcmCof[i].matrixUsed_len);
272     }
273 
274     LOG1_ACCM( "%s(%d): (exit)\n", __FUNCTION__, __LINE__);
275     return ret;
276 }
SatSelectCcmProfiles(const float fSaturation,int32_t no_ccm,const CalibDbV2_Ccm_Matrix_Para_t * pCcmProfiles[],const CalibDbV2_Ccm_Matrix_Para_t ** pCcmProfile1,const CalibDbV2_Ccm_Matrix_Para_t ** pCcmProfile2)277 static XCamReturn SatSelectCcmProfiles
278 (
279     const float     fSaturation,
280     int32_t         no_ccm,
281     const CalibDbV2_Ccm_Matrix_Para_t* pCcmProfiles[],
282     const CalibDbV2_Ccm_Matrix_Para_t** pCcmProfile1,
283     const CalibDbV2_Ccm_Matrix_Para_t** pCcmProfile2
284 ) {
285     XCamReturn XCamReturn = XCAM_RETURN_NO_ERROR;
286 
287     if ((no_ccm == 0) || (pCcmProfiles == NULL)
288             || (pCcmProfile1 == NULL) || (pCcmProfile2 == NULL)) {
289         return (XCAM_RETURN_ERROR_PARAM);
290     }
291 
292     if (fSaturation >= pCcmProfiles[0]->saturation) {
293         *pCcmProfile1 = pCcmProfiles[0];
294         *pCcmProfile2 = pCcmProfiles[0];
295         LOGV_ACCM( "select:%s \n", (*pCcmProfile1)->name);
296         XCamReturn = XCAM_RETURN_ERROR_OUTOFRANGE;
297     } else {
298         int32_t nLast = no_ccm - 1;
299         if (fSaturation <= pCcmProfiles[nLast]->saturation) {
300             *pCcmProfile1 = pCcmProfiles[nLast];
301             *pCcmProfile2 = pCcmProfiles[nLast];
302             LOGV_ACCM( "select:%s \n", (*pCcmProfile1)->name);
303             XCamReturn = XCAM_RETURN_ERROR_OUTOFRANGE;
304         } else {
305             uint16_t n = 0;
306 
307             /* find the segment */
308             while ((fSaturation <= pCcmProfiles[n]->saturation) && (n <= nLast)) {
309                 n++;
310             }
311 
312             if (n > 0)
313                 n--;
314 
315             *pCcmProfile1 = pCcmProfiles[n];
316             *pCcmProfile2 = pCcmProfiles[n + 1];
317 
318         }
319     }
320 
321     return (XCamReturn);
322 }
323 
324 
325 /******************************************************************************
326  * InterpolateMatrices
327  *****************************************************************************/
SatInterpolateMatrices(const float fSat,const CalibDbV2_Ccm_Matrix_Para_t * pCcProfileA,const CalibDbV2_Ccm_Matrix_Para_t * pCcProfileB,float * pResMatrix)328 static XCamReturn SatInterpolateMatrices
329 (
330     const float             fSat,
331     const CalibDbV2_Ccm_Matrix_Para_t*   pCcProfileA,
332     const CalibDbV2_Ccm_Matrix_Para_t*   pCcProfileB,
333     float*          pResMatrix
334 ) {
335     XCamReturn iXCamReturn = XCAM_RETURN_ERROR_PARAM;
336 
337     if ((pCcProfileA != NULL) && (pCcProfileA != NULL) && (pResMatrix != NULL)) {
338         const float *pMatrixA = pCcProfileA->ccMatrix;
339         const float *pMatrixB = pCcProfileB->ccMatrix;
340 
341         float fSatA = pCcProfileA->saturation;
342         float fSatB = pCcProfileB->saturation;
343 
344         float f1 = ( fSatB - fSat ) / ( fSatB - fSatA ); // test: if fSat == fSatA => f1 = 1 => choose A: ok
345         float f2 = 1.0f - f1;
346 
347         int i;
348 
349         for ( i = 0; i < 9; i++)
350         {
351             pResMatrix[i] = f1 * pMatrixA[i] + f2 * pMatrixB[i];
352         }
353 
354         iXCamReturn = XCAM_RETURN_NO_ERROR;
355 
356     }
357 
358     return (iXCamReturn);
359 }
360 
361 /******************************************************************************
362  * InterpolateMatrices
363  *****************************************************************************/
SatInterpolateOffset(const float fSat,const CalibDbV2_Ccm_Matrix_Para_t * pCcProfileA,const CalibDbV2_Ccm_Matrix_Para_t * pCcProfileB,float * pResOffset)364 static XCamReturn SatInterpolateOffset
365 (
366     const float             fSat,
367     const CalibDbV2_Ccm_Matrix_Para_t*   pCcProfileA,
368     const CalibDbV2_Ccm_Matrix_Para_t*   pCcProfileB,
369     float     *pResOffset
370 ) {
371     XCamReturn result = XCAM_RETURN_ERROR_PARAM;
372 
373     if ( (pCcProfileA != NULL) && (pCcProfileB != NULL) && (pResOffset != NULL) )
374     {
375         const float *pOffsetA = pCcProfileA->ccOffsets;
376         const float *pOffsetB = pCcProfileB->ccOffsets;
377 
378         float fSatA = pCcProfileA->saturation;
379         float fSatB = pCcProfileB->saturation;
380 
381         float f1 = ( fSatB - fSat ) / ( fSatB - fSatA ); // test: if fSat == fSatA => f1 = 1 => choose A: ok
382         float f2 = 1.0f - f1;
383 
384         pResOffset[CAM_3CH_COLOR_COMPONENT_RED]
385             = f1 * pOffsetA[CAM_3CH_COLOR_COMPONENT_RED] + f2 * pOffsetB[CAM_3CH_COLOR_COMPONENT_RED];
386         pResOffset[CAM_3CH_COLOR_COMPONENT_GREEN]
387             = f1 * pOffsetA[CAM_3CH_COLOR_COMPONENT_GREEN] + f2 * pOffsetB[CAM_3CH_COLOR_COMPONENT_GREEN];
388         pResOffset[CAM_3CH_COLOR_COMPONENT_BLUE]
389             = f1 * pOffsetA[CAM_3CH_COLOR_COMPONENT_BLUE] + f2 * pOffsetB[CAM_3CH_COLOR_COMPONENT_BLUE];
390 
391         result = XCAM_RETURN_NO_ERROR;
392     }
393 
394     return ( result );
395 
396 }
397 
398 /******************************************************************************
399  * Damping
400  *****************************************************************************/
Damping(const float damp,float * pMatrixUndamped,float * pMatrixDamped,float * pOffsetUndamped,float * pOffsetDamped,bool * converge_flag)401 XCamReturn Damping
402 (
403     const float       damp,                /**< damping coefficient */
404     float *pMatrixUndamped,   /**< undamped new computed matrices */
405     float *pMatrixDamped,     /**< old matrices and result */
406     float *pOffsetUndamped,   /**< undamped new computed offsets */
407     float *pOffsetDamped,     /**< old offset and result */
408     bool *converge_flag
409 )
410 {
411     XCamReturn result = XCAM_RETURN_ERROR_PARAM;
412 
413     if ( (pMatrixUndamped != NULL) && (pMatrixDamped != NULL)
414             && (pOffsetUndamped != NULL) && (pOffsetDamped != NULL) )
415     {
416         bool flag = false;
417         int32_t i;
418         float f = (1.0f - damp);
419 
420         /* calc. damped cc matrix */
421         for( i = 0; i < 9; i++ )
422         {
423             pMatrixDamped[i] = (damp * pMatrixDamped[i]) + (f *  pMatrixUndamped[i]);
424             if (!flag) flag = (fabs(pMatrixDamped[i] - pMatrixUndamped[i]) > DIVMIN);
425         }
426 
427         /* calc. damped cc offsets */
428         pOffsetDamped[CAM_3CH_COLOR_COMPONENT_RED]
429             = (damp * pOffsetDamped[CAM_3CH_COLOR_COMPONENT_RED])
430             + (f * pOffsetUndamped[CAM_3CH_COLOR_COMPONENT_RED]);
431         pOffsetDamped[CAM_3CH_COLOR_COMPONENT_GREEN]
432             = (damp * pOffsetDamped[CAM_3CH_COLOR_COMPONENT_GREEN])
433             + (f * pOffsetUndamped[CAM_3CH_COLOR_COMPONENT_GREEN]);
434         pOffsetDamped[CAM_3CH_COLOR_COMPONENT_BLUE]
435             = (damp * pOffsetDamped[CAM_3CH_COLOR_COMPONENT_BLUE])
436             + (f * pOffsetUndamped[CAM_3CH_COLOR_COMPONENT_BLUE]);
437 
438         for (i = 0; i < 3 && !flag; i++)
439             flag = (fabs(pOffsetDamped[i] - pOffsetUndamped[i]) > DIVMIN);
440 
441         *converge_flag = !flag;
442 
443         result = XCAM_RETURN_NO_ERROR;
444     }
445 
446     return ( result );
447 }
448 
Saturationadjust(float fScale,float flevel1,float * pccMatrixA)449 void Saturationadjust(float fScale, float flevel1, float *pccMatrixA)
450 {
451     float  Matrix_tmp[9];
452     if (fScale < DIVMIN) {
453         if(fabs((flevel1-50))>DIVMIN){
454             LOGW_ACCM("fSclae is  %f, so saturation adjust bypass\n", fScale);
455         }
456      } else {
457         flevel1 = (flevel1 - 50) / 50 + 1;
458         LOGD_ACCM("Satura: %f \n", flevel1);
459         memcpy(&Matrix_tmp, pccMatrixA, sizeof(Matrix_tmp));
460         float *pccMatrixB;
461         pccMatrixB = Matrix_tmp;
462         /* ************************************
463         *  M_A =  (M0 - E) * fscale + E
464         *  M_B = rgb2ycbcr(M_A)
465         *  M_B' = ycbcr2rgb[ sat_matrix * M_B ]
466         *  M_A' = (M_B' - E) / fscale + E
467         *  return (M_A')
468         * ***********************************/
469         if ( (pccMatrixA != NULL) && (pccMatrixB != NULL) )
470         {
471             for(int i =0; i < 9; i++)
472             {
473                 if (i == 0 || i == 4 || i == 8){
474                   pccMatrixA[i] = (pccMatrixA[i] - 1)*fScale+1;
475                 }
476                 else{
477                   pccMatrixA[i] = pccMatrixA[i]*fScale;
478                 }
479             }
480             pccMatrixB[0] = 0.299 * pccMatrixA[0] + 0.587 * pccMatrixA[3] + 0.114 * pccMatrixA[6];
481             pccMatrixB[1] = 0.299 * pccMatrixA[1] + 0.587 * pccMatrixA[4] + 0.114 * pccMatrixA[7];
482             pccMatrixB[2] = 0.299 * pccMatrixA[2] + 0.587 * pccMatrixA[5] + 0.114 * pccMatrixA[8];
483             pccMatrixB[3] = -0.1687 * pccMatrixA[0] - 0.3313 * pccMatrixA[3] + 0.5 * pccMatrixA[6];
484             pccMatrixB[4] = -0.1687 * pccMatrixA[1] - 0.3313 * pccMatrixA[4] + 0.5 * pccMatrixA[7];
485             pccMatrixB[5] = -0.1687 * pccMatrixA[2] - 0.3313 * pccMatrixA[5] + 0.5 * pccMatrixA[8];
486             pccMatrixB[6] = 0.5 * pccMatrixA[0]  - 0.4187 * pccMatrixA[3] - 0.0813 * pccMatrixA[6];
487             pccMatrixB[7] = 0.5 * pccMatrixA[1]  - 0.4187 * pccMatrixA[4] - 0.0813 * pccMatrixA[7];
488             pccMatrixB[8] = 0.5 * pccMatrixA[2]  - 0.4187 * pccMatrixA[5] - 0.0813 * pccMatrixA[8];
489 
490             for(int i = 3; i < 9; i++)
491             {
492                  pccMatrixB[i] = flevel1 * pccMatrixB[i];
493              }
494             pccMatrixA[0] = 1 * pccMatrixB[0] + 0 * pccMatrixB[3] + 1.402 * pccMatrixB[6];
495             pccMatrixA[1] = 1 * pccMatrixB[1] + 0 * pccMatrixB[4] + 1.402 * pccMatrixB[7];
496             pccMatrixA[2] = 1 * pccMatrixB[2] + 0 * pccMatrixB[5] + 1.402 * pccMatrixB[8];
497             pccMatrixA[3] = 1 * pccMatrixB[0] - 0.34414 * pccMatrixB[3]  - 0.71414 * pccMatrixB[6];
498             pccMatrixA[4] = 1 * pccMatrixB[1] - 0.34414 * pccMatrixB[4]  - 0.71414 * pccMatrixB[7];
499             pccMatrixA[5] = 1 * pccMatrixB[2] - 0.34414 * pccMatrixB[5]  - 0.71414 * pccMatrixB[8];
500             pccMatrixA[6] = 1 * pccMatrixB[0]  + 1.772 * pccMatrixB[3] + 0 * pccMatrixB[6];
501             pccMatrixA[7] = 1 * pccMatrixB[1]  + 1.772 * pccMatrixB[4] + 0 * pccMatrixB[7];
502             pccMatrixA[8] = 1 * pccMatrixB[2]  + 1.772 * pccMatrixB[5] + 0 * pccMatrixB[8];
503 
504 
505             for(int i =0; i < 9; i++)
506             {
507                 if (i == 0 || i == 4 || i == 8){
508                   pccMatrixA[i] = (pccMatrixA[i] - 1)/fScale+1;
509                 }
510                 else{
511                   pccMatrixA[i] = pccMatrixA[i]/fScale;
512                 }
513             }
514         }
515 
516       }
517 
518 }
519 
520 
CamCalibDbGetCcmProfileByName(const CalibDbV2_Ccm_Tuning_Para_t * calibCcm,char * name,const CalibDbV2_Ccm_Matrix_Para_t ** pCcmMatrixProfile)521 XCamReturn CamCalibDbGetCcmProfileByName(const CalibDbV2_Ccm_Tuning_Para_t *calibCcm, char* name, const CalibDbV2_Ccm_Matrix_Para_t **pCcmMatrixProfile)
522 {
523     LOG1_ACCM("%s: (enter)\n", __FUNCTION__);
524 
525     XCamReturn ret = XCAM_RETURN_ERROR_FAILED;
526 
527     for(int i = 0; i <calibCcm->matrixAll_len; i++) {
528         if(strcmp(calibCcm->matrixAll[i].name, name) == 0) {
529             *pCcmMatrixProfile = &calibCcm->matrixAll[i];
530             ret = XCAM_RETURN_NO_ERROR;
531             break;
532         }
533     }
534     if(ret != XCAM_RETURN_NO_ERROR) {
535         LOGE_ACCM("can't find %s in matrixAll \n", name);
536     }
537     LOG1_ACCM("%s: (exit)\n", __FUNCTION__);
538 
539     return ret;
540 }
541 
UpdateIlluProbList(struct list_head * l,int illu,float prob,int listMaxSize)542 static void UpdateIlluProbList(struct list_head *l, int illu, float prob, int listMaxSize)
543 {
544     prob_node_t *pCurNode, *pNode0;
545 
546     if(listMaxSize == 0) {
547         return;
548     }
549     int sizeList = get_list_num(l);
550     if (sizeList < listMaxSize) {
551         pCurNode = (prob_node_t*)malloc(sizeof(prob_node_t));
552         pCurNode->value = illu;
553         pCurNode->prob = prob;
554         list_prepare_item(&pCurNode->node);
555         list_add_tail((struct list_head*)(&pCurNode->node), l);
556     } else {
557         // input list
558         //     |-------------------------|
559         //     head<->n0<->n1<->n2<->n3
560         // output list
561         //     |-------------------------|
562         //     n0'<->head<->n1<->n2<->n3
563         //     n0'->value = illu;
564         pNode0 = (prob_node_t*)(l->next);
565         pNode0->value = illu;
566         pNode0->prob = prob;
567         struct list_head* nodeH = l;
568         struct list_head* node0 = nodeH->next;
569         list_swap_item(nodeH, node0);
570 
571     }
572 }
573 
574 
StableProbEstimation(struct list_head * l,int listSize,int count,int illuNum,float * probSet)575 static void StableProbEstimation(struct list_head *l, int listSize, int count, int illuNum, float* probSet)
576 {
577     int sizeList = get_list_num(l);
578     if(sizeList < listSize || listSize == 0) {
579         return;
580     }
581     float *prob_tmp = (float*)malloc(illuNum*sizeof(float));
582     memset(prob_tmp, 0, illuNum*sizeof(float));
583     struct list_head *pNextNode = l->next;
584     while (NULL != pNextNode)
585     {
586         prob_node_t *pL;
587         pL = (prob_node_t*)pNextNode;
588         prob_tmp[pL->value] += pL->prob;
589         pNextNode = pNextNode->next;
590     }
591 
592     for(int i=0; i<illuNum; i++){
593         probSet[i] = prob_tmp[i]/(float)count;
594         LOGD_ACCM("illu(%d), stable prob = %f \n", i, probSet[i]);
595     }
596     free(prob_tmp);
597     prob_tmp = NULL;
598 }
599 
600 #if RKAIQ_ACCM_ILLU_VOTE
UpdateDominateIlluList(struct list_head * l_head,int illu,int listMaxSize)601 static void UpdateDominateIlluList(struct list_head* l_head, int illu, int listMaxSize)
602 {
603     illu_node_t* pCurNode, * pNode0;
604     if (listMaxSize == 0) {
605         return;
606     }
607     int sizeList = get_list_num(l_head);
608     if (sizeList < listMaxSize) {
609         pCurNode = (illu_node_t*)malloc(sizeof(illu_node_t));
610         pCurNode->value = illu;
611         list_prepare_item(&pCurNode->node);
612         list_add_tail((struct list_head*)(&pCurNode->node), l_head);
613     }
614     else {
615         // input list
616         //     |-------------------------|
617         //     head<->n0<->n1<->n2<->n3
618         // output list
619         //     |-------------------------|
620         //     n0'<->head<->n1<->n2<->n3
621         //     n0'->value = illu;
622         pNode0 = (illu_node_t*)(l_head->next);
623         pNode0->value = illu;
624         struct list_head* nodeH = l_head;
625         struct list_head* node0 = nodeH->next;
626         list_swap_item(nodeH, node0);
627 
628     }
629 }
630 
StableIlluEstimation(struct list_head * head,int listSize,int illuNum,float varianceLuma,float varianceLumaTh,bool awbConverged,int preIllu,int * newIllu)631 static void StableIlluEstimation(struct list_head * head, int listSize, int illuNum, float varianceLuma, float varianceLumaTh, bool awbConverged, int preIllu, int *newIllu)
632 {
633     int sizeList = get_list_num(head);
634     if (sizeList < listSize || listSize == 0) {
635         return;
636     }
637     /*if( awbConverged) {
638         *newIllu = preIllu;
639         LOGD_ACCM("awb is converged , reserve the last illumination(%d) \n", preIllu );
640         return;
641     }*/
642     /*if( varianceLuma <= varianceLumaTh) {
643         *newIllu = preIllu;
644         LOGD_ACCM("varianceLuma %f < varianceLumaTh %f , reserve the last illumination(%d) \n", varianceLuma,varianceLumaTh,preIllu );
645         return;
646     }*/
647     struct list_head* pNextNode = head->next;
648     illu_node_t* pL;
649     int* illuSet = (int*)malloc(illuNum * sizeof(int));
650     memset(illuSet, 0, illuNum * sizeof(int));
651     while (head != pNextNode)
652     {
653         pL = (illu_node_t*)pNextNode;
654         illuSet[pL->value]++;
655         pNextNode = pNextNode->next;
656     }
657     int max_count = 0;
658     for (int i = 0; i < illuNum; i++) {
659         LOGV_ACCM("illu(%d), count(%d)\n", i, illuSet[i]);
660         if (illuSet[i] > max_count) {
661             max_count = illuSet[i];
662             *newIllu = i;
663         }
664     }
665     free(illuSet);
666     LOGD_ACCM("varianceLuma %f, varianceLumaTh %f final estmination illu is %d\n", varianceLuma, varianceLumaTh, *newIllu);
667 
668 }
669 #endif
670 
interpCCMbywbgain(const CalibDbV2_Ccm_Tuning_Para_t * pCcm,accm_handle_t hAccm,float fSaturation)671 XCamReturn interpCCMbywbgain(const CalibDbV2_Ccm_Tuning_Para_t* pCcm, accm_handle_t hAccm,
672                              float fSaturation) {
673     XCamReturn ret = XCAM_RETURN_NO_ERROR;
674     //1) estimate illuminant prob
675     float probfSaturation = 0;
676     const CalibDbV2_Ccm_Matrix_Para_t* pCcmProfile1 = NULL;
677     const CalibDbV2_Ccm_Matrix_Para_t* pCcmProfile2 = NULL;
678 
679     memset(hAccm->accmRest.undampedCcmMatrix, 0, sizeof(hAccm->accmRest.undampedCcmMatrix));
680     memset(hAccm->accmRest.undampedCcOffset, 0, sizeof(hAccm->accmRest.undampedCcOffset));
681     float* prob = (float*)malloc(pCcm->aCcmCof_len * sizeof(float));
682     ret         = illuminant_index_candidate_ccm(
683         pCcm->aCcmCof_len, pCcm->aCcmCof, hAccm->accmSwInfo.awbGain, pCcm->illu_estim.default_illu,
684         pCcm->illu_estim.prob_limit, pCcm->illu_estim.weightRB, prob);
685     RETURN_RESULT_IF_DIFFERENT(ret, XCAM_RETURN_NO_ERROR);
686 
687     // calculate stable prob
688     int problistsize = pCcm->illu_estim.frame_no * pCcm->aCcmCof_len;
689     for (int i = 0; i < pCcm->aCcmCof_len; i++)
690         UpdateIlluProbList(&hAccm->accmRest.problist, i, prob[i], problistsize);
691     int frames = (int)hAccm->count > (pCcm->illu_estim.frame_no - 1) ? pCcm->illu_estim.frame_no
692                                                                      : hAccm->count;  // todo
693 
694     StableProbEstimation(&hAccm->accmRest.problist, problistsize, frames, pCcm->aCcmCof_len, prob);
695 
696     // 2) all illuminant do interp by fSaturation
697     float undampedCcmMatrix[9];
698     float undampedCcOffset[3];
699     for (int i = 0; i < pCcm->aCcmCof_len; i++) {
700         if (fabs(prob[i])<DIVMIN)
701             continue;
702         //     (1) get IlluProfiles of Candidate illuminants, and calculate fSaturation
703         const CalibDbV2_Ccm_Accm_Cof_Para_t* pDomIlluProfile = &pCcm->aCcmCof[i];
704         interpolation(pDomIlluProfile->gain_sat_curve.gains,
705                         pDomIlluProfile->gain_sat_curve.sat,
706                         4,
707                         hAccm->accmSwInfo.sensorGain, &fSaturation);
708 
709         //     (2) interp CCM matrix and offset
710         ret = SatSelectCcmProfiles(fSaturation, pDomIlluProfile->matrixUsed_len, hAccm->pCcmMatrixAll[i],
711                                     &pCcmProfile1, &pCcmProfile2);
712         if (ret == XCAM_RETURN_NO_ERROR) {
713             XCamReturn ret1 = XCAM_RETURN_NO_ERROR;
714             if (pCcmProfile1 && pCcmProfile2) {
715                 LOGV_ACCM("Illu : %s interp by sat, final fSaturation: %f (%f .. %f)\n",
716                           pDomIlluProfile->name, fSaturation, pCcmProfile1->saturation,
717                           pCcmProfile2->saturation);
718                 ret = SatInterpolateMatrices(fSaturation, pCcmProfile1, pCcmProfile2,
719                                              undampedCcmMatrix);
720                 ret1 =
721                     SatInterpolateOffset(fSaturation, pCcmProfile1, pCcmProfile2, undampedCcOffset);
722                 if ((ret != XCAM_RETURN_NO_ERROR) && (ret1 != XCAM_RETURN_NO_ERROR)) {
723                     free(prob);
724                     return (ret);
725                 }
726             }
727         } else if (ret == XCAM_RETURN_ERROR_OUTOFRANGE) {
728             /* we don't need to interpolate */
729             LOGV_ACCM("Illu : %s, final fSaturation: %f (%f)\n", pDomIlluProfile->name, fSaturation,
730                       pCcmProfile1->saturation);
731             memcpy(undampedCcmMatrix, pCcmProfile1->ccMatrix, sizeof(float)*9);
732             memcpy(undampedCcOffset, pCcmProfile1->ccOffsets, sizeof(float)*3);
733             ret = XCAM_RETURN_NO_ERROR;
734         } else {
735             free(prob);
736             return (ret);
737         }
738         probfSaturation = probfSaturation + fSaturation*prob[i];
739 
740         for (int j = 0; j < 9; j++)
741             hAccm->accmRest.undampedCcmMatrix[j] += undampedCcmMatrix[j]*prob[i];
742         for (int j = 0; j < 3; j++)
743             hAccm->accmRest.undampedCcOffset[j] += undampedCcOffset[j]*prob[i];
744     }
745     hAccm->accmRest.fSaturation =  probfSaturation;
746     hAccm->accmRest.pCcmProfile1 = pCcmProfile1;
747     hAccm->accmRest.pCcmProfile2 = pCcmProfile2;
748 
749     // 3)
750     free(prob);
751     prob = NULL;
752     return ret;
753 }
754 
selectCCM(const CalibDbV2_Ccm_Tuning_Para_t * pCcm,accm_handle_t hAccm,float fSaturation)755 XCamReturn selectCCM(const CalibDbV2_Ccm_Tuning_Para_t* pCcm, accm_handle_t hAccm,
756                      float fSaturation) {
757     XCamReturn ret = XCAM_RETURN_NO_ERROR;
758 
759     const CalibDbV2_Ccm_Matrix_Para_t* pCcmProfile1 = NULL;
760     const CalibDbV2_Ccm_Matrix_Para_t* pCcmProfile2 = NULL;
761     int dominateIlluProfileIdx;
762 #if RKAIQ_ACCM_ILLU_VOTE
763     int dominateIlluListSize = 15;//to do from xml;
764     float varianceLumaTh = 0.006;//to do from xml;
765 #endif
766 
767     ret                      = illuminant_index_estimation_ccm(pCcm->aCcmCof_len, pCcm->aCcmCof,
768                                           hAccm->accmSwInfo.awbGain, &dominateIlluProfileIdx);
769     RETURN_RESULT_IF_DIFFERENT(ret, XCAM_RETURN_NO_ERROR);
770 #if RKAIQ_ACCM_ILLU_VOTE
771     UpdateDominateIlluList(&hAccm->accmRest.dominateIlluList, dominateIlluProfileIdx, dominateIlluListSize);
772     StableIlluEstimation(&hAccm->accmRest.dominateIlluList, dominateIlluListSize, pCcm->aCcmCof_len,
773                          hAccm->accmSwInfo.varianceLuma, varianceLumaTh,
774                          hAccm->accmSwInfo.awbConverged, hAccm->accmRest.dominateIlluProfileIdx,
775                          &dominateIlluProfileIdx);
776 #endif
777 
778     // 2)
779     const CalibDbV2_Ccm_Accm_Cof_Para_t* pDomIlluProfile = &pCcm->aCcmCof[dominateIlluProfileIdx];
780     interpolation(pDomIlluProfile->gain_sat_curve.gains,
781                     pDomIlluProfile->gain_sat_curve.sat,
782                     4,
783                     hAccm->accmSwInfo.sensorGain, &fSaturation);
784     LOGD_ACCM("pickCCMprof = graymode chg (%d) || calib_update (%d) || dominateIlluProfileIdx: %d->%d || fSaturation: %f->%f\n",
785             hAccm->isReCal_, hAccm->calib_update, hAccm->accmRest.dominateIlluProfileIdx, dominateIlluProfileIdx,
786             hAccm->accmRest.fSaturation, fSaturation);
787 
788     hAccm->isReCal_ = hAccm->isReCal_ ||
789                         hAccm->calib_update ||
790                         (dominateIlluProfileIdx != hAccm->accmRest.dominateIlluProfileIdx) ||
791                         (fabs(fSaturation - hAccm->accmRest.fSaturation) > DIVMIN);
792 
793     hAccm->accmRest.dominateIlluProfileIdx = dominateIlluProfileIdx;
794     hAccm->accmRest.fSaturation =  fSaturation;
795 
796     //3)
797     if (hAccm->isReCal_) {
798         ret = SatSelectCcmProfiles(hAccm->accmRest.fSaturation, pDomIlluProfile->matrixUsed_len,
799                                 hAccm->pCcmMatrixAll[dominateIlluProfileIdx], &pCcmProfile1,
800                                 &pCcmProfile2);
801         if (pCcmProfile1 && pCcmProfile2) {
802             hAccm->isReCal_ = hAccm->calib_update ||
803                             strcmp(pCcmProfile1->name, hAccm->accmRest.pCcmProfile1->name) ||
804                             strcmp(pCcmProfile2->name, hAccm->accmRest.pCcmProfile2->name);
805             LOGD_ACCM("CcmProfile changed: %d = calib_update(%d) || pCcmProfile1/2 changed",
806                         hAccm->isReCal_, hAccm->calib_update);
807         } else {
808             LOGD_ACCM("check %s pCcmProfile: %p %p \n", pDomIlluProfile->name, pCcmProfile1, pCcmProfile2);
809             return XCAM_RETURN_ERROR_PARAM;
810         }
811         if (hAccm->isReCal_) {
812             if (ret == XCAM_RETURN_NO_ERROR) {
813                 LOGD_ACCM("final fSaturation: %f (%f .. %f)\n", hAccm->accmRest.fSaturation,
814                         pCcmProfile1->saturation, pCcmProfile2->saturation);
815                 ret = SatInterpolateMatrices(hAccm->accmRest.fSaturation, pCcmProfile1, pCcmProfile2,
816                                             hAccm->accmRest.undampedCcmMatrix);
817                 RETURN_RESULT_IF_DIFFERENT(ret, XCAM_RETURN_NO_ERROR);
818 
819                 ret = SatInterpolateOffset(hAccm->accmRest.fSaturation, pCcmProfile1, pCcmProfile2,
820                                         hAccm->accmRest.undampedCcOffset);
821                 RETURN_RESULT_IF_DIFFERENT(ret, XCAM_RETURN_NO_ERROR);
822             } else if (ret == XCAM_RETURN_ERROR_OUTOFRANGE) {
823                 /* we don't need to interpolate */
824                 LOGD_ACCM("final fSaturation: %f (%f)\n",   hAccm->accmRest.fSaturation, pCcmProfile1->saturation);
825                 memcpy(hAccm->accmRest.undampedCcmMatrix, pCcmProfile1->ccMatrix, sizeof(float)*9);
826                 memcpy(hAccm->accmRest.undampedCcOffset, pCcmProfile1->ccOffsets, sizeof(float)*3);
827                 ret = XCAM_RETURN_NO_ERROR;
828             } else {
829                 return (ret);
830             }
831         }
832         hAccm->accmRest.pCcmProfile1 = pCcmProfile1;
833         hAccm->accmRest.pCcmProfile2 = pCcmProfile2;
834     }
835 
836     return (ret);
837 }
838 
JudgeCcmRes3aConverge(ccm_3ares_info_t * res3a_info,accm_sw_info_t * accmSwInfo,float gain_th,float wbgain_th)839 bool JudgeCcmRes3aConverge
840 (
841     ccm_3ares_info_t *res3a_info,
842     accm_sw_info_t *accmSwInfo,
843     float gain_th,
844     float wbgain_th
845 ) {
846     bool gain_upd = true;
847     bool wbgain_upd = true;
848     float wb_th = wbgain_th*wbgain_th;
849     if (fabs(res3a_info->sensorGain - accmSwInfo->sensorGain) > gain_th) {
850         res3a_info->sensorGain = accmSwInfo->sensorGain;
851     } else {
852         gain_upd = false;
853         accmSwInfo->sensorGain = res3a_info->sensorGain;
854     }
855 
856     if ((res3a_info->awbGain[0]-accmSwInfo->awbGain[0])*(res3a_info->awbGain[0]-accmSwInfo->awbGain[0])
857          + (res3a_info->awbGain[1]-accmSwInfo->awbGain[1])*(res3a_info->awbGain[1]-accmSwInfo->awbGain[1]) > wb_th) {
858         res3a_info->awbGain[0] = accmSwInfo->awbGain[0];
859         res3a_info->awbGain[1] = accmSwInfo->awbGain[1];
860         LOGD_ACCM("update wbgain: %f, %f\n", accmSwInfo->awbGain[0], accmSwInfo->awbGain[1]);
861     } else {
862         wbgain_upd = false;
863         accmSwInfo->awbGain[0] = res3a_info->awbGain[0];
864         accmSwInfo->awbGain[1] = res3a_info->awbGain[1];
865     }
866 
867     return (gain_upd || wbgain_upd);
868 }
869 
870 /**************************************************
871   * ReloadCCMCalibV2
872   *      config ccm_tune used new CalibV2 json para
873 ***************************************************/
874 #if RKAIQ_ACCM_ILLU_VOTE
ReloadCCMCalibV2(accm_handle_t hAccm,const CalibDbV2_Ccm_Tuning_Para_t * TuningPara)875 XCamReturn ReloadCCMCalibV2(accm_handle_t hAccm, const CalibDbV2_Ccm_Tuning_Para_t* TuningPara)
876 {
877     CalibDbV2_Ccm_Tuning_Para_t *stCcm = &hAccm->ccm_tune;
878     if (stCcm == NULL || TuningPara == NULL){
879         LOGE_ACCM("%s: ccm_tune OR calib tuningpara is NULL !!!", __FUNCTION__);
880         return XCAM_RETURN_ERROR_PARAM;
881     }
882     if (TuningPara->aCcmCof_len != stCcm->aCcmCof_len)
883         clear_list(&hAccm->accmRest.dominateIlluList);
884 
885     hAccm->ccm_tune = *TuningPara;
886     return (XCAM_RETURN_NO_ERROR);
887 }
888 #endif
889 
890 
891 RKAIQ_END_DECLARE
892 
893 
894