| /* |
| * cl_retinex_handler.cpp - CL retinex handler |
| * |
| * Copyright (c) 2016 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: wangfei <[email protected]> |
| * Wind Yuan <[email protected]> |
| */ |
| |
| #include "cl_utils.h" |
| #include "cl_retinex_handler.h" |
| #include <algorithm> |
| #include "cl_device.h" |
| |
| namespace XCam { |
| |
| static uint32_t retinex_gauss_scale [3] = {2, 8, 20}; //{20, 60, 150}; |
| static float retinex_gauss_sigma [3] = {2.0f, 8.0f, 20.0f}; //{12.0f, 40.0f, 120.0f}; |
| static float retinex_config_log_min = -0.12f; // -0.18f |
| static float retinex_config_log_max = 0.18f; //0.2f |
| |
| enum { |
| KernelScaler = 0, |
| KernelGaussian, |
| KernelRetinex, |
| }; |
| |
| const static XCamKernelInfo kernel_retinex_info [] = { |
| { |
| "kernel_image_scaler", |
| #include "kernel_image_scaler.clx" |
| , 0, |
| }, |
| { |
| "kernel_gauss", |
| #include "kernel_gauss.clx" |
| , 0, |
| }, |
| { |
| "kernel_retinex", |
| #include "kernel_retinex.clx" |
| , 0, |
| }, |
| }; |
| |
| CLRetinexScalerImageKernel::CLRetinexScalerImageKernel ( |
| const SmartPtr<CLContext> &context, |
| const CLImageScalerMemoryLayout mem_layout, |
| SmartPtr<CLRetinexImageHandler> &retinex) |
| : CLScalerKernel (context, mem_layout) |
| , _retinex(retinex) |
| { |
| } |
| |
| SmartPtr<VideoBuffer> |
| CLRetinexScalerImageKernel::get_input_buffer () |
| { |
| return _retinex->get_input_buf (); |
| } |
| |
| SmartPtr<VideoBuffer> |
| CLRetinexScalerImageKernel::get_output_buffer () |
| { |
| return _retinex->get_scaler_buf1 (); |
| } |
| |
| CLRetinexGaussImageKernel::CLRetinexGaussImageKernel ( |
| const SmartPtr<CLContext> &context, |
| SmartPtr<CLRetinexImageHandler> &retinex, |
| uint32_t index, |
| uint32_t radius, float sigma) |
| : CLGaussImageKernel (context, radius, sigma) |
| , _retinex (retinex) |
| , _index (index) |
| { |
| } |
| |
| SmartPtr<VideoBuffer> |
| CLRetinexGaussImageKernel::get_input_buf () |
| { |
| return _retinex->get_scaler_buf1 (); |
| } |
| |
| SmartPtr<VideoBuffer> |
| CLRetinexGaussImageKernel::get_output_buf () |
| { |
| return _retinex->get_gaussian_buf (_index); |
| } |
| |
| CLRetinexImageKernel::CLRetinexImageKernel (const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> &retinex) |
| : CLImageKernel (context, "kernel_retinex"), |
| _retinex (retinex) |
| { |
| } |
| |
| XCamReturn |
| CLRetinexImageKernel::prepare_arguments ( |
| CLArgList &args, CLWorkSize &work_size) |
| { |
| SmartPtr<CLContext> context = get_context (); |
| SmartPtr<VideoBuffer> input = _retinex->get_input_buf (); |
| SmartPtr<VideoBuffer> output = _retinex->get_output_buf (); |
| |
| const VideoBufferInfo & video_info_in = input->get_video_info (); |
| const VideoBufferInfo & video_info_out = output->get_video_info (); |
| SmartPtr<CLImage> image_in, image_in_uv; |
| SmartPtr<CLImage> image_out, image_out_uv; |
| SmartPtr<CLImage> image_in_ga[XCAM_RETINEX_MAX_SCALE]; |
| |
| CLImageDesc cl_desc_in, cl_desc_out, cl_desc_ga; |
| |
| cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; //CL_UNSIGNED_INT32; |
| cl_desc_in.format.image_channel_order = CL_RGBA; |
| cl_desc_in.width = video_info_in.width / 4; // 16; |
| cl_desc_in.height = video_info_in.height; |
| cl_desc_in.row_pitch = video_info_in.strides[0]; |
| image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]); |
| |
| cl_desc_in.height = video_info_in.height / 2; |
| cl_desc_in.row_pitch = video_info_in.strides[1]; |
| image_in_uv = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[1]); |
| |
| cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; //CL_UNSIGNED_INT32; |
| cl_desc_out.format.image_channel_order = CL_RGBA; |
| cl_desc_out.width = video_info_out.width / 4; // 16; |
| cl_desc_out.height = video_info_out.height; |
| cl_desc_out.row_pitch = video_info_out.strides[0]; |
| image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]); |
| |
| cl_desc_out.height = video_info_out.height / 2; |
| cl_desc_out.row_pitch = video_info_out.strides[1]; |
| 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 ()); |
| |
| for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { |
| SmartPtr<VideoBuffer> gaussian_buf = _retinex->get_gaussian_buf (i); |
| XCAM_ASSERT (gaussian_buf.ptr ()); |
| |
| const VideoBufferInfo & video_info_gauss = gaussian_buf->get_video_info (); |
| |
| cl_desc_ga.format.image_channel_data_type = CL_UNORM_INT8; |
| cl_desc_ga.format.image_channel_order = CL_R; |
| cl_desc_ga.width = video_info_gauss.width; |
| cl_desc_ga.height = video_info_gauss.height; |
| cl_desc_ga.row_pitch = video_info_gauss.strides[0]; |
| image_in_ga[i] = convert_to_climage (context, gaussian_buf, cl_desc_ga, video_info_gauss.offsets[0]); |
| |
| XCAM_FAIL_RETURN ( |
| WARNING, |
| image_in_ga[i]->is_valid (), |
| XCAM_RETURN_ERROR_MEM, |
| "cl image kernel(%s) gauss memory[%d] is invalid", get_kernel_name (), i); |
| } |
| CLRetinexConfig retinex_config; |
| retinex_config.log_min = retinex_config_log_min; |
| retinex_config.log_max = retinex_config_log_max; |
| retinex_config.gain = 1.0f / (retinex_config.log_max - retinex_config.log_min); |
| retinex_config.width = (float)video_info_in.width; |
| retinex_config.height = (float)video_info_in.height; |
| |
| //set args; |
| args.push_back (new CLMemArgument (image_in)); |
| args.push_back (new CLMemArgument (image_in_uv)); |
| for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { |
| args.push_back (new CLMemArgument (image_in_ga[i])); |
| } |
| args.push_back (new CLMemArgument (image_out)); |
| args.push_back (new CLMemArgument (image_out_uv)); |
| args.push_back (new CLArgumentT<CLRetinexConfig> (retinex_config)); |
| |
| work_size.dim = XCAM_DEFAULT_IMAGE_DIM; |
| work_size.global[0] = video_info_out.width / 4; |
| work_size.global[1] = video_info_out.height; |
| work_size.local[0] = 16; |
| work_size.local[1] = 2; |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| CLRetinexImageHandler::CLRetinexImageHandler (const SmartPtr<CLContext> &context, const char *name) |
| : CLImageHandler (context, name) |
| , _scaler_factor(XCAM_RETINEX_SCALER_FACTOR) |
| { |
| } |
| |
| void |
| CLRetinexImageHandler::emit_stop () |
| { |
| if (_scaler_buf_pool.ptr ()) |
| _scaler_buf_pool->stop (); |
| } |
| |
| XCamReturn |
| CLRetinexImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) |
| { |
| CLImageHandler::prepare_output_buf(input, output); |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| ret = prepare_scaler_buf (input->get_video_info ()); |
| XCAM_FAIL_RETURN( |
| WARNING, |
| ret == XCAM_RETURN_NO_ERROR, |
| ret, |
| "CLRetinexImageHandler prepare scaled video buf failed"); |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn |
| CLRetinexImageHandler::prepare_scaler_buf (const VideoBufferInfo &video_info) |
| { |
| if (!_scaler_buf_pool.ptr ()) { |
| SmartPtr<CLContext> context = get_context (); |
| VideoBufferInfo scaler_video_info; |
| uint32_t new_width = XCAM_ALIGN_UP ((uint32_t)(video_info.width * _scaler_factor), 8); |
| uint32_t new_height = XCAM_ALIGN_UP ((uint32_t)(video_info.height * _scaler_factor), 4); |
| |
| scaler_video_info.init (video_info.format, new_width, new_height); |
| |
| _scaler_buf_pool = new CLVideoBufferPool (); |
| XCAM_ASSERT (_scaler_buf_pool.ptr ()); |
| _scaler_buf_pool->set_video_info (scaler_video_info); |
| _scaler_buf_pool->reserve (XCAM_RETINEX_MAX_SCALE + 1); |
| |
| _scaler_buf1 = _scaler_buf_pool->get_buffer (_scaler_buf_pool); |
| XCAM_ASSERT (_scaler_buf1.ptr ()); |
| |
| for (int i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { |
| _gaussian_buf[i] = _scaler_buf_pool->get_buffer (_scaler_buf_pool); |
| XCAM_ASSERT (_gaussian_buf[i].ptr ()); |
| } |
| } |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| bool |
| CLRetinexImageHandler::set_retinex_kernel(SmartPtr<CLRetinexImageKernel> &kernel) |
| { |
| SmartPtr<CLImageKernel> image_kernel = kernel; |
| add_kernel (image_kernel); |
| _retinex_kernel = kernel; |
| return true; |
| } |
| |
| bool |
| CLRetinexImageHandler::set_retinex_scaler_kernel(SmartPtr<CLRetinexScalerImageKernel> &kernel) |
| { |
| SmartPtr<CLImageKernel> image_kernel = kernel; |
| add_kernel (image_kernel); |
| _retinex_scaler_kernel = kernel; |
| return true; |
| } |
| |
| static SmartPtr<CLRetinexScalerImageKernel> |
| create_kernel_retinex_scaler ( |
| const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> handler) |
| { |
| SmartPtr<CLRetinexScalerImageKernel> kernel; |
| |
| kernel = new CLRetinexScalerImageKernel (context, CL_IMAGE_SCALER_NV12_Y, handler); |
| XCAM_ASSERT (kernel.ptr ()); |
| XCAM_FAIL_RETURN ( |
| ERROR, kernel->build_kernel (kernel_retinex_info[KernelScaler], NULL) == XCAM_RETURN_NO_ERROR, NULL, |
| "build retinex scaler kernel(%s) failed", kernel_retinex_info[KernelScaler].kernel_name); |
| |
| XCAM_ASSERT (kernel->is_valid ()); |
| return kernel; |
| } |
| |
| static SmartPtr<CLRetinexGaussImageKernel> |
| create_kernel_retinex_gaussian ( |
| const SmartPtr<CLContext> &context, |
| SmartPtr<CLRetinexImageHandler> handler, |
| uint32_t index, |
| uint32_t radius, float sigma) |
| { |
| SmartPtr<CLRetinexGaussImageKernel> kernel; |
| char build_options[1024]; |
| |
| xcam_mem_clear (build_options); |
| snprintf (build_options, sizeof (build_options), " -DGAUSS_RADIUS=%d ", radius); |
| |
| kernel = new CLRetinexGaussImageKernel (context, handler, index, radius, sigma); |
| XCAM_ASSERT (kernel.ptr ()); |
| XCAM_FAIL_RETURN ( |
| ERROR, kernel->build_kernel (kernel_retinex_info[KernelGaussian], build_options) == XCAM_RETURN_NO_ERROR, NULL, |
| "build retinex gaussian kernel(%s) failed", kernel_retinex_info[KernelGaussian].kernel_name); |
| |
| XCAM_ASSERT (kernel->is_valid ()); |
| |
| return kernel; |
| } |
| |
| static SmartPtr<CLRetinexImageKernel> |
| create_kernel_retinex (const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> handler) |
| { |
| SmartPtr<CLRetinexImageKernel> kernel; |
| char build_options[1024]; |
| |
| xcam_mem_clear (build_options); |
| snprintf (build_options, sizeof (build_options), " -DRETINEX_SCALE_SIZE=%d ", XCAM_RETINEX_MAX_SCALE); |
| |
| kernel = new CLRetinexImageKernel (context, handler); |
| XCAM_ASSERT (kernel.ptr ()); |
| XCAM_FAIL_RETURN ( |
| ERROR, kernel->build_kernel (kernel_retinex_info[KernelRetinex], build_options) == XCAM_RETURN_NO_ERROR, NULL, |
| "build retinex kernel(%s) failed", kernel_retinex_info[KernelRetinex].kernel_name); |
| |
| XCAM_ASSERT (kernel->is_valid ()); |
| return kernel; |
| } |
| |
| SmartPtr<CLImageHandler> |
| create_cl_retinex_image_handler (const SmartPtr<CLContext> &context) |
| { |
| SmartPtr<CLRetinexImageHandler> retinex_handler; |
| |
| SmartPtr<CLRetinexScalerImageKernel> retinex_scaler_kernel; |
| SmartPtr<CLRetinexImageKernel> retinex_kernel; |
| |
| retinex_handler = new CLRetinexImageHandler (context, "cl_handler_retinex"); |
| retinex_scaler_kernel = create_kernel_retinex_scaler (context, retinex_handler); |
| XCAM_FAIL_RETURN ( |
| ERROR, |
| retinex_scaler_kernel.ptr () && retinex_scaler_kernel->is_valid (), |
| NULL, |
| "Retinex handler create scaler kernel failed"); |
| retinex_handler->set_retinex_scaler_kernel (retinex_scaler_kernel); |
| |
| for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { |
| SmartPtr<CLImageKernel> retinex_gauss_kernel; |
| retinex_gauss_kernel = create_kernel_retinex_gaussian ( |
| context, retinex_handler, i, retinex_gauss_scale [i], retinex_gauss_sigma [i]); |
| XCAM_FAIL_RETURN ( |
| ERROR, |
| retinex_gauss_kernel.ptr () && retinex_gauss_kernel->is_valid (), |
| NULL, |
| "Retinex handler create gaussian kernel failed"); |
| retinex_handler->add_kernel (retinex_gauss_kernel); |
| } |
| |
| retinex_kernel = create_kernel_retinex (context, retinex_handler); |
| XCAM_FAIL_RETURN ( |
| ERROR, |
| retinex_kernel.ptr () && retinex_kernel->is_valid (), |
| NULL, |
| "Retinex handler create retinex kernel failed"); |
| retinex_handler->set_retinex_kernel (retinex_kernel); |
| |
| return retinex_handler; |
| } |
| |
| } |