/*
* test_cl_image.cpp - test cl image
*
* Copyright (c) 2014-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: Wind Yuan <feng.yuan@intel.com>
* Author: Yinhang Liu <yinhangx.liu@intel.com>
* Author: Wei Zong <wei.zong@intel.com>
*/
#include "test_common.h"
#include "test_inline.h"
#include "image_file_handle.h"
#include "ocl/cl_device.h"
#include "ocl/cl_context.h"
#include "ocl/cl_demo_handler.h"
#include "ocl/cl_csc_handler.h"
#include "ocl/cl_bayer_pipe_handler.h"
#include "ocl/cl_yuv_pipe_handler.h"
#include "ocl/cl_tonemapping_handler.h"
#include "ocl/cl_retinex_handler.h"
#include "ocl/cl_gauss_handler.h"
#include "ocl/cl_wavelet_denoise_handler.h"
#include "ocl/cl_newwavelet_denoise_handler.h"
#include "ocl/cl_defog_dcp_handler.h"
#include "ocl/cl_3d_denoise_handler.h"
#include "ocl/cl_image_warp_handler.h"
#include "ocl/cl_fisheye_handler.h"
#include "ocl/cl_utils.h"
using namespace XCam;
enum TestHandlerType {
TestHandlerUnknown = 0,
TestHandlerDemo,
TestHandlerColorConversion,
TestHandlerBayerPipe,
TestHandlerYuvPipe,
TestHandlerTonemapping,
TestHandlerRetinex,
TestHandlerGauss,
TestHandlerHatWavelet,
TestHandlerHaarWavelet,
TestHandlerDefogDcp,
TestHandler3DDenoise,
TestHandlerImageWarp,
TestHandlerFisheye,
};
enum PsnrType {
PSNRY = 0,
PSNRR,
PSNRG,
PSNRB,
};
static XCamReturn
calculate_psnr (SmartPtr<VideoBuffer> &psnr_cur, SmartPtr<VideoBuffer> &psnr_ref, PsnrType psnr_type, float &psnr)
{
const VideoBufferInfo info = psnr_cur->get_video_info ();
VideoBufferPlanarInfo planar;
uint8_t *cur_mem = NULL, *ref_mem = NULL;
XCamReturn ret = XCAM_RETURN_NO_ERROR;
int8_t interval = 1, index = 0;
if (PSNRY == psnr_type) {
interval = 1;
index = 0;
} else if (PSNRR == psnr_type) {
interval = 4;
index = 0;
} else if (PSNRG == psnr_type) {
interval = 4;
index = 1;
} else if (PSNRB == psnr_type) {
interval = 4;
index = 2;
}
cur_mem = psnr_cur->map ();
ref_mem = psnr_ref->map ();
if (!cur_mem || !ref_mem) {
XCAM_LOG_ERROR ("calculate_psnr map buffer failed");
return XCAM_RETURN_ERROR_MEM;
}
uint32_t sum = 0, pos = 0;
info.get_planar_info (planar, 0);
for (uint32_t i = 0; i < planar.height; i++) {
for (uint32_t j = 0; j < planar.width / interval; j++) {
pos = i * planar.width + j * interval + index;
sum += (cur_mem [pos] - ref_mem [pos]) * (cur_mem [pos] - ref_mem [pos]);
}
}
float mse = (float) sum / (planar.height * planar.width / interval) + 0.000001f;
psnr = 10 * log10 (255 * 255 / mse);
psnr_cur->unmap ();
psnr_ref->unmap ();
return ret;
}
static XCamReturn
kernel_loop(SmartPtr<CLImageHandler> &image_handler, SmartPtr<VideoBuffer> &input_buf, SmartPtr<VideoBuffer> &output_buf, uint32_t kernel_loop_count)
{
XCamReturn ret = XCAM_RETURN_NO_ERROR;
for (uint32_t i = 0; i < kernel_loop_count; i++) {
PROFILING_START(cl_kernel);
ret = image_handler->execute (input_buf, output_buf);
PROFILING_END(cl_kernel, kernel_loop_count)
}
return ret;
}
static void
print_help (const char *bin_name)
{
printf ("Usage: %s [-f format] -i input -o output\n"
"\t -t type specify image handler type\n"
"\t select from [demo, blacklevel, defect, demosaic, tonemapping, csc, hdr, wb, denoise,"
" gamma, snr, bnr, macc, ee, bayerpipe, yuvpipe, retinex, gauss, wavelet-hat, wavelet-haar, dcp, fisheye]\n"
"\t -f input_format specify a input format\n"
"\t -W image_width specify input image width\n"
"\t -H image_height specify input image height\n"
"\t -g output_format specify a output format\n"
"\t select from [NV12, BA10, RGBA, RGBA64]\n"
"\t -i input specify input file path\n"
"\t -o output specify output file path\n"
"\t -r refer specify reference file path\n"
"\t -k binary_kernel specify binary kernel path\n"
"\t -p count specify cl kernel loop count\n"
"\t -c csc_type specify csc type, default:rgba2nv12\n"
"\t select from [rgbatonv12, rgbatolab, rgba64torgba, yuyvtorgba, nv12torgba]\n"
"\t -b enable bayer-nr, default: disable\n"
"\t -P enable psnr calculation, default: disable\n"
"\t -h help\n"
, bin_name);
printf ("Note:\n"
"Usage of binary kernel:\n"
"1. generate binary kernel:\n"
" $ test-binary-kernel --src-kernel kernel_demo.cl --bin-kernel kernel_demo.cl.bin"
" --kernel-name kernel_demo\n"
"2. execute binary kernel:\n"
" $ test-cl-image -t demo -f BA10 -i input.raw -o output.raw -k kernel_demo.cl.bin\n");
}
int main (int argc, char *argv[])
{
uint32_t input_format = 0;
uint32_t output_format = V4L2_PIX_FMT_RGBA32;
uint32_t width = 1920;
uint32_t height = 1080;
uint32_t buf_count = 0;
int32_t kernel_loop_count = 0;
const char *input_file = NULL, *output_file = NULL, *refer_file = NULL;
const char *bin_kernel_path = NULL;
ImageFileHandle input_fp, output_fp, refer_fp;
const char *bin_name = argv[0];
TestHandlerType handler_type = TestHandlerUnknown;
XCamReturn ret = XCAM_RETURN_NO_ERROR;
SmartPtr<CLImageHandler> image_handler;
VideoBufferInfo input_buf_info;
SmartPtr<CLContext> context;
SmartPtr<BufferPool> buf_pool;
int opt = 0;
CLCscType csc_type = CL_CSC_TYPE_RGBATONV12;
bool enable_bnr = false;
bool enable_psnr = false;
while ((opt = getopt(argc, argv, "f:W:H:i:o:r:t:k:p:c:g:bPh")) != -1) {
switch (opt) {
case 'i':
input_file = optarg;
break;
case 'o':
output_file = optarg;
break;
case 'r':
refer_file = optarg;
break;
case 'f': {
if (!strcasecmp (optarg, "nv12"))
input_format = V4L2_PIX_FMT_NV12;
else if (!strcasecmp (optarg, "ba10"))
input_format = V4L2_PIX_FMT_SGRBG10;
else if (! strcasecmp (optarg, "rgba"))
input_format = V4L2_PIX_FMT_RGBA32;
else if (! strcasecmp (optarg, "rgba64"))
input_format = XCAM_PIX_FMT_RGBA64;
else if (!strcasecmp (optarg, "ba12"))
input_format = V4L2_PIX_FMT_SGRBG12;
else
print_help (bin_name);
break;
}
case 'W': {
width = atoi (optarg);
break;
}
case 'H': {
height = atoi (optarg);
break;
}
case 'g': {
if (!strcasecmp (optarg, "nv12"))
output_format = V4L2_PIX_FMT_NV12;
else if (!strcasecmp (optarg, "ba10"))
output_format = V4L2_PIX_FMT_SGRBG10;
else if (! strcasecmp (optarg, "rgba"))
output_format = V4L2_PIX_FMT_RGBA32;
else if (! strcasecmp (optarg, "rgba64"))
output_format = XCAM_PIX_FMT_RGBA64;
else
print_help (bin_name);
break;
}
case 't': {
if (!strcasecmp (optarg, "demo"))
handler_type = TestHandlerDemo;
else if (!strcasecmp (optarg, "csc"))
handler_type = TestHandlerColorConversion;
else if (!strcasecmp (optarg, "bayerpipe"))
handler_type = TestHandlerBayerPipe;
else if (!strcasecmp (optarg, "yuvpipe"))
handler_type = TestHandlerYuvPipe;
else if (!strcasecmp (optarg, "tonemapping"))
handler_type = TestHandlerTonemapping;
else if (!strcasecmp (optarg, "retinex"))
handler_type = TestHandlerRetinex;
else if (!strcasecmp (optarg, "gauss"))
handler_type = TestHandlerGauss;
else if (!strcasecmp (optarg, "wavelet-hat"))
handler_type = TestHandlerHatWavelet;
else if (!strcasecmp (optarg, "wavelet-haar"))
handler_type = TestHandlerHaarWavelet;
else if (!strcasecmp (optarg, "dcp"))
handler_type = TestHandlerDefogDcp;
else if (!strcasecmp (optarg, "3d-denoise"))
handler_type = TestHandler3DDenoise;
else if (!strcasecmp (optarg, "warp"))
handler_type = TestHandlerImageWarp;
else if (!strcasecmp (optarg, "fisheye"))
handler_type = TestHandlerFisheye;
else
print_help (bin_name);
break;
}
case 'k':
bin_kernel_path = optarg;
break;
case 'p':
kernel_loop_count = atoi (optarg);
XCAM_ASSERT (kernel_loop_count >= 0 && kernel_loop_count < INT32_MAX);
break;
case 'c':
if (!strcasecmp (optarg, "rgbatonv12"))
csc_type = CL_CSC_TYPE_RGBATONV12;
else if (!strcasecmp (optarg, "rgbatolab"))
csc_type = CL_CSC_TYPE_RGBATOLAB;
else if (!strcasecmp (optarg, "rgba64torgba"))
csc_type = CL_CSC_TYPE_RGBA64TORGBA;
else if (!strcasecmp (optarg, "yuyvtorgba"))
csc_type = CL_CSC_TYPE_YUYVTORGBA;
else if (!strcasecmp (optarg, "nv12torgba"))
csc_type = CL_CSC_TYPE_NV12TORGBA;
else
print_help (bin_name);
break;
case 'b':
enable_bnr = true;
break;
case 'P':
enable_psnr = true;
break;
case 'h':
print_help (bin_name);
return 0;
default:
print_help (bin_name);
return -1;
}
}
if (!input_format || !input_file || !output_file || (enable_psnr && !refer_file) || handler_type == TestHandlerUnknown) {
print_help (bin_name);
return -1;
}
ret = input_fp.open (input_file, "rb");
CHECK (ret, "open input file(%s) failed", XCAM_STR (input_file));
ret = output_fp.open (output_file, "wb");
CHECK (ret, "open output file(%s) failed", XCAM_STR (output_file));
if (enable_psnr) {
refer_fp.open (refer_file, "rb");
CHECK (ret, "open reference file(%s) failed", XCAM_STR (refer_file));
}
context = CLDevice::instance ()->get_context ();
switch (handler_type) {
case TestHandlerDemo:
if (!bin_kernel_path)
image_handler = create_cl_demo_image_handler (context);
else {
FileHandle file;
if (file.open (bin_kernel_path, "r") != XCAM_RETURN_NO_ERROR) {
XCAM_LOG_ERROR ("open binary kernel failed");
return -1;
}
size_t size;
if (file.get_file_size (size) != XCAM_RETURN_NO_ERROR) {
XCAM_LOG_ERROR ("get binary kernel size failed");
return -1;
}
uint8_t *binary = (uint8_t *) xcam_malloc0 (sizeof (uint8_t) * (size));
XCAM_ASSERT (binary);
if (file.read_file (binary, size) != XCAM_RETURN_NO_ERROR) {
XCAM_LOG_ERROR ("read binary kernel failed");
xcam_free (binary);
return -1;
}
image_handler = create_cl_binary_demo_image_handler (context, binary, size);
xcam_free (binary);
}
break;
case TestHandlerColorConversion: {
SmartPtr<CLCscImageHandler> csc_handler;
XCam3aResultColorMatrix color_matrix;
xcam_mem_clear (color_matrix);
double matrix_table[XCAM_COLOR_MATRIX_SIZE] = {0.299, 0.587, 0.114, -0.14713, -0.28886, 0.436, 0.615, -0.51499, -0.10001};
memcpy (color_matrix.matrix, matrix_table, sizeof(double)*XCAM_COLOR_MATRIX_SIZE);
image_handler = create_cl_csc_image_handler (context, csc_type);
csc_handler = image_handler.dynamic_cast_ptr<CLCscImageHandler> ();
XCAM_ASSERT (csc_handler.ptr ());
csc_handler->set_matrix(color_matrix);
break;
}
case TestHandlerBayerPipe: {
image_handler = create_cl_bayer_pipe_image_handler (context);
SmartPtr<CLBayerPipeImageHandler> bayer_pipe = image_handler.dynamic_cast_ptr<CLBayerPipeImageHandler> ();
XCAM_ASSERT (bayer_pipe.ptr ());
bayer_pipe->set_output_format (output_format);
bayer_pipe->enable_denoise (enable_bnr);
break;
}
case TestHandlerYuvPipe: {
image_handler = create_cl_yuv_pipe_image_handler (context);
SmartPtr<CLYuvPipeImageHandler> yuv_pipe = image_handler.dynamic_cast_ptr<CLYuvPipeImageHandler> ();
XCAM_ASSERT (yuv_pipe.ptr ());
break;
}
case TestHandlerTonemapping: {
image_handler = create_cl_tonemapping_image_handler (context);
SmartPtr<CLTonemappingImageHandler> tonemapping_pipe = image_handler.dynamic_cast_ptr<CLTonemappingImageHandler> ();
XCAM_ASSERT (tonemapping_pipe.ptr ());
break;
}
case TestHandlerRetinex: {
image_handler = create_cl_retinex_image_handler (context);
SmartPtr<CLRetinexImageHandler> retinex = image_handler.dynamic_cast_ptr<CLRetinexImageHandler> ();
XCAM_ASSERT (retinex.ptr ());
break;
}
case TestHandlerGauss: {
image_handler = create_cl_gauss_image_handler (context);
SmartPtr<CLGaussImageHandler> gauss = image_handler.dynamic_cast_ptr<CLGaussImageHandler> ();
XCAM_ASSERT (gauss.ptr ());
break;
}
case TestHandlerHatWavelet: {
image_handler = create_cl_wavelet_denoise_image_handler (context, CL_IMAGE_CHANNEL_UV);
SmartPtr<CLWaveletDenoiseImageHandler> wavelet = image_handler.dynamic_cast_ptr<CLWaveletDenoiseImageHandler> ();
XCAM_ASSERT (wavelet.ptr ());
XCam3aResultWaveletNoiseReduction wavelet_config;
xcam_mem_clear (wavelet_config);
wavelet_config.threshold[0] = 0.2;
wavelet_config.threshold[1] = 0.5;
wavelet_config.decomposition_levels = 4;
wavelet_config.analog_gain = 0.001;
wavelet->set_denoise_config (wavelet_config);
break;
}
case TestHandlerHaarWavelet: {
image_handler = create_cl_newwavelet_denoise_image_handler (context, CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y, false);
SmartPtr<CLNewWaveletDenoiseImageHandler> wavelet = image_handler.dynamic_cast_ptr<CLNewWaveletDenoiseImageHandler> ();
XCAM_ASSERT (wavelet.ptr ());
XCam3aResultWaveletNoiseReduction wavelet_config;
wavelet_config.threshold[0] = 0.2;
wavelet_config.threshold[1] = 0.5;
wavelet_config.decomposition_levels = 4;
wavelet_config.analog_gain = 0.001;
wavelet->set_denoise_config (wavelet_config);
break;
}
case TestHandlerDefogDcp: {
image_handler = create_cl_defog_dcp_image_handler (context);
XCAM_ASSERT (image_handler.ptr ());
break;
}
case TestHandler3DDenoise: {
uint8_t ref_count = 2;
image_handler = create_cl_3d_denoise_image_handler (context, CL_IMAGE_CHANNEL_Y | CL_IMAGE_CHANNEL_UV, ref_count);
SmartPtr<CL3DDenoiseImageHandler> denoise = image_handler.dynamic_cast_ptr<CL3DDenoiseImageHandler> ();
XCAM_ASSERT (denoise.ptr ());
XCam3aResultTemporalNoiseReduction denoise_config;
xcam_mem_clear (denoise_config);
denoise_config.threshold[0] = 0.05;
denoise_config.threshold[1] = 0.05;
denoise_config.gain = 0.6;
denoise->set_denoise_config (denoise_config);
break;
}
case TestHandlerImageWarp: {
image_handler = create_cl_image_warp_handler (context);
SmartPtr<CLImageWarpHandler> warp = image_handler.dynamic_cast_ptr<CLImageWarpHandler> ();
XCAM_ASSERT (warp.ptr ());
XCamDVSResult warp_config;
xcam_mem_clear (warp_config);
warp_config.frame_id = 1;
warp_config.frame_width = width;
warp_config.frame_height = height;
float theta = -10.0f;
float phi = 10.0f;
float shift_x = -0.2f * width;
float shift_y = 0.2f * height;
float scale_x = 2.0f;
float scale_y = 0.5f;
float shear_x = tan(theta * 3.1415926 / 180.0f);
float shear_y = tan(phi * 3.1415926 / 180.0f);
float project_x = 2.0f / width;
float project_y = -1.0f / height;
warp_config.proj_mat[0] = scale_x;
warp_config.proj_mat[1] = shear_x;
warp_config.proj_mat[2] = shift_x;
warp_config.proj_mat[3] = shear_y;
warp_config.proj_mat[4] = scale_y;
warp_config.proj_mat[5] = shift_y;
warp_config.proj_mat[6] = project_x;
warp_config.proj_mat[7] = project_y;
warp_config.proj_mat[8] = 1.0f;
warp->set_warp_config (warp_config);
break;
}
case TestHandlerFisheye: {
image_handler = create_fisheye_handler (context);
SmartPtr<CLFisheyeHandler> fisheye = image_handler.dynamic_cast_ptr<CLFisheyeHandler> ();
XCAM_ASSERT (fisheye.ptr ());
FisheyeInfo fisheye_info;
//fisheye0 {480.0f, 480.0f, 190.0f, 480.0f, -90.0f},
//fisheye1 {1440.0f, 480.0f, 190.0f, 480.0f, 90.0f}
fisheye_info.center_x = 480.0f;
fisheye_info.center_y = 480.0f;
fisheye_info.wide_angle = 190.0f;
fisheye_info.radius = 480.0f;
fisheye_info.rotate_angle = -90.0f;
fisheye->set_fisheye_info (fisheye_info);
fisheye->set_dst_range (210.0f, 180.0f);
fisheye->set_output_size (1120, 960);
break;
}
default:
XCAM_LOG_ERROR ("unsupported image handler type:%d", handler_type);
return -1;
}
if (!image_handler.ptr ()) {
XCAM_LOG_ERROR ("create image_handler failed");
return -1;
}
input_buf_info.init (input_format, width, height);
buf_pool = new CLVideoBufferPool ();
image_handler->set_pool_type (CLImageHandler::CLVideoPoolType);
buf_pool->set_video_info (input_buf_info);
if (!buf_pool->reserve (6)) {
XCAM_LOG_ERROR ("init buffer pool failed");
return -1;
}
SmartPtr<VideoBuffer> input_buf, output_buf, psnr_cur, psnr_ref;
while (true) {
input_buf = buf_pool->get_buffer (buf_pool);
XCAM_ASSERT (input_buf.ptr ());
ret = input_fp.read_buf (input_buf);
if (ret == XCAM_RETURN_BYPASS)
break;
if (ret == XCAM_RETURN_ERROR_FILE) {
XCAM_LOG_ERROR ("read buffer from %s failed", XCAM_STR (input_file));
return -1;
}
if (kernel_loop_count != 0)
{
kernel_loop (image_handler, input_buf, output_buf, kernel_loop_count);
CHECK (ret, "execute kernels failed");
return 0;
}
ret = image_handler->execute (input_buf, output_buf);
CHECK_EXP ((ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS), "execute kernels failed");
if (ret == XCAM_RETURN_BYPASS)
continue;
context->finish ();
XCAM_ASSERT (output_buf.ptr ());
ret = output_fp.write_buf (output_buf);
CHECK (ret, "write buffer to %s failed", XCAM_STR (output_file));
psnr_cur = output_buf;
++buf_count;
}
XCAM_LOG_INFO ("processed %d buffers successfully", buf_count);
if (enable_psnr) {
buf_pool = new CLVideoBufferPool ();
XCAM_ASSERT (buf_pool.ptr ());
buf_pool->set_video_info (input_buf_info);
if (!buf_pool->reserve (6)) {
XCAM_LOG_ERROR ("init buffer pool failed");
return -1;
}
psnr_ref = buf_pool->get_buffer (buf_pool);
XCAM_ASSERT (psnr_ref.ptr ());
ret = refer_fp.read_buf (psnr_ref);
CHECK (ret, "read buffer from %s failed", refer_file);
float psnr = 0.0f;
ret = calculate_psnr (psnr_cur, psnr_ref, PSNRY, psnr);
CHECK (ret, "calculate PSNR_Y failed");
XCAM_LOG_INFO ("PSNR_Y: %.2f", psnr);
image_handler = create_cl_csc_image_handler (context, CL_CSC_TYPE_NV12TORGBA);
XCAM_ASSERT (image_handler.ptr ());
SmartPtr<VideoBuffer> psnr_cur_output, psnr_ref_output;
ret = image_handler->execute (psnr_cur, psnr_cur_output);
CHECK (ret, "execute kernels failed");
XCAM_ASSERT (psnr_cur_output.ptr ());
ret = image_handler->execute (psnr_ref, psnr_ref_output);
CHECK (ret, "execute kernels failed");
XCAM_ASSERT (psnr_ref_output.ptr ());
ret = calculate_psnr (psnr_cur_output, psnr_ref_output, PSNRR, psnr);
CHECK (ret, "calculate PSNR_R failed");
XCAM_LOG_INFO ("PSNR_R: %.2f", psnr);
ret = calculate_psnr (psnr_cur_output, psnr_ref_output, PSNRG, psnr);
CHECK (ret, "calculate PSNR_G failed");
XCAM_LOG_INFO ("PSNR_G: %.2f", psnr);
ret = calculate_psnr (psnr_cur_output, psnr_ref_output, PSNRB, psnr);
CHECK (ret, "calculate PSNR_B failed");
XCAM_LOG_INFO ("PSNR_B: %.2f", psnr);
}
return 0;
}