| /* |
| * 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 <[email protected]> |
| */ |
| |
| #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<CLContext> &context, |
| const char *name, |
| SmartPtr<CLNewWaveletDenoiseImageHandler> &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<CLImage> |
| CLWaveletNoiseEstimateKernel::get_input_buffer () |
| { |
| SmartPtr<VideoBuffer> input = _handler->get_input_buf (); |
| const VideoBufferInfo & video_info = input->get_video_info (); |
| |
| SmartPtr<CLImage> image; |
| SmartPtr<CLWaveletDecompBuffer> 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<CLImage> |
| CLWaveletNoiseEstimateKernel::get_output_buffer () |
| { |
| SmartPtr<CLImage> image; |
| SmartPtr<CLWaveletDecompBuffer> 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<CLContext> context = get_context (); |
| |
| SmartPtr<CLImage> image_in = get_input_buffer (); |
| SmartPtr<CLImage> 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<uint32_t> (_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<CLImage> image, float* noise_var) |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| |
| SmartPtr<CLEvent> 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<CLEvent> 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<CLContext> &context, |
| const char *name, |
| SmartPtr<CLNewWaveletDenoiseImageHandler> &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<CLContext> 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<CLWaveletDecompBuffer> 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<CLImage> 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<float> (noise_variance[0])); |
| args.push_back (new CLArgumentT<float> (noise_variance[0])); |
| } else { |
| args.push_back (new CLArgumentT<float> (noise_variance[0])); |
| args.push_back (new CLArgumentT<float> (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<uint32_t> (_current_layer)); |
| args.push_back (new CLArgumentT<uint32_t> (_decomposition_levels)); |
| args.push_back (new CLArgumentT<float> (hard_threshold)); |
| args.push_back (new CLArgumentT<float> (soft_threshold)); |
| args.push_back (new CLArgumentT<float> (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<CLContext> &context, |
| const char *name, |
| SmartPtr<CLNewWaveletDenoiseImageHandler> &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<VideoBuffer> input = _handler->get_input_buf (); |
| SmartPtr<VideoBuffer> output = _handler->get_output_buf (); |
| SmartPtr<CLContext> 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<CLImage> image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]); |
| SmartPtr<CLImage> 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<CLImage> image_in_uv = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[1]); |
| SmartPtr<CLImage> 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<CLWaveletDecompBuffer> 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<uint32_t> (_current_layer)); |
| args.push_back (new CLArgumentT<uint32_t> (_decomposition_levels)); |
| args.push_back (new CLArgumentT<float> (hard_threshold)); |
| args.push_back (new CLArgumentT<float> (soft_threshold)); |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| SmartPtr<CLWaveletDecompBuffer> |
| CLWaveletTransformKernel::get_decomp_buffer (uint32_t channel, int layer) |
| { |
| SmartPtr<CLWaveletDecompBuffer> 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<CLContext> &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<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| CLImageHandler::prepare_output_buf(input, output); |
| |
| SmartPtr<CLContext> context = get_context (); |
| const VideoBufferInfo & video_info = input->get_video_info (); |
| CLImageDesc cl_desc; |
| SmartPtr<CLWaveletDecompBuffer> 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<CLBuffer> 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<CLBuffer> 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<CLWaveletDecompBuffer> |
| CLNewWaveletDenoiseImageHandler::get_decomp_buffer (uint32_t channel, int layer) |
| { |
| SmartPtr<CLWaveletDecompBuffer> 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<CLImage> image, uint32_t channel, uint32_t layer, uint32_t subband) |
| { |
| FILE *file; |
| |
| void *buf_ptr = NULL; |
| SmartPtr<CLEvent> 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<CLEvent> 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<CLWaveletTransformKernel> |
| create_kernel_haar_decomposition ( |
| const SmartPtr<CLContext> &context, |
| SmartPtr<CLNewWaveletDenoiseImageHandler> handler, |
| uint32_t channel, |
| uint32_t layer, |
| bool bayes_shrink) |
| { |
| SmartPtr<CLWaveletTransformKernel> 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<CLWaveletTransformKernel> |
| create_kernel_haar_reconstruction ( |
| const SmartPtr<CLContext> &context, |
| SmartPtr<CLNewWaveletDenoiseImageHandler> handler, |
| uint32_t channel, |
| uint32_t layer, |
| bool bayes_shrink) |
| { |
| SmartPtr<CLWaveletTransformKernel> 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<CLWaveletNoiseEstimateKernel> |
| create_kernel_noise_estimation ( |
| const SmartPtr<CLContext> &context, |
| SmartPtr<CLNewWaveletDenoiseImageHandler> handler, |
| uint32_t channel, uint32_t subband, uint32_t layer) |
| { |
| SmartPtr<CLWaveletNoiseEstimateKernel> 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<CLWaveletThresholdingKernel> |
| create_kernel_thresholding ( |
| const SmartPtr<CLContext> &context, |
| SmartPtr<CLNewWaveletDenoiseImageHandler> handler, |
| uint32_t channel, uint32_t layer) |
| { |
| SmartPtr<CLWaveletThresholdingKernel> 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<CLImageHandler> |
| create_cl_newwavelet_denoise_image_handler ( |
| const SmartPtr<CLContext> &context, uint32_t channel, bool bayes_shrink) |
| { |
| SmartPtr<CLNewWaveletDenoiseImageHandler> wavelet_handler; |
| SmartPtr<CLWaveletTransformKernel> haar_decomposition_kernel; |
| SmartPtr<CLWaveletTransformKernel> 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<CLImageKernel> 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<CLImageKernel> 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<CLImageKernel> 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<CLImageKernel> 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<CLImageKernel> 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<CLImageKernel> 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<CLImageKernel> 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<CLImageKernel> 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; |
| } |
| |
| }; |