blob: 071b35c633f9b927064d8e5c2bb3c305b0da31e6 [file] [log] [blame]
/*
* Copyright (c) 2012-2017 The Khronos Group Inc.
*
* 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.
*/
#if defined OPENVX_USE_ENHANCED_VISION || OPENVX_CONFORMANCE_VISION
#include <math.h>
#include <float.h>
#include <string.h>
#include <VX/vx.h>
#include <VX/vxu.h>
#include "test_engine/test.h"
TESTCASE(WarpAffine, CT_VXContext, ct_setup_vx_context, 0)
TEST(WarpAffine, testNodeCreation)
{
vx_context context = context_->vx_context_;
vx_image input = 0, output = 0;
vx_matrix matrix = 0;
vx_graph graph = 0;
vx_node node = 0;
vx_enum type = VX_INTERPOLATION_NEAREST_NEIGHBOR;
const vx_enum matrix_type = VX_TYPE_FLOAT32;
const vx_size matrix_rows = 3;
const vx_size matrix_cols = 2;
const vx_size matrix_data_size = 4 * matrix_rows * matrix_cols;
ASSERT_VX_OBJECT(input = vxCreateImage(context, 128, 128, VX_DF_IMAGE_U8), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(output = vxCreateImage(context, 128, 128, VX_DF_IMAGE_U8), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(matrix = vxCreateMatrix(context, matrix_type, matrix_cols, matrix_rows), VX_TYPE_MATRIX);
{
vx_enum ch_matrix_type;
vx_size ch_matrix_rows, ch_matrix_cols, ch_data_size;
VX_CALL(vxQueryMatrix(matrix, VX_MATRIX_TYPE, &ch_matrix_type, sizeof(ch_matrix_type)));
if (matrix_type != ch_matrix_type)
{
CT_FAIL("check for Matrix attribute VX_MATRIX_TYPE failed\n");
}
VX_CALL(vxQueryMatrix(matrix, VX_MATRIX_ROWS, &ch_matrix_rows, sizeof(ch_matrix_rows)));
if (matrix_rows != ch_matrix_rows)
{
CT_FAIL("check for Matrix attribute VX_MATRIX_ROWS failed\n");
}
VX_CALL(vxQueryMatrix(matrix, VX_MATRIX_COLUMNS, &ch_matrix_cols, sizeof(ch_matrix_cols)));
if (matrix_cols != ch_matrix_cols)
{
CT_FAIL("check for Matrix attribute VX_MATRIX_COLUMNS failed\n");
}
VX_CALL(vxQueryMatrix(matrix, VX_MATRIX_SIZE, &ch_data_size, sizeof(ch_data_size)));
if (matrix_data_size > ch_data_size)
{
CT_FAIL("check for Matrix attribute VX_MATRIX_SIZE failed\n");
}
}
graph = vxCreateGraph(context);
ASSERT_VX_OBJECT(graph, VX_TYPE_GRAPH);
ASSERT_VX_OBJECT(node = vxWarpAffineNode(graph, input, matrix, type, output), VX_TYPE_NODE);
VX_CALL(vxVerifyGraph(graph));
VX_CALL(vxReleaseNode(&node));
VX_CALL(vxReleaseGraph(&graph));
VX_CALL(vxReleaseMatrix(&matrix));
VX_CALL(vxReleaseImage(&output));
VX_CALL(vxReleaseImage(&input));
ASSERT(node == 0);
ASSERT(graph == 0);
ASSERT(matrix == 0);
ASSERT(output == 0);
ASSERT(input == 0);
}
enum CT_AffineMatrixType {
VX_MATRIX_IDENT = 0,
VX_MATRIX_ROTATE_90,
VX_MATRIX_SCALE,
VX_MATRIX_SCALE_ROTATE,
VX_MATRIX_RANDOM
};
#define VX_NN_AREA_SIZE 1.5
#define VX_BILINEAR_TOLERANCE 1
static CT_Image warp_affine_read_image(const char* fileName, int width, int height, vx_df_image format)
{
CT_Image image_load = NULL, image_ret = NULL;
ASSERT_(return 0, format == VX_DF_IMAGE_U1 || format == VX_DF_IMAGE_U8);
image_load = ct_read_image(fileName, 1);
ASSERT_(return 0, image_load);
ASSERT_(return 0, image_load->format == VX_DF_IMAGE_U8);
if (format == VX_DF_IMAGE_U1)
{
ASSERT_NO_FAILURE_(return 0, threshold_U8_ct_image(image_load, 127)); // Threshold to make the U1 image less trivial
ASSERT_NO_FAILURE_(return 0, image_ret = ct_allocate_image(image_load->width, image_load->height, VX_DF_IMAGE_U1));
ASSERT_NO_FAILURE_(return 0, U8_ct_image_to_U1_ct_image(image_load, image_ret));
}
else // format == VX_DF_IMAGE_U8
{
image_ret = image_load;
}
ASSERT_(return 0, image_ret);
ASSERT_(return 0, image_ret->format == format);
return image_ret;
}
static CT_Image warp_affine_generate_random(const char* fileName, int width, int height, vx_df_image format)
{
CT_Image image;
ASSERT_(return 0, format == VX_DF_IMAGE_U1 || format == VX_DF_IMAGE_U8);
if (format == VX_DF_IMAGE_U1)
ASSERT_NO_FAILURE_(return 0, image = ct_allocate_ct_image_random(width, height, format, &CT()->seed_, 0, 2));
else // format == VX_DF_IMAGE_U8
ASSERT_NO_FAILURE_(return 0, image = ct_allocate_ct_image_random(width, height, format, &CT()->seed_, 0, 256));
return image;
}
#define RND_FLT(low, high) (vx_float32)CT_RNG_NEXT_REAL(CT()->seed_, low, high);
static void warp_affine_generate_matrix(vx_float32* m, int src_width, int src_height, int dst_width, int dst_height, int type)
{
vx_float32 mat[3][2];
vx_float32 angle, scale_x, scale_y, cos_a, sin_a;
if (VX_MATRIX_IDENT == type)
{
mat[0][0] = 1.f;
mat[0][1] = 0.f;
mat[1][0] = 0.f;
mat[1][1] = 1.f;
mat[2][0] = 0.f;
mat[2][1] = 0.f;
}
else if (VX_MATRIX_ROTATE_90 == type)
{
mat[0][0] = 0.f;
mat[0][1] = 1.f;
mat[1][0] = -1.f;
mat[1][1] = 0.f;
mat[2][0] = (vx_float32)src_width;
mat[2][1] = 0.f;
}
else if (VX_MATRIX_SCALE == type)
{
scale_x = src_width / (vx_float32)dst_width;
scale_y = src_height / (vx_float32)dst_height;
mat[0][0] = scale_x;
mat[0][1] = 0.f;
mat[1][0] = 0.f;
mat[1][1] = scale_y;
mat[2][0] = 0.f;
mat[2][1] = 0.f;
}
else if (VX_MATRIX_SCALE_ROTATE == type)
{
angle = M_PIF / RND_FLT(3.f, 6.f);
scale_x = src_width / (vx_float32)dst_width;
scale_y = src_height / (vx_float32)dst_height;
cos_a = cosf(angle);
sin_a = sinf(angle);
mat[0][0] = cos_a * scale_x;
mat[0][1] = sin_a * scale_y;
mat[1][0] = -sin_a * scale_x;
mat[1][1] = cos_a * scale_y;
mat[2][0] = 0.f;
mat[2][1] = 0.f;
}
else// if (VX_MATRIX_RANDOM == type)
{
angle = M_PIF / RND_FLT(3.f, 6.f);
scale_x = src_width / (vx_float32)dst_width;
scale_y = src_height / (vx_float32)dst_height;
cos_a = cosf(angle);
sin_a = sinf(angle);
mat[0][0] = cos_a * RND_FLT(scale_x / 2.f, scale_x);
mat[0][1] = sin_a * RND_FLT(scale_y / 2.f, scale_y);
mat[1][0] = -sin_a * RND_FLT(scale_y / 2.f, scale_y);
mat[1][1] = cos_a * RND_FLT(scale_x / 2.f, scale_x);
mat[2][0] = src_width / 5.f * RND_FLT(-1.f, 1.f);
mat[2][1] = src_height / 5.f * RND_FLT(-1.f, 1.f);
}
memcpy(m, mat, sizeof(mat));
}
static vx_matrix warp_affine_create_matrix(vx_context context, vx_float32 *m)
{
vx_matrix matrix;
matrix = vxCreateMatrix(context, VX_TYPE_FLOAT32, 2, 3);
if (vxGetStatus((vx_reference)matrix) == VX_SUCCESS)
{
if (VX_SUCCESS != vxCopyMatrix(matrix, m, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST))
{
VX_CALL_(return 0, vxReleaseMatrix(&matrix));
}
}
return matrix;
}
static int warp_affine_check_pixel(CT_Image input, CT_Image output, int x, int y, vx_enum interp_type, vx_border_t border, vx_float32 *m)
{
vx_float64 x0, y0, xlower, ylower, s, t;
vx_int32 xo, yo, xi, yi, roi_xi, roi_yi, xiShft;
int candidate;
vx_df_image format = input->format;
xo = x + output->roi.x - (format == VX_DF_IMAGE_U1 ? output->roi.x % 8 : 0); // ROI independent cordinates
yo = y + output->roi.y;
roi_xi = input->roi.x;
roi_yi = input->roi.y;
xiShft = (format == VX_DF_IMAGE_U1) ? input->roi.x % 8 : 0; // Bit-shift used for U1 input image
vx_uint8 res;
if (format == VX_DF_IMAGE_U1)
res = (*CT_IMAGE_DATA_PTR_1U(output, x, y) & (1 << (x % 8))) >> (x % 8);
else
res = *CT_IMAGE_DATA_PTR_8U(output, x, y);
x0 = (vx_float64)m[2 * 0 + 0] * (vx_float64)xo + (vx_float64)m[2 * 1 + 0] * (vx_float64)yo + (vx_float64)m[2 * 2 + 0];
y0 = (vx_float64)m[2 * 0 + 1] * (vx_float64)xo + (vx_float64)m[2 * 1 + 1] * (vx_float64)yo + (vx_float64)m[2 * 2 + 1];
x0 = x0 - (vx_float64)roi_xi + xiShft; // Switch to ROI-respecting coordinates
y0 = y0 - (vx_float64)roi_yi;
if (VX_INTERPOLATION_NEAREST_NEIGHBOR == interp_type)
{
for (yi = (vx_int32)ceil(y0 - VX_NN_AREA_SIZE); (vx_float64)yi <= y0 + VX_NN_AREA_SIZE; yi++)
{
for (xi = (vx_int32)ceil(x0 - VX_NN_AREA_SIZE); (vx_float64)xi <= x0 + VX_NN_AREA_SIZE; xi++)
{
if (xi >= xiShft && yi >= 0 &&
xi < (vx_int32)input->width + xiShft && yi < (vx_int32)input->height)
{
if (format == VX_DF_IMAGE_U1)
candidate = (*CT_IMAGE_DATA_PTR_1U(input, xi, yi) & (1 << (xi % 8))) >> (xi % 8);
else
candidate = *CT_IMAGE_DATA_PTR_8U(input, xi, yi);
}
else if (VX_BORDER_CONSTANT == border.mode)
{
if (format == VX_DF_IMAGE_U1)
candidate = border.constant_value.U1 ? 1 : 0;
else
candidate = border.constant_value.U8;
}
else
{
candidate = -1;
}
if (candidate == -1 || candidate == res)
return 0;
}
}
CT_FAIL_(return 1, "Check failed for pixel (%d, %d): %d", xo, yo, (int)res);
}
else if (VX_INTERPOLATION_BILINEAR == interp_type)
{
xlower = floor(x0);
ylower = floor(y0);
s = x0 - xlower;
t = y0 - ylower;
xi = (vx_int32)xlower;
yi = (vx_int32)ylower;
candidate = -1;
if (VX_BORDER_UNDEFINED == border.mode)
{
if (xi >= xiShft && yi >= 0 &&
xi < (vx_int32)input->width - 1 + xiShft && yi < (vx_int32)input->height - 1)
{
if (format == VX_DF_IMAGE_U1)
{
vx_uint8 p00 = (*CT_IMAGE_DATA_PTR_1U(input, xi , yi ) & (1 << xi % 8)) >> ( xi % 8);
vx_uint8 p10 = (*CT_IMAGE_DATA_PTR_1U(input, xi + 1, yi ) & (1 << (xi + 1) % 8)) >> ((xi + 1) % 8);
vx_uint8 p01 = (*CT_IMAGE_DATA_PTR_1U(input, xi , yi + 1) & (1 << xi % 8)) >> ( xi % 8);
vx_uint8 p11 = (*CT_IMAGE_DATA_PTR_1U(input, xi + 1, yi + 1) & (1 << (xi + 1) % 8)) >> ((xi + 1) % 8);
candidate = (int)((1. - s) * (1. - t) * (vx_float64) p00 +
s * (1. - t) * (vx_float64) p10 +
(1. - s) * t * (vx_float64) p01 +
s * t * (vx_float64) p11 + 0.5); // Arithmetic rounding instead of truncation
candidate = (candidate > 1) ? 1 : (candidate < 0) ? 0 : candidate;
}
else
{
candidate = (int)((1. - s) * (1. - t) * (vx_float64) *CT_IMAGE_DATA_PTR_8U(input, xi , yi ) +
s * (1. - t) * (vx_float64) *CT_IMAGE_DATA_PTR_8U(input, xi + 1, yi ) +
(1. - s) * t * (vx_float64) *CT_IMAGE_DATA_PTR_8U(input, xi , yi + 1) +
s * t * (vx_float64) *CT_IMAGE_DATA_PTR_8U(input, xi + 1, yi + 1));
}
}
}
else if (VX_BORDER_CONSTANT == border.mode)
{
if (format == VX_DF_IMAGE_U1)
{
vx_uint8 p00 = CT_IMAGE_DATA_CONSTANT_1U(input, xi , yi , border.constant_value.U1);
vx_uint8 p10 = CT_IMAGE_DATA_CONSTANT_1U(input, xi + 1, yi , border.constant_value.U1);
vx_uint8 p01 = CT_IMAGE_DATA_CONSTANT_1U(input, xi , yi + 1, border.constant_value.U1);
vx_uint8 p11 = CT_IMAGE_DATA_CONSTANT_1U(input, xi + 1, yi + 1, border.constant_value.U1);
candidate = (int)((1. - s) * (1. - t) * (vx_float32)p00 +
s * (1. - t) * (vx_float32)p10 +
(1. - s) * t * (vx_float32)p01 +
s * t * (vx_float32)p11 + 0.5);
candidate = (candidate > 1) ? 1 : (candidate < 0) ? 0 : candidate;
}
else
{
vx_uint8 p00 = CT_IMAGE_DATA_CONSTANT_8U(input, xi , yi , border.constant_value.U8);
vx_uint8 p10 = CT_IMAGE_DATA_CONSTANT_8U(input, xi + 1, yi , border.constant_value.U8);
vx_uint8 p01 = CT_IMAGE_DATA_CONSTANT_8U(input, xi , yi + 1, border.constant_value.U8);
vx_uint8 p11 = CT_IMAGE_DATA_CONSTANT_8U(input, xi + 1, yi + 1, border.constant_value.U8);
candidate = (int)((1. - s) * (1. - t) * (vx_float32)p00 +
s * (1. - t) * (vx_float32)p10 +
(1. - s) * t * (vx_float32)p01 +
s * t * (vx_float32)p11);
}
}
// A tolerance of 1 would make tests on U1 images trivial
if ( candidate == -1 || (abs(candidate - res) <= ((format == VX_DF_IMAGE_U1) ? 0 : VX_BILINEAR_TOLERANCE)) )
return 0;
else
return 1;
}
CT_FAIL_(return 1, "Interpolation type undefined");
}
static void warp_affine_validate(CT_Image input, CT_Image output, vx_enum interp_type, vx_border_t border, vx_float32* m)
{
vx_uint32 err_count = 0;
if (input->format == VX_DF_IMAGE_U1)
{
CT_FILL_IMAGE_1U(, output,
{
ASSERT_NO_FAILURE(err_count += warp_affine_check_pixel(input, output, xShftd, y, interp_type, border, m));
});
}
else
{
CT_FILL_IMAGE_8U(, output,
{
ASSERT_NO_FAILURE(err_count += warp_affine_check_pixel(input, output, x, y, interp_type, border, m));
});
}
if (10 * err_count > output->width * output->height)
CT_FAIL_(return, "Check failed for %d pixels", err_count);
}
static void warp_affine_check(CT_Image input, CT_Image output, vx_enum interp_type, vx_border_t border, vx_float32* m)
{
ASSERT(input && output);
ASSERT( (interp_type == VX_INTERPOLATION_NEAREST_NEIGHBOR) ||
(interp_type == VX_INTERPOLATION_BILINEAR));
ASSERT( (border.mode == VX_BORDER_UNDEFINED) ||
(border.mode == VX_BORDER_CONSTANT));
ASSERT( (input->format == output->format) &&
(input->format == VX_DF_IMAGE_U1 || input->format == VX_DF_IMAGE_U8));
ASSERT( ((input->width == output->width) || (input->roi.width == output->roi.width)) &&
((input->height == output->height) || (input->roi.height == output->roi.height)));
warp_affine_validate(input, output, interp_type, border, m);
if (CT_HasFailure())
{
printf("=== INPUT ===\n");
ct_dump_image_info(input);
printf("=== OUTPUT ===\n");
ct_dump_image_info(output);
printf("Matrix:\n%g %g %g\n%g %g %g\n",
m[0], m[2], m[4],
m[1], m[3], m[5]);
}
}
typedef struct {
const char* testName;
CT_Image(*generator)(const char* fileName, int width, int height, vx_df_image format);
const char* fileName;
int width, height;
vx_border_t border;
vx_enum interp_type;
int matrix_type;
vx_df_image format;
} Arg;
#define ADD_VX_BORDERS_WARP_AFFINE(testArgName, nextmacro, ...) \
CT_EXPAND(nextmacro(testArgName "/VX_BORDER_UNDEFINED", __VA_ARGS__, { VX_BORDER_UNDEFINED, {{ 0 }} })), \
CT_EXPAND(nextmacro(testArgName "/VX_BORDER_CONSTANT=0", __VA_ARGS__, { VX_BORDER_CONSTANT, {{ 0 }} })), \
CT_EXPAND(nextmacro(testArgName "/VX_BORDER_CONSTANT=1", __VA_ARGS__, { VX_BORDER_CONSTANT, {{ 1 }} })), \
CT_EXPAND(nextmacro(testArgName "/VX_BORDER_CONSTANT=127", __VA_ARGS__, { VX_BORDER_CONSTANT, {{ 127 }} })), \
CT_EXPAND(nextmacro(testArgName "/VX_BORDER_CONSTANT=255", __VA_ARGS__, { VX_BORDER_CONSTANT, {{ 255 }} }))
#define ADD_VX_BORDERS_WARP_AFFINE_MINIMAL(testArgName, nextmacro, ...) \
CT_EXPAND(nextmacro(testArgName "/VX_BORDER_UNDEFINED", __VA_ARGS__, { VX_BORDER_UNDEFINED, {{ 0 }} })), \
CT_EXPAND(nextmacro(testArgName "/VX_BORDER_CONSTANT=0", __VA_ARGS__, { VX_BORDER_CONSTANT, {{ 0 }} })), \
CT_EXPAND(nextmacro(testArgName "/VX_BORDER_CONSTANT=255", __VA_ARGS__, { VX_BORDER_CONSTANT, {{ 255 }} }))
#define ADD_VX_INTERP_TYPE_WARP_AFFINE(testArgName, nextmacro, ...) \
CT_EXPAND(nextmacro(testArgName "/VX_INTERPOLATION_NEAREST_NEIGHBOR", __VA_ARGS__, VX_INTERPOLATION_NEAREST_NEIGHBOR)), \
CT_EXPAND(nextmacro(testArgName "/VX_INTERPOLATION_BILINEAR", __VA_ARGS__, VX_INTERPOLATION_BILINEAR ))
#define ADD_VX_INTERPOLATION_TYPE_NEAREST_NEIGHBOR(testArgName, nextmacro, ...) \
CT_EXPAND(nextmacro(testArgName "/VX_INTERPOLATION_NEAREST_NEIGHBOR", __VA_ARGS__, VX_INTERPOLATION_NEAREST_NEIGHBOR))
#define ADD_VX_MATRIX_PARAM_WARP_AFFINE(testArgName, nextmacro, ...) \
CT_EXPAND(nextmacro(testArgName "/VX_MATRIX_IDENT", __VA_ARGS__, VX_MATRIX_IDENT)), \
CT_EXPAND(nextmacro(testArgName "/VX_MATRIX_ROTATE_90", __VA_ARGS__, VX_MATRIX_ROTATE_90)), \
CT_EXPAND(nextmacro(testArgName "/VX_MATRIX_SCALE", __VA_ARGS__, VX_MATRIX_SCALE)), \
CT_EXPAND(nextmacro(testArgName "/VX_MATRIX_SCALE_ROTATE", __VA_ARGS__, VX_MATRIX_SCALE_ROTATE)), \
CT_EXPAND(nextmacro(testArgName "/VX_MATRIX_RANDOM", __VA_ARGS__, VX_MATRIX_RANDOM))
#define ADD_VX_MATRIX_PARAM_WARP_AFFINE_MINIMAL(testArgName, nextmacro, ...) \
CT_EXPAND(nextmacro(testArgName "/VX_MATRIX_IDENT", __VA_ARGS__, VX_MATRIX_IDENT)), \
CT_EXPAND(nextmacro(testArgName "/VX_MATRIX_SCALE_ROTATE", __VA_ARGS__, VX_MATRIX_SCALE_ROTATE)), \
CT_EXPAND(nextmacro(testArgName "/VX_MATRIX_RANDOM", __VA_ARGS__, VX_MATRIX_RANDOM))
#define PARAMETERS \
CT_GENERATE_PARAMETERS("random", ADD_SIZE_SMALL_SET, ADD_VX_BORDERS_WARP_AFFINE, ADD_VX_INTERPOLATION_TYPE_NEAREST_NEIGHBOR, ADD_VX_MATRIX_PARAM_WARP_AFFINE, ADD_TYPE_U8, ARG, warp_affine_generate_random, NULL), \
CT_GENERATE_PARAMETERS("lena", ADD_SIZE_NONE, ADD_VX_BORDERS_WARP_AFFINE, ADD_VX_INTERP_TYPE_WARP_AFFINE, ADD_VX_MATRIX_PARAM_WARP_AFFINE, ADD_TYPE_U8, ARG, warp_affine_read_image, "lena.bmp"), \
CT_GENERATE_PARAMETERS("_U1_/random", ADD_SIZE_SMALL_SET, ADD_VX_BORDERS_WARP_AFFINE_MINIMAL, ADD_VX_INTERPOLATION_TYPE_NEAREST_NEIGHBOR, ADD_VX_MATRIX_PARAM_WARP_AFFINE, ADD_TYPE_U1, ARG, warp_affine_generate_random, NULL), \
CT_GENERATE_PARAMETERS("_U1_/lena", ADD_SIZE_NONE, ADD_VX_BORDERS_WARP_AFFINE_MINIMAL, ADD_VX_INTERP_TYPE_WARP_AFFINE, ADD_VX_MATRIX_PARAM_WARP_AFFINE, ADD_TYPE_U1, ARG, warp_affine_read_image, "lena.bmp")
TEST_WITH_ARG(WarpAffine, testGraphProcessing, Arg,
PARAMETERS
)
{
vx_context context = context_->vx_context_;
vx_graph graph = 0;
vx_node node = 0;
vx_image input_image = 0, output_image = 0;
vx_matrix matrix = 0;
vx_float32 m[6];
CT_Image input = NULL, output = NULL;
vx_border_t border = arg_->border;
ASSERT_NO_FAILURE(input = arg_->generator(arg_->fileName, arg_->width, arg_->height, arg_->format));
ASSERT_NO_FAILURE(output = ct_allocate_image(input->width, input->height, input->format));
ASSERT_VX_OBJECT(input_image = ct_image_to_vx_image(input, context), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(output_image = ct_image_to_vx_image(output, context), VX_TYPE_IMAGE);
ASSERT_NO_FAILURE(warp_affine_generate_matrix(m, input->width, input->height, input->width/2, input->height/2, arg_->matrix_type));
ASSERT_VX_OBJECT(matrix = warp_affine_create_matrix(context, m), VX_TYPE_MATRIX);
ASSERT_VX_OBJECT(graph = vxCreateGraph(context), VX_TYPE_GRAPH);
ASSERT_VX_OBJECT(node = vxWarpAffineNode(graph, input_image, matrix, arg_->interp_type, output_image), VX_TYPE_NODE);
VX_CALL(vxSetNodeAttribute(node, VX_NODE_BORDER, &border, sizeof(border)));
VX_CALL(vxVerifyGraph(graph));
VX_CALL(vxProcessGraph(graph));
ASSERT_NO_FAILURE(output = ct_image_from_vx_image(output_image));
ASSERT_NO_FAILURE(warp_affine_check(input, output, arg_->interp_type, arg_->border, m));
VX_CALL(vxReleaseNode(&node));
VX_CALL(vxReleaseGraph(&graph));
VX_CALL(vxReleaseMatrix(&matrix));
VX_CALL(vxReleaseImage(&output_image));
VX_CALL(vxReleaseImage(&input_image));
ASSERT(node == 0);
ASSERT(graph == 0);
ASSERT(matrix == 0);
ASSERT(output_image == 0);
ASSERT(input_image == 0);
}
TEST_WITH_ARG(WarpAffine, testImmediateProcessing, Arg,
PARAMETERS
)
{
vx_context context = context_->vx_context_;
vx_image input_image = 0, output_image = 0;
vx_matrix matrix = 0;
vx_float32 m[6];
CT_Image input = NULL, output = NULL;
vx_border_t border = arg_->border;
ASSERT_NO_FAILURE(input = arg_->generator(arg_->fileName, arg_->width, arg_->height, arg_->format));
ASSERT_NO_FAILURE(output = ct_allocate_image(input->width, input->height, input->format));
ASSERT_VX_OBJECT(input_image = ct_image_to_vx_image(input, context), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(output_image = ct_image_to_vx_image(output, context), VX_TYPE_IMAGE);
ASSERT_NO_FAILURE(warp_affine_generate_matrix(m, input->width, input->height, input->width/2, input->height/2, arg_->matrix_type));
ASSERT_VX_OBJECT(matrix = warp_affine_create_matrix(context, m), VX_TYPE_MATRIX);
VX_CALL(vxSetContextAttribute(context, VX_CONTEXT_IMMEDIATE_BORDER, &border, sizeof(border)));
VX_CALL(vxuWarpAffine(context, input_image, matrix, arg_->interp_type, output_image));
ASSERT_NO_FAILURE(output = ct_image_from_vx_image(output_image));
ASSERT_NO_FAILURE(warp_affine_check(input, output, arg_->interp_type, arg_->border, m));
VX_CALL(vxReleaseMatrix(&matrix));
VX_CALL(vxReleaseImage(&output_image));
VX_CALL(vxReleaseImage(&input_image));
ASSERT(matrix == 0);
ASSERT(output_image == 0);
ASSERT(input_image == 0);
}
typedef struct {
const char* testName;
CT_Image (*generator)(const char* fileName, int width, int height, vx_df_image format);
const char* fileName;
int width, height;
vx_border_t border;
vx_enum interp_type;
int matrix_type;
vx_df_image format;
vx_rectangle_t region_shift;
} ValidRegionTest_Arg;
#define REGION_PARAMETERS \
CT_GENERATE_PARAMETERS("lena", ADD_SIZE_256x256, ADD_VX_BORDERS_WARP_AFFINE_MINIMAL, ADD_VX_INTERP_TYPE_WARP_AFFINE, ADD_VX_MATRIX_PARAM_WARP_AFFINE_MINIMAL, ADD_TYPE_U8, ADD_VALID_REGION_SHRINKS, ARG, warp_affine_read_image, "lena.bmp"), \
CT_GENERATE_PARAMETERS("_U1_/lena", ADD_SIZE_256x256, ADD_VX_BORDERS_WARP_AFFINE_MINIMAL, ADD_VX_INTERP_TYPE_WARP_AFFINE, ADD_VX_MATRIX_PARAM_WARP_AFFINE_MINIMAL, ADD_TYPE_U1, ADD_VALID_REGION_SHRINKS, ARG, warp_affine_read_image, "lena.bmp")
TEST_WITH_ARG(WarpAffine, testWithValidRegion, ValidRegionTest_Arg,
REGION_PARAMETERS
)
{
vx_context context = context_->vx_context_;
vx_image input_image = 0, output_image = 0;
vx_matrix matrix = 0;
vx_float32 m[6];
CT_Image input = NULL, output = NULL;
vx_border_t border = arg_->border;
vx_rectangle_t rect = {0, 0, 0, 0}, rect_shft = arg_->region_shift;
ASSERT_NO_FAILURE(input = arg_->generator(arg_->fileName, arg_->width, arg_->height, arg_->format));
ASSERT_NO_FAILURE(output = ct_allocate_image(input->width, input->height, input->format));
ASSERT_VX_OBJECT(input_image = ct_image_to_vx_image(input, context), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(output_image = ct_image_to_vx_image(output, context), VX_TYPE_IMAGE);
ASSERT_NO_FAILURE(warp_affine_generate_matrix(m, input->width, input->height, input->width/2, input->height/2, arg_->matrix_type));
ASSERT_VX_OBJECT(matrix = warp_affine_create_matrix(context, m), VX_TYPE_MATRIX);
ASSERT_NO_FAILURE(vxGetValidRegionImage(input_image, &rect));
ALTERRECTANGLE(rect, rect_shft.start_x, rect_shft.start_y, rect_shft.end_x, rect_shft.end_y);
ASSERT_NO_FAILURE(vxSetImageValidRectangle(input_image, &rect));
VX_CALL(vxSetContextAttribute(context, VX_CONTEXT_IMMEDIATE_BORDER, &border, sizeof(border)));
VX_CALL(vxuWarpAffine(context, input_image, matrix, arg_->interp_type, output_image));
ASSERT_NO_FAILURE(output = ct_image_from_vx_image(output_image));
ASSERT_NO_FAILURE(ct_adjust_roi(input, rect_shft.start_x, rect_shft.start_y, -rect_shft.end_x, -rect_shft.end_y));
ASSERT_NO_FAILURE(warp_affine_check(input, output, arg_->interp_type, border, m));
VX_CALL(vxReleaseMatrix(&matrix));
VX_CALL(vxReleaseImage(&output_image));
VX_CALL(vxReleaseImage(&input_image));
ASSERT(matrix == 0);
ASSERT(output_image == 0);
ASSERT(input_image == 0);
}
TESTCASE_TESTS(WarpAffine,
testNodeCreation,
testGraphProcessing,
testImmediateProcessing,
testWithValidRegion
)
#endif //OPENVX_USE_ENHANCED_VISION || OPENVX_CONFORMANCE_VISION