/* * cl_newwavelet_denoise_handler.cpp - CL wavelet denoise handler * * Copyright (c) 2015 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Author: Wei Zong */ #include "cl_utils.h" #include "cl_context.h" #include "cl_device.h" #include "cl_newwavelet_denoise_handler.h" #define WAVELET_DECOMPOSITION_LEVELS 4 namespace XCam { enum { KernelWaveletDecompose = 0, KernelWaveletReconstruct, KernelWaveletNoiseEstimate, KernelWaveletThreshold, }; static const XCamKernelInfo kernel_new_wavelet_info[] = { { "kernel_wavelet_haar_decomposition", #include "kernel_wavelet_haar.clx" , 0, }, { "kernel_wavelet_haar_reconstruction", #include "kernel_wavelet_haar.clx" , 0, }, { "kernel_wavelet_coeff_variance", #include "kernel_wavelet_coeff.clx" , 0, }, { "kernel_wavelet_coeff_thresholding", #include "kernel_wavelet_coeff.clx" , 0, }, }; CLWaveletNoiseEstimateKernel::CLWaveletNoiseEstimateKernel ( const SmartPtr &context, const char *name, SmartPtr &handler, uint32_t channel, uint32_t subband, uint32_t layer) : CLImageKernel (context, name) , _decomposition_levels (WAVELET_DECOMPOSITION_LEVELS) , _channel (channel) , _subband (subband) , _current_layer (layer) , _analog_gain (-1.0) , _handler (handler) { } SmartPtr CLWaveletNoiseEstimateKernel::get_input_buffer () { SmartPtr input = _handler->get_input_buf (); const VideoBufferInfo & video_info = input->get_video_info (); SmartPtr image; SmartPtr buffer = _handler->get_decomp_buffer (_channel, _current_layer); XCAM_ASSERT (buffer.ptr ()); if (_subband == CL_WAVELET_SUBBAND_HL) { image = buffer->hl[0]; } else if (_subband == CL_WAVELET_SUBBAND_LH) { image = buffer->lh[0]; } else if (_subband == CL_WAVELET_SUBBAND_HH) { image = buffer->hh[0]; } else { image = buffer->ll; } float current_ag = _handler->get_denoise_config ().analog_gain; if ((_analog_gain == -1.0f) || (fabs(_analog_gain - current_ag) > 0.2)) { if ((_current_layer == 1) && (_subband == CL_WAVELET_SUBBAND_HH)) { _analog_gain = current_ag; estimate_noise_variance (video_info, buffer->hh[0], buffer->noise_variance); _handler->set_estimated_noise_variation (buffer->noise_variance); } else { _handler->get_estimated_noise_variation (buffer->noise_variance); } } else { _handler->get_estimated_noise_variation (buffer->noise_variance); } return image; } SmartPtr CLWaveletNoiseEstimateKernel::get_output_buffer () { SmartPtr image; SmartPtr buffer = _handler->get_decomp_buffer (_channel, _current_layer); XCAM_ASSERT (buffer.ptr ()); if (_subband == CL_WAVELET_SUBBAND_HL) { image = buffer->hl[1]; } else if (_subband == CL_WAVELET_SUBBAND_LH) { image = buffer->lh[1]; } else if (_subband == CL_WAVELET_SUBBAND_HH) { image = buffer->hh[1]; } else { image = buffer->ll; } return image; } XCamReturn CLWaveletNoiseEstimateKernel::prepare_arguments ( CLArgList &args, CLWorkSize &work_size) { SmartPtr context = get_context (); SmartPtr image_in = get_input_buffer (); SmartPtr image_out = get_output_buffer (); CLImageDesc cl_desc = image_in->get_image_desc (); uint32_t cl_width = XCAM_ALIGN_UP (cl_desc.width, 2); uint32_t cl_height = XCAM_ALIGN_UP (cl_desc.height, 2); XCAM_FAIL_RETURN ( WARNING, image_in->is_valid () && image_out->is_valid (), XCAM_RETURN_ERROR_MEM, "cl image kernel(%s) in/out memory not available", get_kernel_name ()); //set args; args.push_back (new CLMemArgument (image_in)); args.push_back (new CLMemArgument (image_out)); args.push_back (new CLArgumentT (_current_layer)); work_size.dim = XCAM_DEFAULT_IMAGE_DIM; work_size.local[0] = 8; work_size.local[1] = 8; work_size.global[0] = XCAM_ALIGN_UP (cl_width, work_size.local[0]); work_size.global[1] = XCAM_ALIGN_UP (cl_height, work_size.local[1]); return XCAM_RETURN_NO_ERROR; } XCamReturn CLWaveletNoiseEstimateKernel::estimate_noise_variance (const VideoBufferInfo & video_info, SmartPtr image, float* noise_var) { XCamReturn ret = XCAM_RETURN_NO_ERROR; SmartPtr map_event = new CLEvent; void *buf_ptr = NULL; CLImageDesc cl_desc = image->get_image_desc (); uint32_t cl_width = XCAM_ALIGN_UP (cl_desc.width, 2); uint32_t cl_height = XCAM_ALIGN_UP (cl_desc.height, 2); uint32_t image_width = cl_width << 2; uint32_t image_height = cl_height; size_t origin[3] = {0, 0, 0}; size_t row_pitch = cl_desc.row_pitch; size_t slice_pitch = 0; size_t region[3] = {cl_width, cl_height, 1}; ret = image->enqueue_map (buf_ptr, origin, region, &row_pitch, &slice_pitch, CL_MAP_READ, CLEvent::EmptyList, map_event); if (ret != XCAM_RETURN_NO_ERROR) { XCAM_LOG_ERROR ("wavelet noise variance buffer enqueue map failed"); } XCAM_ASSERT (map_event->get_event_id ()); ret = map_event->wait (); if (ret != XCAM_RETURN_NO_ERROR) { XCAM_LOG_ERROR ("wavelet noise variance buffer enqueue map event wait failed"); } uint8_t* pixel = (uint8_t*)buf_ptr; uint32_t pixel_count = image_width * image_height; uint32_t pixel_sum = 0; uint32_t median_thresh = pixel_count >> 1; float median = 0; float noise_std_deviation = 0; uint32_t hist_bin_count = 1 << video_info.color_bits; uint32_t hist_y[128] = {0}; uint32_t hist_u[128] = {0}; uint32_t hist_v[128] = {0}; if (_channel == CL_IMAGE_CHANNEL_Y) { for (uint32_t i = 0; i < image_width; i++) { for (uint32_t j = 0; j < image_height; j++) { uint8_t base = (pixel[i + j * row_pitch] <= 127) ? 127 : 128; hist_y[abs(pixel[i + j * row_pitch] - base)]++; } } pixel_sum = 0; median = 0; for (uint32_t i = 0; i < (hist_bin_count - 1); i++) { pixel_sum += hist_y[i]; if (pixel_sum >= median_thresh) { median = i; break; } } noise_std_deviation = median / 0.6745; noise_var[0] = noise_std_deviation * noise_std_deviation; } if (_channel == CL_IMAGE_CHANNEL_UV) { for (uint32_t i = 0; i < (image_width / 2); i++) { for (uint32_t j = 0; j < image_height; j++) { uint8_t base = (pixel[2 * i + j * row_pitch] <= 127) ? 127 : 128; hist_u[abs(pixel[2 * i + j * row_pitch] - base)]++; base = (pixel[2 * i + 1 + j * row_pitch] <= 127) ? 127 : 128; hist_v[abs(pixel[2 * i + 1 + j * row_pitch] - base)]++; } } pixel_sum = 0; median = 0; for (uint32_t i = 0; i < (hist_bin_count - 1); i++) { pixel_sum += hist_u[i]; if (pixel_sum >= median_thresh >> 1) { median = i; break; } } noise_std_deviation = median / 0.6745; noise_var[1] = noise_std_deviation * noise_std_deviation; pixel_sum = 0; median = 0; for (uint32_t i = 0; i < (hist_bin_count - 1); i++) { pixel_sum += hist_v[i]; if (pixel_sum >= median_thresh >> 1) { median = i; break; } } noise_std_deviation = median / 0.6745; noise_var[2] = noise_std_deviation * noise_std_deviation; } map_event.release (); SmartPtr unmap_event = new CLEvent; ret = image->enqueue_unmap (buf_ptr, CLEvent::EmptyList, unmap_event); if (ret != XCAM_RETURN_NO_ERROR) { XCAM_LOG_ERROR ("wavelet noise variance buffer enqueue unmap failed"); } XCAM_ASSERT (unmap_event->get_event_id ()); ret = unmap_event->wait (); if (ret != XCAM_RETURN_NO_ERROR) { XCAM_LOG_ERROR ("wavelet noise variance buffer enqueue unmap event wait failed"); } unmap_event.release (); return ret; } CLWaveletThresholdingKernel::CLWaveletThresholdingKernel ( const SmartPtr &context, const char *name, SmartPtr &handler, uint32_t channel, uint32_t layer) : CLImageKernel (context, name, true) , _decomposition_levels (WAVELET_DECOMPOSITION_LEVELS) , _channel (channel) , _current_layer (layer) , _handler (handler) { } XCamReturn CLWaveletThresholdingKernel::prepare_arguments ( CLArgList &args, CLWorkSize &work_size) { SmartPtr context = get_context (); float noise_variance[2]; xcam_mem_clear (noise_variance); _decomposition_levels = WAVELET_DECOMPOSITION_LEVELS; float soft_threshold = _handler->get_denoise_config ().threshold[0]; float hard_threshold = _handler->get_denoise_config ().threshold[1]; float anolog_gain_weight = 1.0 + 100 * _handler->get_denoise_config ().analog_gain; SmartPtr buffer; buffer = _handler->get_decomp_buffer (_channel, _current_layer); CLImageDesc cl_desc = buffer->ll->get_image_desc (); float weight = 4; if (_channel == CL_IMAGE_CHANNEL_Y) { noise_variance[0] = buffer->noise_variance[0] * weight; noise_variance[1] = buffer->noise_variance[0] * weight; } else { noise_variance[0] = buffer->noise_variance[1] * weight; noise_variance[1] = buffer->noise_variance[2] * weight; } #if 0 { SmartPtr save_image = buffer->hh[0]; _handler->dump_coeff (save_image, _channel, _current_layer, CL_WAVELET_SUBBAND_HH); } #endif if (_channel == CL_IMAGE_CHANNEL_Y) { args.push_back (new CLArgumentT (noise_variance[0])); args.push_back (new CLArgumentT (noise_variance[0])); } else { args.push_back (new CLArgumentT (noise_variance[0])); args.push_back (new CLArgumentT (noise_variance[1])); } args.push_back (new CLMemArgument (buffer->hl[0])); args.push_back (new CLMemArgument (buffer->hl[1])); args.push_back (new CLMemArgument (buffer->hl[2])); args.push_back (new CLMemArgument (buffer->lh[0])); args.push_back (new CLMemArgument (buffer->lh[1])); args.push_back (new CLMemArgument (buffer->lh[2])); args.push_back (new CLMemArgument (buffer->hh[0])); args.push_back (new CLMemArgument (buffer->hh[1])); args.push_back (new CLMemArgument (buffer->hh[2])); args.push_back (new CLArgumentT (_current_layer)); args.push_back (new CLArgumentT (_decomposition_levels)); args.push_back (new CLArgumentT (hard_threshold)); args.push_back (new CLArgumentT (soft_threshold)); args.push_back (new CLArgumentT (anolog_gain_weight)); uint32_t cl_width = XCAM_ALIGN_UP (cl_desc.width, 2); uint32_t cl_height = XCAM_ALIGN_UP (cl_desc.height, 2); //set args; work_size.dim = XCAM_DEFAULT_IMAGE_DIM; work_size.local[0] = 8; work_size.local[1] = 4; work_size.global[0] = XCAM_ALIGN_UP (cl_width , work_size.local[0]); work_size.global[1] = XCAM_ALIGN_UP (cl_height, work_size.local[1]); return XCAM_RETURN_NO_ERROR; } CLWaveletTransformKernel::CLWaveletTransformKernel ( const SmartPtr &context, const char *name, SmartPtr &handler, CLWaveletFilterBank fb, uint32_t channel, uint32_t layer, bool bayes_shrink) : CLImageKernel (context, name, true) , _filter_bank (fb) , _decomposition_levels (WAVELET_DECOMPOSITION_LEVELS) , _channel (channel) , _current_layer (layer) , _bayes_shrink (bayes_shrink) , _handler (handler) { } XCamReturn CLWaveletTransformKernel::prepare_arguments ( CLArgList &args, CLWorkSize &work_size) { SmartPtr input = _handler->get_input_buf (); SmartPtr output = _handler->get_output_buf (); SmartPtr context = get_context (); const VideoBufferInfo & video_info_in = input->get_video_info (); const VideoBufferInfo & video_info_out = output->get_video_info (); _decomposition_levels = WAVELET_DECOMPOSITION_LEVELS; float soft_threshold = _handler->get_denoise_config ().threshold[0]; float hard_threshold = _handler->get_denoise_config ().threshold[1]; CLImageDesc cl_desc_in, cl_desc_out; cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; cl_desc_in.format.image_channel_order = CL_RGBA; cl_desc_in.width = XCAM_ALIGN_UP (video_info_in.width, 4) / 4; cl_desc_in.height = video_info_in.height; cl_desc_in.row_pitch = video_info_in.strides[0]; cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; cl_desc_out.format.image_channel_order = CL_RGBA; cl_desc_out.width = XCAM_ALIGN_UP (video_info_out.width, 4) / 4; cl_desc_out.height = video_info_out.height; cl_desc_out.row_pitch = video_info_out.strides[0]; SmartPtr image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]); SmartPtr image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]); cl_desc_in.height = XCAM_ALIGN_UP (video_info_in.height, 2) / 2; cl_desc_in.row_pitch = video_info_in.strides[1]; cl_desc_out.height = XCAM_ALIGN_UP (video_info_out.height, 2) / 2; cl_desc_out.row_pitch = video_info_out.strides[1]; SmartPtr image_in_uv = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[1]); SmartPtr image_out_uv = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[1]); XCAM_FAIL_RETURN ( WARNING, image_in->is_valid () && image_in_uv->is_valid () && image_out->is_valid () && image_out_uv->is_valid(), XCAM_RETURN_ERROR_MEM, "cl image kernel(%s) in/out memory not available", get_kernel_name ()); //set args; work_size.dim = XCAM_DEFAULT_IMAGE_DIM; work_size.local[0] = 8; work_size.local[1] = 4; if (_channel == CL_IMAGE_CHANNEL_Y) { work_size.global[0] = XCAM_ALIGN_UP ((video_info_in.width >> _current_layer) / 4 , work_size.local[0]); work_size.global[1] = XCAM_ALIGN_UP (video_info_in.height >> _current_layer, work_size.local[1]); } else if (_channel == CL_IMAGE_CHANNEL_UV) { work_size.global[0] = XCAM_ALIGN_UP ((video_info_in.width >> _current_layer) / 4 , work_size.local[0]); work_size.global[1] = XCAM_ALIGN_UP (video_info_in.height >> (_current_layer + 1), work_size.local[1]); } SmartPtr buffer; if (_current_layer == 1) { if (_filter_bank == CL_WAVELET_HAAR_ANALYSIS) { if (_channel == CL_IMAGE_CHANNEL_Y) { args.push_back (new CLMemArgument (image_in)); } else if (_channel == CL_IMAGE_CHANNEL_UV) { args.push_back (new CLMemArgument (image_in_uv)); } } else if (_filter_bank == CL_WAVELET_HAAR_SYNTHESIS) { if (_channel == CL_IMAGE_CHANNEL_Y) { args.push_back (new CLMemArgument (image_out)); } else if (_channel == CL_IMAGE_CHANNEL_UV) { args.push_back (new CLMemArgument (image_out_uv)); } } } else { buffer = get_decomp_buffer (_channel, _current_layer - 1); args.push_back (new CLMemArgument (buffer->ll)); } buffer = get_decomp_buffer (_channel, _current_layer); args.push_back (new CLMemArgument (buffer->ll)); if (_bayes_shrink == true) { if (_filter_bank == CL_WAVELET_HAAR_ANALYSIS) { args.push_back (new CLMemArgument (buffer->hl[0])); args.push_back (new CLMemArgument (buffer->lh[0])); args.push_back (new CLMemArgument (buffer->hh[0])); } else if (_filter_bank == CL_WAVELET_HAAR_SYNTHESIS) { args.push_back (new CLMemArgument (buffer->hl[2])); args.push_back (new CLMemArgument (buffer->lh[2])); args.push_back (new CLMemArgument (buffer->hh[2])); } } else { args.push_back (new CLMemArgument (buffer->hl[0])); args.push_back (new CLMemArgument (buffer->lh[0])); args.push_back (new CLMemArgument (buffer->hh[0])); } args.push_back (new CLArgumentT (_current_layer)); args.push_back (new CLArgumentT (_decomposition_levels)); args.push_back (new CLArgumentT (hard_threshold)); args.push_back (new CLArgumentT (soft_threshold)); return XCAM_RETURN_NO_ERROR; } SmartPtr CLWaveletTransformKernel::get_decomp_buffer (uint32_t channel, int layer) { SmartPtr buffer; if (_handler.ptr ()) { buffer = _handler->get_decomp_buffer (channel, layer); } if (!buffer.ptr ()) { XCAM_LOG_ERROR ("get channel(%d) layer(%d) decomposition buffer failed!", channel, layer); } XCAM_ASSERT (buffer.ptr ()); return buffer; } CLNewWaveletDenoiseImageHandler::CLNewWaveletDenoiseImageHandler ( const SmartPtr &context, const char *name, uint32_t channel) : CLImageHandler (context, name) , _channel (channel) { _config.decomposition_levels = 5; _config.threshold[0] = 0.5; _config.threshold[1] = 5.0; xcam_mem_clear (_noise_variance); } XCamReturn CLNewWaveletDenoiseImageHandler::prepare_output_buf (SmartPtr &input, SmartPtr &output) { XCamReturn ret = XCAM_RETURN_NO_ERROR; CLImageHandler::prepare_output_buf(input, output); SmartPtr context = get_context (); const VideoBufferInfo & video_info = input->get_video_info (); CLImageDesc cl_desc; SmartPtr decompBuffer; CLImage::video_info_2_cl_image_desc (video_info, cl_desc); _decompBufferList.clear (); if (_channel & CL_IMAGE_CHANNEL_Y) { for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { decompBuffer = new CLWaveletDecompBuffer (); if (decompBuffer.ptr ()) { decompBuffer->width = XCAM_ALIGN_UP (video_info.width, 1 << layer) >> layer; decompBuffer->height = XCAM_ALIGN_UP (video_info.height, 1 << layer) >> layer; decompBuffer->width = XCAM_ALIGN_UP (decompBuffer->width, 4); decompBuffer->height = XCAM_ALIGN_UP (decompBuffer->height, 2); decompBuffer->channel = CL_IMAGE_CHANNEL_Y; decompBuffer->layer = layer; decompBuffer->noise_variance[0] = 0; cl_desc.width = decompBuffer->width / 4; cl_desc.height = decompBuffer->height; cl_desc.slice_pitch = 0; cl_desc.format.image_channel_order = CL_RGBA; cl_desc.format.image_channel_data_type = CL_UNORM_INT8; decompBuffer->ll = new CLImage2D (context, cl_desc); decompBuffer->hl[0] = new CLImage2D (context, cl_desc); decompBuffer->lh[0] = new CLImage2D (context, cl_desc); decompBuffer->hh[0] = new CLImage2D (context, cl_desc); /* uint32_t width = decompBuffer->width / 4; uint32_t height = decompBuffer->height; SmartPtr hh_buffer = new CLBuffer ( context, sizeof(uint8_t) * width * height, CL_MEM_READ_WRITE, NULL); CLImageDesc hh_desc; hh_desc.format = {CL_RGBA, CL_UNORM_INT8}; hh_desc.width = width; hh_desc.height = height; hh_desc.row_pitch = sizeof(uint8_t) * width; hh_desc.slice_pitch = 0; hh_desc.size = 0; hh_desc.array_size = 0; decompBuffer->hh[0] = new CLImage2D ( context, hh_desc, 0, hh_buffer); */ cl_desc.format.image_channel_data_type = CL_UNORM_INT16; decompBuffer->hl[1] = new CLImage2D (context, cl_desc); decompBuffer->lh[1] = new CLImage2D (context, cl_desc); decompBuffer->hh[1] = new CLImage2D (context, cl_desc); cl_desc.format.image_channel_data_type = CL_UNORM_INT8; decompBuffer->hl[2] = new CLImage2D (context, cl_desc); decompBuffer->lh[2] = new CLImage2D (context, cl_desc); decompBuffer->hh[2] = new CLImage2D (context, cl_desc); _decompBufferList.push_back (decompBuffer); } else { XCAM_LOG_ERROR ("create Y decomposition buffer failed!"); ret = XCAM_RETURN_ERROR_MEM; } } } if (_channel & CL_IMAGE_CHANNEL_UV) { for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { decompBuffer = new CLWaveletDecompBuffer (); if (decompBuffer.ptr ()) { decompBuffer->width = XCAM_ALIGN_UP (video_info.width, 1 << layer) >> layer; decompBuffer->height = XCAM_ALIGN_UP (video_info.height, 1 << (layer + 1)) >> (layer + 1); decompBuffer->width = XCAM_ALIGN_UP (decompBuffer->width, 4); decompBuffer->height = XCAM_ALIGN_UP (decompBuffer->height, 2); decompBuffer->channel = CL_IMAGE_CHANNEL_UV; decompBuffer->layer = layer; decompBuffer->noise_variance[1] = 0; decompBuffer->noise_variance[2] = 0; cl_desc.width = decompBuffer->width / 4; cl_desc.height = decompBuffer->height; cl_desc.slice_pitch = 0; cl_desc.format.image_channel_order = CL_RGBA; cl_desc.format.image_channel_data_type = CL_UNORM_INT8; decompBuffer->ll = new CLImage2D (context, cl_desc); decompBuffer->hl[0] = new CLImage2D (context, cl_desc); decompBuffer->lh[0] = new CLImage2D (context, cl_desc); decompBuffer->hh[0] = new CLImage2D (context, cl_desc); /* uint32_t width = decompBuffer->width / 4; uint32_t height = decompBuffer->height; SmartPtr hh_buffer = new CLBuffer ( context, sizeof(uint8_t) * width * height, CL_MEM_READ_WRITE, NULL); CLImageDesc hh_desc; hh_desc.format = {CL_RGBA, CL_UNORM_INT8}; hh_desc.width = width; hh_desc.height = height; hh_desc.row_pitch = sizeof(uint8_t) * width; hh_desc.slice_pitch = 0; hh_desc.size = 0; hh_desc.array_size = 0; decompBuffer->hh[0] = new CLImage2D ( context, hh_desc, 0, hh_buffer); */ cl_desc.format.image_channel_data_type = CL_UNORM_INT16; decompBuffer->hl[1] = new CLImage2D (context, cl_desc); decompBuffer->lh[1] = new CLImage2D (context, cl_desc); decompBuffer->hh[1] = new CLImage2D (context, cl_desc); cl_desc.format.image_channel_data_type = CL_UNORM_INT8; decompBuffer->hl[2] = new CLImage2D (context, cl_desc); decompBuffer->lh[2] = new CLImage2D (context, cl_desc); decompBuffer->hh[2] = new CLImage2D (context, cl_desc); _decompBufferList.push_back (decompBuffer); } else { XCAM_LOG_ERROR ("create UV decomposition buffer failed!"); ret = XCAM_RETURN_ERROR_MEM; } } } return ret; } bool CLNewWaveletDenoiseImageHandler::set_denoise_config (const XCam3aResultWaveletNoiseReduction& config) { _config = config; return true; } SmartPtr CLNewWaveletDenoiseImageHandler::get_decomp_buffer (uint32_t channel, int layer) { SmartPtr buffer; for (CLWaveletDecompBufferList::iterator it = _decompBufferList.begin (); it != _decompBufferList.end (); ++it) { if ((channel == (*it)->channel) && (layer == (*it)->layer)) buffer = (*it); } return buffer; } void CLNewWaveletDenoiseImageHandler::set_estimated_noise_variation (float* noise_var) { if (noise_var == NULL) { XCAM_LOG_ERROR ("invalid input noise variation!"); return; } _noise_variance[0] = noise_var[0]; _noise_variance[1] = noise_var[1]; _noise_variance[2] = noise_var[2]; } void CLNewWaveletDenoiseImageHandler::get_estimated_noise_variation (float* noise_var) { if (noise_var == NULL) { XCAM_LOG_ERROR ("invalid output parameters!"); return; } noise_var[0] = _noise_variance[0]; noise_var[1] = _noise_variance[1]; noise_var[2] = _noise_variance[2]; } void CLNewWaveletDenoiseImageHandler::dump_coeff (SmartPtr image, uint32_t channel, uint32_t layer, uint32_t subband) { FILE *file; void *buf_ptr = NULL; SmartPtr map_event = new CLEvent; CLImageDesc cl_desc = image->get_image_desc (); uint32_t cl_width = XCAM_ALIGN_UP (cl_desc.width, 2); uint32_t cl_height = XCAM_ALIGN_UP (cl_desc.height, 2); size_t origin[3] = {0, 0, 0}; size_t row_pitch = cl_desc.row_pitch; size_t slice_pitch = 0; size_t region[3] = {cl_width, cl_height, 1}; image->enqueue_map (buf_ptr, origin, region, &row_pitch, &slice_pitch, CL_MAP_READ, CLEvent::EmptyList, map_event); XCAM_ASSERT (map_event->get_event_id ()); map_event->wait (); uint8_t* pixel = (uint8_t*)buf_ptr; uint32_t pixel_count = row_pitch * cl_height; char file_name[512]; snprintf (file_name, sizeof(file_name), "wavelet_cl_coeff_" "channel%d_" "layer%d_" "subband%d_" "rowpitch%d_" "width%dxheight%d" ".raw", channel, layer, subband, (uint32_t)row_pitch, cl_width, cl_height); file = fopen(file_name, "wb"); if (file != NULL) { if (fwrite (pixel, pixel_count, 1, file) <= 0) { XCAM_LOG_WARNING ("write frame failed."); } fclose (file); } map_event.release (); SmartPtr unmap_event = new CLEvent; image->enqueue_unmap (buf_ptr, CLEvent::EmptyList, unmap_event); XCAM_ASSERT (unmap_event->get_event_id ()); unmap_event->wait (); unmap_event.release (); } static SmartPtr create_kernel_haar_decomposition ( const SmartPtr &context, SmartPtr handler, uint32_t channel, uint32_t layer, bool bayes_shrink) { SmartPtr haar_decomp_kernel; char build_options[1024]; xcam_mem_clear (build_options); snprintf (build_options, sizeof (build_options), " -DWAVELET_DENOISE_Y=%d " " -DWAVELET_DENOISE_UV=%d ", (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0), (channel == CL_IMAGE_CHANNEL_UV ? 1 : 0)); haar_decomp_kernel = new CLWaveletTransformKernel (context, "kernel_wavelet_haar_decomposition", handler, CL_WAVELET_HAAR_ANALYSIS, channel, layer, bayes_shrink); XCAM_ASSERT (haar_decomp_kernel.ptr ()); XCAM_FAIL_RETURN ( WARNING, haar_decomp_kernel->build_kernel (kernel_new_wavelet_info[KernelWaveletDecompose], build_options) == XCAM_RETURN_NO_ERROR, NULL, "wavelet denoise build kernel(%s) failed", kernel_new_wavelet_info[KernelWaveletDecompose].kernel_name); XCAM_ASSERT (haar_decomp_kernel->is_valid ()); return haar_decomp_kernel; } static SmartPtr create_kernel_haar_reconstruction ( const SmartPtr &context, SmartPtr handler, uint32_t channel, uint32_t layer, bool bayes_shrink) { SmartPtr haar_reconstruction_kernel; char build_options[1024]; xcam_mem_clear (build_options); snprintf (build_options, sizeof (build_options), " -DWAVELET_DENOISE_Y=%d " " -DWAVELET_DENOISE_UV=%d " " -DWAVELET_BAYES_SHRINK=%d", (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0), (channel == CL_IMAGE_CHANNEL_UV ? 1 : 0), (bayes_shrink == true ? 1 : 0)); haar_reconstruction_kernel = new CLWaveletTransformKernel (context, "kernel_wavelet_haar_reconstruction", handler, CL_WAVELET_HAAR_SYNTHESIS, channel, layer, bayes_shrink); XCAM_ASSERT (haar_reconstruction_kernel.ptr ()); XCAM_FAIL_RETURN ( WARNING, haar_reconstruction_kernel->build_kernel (kernel_new_wavelet_info[KernelWaveletReconstruct], build_options) == XCAM_RETURN_NO_ERROR, NULL, "wavelet denoise build kernel(%s) failed", kernel_new_wavelet_info[KernelWaveletReconstruct].kernel_name); XCAM_ASSERT (haar_reconstruction_kernel->is_valid ()); return haar_reconstruction_kernel; } static SmartPtr create_kernel_noise_estimation ( const SmartPtr &context, SmartPtr handler, uint32_t channel, uint32_t subband, uint32_t layer) { SmartPtr estimation_kernel; char build_options[1024]; xcam_mem_clear (build_options); snprintf (build_options, sizeof (build_options), " -DWAVELET_DENOISE_Y=%d " " -DWAVELET_DENOISE_UV=%d ", (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0), (channel == CL_IMAGE_CHANNEL_UV ? 1 : 0)); estimation_kernel = new CLWaveletNoiseEstimateKernel ( context, "kernel_wavelet_coeff_variance", handler, channel, subband, layer); XCAM_ASSERT (estimation_kernel.ptr ()); XCAM_FAIL_RETURN ( WARNING, estimation_kernel->build_kernel (kernel_new_wavelet_info[KernelWaveletNoiseEstimate], build_options) == XCAM_RETURN_NO_ERROR, NULL, "wavelet denoise build kernel(%s) failed", kernel_new_wavelet_info[KernelWaveletNoiseEstimate].kernel_name); XCAM_ASSERT (estimation_kernel->is_valid ()); return estimation_kernel; } static SmartPtr create_kernel_thresholding ( const SmartPtr &context, SmartPtr handler, uint32_t channel, uint32_t layer) { SmartPtr threshold_kernel; char build_options[1024]; xcam_mem_clear (build_options); snprintf (build_options, sizeof (build_options), " -DWAVELET_DENOISE_Y=%d " " -DWAVELET_DENOISE_UV=%d ", (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0), (channel == CL_IMAGE_CHANNEL_UV ? 1 : 0)); threshold_kernel = new CLWaveletThresholdingKernel (context, "kernel_wavelet_coeff_thresholding", handler, channel, layer); XCAM_ASSERT (threshold_kernel.ptr ()); XCAM_FAIL_RETURN ( WARNING, threshold_kernel->build_kernel (kernel_new_wavelet_info[KernelWaveletThreshold], build_options) == XCAM_RETURN_NO_ERROR, NULL, "wavelet denoise build kernel(%s) failed", kernel_new_wavelet_info[KernelWaveletThreshold].kernel_name); XCAM_ASSERT (threshold_kernel->is_valid ()); return threshold_kernel; } SmartPtr create_cl_newwavelet_denoise_image_handler ( const SmartPtr &context, uint32_t channel, bool bayes_shrink) { SmartPtr wavelet_handler; SmartPtr haar_decomposition_kernel; SmartPtr haar_reconstruction_kernel; wavelet_handler = new CLNewWaveletDenoiseImageHandler (context, "cl_newwavelet_denoise_handler", channel); XCAM_ASSERT (wavelet_handler.ptr ()); if (channel & CL_IMAGE_CHANNEL_Y) { for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { SmartPtr image_kernel = create_kernel_haar_decomposition (context, wavelet_handler, CL_IMAGE_CHANNEL_Y, layer, bayes_shrink); wavelet_handler->add_kernel (image_kernel); } if (bayes_shrink) { for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { SmartPtr image_kernel; image_kernel = create_kernel_noise_estimation (context, wavelet_handler, CL_IMAGE_CHANNEL_Y, CL_WAVELET_SUBBAND_HH, layer); wavelet_handler->add_kernel (image_kernel); image_kernel = create_kernel_noise_estimation (context, wavelet_handler, CL_IMAGE_CHANNEL_Y, CL_WAVELET_SUBBAND_LH, layer); wavelet_handler->add_kernel (image_kernel); image_kernel = create_kernel_noise_estimation (context, wavelet_handler, CL_IMAGE_CHANNEL_Y, CL_WAVELET_SUBBAND_HL, layer); wavelet_handler->add_kernel (image_kernel); } for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { SmartPtr image_kernel; image_kernel = create_kernel_thresholding (context, wavelet_handler, CL_IMAGE_CHANNEL_Y, layer); wavelet_handler->add_kernel (image_kernel); } } for (int layer = WAVELET_DECOMPOSITION_LEVELS; layer >= 1; layer--) { SmartPtr image_kernel = create_kernel_haar_reconstruction (context, wavelet_handler, CL_IMAGE_CHANNEL_Y, layer, bayes_shrink); wavelet_handler->add_kernel (image_kernel); } } if (channel & CL_IMAGE_CHANNEL_UV) { for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { SmartPtr image_kernel = create_kernel_haar_decomposition (context, wavelet_handler, CL_IMAGE_CHANNEL_UV, layer, bayes_shrink); wavelet_handler->add_kernel (image_kernel); } if (bayes_shrink) { for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { SmartPtr image_kernel; image_kernel = create_kernel_noise_estimation (context, wavelet_handler, CL_IMAGE_CHANNEL_UV, CL_WAVELET_SUBBAND_HH, layer); wavelet_handler->add_kernel (image_kernel); image_kernel = create_kernel_noise_estimation (context, wavelet_handler, CL_IMAGE_CHANNEL_UV, CL_WAVELET_SUBBAND_LH, layer); wavelet_handler->add_kernel (image_kernel); image_kernel = create_kernel_noise_estimation (context, wavelet_handler, CL_IMAGE_CHANNEL_UV, CL_WAVELET_SUBBAND_HL, layer); wavelet_handler->add_kernel (image_kernel); } for (int layer = 1; layer <= WAVELET_DECOMPOSITION_LEVELS; layer++) { SmartPtr image_kernel; image_kernel = create_kernel_thresholding (context, wavelet_handler, CL_IMAGE_CHANNEL_UV, layer); wavelet_handler->add_kernel (image_kernel); } } for (int layer = WAVELET_DECOMPOSITION_LEVELS; layer >= 1; layer--) { SmartPtr image_kernel = create_kernel_haar_reconstruction (context, wavelet_handler, CL_IMAGE_CHANNEL_UV, layer, bayes_shrink); wavelet_handler->add_kernel (image_kernel); } } return wavelet_handler; } };