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