/*
|
* cl_tnr_handler.cpp - CL tnr 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 <wei.zong@intel.com>
|
*/
|
|
#include "cl_tnr_handler.h"
|
|
#define TNR_PROCESSING_FRAME_COUNT 4
|
#define TNR_LIST_FRAME_COUNT 4
|
#define TNR_MOTION_THRESHOLD 2
|
|
namespace XCam {
|
|
static const XCamKernelInfo kernel_tnr_yuv_info = {
|
"kernel_tnr_yuv",
|
#include "kernel_tnr.clx"
|
, 0
|
};
|
|
static const XCamKernelInfo kernel_tnr_rgb_info = {
|
"kernel_tnr_rgb",
|
#include "kernel_tnr.clx"
|
, 0,
|
};
|
|
CLTnrImageHandler::CLTnrMotionInfo::CLTnrMotionInfo ()
|
: hor_shift (0)
|
, ver_shift (0)
|
, hor_corr (0)
|
, ver_corr (0)
|
{
|
}
|
|
CLTnrImageHandler::CLTnrHistogram::CLTnrHistogram() {
|
hor_hist_bin = 0;
|
ver_hist_bin = 0;
|
hor_hist_current = NULL;
|
hor_hist_reference = NULL;
|
ver_hist_current = NULL;
|
ver_hist_reference = NULL;
|
};
|
|
CLTnrImageHandler::CLTnrHistogram::CLTnrHistogram(uint32_t width, uint32_t height) {
|
hor_hist_bin = width;
|
ver_hist_bin = height;
|
if ((NULL == hor_hist_current) && (hor_hist_bin != 0)) {
|
hor_hist_current = (float*)xcam_malloc0(hor_hist_bin * sizeof(float));
|
}
|
if ((NULL == ver_hist_current) && (ver_hist_bin != 0)) {
|
ver_hist_current = (float*)xcam_malloc0(ver_hist_bin * sizeof(float));
|
}
|
if ((NULL == hor_hist_reference) && (hor_hist_bin != 0)) {
|
hor_hist_reference = (float*)xcam_malloc0(hor_hist_bin * sizeof(float));
|
}
|
if ((NULL == ver_hist_reference) && (ver_hist_bin != 0)) {
|
ver_hist_reference = (float*)xcam_malloc0(ver_hist_bin * sizeof(float));
|
}
|
};
|
|
CLTnrImageHandler::CLTnrHistogram::~CLTnrHistogram() {
|
if (NULL != hor_hist_current) {
|
xcam_free(hor_hist_current);
|
hor_hist_current = NULL;
|
}
|
if (NULL != ver_hist_current) {
|
xcam_free(ver_hist_current);
|
ver_hist_current = NULL;
|
}
|
if (NULL != hor_hist_reference) {
|
xcam_free(hor_hist_reference);
|
hor_hist_reference = NULL;
|
}
|
if (NULL != ver_hist_reference) {
|
xcam_free(ver_hist_reference);
|
ver_hist_reference = NULL;
|
}
|
hor_hist_bin = 0;
|
ver_hist_bin = 0;
|
}
|
|
CLTnrImageKernel::CLTnrImageKernel (
|
const SmartPtr<CLContext> &context, CLTnrType type)
|
: CLImageKernel (context)
|
, _type (type)
|
{
|
}
|
|
bool
|
CLTnrImageHandler::calculate_image_histogram (XCam3AStats* stats, CLTnrHistogramType type, float* histogram)
|
{
|
if ( NULL == stats || NULL == histogram ) {
|
return false;
|
}
|
|
uint32_t normalize_factor = (1 << stats->info.bit_depth) - 1;
|
uint32_t image_width = stats->info.width;
|
uint32_t image_height = stats->info.height;
|
uint32_t image_aligned_width = stats->info.aligned_width;
|
uint32_t hor_hist_bin = image_width;
|
uint32_t ver_hist_bin = image_height;
|
|
switch (type) {
|
case CL_TNR_HIST_HOR_PROJECTION :
|
for (uint32_t bin = 0; bin < hor_hist_bin; bin++) {
|
for (uint32_t row_index = 0; row_index < image_height; row_index++) {
|
histogram[bin] += (float)(stats->stats[row_index * image_aligned_width + bin].avg_y)
|
/ (1.0 * normalize_factor);
|
}
|
}
|
break;
|
case CL_TNR_HIST_VER_PROJECTION :
|
for (uint32_t bin = 0; bin < ver_hist_bin; bin++) {
|
for (uint32_t col_index = 0; col_index < image_width; col_index++) {
|
histogram[bin] += (float)(stats->stats[col_index + bin * image_aligned_width].avg_y)
|
/ (1.0 * normalize_factor);
|
}
|
}
|
break;
|
case CL_TNR_HIST_BRIGHTNESS :
|
for (uint32_t row_index = 0; row_index < image_height; row_index++) {
|
for (uint32_t col_index = 0; col_index < image_width; col_index++) {
|
uint8_t bin = (stats->stats[row_index * image_aligned_width + col_index].avg_y * 255)
|
/ normalize_factor;
|
histogram[bin]++;
|
}
|
}
|
break;
|
default :
|
break;
|
}
|
|
return true;
|
}
|
|
bool
|
CLTnrImageHandler::calculate_image_histogram (SmartPtr<VideoBuffer> &input, CLTnrHistogramType type, float* histogram)
|
{
|
if ( NULL == histogram ) {
|
return false;
|
}
|
|
uint32_t normalize_factor = (1 << input->get_video_info ().color_bits) - 1;
|
uint32_t image_width = input->get_video_info ().width;
|
uint32_t image_height = input->get_video_info ().height;
|
uint32_t image_aligned_width = input->get_video_info ().aligned_width;
|
uint32_t stride = input->get_video_info ().strides[0];
|
|
uint32_t hor_hist_bin = image_width;
|
uint32_t ver_hist_bin = image_height;
|
uint32_t pxiel_bytes = stride / image_aligned_width;
|
|
uint32_t format = input->get_video_info ().format;
|
if (XCAM_PIX_FMT_RGBA64 != format) {
|
XCAM_LOG_ERROR ("Only support RGBA64 format !");
|
return false;
|
}
|
|
uint8_t* image_buffer = input->map();
|
if (NULL == image_buffer) {
|
return false;
|
}
|
|
switch (type) {
|
case CL_TNR_HIST_HOR_PROJECTION :
|
for (uint32_t bin = 0; bin < hor_hist_bin; bin++) {
|
for (uint32_t row_index = 0; row_index < image_height; row_index++) {
|
histogram[bin] += (float)(image_buffer[row_index * stride + pxiel_bytes * bin] +
|
(image_buffer[row_index * stride + pxiel_bytes * bin + 1] << 8) +
|
image_buffer[row_index * stride + pxiel_bytes * bin + 2] +
|
(image_buffer[row_index * stride + pxiel_bytes * bin + 3] << 8) +
|
image_buffer[row_index * stride + pxiel_bytes * bin + 4] +
|
(image_buffer[row_index * stride + pxiel_bytes * bin + 5] << 8) )
|
/ (3.0 * normalize_factor);
|
}
|
}
|
break;
|
case CL_TNR_HIST_VER_PROJECTION :
|
for (uint32_t bin = 0; bin < ver_hist_bin; bin++) {
|
for (uint32_t col_index = 0; col_index < stride; col_index += pxiel_bytes) {
|
histogram[bin] += (float)(image_buffer[col_index + bin * stride] +
|
(image_buffer[col_index + bin * stride + 1] << 8) +
|
image_buffer[col_index + bin * stride + 2] +
|
(image_buffer[col_index + bin * stride + 3] << 8) +
|
image_buffer[col_index + bin * stride + 4] +
|
(image_buffer[col_index + bin * stride + 5] << 8) )
|
/ (3.0 * normalize_factor);
|
}
|
}
|
break;
|
case CL_TNR_HIST_BRIGHTNESS :
|
for (uint32_t row_index = 0; row_index < image_height; row_index++) {
|
for (uint32_t col_index = 0; col_index < stride; col_index += pxiel_bytes) {
|
uint8_t bin = (image_buffer[row_index * stride + col_index] +
|
(image_buffer[row_index * stride + col_index + 1] << 8) +
|
image_buffer[row_index * stride + col_index + 2] +
|
(image_buffer[row_index * stride + col_index + 3] << 8) +
|
image_buffer[row_index * stride + col_index + 4] +
|
(image_buffer[row_index * stride + col_index + 5] << 8) ) * 255
|
/ (3 * normalize_factor);
|
histogram[bin]++;
|
}
|
}
|
break;
|
default :
|
break;
|
}
|
|
input->unmap();
|
|
return true;
|
}
|
|
void
|
CLTnrImageHandler::print_image_histogram ()
|
{
|
uint32_t hor_hist_bin = _image_histogram.hor_hist_bin;
|
uint32_t ver_hist_bin = _image_histogram.ver_hist_bin;
|
|
XCAM_LOG_DEBUG ("hor hist bin = %d, ver hist bin = %d", hor_hist_bin, ver_hist_bin);
|
|
printf("float hor_hist_current[] = { ");
|
for (uint32_t i = 0; i < hor_hist_bin; i++) {
|
printf("%f, ", _image_histogram.hor_hist_current[i]);
|
}
|
printf(" }; \n\n\n");
|
|
printf("float ver_hist_current[] = { ");
|
for (uint32_t i = 0; i < ver_hist_bin; i++) {
|
printf("%f, ", _image_histogram.ver_hist_current[i]);
|
}
|
printf(" }; \n\n\n");
|
|
printf("float hor_hist_reference[] = { ");
|
for (uint32_t i = 0; i < hor_hist_bin; i++) {
|
printf("%f, ", _image_histogram.hor_hist_reference[i]);
|
}
|
printf(" }; \n\n\n");
|
|
printf("float ver_hist_reference[] = { ");
|
for (uint32_t i = 0; i < ver_hist_bin; i++) {
|
printf("%f, ", _image_histogram.ver_hist_reference[i]);
|
}
|
printf(" }; \n\n\n");
|
}
|
|
CLTnrImageHandler::CLTnrImageHandler (const SmartPtr<CLContext> &context, CLTnrType type, const char *name)
|
: CLImageHandler (context, name)
|
, _type (type)
|
, _gain_yuv (1.0)
|
, _thr_y (0.05)
|
, _thr_uv (0.05)
|
, _gain_rgb (0.0)
|
, _thr_r (0.064) // set high initial threshold to get strong denoise effect
|
, _thr_g (0.045)
|
, _thr_b (0.073)
|
, _frame_count (TNR_PROCESSING_FRAME_COUNT)
|
{
|
}
|
|
bool
|
CLTnrImageHandler::set_tnr_kernel(SmartPtr<CLTnrImageKernel> &kernel)
|
{
|
SmartPtr<CLImageKernel> image_kernel = kernel;
|
add_kernel (image_kernel);
|
_tnr_kernel = kernel;
|
return true;
|
}
|
|
bool
|
CLTnrImageHandler::set_framecount (uint8_t count)
|
{
|
if (!_tnr_kernel->is_valid ()) {
|
XCAM_LOG_ERROR ("set framecount error, invalid TNR kernel !");
|
return false;
|
}
|
|
XCAM_ASSERT (count >= 2 && count <= 4);
|
_frame_count = count;
|
|
return true;
|
}
|
|
bool
|
CLTnrImageHandler::set_rgb_config (const XCam3aResultTemporalNoiseReduction& config)
|
|
{
|
if (!_tnr_kernel->is_valid ()) {
|
XCAM_LOG_ERROR ("set threshold error, invalid TNR kernel !");
|
return false;
|
}
|
_gain_rgb = (float)config.gain;
|
_thr_r = (float)config.threshold[0];
|
_thr_g = (float)config.threshold[1];
|
_thr_b = (float)config.threshold[2];
|
XCAM_LOG_DEBUG ("set TNR RGB config: _gain(%f), _thr_r(%f), _thr_g(%f), _thr_b(%f)",
|
_gain_rgb, _thr_r, _thr_g, _thr_b);
|
|
return true;
|
}
|
|
bool
|
CLTnrImageHandler::set_yuv_config (const XCam3aResultTemporalNoiseReduction& config)
|
|
{
|
if (!_tnr_kernel->is_valid ()) {
|
XCAM_LOG_ERROR ("set threshold error, invalid TNR kernel !");
|
return false;
|
}
|
|
_gain_yuv = (float)config.gain;
|
_thr_y = (float)config.threshold[0];
|
_thr_uv = (float)config.threshold[1];
|
|
XCAM_LOG_DEBUG ("set TNR YUV config: _gain(%f), _thr_y(%f), _thr_uv(%f)",
|
_gain_yuv, _thr_y, _thr_uv);
|
|
return true;
|
}
|
|
XCamReturn
|
CLTnrImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output)
|
{
|
SmartPtr<CLContext> context = get_context ();
|
const VideoBufferInfo & video_info = input->get_video_info ();
|
CLArgList args;
|
CLWorkSize work_size;
|
XCamReturn ret = XCAM_RETURN_NO_ERROR;
|
|
XCAM_ASSERT (_tnr_kernel.ptr ());
|
|
CLImageDesc desc;
|
if (CL_TNR_TYPE_YUV == _type) {
|
desc.format.image_channel_order = CL_R;
|
desc.format.image_channel_data_type = CL_UNORM_INT8;
|
desc.width = video_info.aligned_width;
|
desc.height = video_info.aligned_height + video_info.height / 2;
|
desc.row_pitch = video_info.strides[0];
|
desc.array_size = 2;
|
desc.slice_pitch = video_info.strides [0] * video_info.aligned_height;
|
} else if (CL_TNR_TYPE_RGB == _type) {
|
desc.format.image_channel_order = CL_RGBA;
|
desc.format.image_channel_data_type = CL_UNORM_INT8;
|
desc.width = video_info.aligned_width;
|
desc.height = video_info.height;
|
desc.row_pitch = video_info.strides[0];
|
desc.array_size = 0;
|
desc.slice_pitch = 0;
|
}
|
|
SmartPtr<CLImage> image_in = convert_to_climage (context, input, desc);
|
SmartPtr<CLImage> image_out = convert_to_climage (context, output, desc);
|
|
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", _tnr_kernel->get_kernel_name ());
|
|
if (CL_TNR_TYPE_YUV == _type) {
|
if (!_image_out_prev.ptr ()) {
|
_image_out_prev = image_in;
|
}
|
} else if (CL_TNR_TYPE_RGB == _type) {
|
// analyze motion between the latest adjacent two frames
|
// Todo: enable analyze when utilize motion compensation next step
|
|
if (_image_in_list.size () < TNR_LIST_FRAME_COUNT) {
|
while (_image_in_list.size () < TNR_LIST_FRAME_COUNT) {
|
_image_in_list.push_back (image_in);
|
}
|
} else {
|
_image_in_list.pop_front ();
|
_image_in_list.push_back (image_in);
|
}
|
}
|
|
uint32_t vertical_offset = video_info.aligned_height;
|
|
//set args;
|
work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
|
work_size.local[0] = 8;
|
work_size.local[1] = 4;
|
if (CL_TNR_TYPE_YUV == _type) {
|
args.push_back (new CLMemArgument (image_in));
|
args.push_back (new CLMemArgument (_image_out_prev));
|
args.push_back (new CLMemArgument (image_out));
|
args.push_back (new CLArgumentT<uint> (vertical_offset));
|
|
args.push_back (new CLArgumentT<float> (_gain_yuv));
|
args.push_back (new CLArgumentT<float> (_thr_y));
|
args.push_back (new CLArgumentT<float> (_thr_uv));
|
|
work_size.global[0] = video_info.width / 2;
|
work_size.global[1] = video_info.height / 2;
|
}
|
else if (CL_TNR_TYPE_RGB == _type) {
|
const CLImageDesc out_info = image_out->get_image_desc ();
|
work_size.global[0] = out_info.width;
|
work_size.global[1] = out_info.height;
|
|
args.push_back (new CLMemArgument (image_out));
|
args.push_back (new CLArgumentT<float> (_gain_rgb));
|
args.push_back (new CLArgumentT<float> (_thr_r));
|
args.push_back (new CLArgumentT<float> (_thr_g));
|
args.push_back (new CLArgumentT<float> (_thr_b));
|
args.push_back (new CLArgumentT<uint8_t> (_frame_count));
|
|
for (std::list<SmartPtr<CLImage>>::iterator it = _image_in_list.begin (); it != _image_in_list.end (); it++) {
|
args.push_back (new CLMemArgument (*it));
|
}
|
}
|
|
XCAM_ASSERT (_tnr_kernel.ptr ());
|
ret = _tnr_kernel->set_arguments (args, work_size);
|
XCAM_FAIL_RETURN (
|
WARNING, ret == XCAM_RETURN_NO_ERROR, ret,
|
"tnr kernel set arguments failed.");
|
|
_image_out_prev = image_out;
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
SmartPtr<CLImageHandler>
|
create_cl_tnr_image_handler (const SmartPtr<CLContext> &context, CLTnrType type)
|
{
|
SmartPtr<CLTnrImageHandler> tnr_handler;
|
SmartPtr<CLTnrImageKernel> tnr_kernel;
|
XCamReturn ret = XCAM_RETURN_NO_ERROR;
|
|
tnr_kernel = new CLTnrImageKernel (context, type);
|
XCAM_ASSERT (tnr_kernel.ptr ());
|
if (CL_TNR_TYPE_YUV == type) {
|
ret = tnr_kernel->build_kernel (kernel_tnr_yuv_info, NULL);
|
} else if (CL_TNR_TYPE_RGB == type) {
|
ret = tnr_kernel->build_kernel (kernel_tnr_rgb_info, NULL);
|
} else {
|
XCAM_LOG_ERROR ("create cl tnr image handler failed, unknown type:%d", type);
|
return NULL;
|
}
|
|
XCAM_FAIL_RETURN (
|
ERROR, ret == XCAM_RETURN_NO_ERROR, NULL,
|
"build tnr kernel failed");
|
|
tnr_handler = new CLTnrImageHandler (context, type, "cl_handler_tnr");
|
XCAM_ASSERT (tnr_kernel->is_valid ());
|
tnr_handler->set_tnr_kernel (tnr_kernel);
|
|
return tnr_handler;
|
}
|
|
};
|