/*
|
* 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 <feix.w.wang@intel.com>
|
* Wind Yuan <feng.yuan@intel.com>
|
*/
|
|
#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;
|
}
|
|
}
|