1 /* 2 * cl_tnr_handler.cpp - CL tnr handler 3 * 4 * Copyright (c) 2015 Intel Corporation 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * Author: Wei Zong <wei.zong (at) intel.com> 19 */ 20 21 #include "cl_tnr_handler.h" 22 23 #define TNR_PROCESSING_FRAME_COUNT 4 24 #define TNR_LIST_FRAME_COUNT 4 25 #define TNR_MOTION_THRESHOLD 2 26 27 namespace XCam { 28 29 static const XCamKernelInfo kernel_tnr_yuv_info = { 30 "kernel_tnr_yuv", 31 #include "kernel_tnr.clx" 32 , 0 33 }; 34 35 static const XCamKernelInfo kernel_tnr_rgb_info = { 36 "kernel_tnr_rgb", 37 #include "kernel_tnr.clx" 38 , 0, 39 }; 40 41 CLTnrImageHandler::CLTnrMotionInfo::CLTnrMotionInfo () 42 : hor_shift (0) 43 , ver_shift (0) 44 , hor_corr (0) 45 , ver_corr (0) 46 { 47 } 48 49 CLTnrImageHandler::CLTnrHistogram::CLTnrHistogram() { 50 hor_hist_bin = 0; 51 ver_hist_bin = 0; 52 hor_hist_current = NULL; 53 hor_hist_reference = NULL; 54 ver_hist_current = NULL; 55 ver_hist_reference = NULL; 56 }; 57 58 CLTnrImageHandler::CLTnrHistogram::CLTnrHistogram(uint32_t width, uint32_t height) { 59 hor_hist_bin = width; 60 ver_hist_bin = height; 61 if ((NULL == hor_hist_current) && (hor_hist_bin != 0)) { 62 hor_hist_current = (float*)xcam_malloc0(hor_hist_bin * sizeof(float)); 63 } 64 if ((NULL == ver_hist_current) && (ver_hist_bin != 0)) { 65 ver_hist_current = (float*)xcam_malloc0(ver_hist_bin * sizeof(float)); 66 } 67 if ((NULL == hor_hist_reference) && (hor_hist_bin != 0)) { 68 hor_hist_reference = (float*)xcam_malloc0(hor_hist_bin * sizeof(float)); 69 } 70 if ((NULL == ver_hist_reference) && (ver_hist_bin != 0)) { 71 ver_hist_reference = (float*)xcam_malloc0(ver_hist_bin * sizeof(float)); 72 } 73 }; 74 75 CLTnrImageHandler::CLTnrHistogram::~CLTnrHistogram() { 76 if (NULL != hor_hist_current) { 77 xcam_free(hor_hist_current); 78 hor_hist_current = NULL; 79 } 80 if (NULL != ver_hist_current) { 81 xcam_free(ver_hist_current); 82 ver_hist_current = NULL; 83 } 84 if (NULL != hor_hist_reference) { 85 xcam_free(hor_hist_reference); 86 hor_hist_reference = NULL; 87 } 88 if (NULL != ver_hist_reference) { 89 xcam_free(ver_hist_reference); 90 ver_hist_reference = NULL; 91 } 92 hor_hist_bin = 0; 93 ver_hist_bin = 0; 94 } 95 96 CLTnrImageKernel::CLTnrImageKernel ( 97 const SmartPtr<CLContext> &context, CLTnrType type) 98 : CLImageKernel (context) 99 , _type (type) 100 { 101 } 102 103 bool 104 CLTnrImageHandler::calculate_image_histogram (XCam3AStats* stats, CLTnrHistogramType type, float* histogram) 105 { 106 if ( NULL == stats || NULL == histogram ) { 107 return false; 108 } 109 110 uint32_t normalize_factor = (1 << stats->info.bit_depth) - 1; 111 uint32_t image_width = stats->info.width; 112 uint32_t image_height = stats->info.height; 113 uint32_t image_aligned_width = stats->info.aligned_width; 114 uint32_t hor_hist_bin = image_width; 115 uint32_t ver_hist_bin = image_height; 116 117 switch (type) { 118 case CL_TNR_HIST_HOR_PROJECTION : 119 for (uint32_t bin = 0; bin < hor_hist_bin; bin++) { 120 for (uint32_t row_index = 0; row_index < image_height; row_index++) { 121 histogram[bin] += (float)(stats->stats[row_index * image_aligned_width + bin].avg_y) 122 / (1.0 * normalize_factor); 123 } 124 } 125 break; 126 case CL_TNR_HIST_VER_PROJECTION : 127 for (uint32_t bin = 0; bin < ver_hist_bin; bin++) { 128 for (uint32_t col_index = 0; col_index < image_width; col_index++) { 129 histogram[bin] += (float)(stats->stats[col_index + bin * image_aligned_width].avg_y) 130 / (1.0 * normalize_factor); 131 } 132 } 133 break; 134 case CL_TNR_HIST_BRIGHTNESS : 135 for (uint32_t row_index = 0; row_index < image_height; row_index++) { 136 for (uint32_t col_index = 0; col_index < image_width; col_index++) { 137 uint8_t bin = (stats->stats[row_index * image_aligned_width + col_index].avg_y * 255) 138 / normalize_factor; 139 histogram[bin]++; 140 } 141 } 142 break; 143 default : 144 break; 145 } 146 147 return true; 148 } 149 150 bool 151 CLTnrImageHandler::calculate_image_histogram (SmartPtr<VideoBuffer> &input, CLTnrHistogramType type, float* histogram) 152 { 153 if ( NULL == histogram ) { 154 return false; 155 } 156 157 uint32_t normalize_factor = (1 << input->get_video_info ().color_bits) - 1; 158 uint32_t image_width = input->get_video_info ().width; 159 uint32_t image_height = input->get_video_info ().height; 160 uint32_t image_aligned_width = input->get_video_info ().aligned_width; 161 uint32_t stride = input->get_video_info ().strides[0]; 162 163 uint32_t hor_hist_bin = image_width; 164 uint32_t ver_hist_bin = image_height; 165 uint32_t pxiel_bytes = stride / image_aligned_width; 166 167 uint32_t format = input->get_video_info ().format; 168 if (XCAM_PIX_FMT_RGBA64 != format) { 169 XCAM_LOG_ERROR ("Only support RGBA64 format !"); 170 return false; 171 } 172 173 uint8_t* image_buffer = input->map(); 174 if (NULL == image_buffer) { 175 return false; 176 } 177 178 switch (type) { 179 case CL_TNR_HIST_HOR_PROJECTION : 180 for (uint32_t bin = 0; bin < hor_hist_bin; bin++) { 181 for (uint32_t row_index = 0; row_index < image_height; row_index++) { 182 histogram[bin] += (float)(image_buffer[row_index * stride + pxiel_bytes * bin] + 183 (image_buffer[row_index * stride + pxiel_bytes * bin + 1] << 8) + 184 image_buffer[row_index * stride + pxiel_bytes * bin + 2] + 185 (image_buffer[row_index * stride + pxiel_bytes * bin + 3] << 8) + 186 image_buffer[row_index * stride + pxiel_bytes * bin + 4] + 187 (image_buffer[row_index * stride + pxiel_bytes * bin + 5] << 8) ) 188 / (3.0 * normalize_factor); 189 } 190 } 191 break; 192 case CL_TNR_HIST_VER_PROJECTION : 193 for (uint32_t bin = 0; bin < ver_hist_bin; bin++) { 194 for (uint32_t col_index = 0; col_index < stride; col_index += pxiel_bytes) { 195 histogram[bin] += (float)(image_buffer[col_index + bin * stride] + 196 (image_buffer[col_index + bin * stride + 1] << 8) + 197 image_buffer[col_index + bin * stride + 2] + 198 (image_buffer[col_index + bin * stride + 3] << 8) + 199 image_buffer[col_index + bin * stride + 4] + 200 (image_buffer[col_index + bin * stride + 5] << 8) ) 201 / (3.0 * normalize_factor); 202 } 203 } 204 break; 205 case CL_TNR_HIST_BRIGHTNESS : 206 for (uint32_t row_index = 0; row_index < image_height; row_index++) { 207 for (uint32_t col_index = 0; col_index < stride; col_index += pxiel_bytes) { 208 uint8_t bin = (image_buffer[row_index * stride + col_index] + 209 (image_buffer[row_index * stride + col_index + 1] << 8) + 210 image_buffer[row_index * stride + col_index + 2] + 211 (image_buffer[row_index * stride + col_index + 3] << 8) + 212 image_buffer[row_index * stride + col_index + 4] + 213 (image_buffer[row_index * stride + col_index + 5] << 8) ) * 255 214 / (3 * normalize_factor); 215 histogram[bin]++; 216 } 217 } 218 break; 219 default : 220 break; 221 } 222 223 input->unmap(); 224 225 return true; 226 } 227 228 void 229 CLTnrImageHandler::print_image_histogram () 230 { 231 uint32_t hor_hist_bin = _image_histogram.hor_hist_bin; 232 uint32_t ver_hist_bin = _image_histogram.ver_hist_bin; 233 234 XCAM_LOG_DEBUG ("hor hist bin = %d, ver hist bin = %d", hor_hist_bin, ver_hist_bin); 235 236 printf("float hor_hist_current[] = { "); 237 for (uint32_t i = 0; i < hor_hist_bin; i++) { 238 printf("%f, ", _image_histogram.hor_hist_current[i]); 239 } 240 printf(" }; \n\n\n"); 241 242 printf("float ver_hist_current[] = { "); 243 for (uint32_t i = 0; i < ver_hist_bin; i++) { 244 printf("%f, ", _image_histogram.ver_hist_current[i]); 245 } 246 printf(" }; \n\n\n"); 247 248 printf("float hor_hist_reference[] = { "); 249 for (uint32_t i = 0; i < hor_hist_bin; i++) { 250 printf("%f, ", _image_histogram.hor_hist_reference[i]); 251 } 252 printf(" }; \n\n\n"); 253 254 printf("float ver_hist_reference[] = { "); 255 for (uint32_t i = 0; i < ver_hist_bin; i++) { 256 printf("%f, ", _image_histogram.ver_hist_reference[i]); 257 } 258 printf(" }; \n\n\n"); 259 } 260 261 CLTnrImageHandler::CLTnrImageHandler (const SmartPtr<CLContext> &context, CLTnrType type, const char *name) 262 : CLImageHandler (context, name) 263 , _type (type) 264 , _gain_yuv (1.0) 265 , _thr_y (0.05) 266 , _thr_uv (0.05) 267 , _gain_rgb (0.0) 268 , _thr_r (0.064) // set high initial threshold to get strong denoise effect 269 , _thr_g (0.045) 270 , _thr_b (0.073) 271 , _frame_count (TNR_PROCESSING_FRAME_COUNT) 272 { 273 } 274 275 bool 276 CLTnrImageHandler::set_tnr_kernel(SmartPtr<CLTnrImageKernel> &kernel) 277 { 278 SmartPtr<CLImageKernel> image_kernel = kernel; 279 add_kernel (image_kernel); 280 _tnr_kernel = kernel; 281 return true; 282 } 283 284 bool 285 CLTnrImageHandler::set_framecount (uint8_t count) 286 { 287 if (!_tnr_kernel->is_valid ()) { 288 XCAM_LOG_ERROR ("set framecount error, invalid TNR kernel !"); 289 return false; 290 } 291 292 XCAM_ASSERT (count >= 2 && count <= 4); 293 _frame_count = count; 294 295 return true; 296 } 297 298 bool 299 CLTnrImageHandler::set_rgb_config (const XCam3aResultTemporalNoiseReduction& config) 300 301 { 302 if (!_tnr_kernel->is_valid ()) { 303 XCAM_LOG_ERROR ("set threshold error, invalid TNR kernel !"); 304 return false; 305 } 306 _gain_rgb = (float)config.gain; 307 _thr_r = (float)config.threshold[0]; 308 _thr_g = (float)config.threshold[1]; 309 _thr_b = (float)config.threshold[2]; 310 XCAM_LOG_DEBUG ("set TNR RGB config: _gain(%f), _thr_r(%f), _thr_g(%f), _thr_b(%f)", 311 _gain_rgb, _thr_r, _thr_g, _thr_b); 312 313 return true; 314 } 315 316 bool 317 CLTnrImageHandler::set_yuv_config (const XCam3aResultTemporalNoiseReduction& config) 318 319 { 320 if (!_tnr_kernel->is_valid ()) { 321 XCAM_LOG_ERROR ("set threshold error, invalid TNR kernel !"); 322 return false; 323 } 324 325 _gain_yuv = (float)config.gain; 326 _thr_y = (float)config.threshold[0]; 327 _thr_uv = (float)config.threshold[1]; 328 329 XCAM_LOG_DEBUG ("set TNR YUV config: _gain(%f), _thr_y(%f), _thr_uv(%f)", 330 _gain_yuv, _thr_y, _thr_uv); 331 332 return true; 333 } 334 335 XCamReturn 336 CLTnrImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) 337 { 338 SmartPtr<CLContext> context = get_context (); 339 const VideoBufferInfo & video_info = input->get_video_info (); 340 CLArgList args; 341 CLWorkSize work_size; 342 XCamReturn ret = XCAM_RETURN_NO_ERROR; 343 344 XCAM_ASSERT (_tnr_kernel.ptr ()); 345 346 CLImageDesc desc; 347 if (CL_TNR_TYPE_YUV == _type) { 348 desc.format.image_channel_order = CL_R; 349 desc.format.image_channel_data_type = CL_UNORM_INT8; 350 desc.width = video_info.aligned_width; 351 desc.height = video_info.aligned_height + video_info.height / 2; 352 desc.row_pitch = video_info.strides[0]; 353 desc.array_size = 2; 354 desc.slice_pitch = video_info.strides [0] * video_info.aligned_height; 355 } else if (CL_TNR_TYPE_RGB == _type) { 356 desc.format.image_channel_order = CL_RGBA; 357 desc.format.image_channel_data_type = CL_UNORM_INT8; 358 desc.width = video_info.aligned_width; 359 desc.height = video_info.height; 360 desc.row_pitch = video_info.strides[0]; 361 desc.array_size = 0; 362 desc.slice_pitch = 0; 363 } 364 365 SmartPtr<CLImage> image_in = convert_to_climage (context, input, desc); 366 SmartPtr<CLImage> image_out = convert_to_climage (context, output, desc); 367 368 XCAM_FAIL_RETURN ( 369 WARNING, 370 image_in->is_valid () && image_out->is_valid (), 371 XCAM_RETURN_ERROR_MEM, 372 "cl image kernel(%s) in/out memory not available", _tnr_kernel->get_kernel_name ()); 373 374 if (CL_TNR_TYPE_YUV == _type) { 375 if (!_image_out_prev.ptr ()) { 376 _image_out_prev = image_in; 377 } 378 } else if (CL_TNR_TYPE_RGB == _type) { 379 // analyze motion between the latest adjacent two frames 380 // Todo: enable analyze when utilize motion compensation next step 381 382 if (_image_in_list.size () < TNR_LIST_FRAME_COUNT) { 383 while (_image_in_list.size () < TNR_LIST_FRAME_COUNT) { 384 _image_in_list.push_back (image_in); 385 } 386 } else { 387 _image_in_list.pop_front (); 388 _image_in_list.push_back (image_in); 389 } 390 } 391 392 uint32_t vertical_offset = video_info.aligned_height; 393 394 //set args; 395 work_size.dim = XCAM_DEFAULT_IMAGE_DIM; 396 work_size.local[0] = 8; 397 work_size.local[1] = 4; 398 if (CL_TNR_TYPE_YUV == _type) { 399 args.push_back (new CLMemArgument (image_in)); 400 args.push_back (new CLMemArgument (_image_out_prev)); 401 args.push_back (new CLMemArgument (image_out)); 402 args.push_back (new CLArgumentT<uint> (vertical_offset)); 403 404 args.push_back (new CLArgumentT<float> (_gain_yuv)); 405 args.push_back (new CLArgumentT<float> (_thr_y)); 406 args.push_back (new CLArgumentT<float> (_thr_uv)); 407 408 work_size.global[0] = video_info.width / 2; 409 work_size.global[1] = video_info.height / 2; 410 } 411 else if (CL_TNR_TYPE_RGB == _type) { 412 const CLImageDesc out_info = image_out->get_image_desc (); 413 work_size.global[0] = out_info.width; 414 work_size.global[1] = out_info.height; 415 416 args.push_back (new CLMemArgument (image_out)); 417 args.push_back (new CLArgumentT<float> (_gain_rgb)); 418 args.push_back (new CLArgumentT<float> (_thr_r)); 419 args.push_back (new CLArgumentT<float> (_thr_g)); 420 args.push_back (new CLArgumentT<float> (_thr_b)); 421 args.push_back (new CLArgumentT<uint8_t> (_frame_count)); 422 423 for (std::list<SmartPtr<CLImage>>::iterator it = _image_in_list.begin (); it != _image_in_list.end (); it++) { 424 args.push_back (new CLMemArgument (*it)); 425 } 426 } 427 428 XCAM_ASSERT (_tnr_kernel.ptr ()); 429 ret = _tnr_kernel->set_arguments (args, work_size); 430 XCAM_FAIL_RETURN ( 431 WARNING, ret == XCAM_RETURN_NO_ERROR, ret, 432 "tnr kernel set arguments failed."); 433 434 _image_out_prev = image_out; 435 return XCAM_RETURN_NO_ERROR; 436 } 437 438 SmartPtr<CLImageHandler> 439 create_cl_tnr_image_handler (const SmartPtr<CLContext> &context, CLTnrType type) 440 { 441 SmartPtr<CLTnrImageHandler> tnr_handler; 442 SmartPtr<CLTnrImageKernel> tnr_kernel; 443 XCamReturn ret = XCAM_RETURN_NO_ERROR; 444 445 tnr_kernel = new CLTnrImageKernel (context, type); 446 XCAM_ASSERT (tnr_kernel.ptr ()); 447 if (CL_TNR_TYPE_YUV == type) { 448 ret = tnr_kernel->build_kernel (kernel_tnr_yuv_info, NULL); 449 } else if (CL_TNR_TYPE_RGB == type) { 450 ret = tnr_kernel->build_kernel (kernel_tnr_rgb_info, NULL); 451 } else { 452 XCAM_LOG_ERROR ("create cl tnr image handler failed, unknown type:%d", type); 453 return NULL; 454 } 455 456 XCAM_FAIL_RETURN ( 457 ERROR, ret == XCAM_RETURN_NO_ERROR, NULL, 458 "build tnr kernel failed"); 459 460 tnr_handler = new CLTnrImageHandler (context, type, "cl_handler_tnr"); 461 XCAM_ASSERT (tnr_kernel->is_valid ()); 462 tnr_handler->set_tnr_kernel (tnr_kernel); 463 464 return tnr_handler; 465 } 466 467 }; 468