| /* |
| * 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. |
| */ |
| |
| #include "test_engine/test.h" |
| #include <VX/vx.h> |
| #include <VX/vxu.h> |
| |
| #include <math.h> |
| #include <float.h> |
| |
| TESTCASE(Remap, CT_VXContext, ct_setup_vx_context, 0) |
| |
| TEST(Remap, testNodeCreation) |
| { |
| vx_uint32 i; |
| vx_uint32 j; |
| vx_context context = context_->vx_context_; |
| vx_image input = 0, output = 0; |
| vx_uint32 src_width; |
| vx_uint32 src_height; |
| vx_uint32 dst_width; |
| vx_uint32 dst_height; |
| vx_remap map = 0; |
| vx_enum attr_name[] = |
| { |
| VX_REMAP_SOURCE_WIDTH, |
| VX_REMAP_SOURCE_HEIGHT, |
| VX_REMAP_DESTINATION_WIDTH, |
| VX_REMAP_DESTINATION_HEIGHT |
| }; |
| vx_uint32 attr_val[4]; |
| vx_graph graph = 0; |
| vx_node node = 0; |
| vx_enum interp = VX_INTERPOLATION_NEAREST_NEIGHBOR; |
| |
| src_width = 16; |
| src_height = 32; |
| dst_width = 128; |
| dst_height = 64; |
| |
| ASSERT_VX_OBJECT(input = vxCreateImage(context, src_width, src_height, VX_DF_IMAGE_U8), VX_TYPE_IMAGE); |
| ASSERT_VX_OBJECT(output = vxCreateImage(context, dst_width, dst_height, VX_DF_IMAGE_U8), VX_TYPE_IMAGE); |
| |
| map = vxCreateRemap(context, src_width, src_height, dst_width, dst_height); |
| ASSERT_VX_OBJECT(map, VX_TYPE_REMAP); |
| |
| vx_rectangle_t rect = { 0, 0, dst_width, dst_height}; |
| vx_size stride = dst_width; |
| vx_size stride_y = sizeof(vx_coordinates2df_t) * (stride); |
| vx_size size = stride * dst_height; |
| vx_coordinates2df_t *ptr_w = ct_calloc(size, sizeof(vx_coordinates2df_t)); |
| ASSERT(ptr_w); |
| |
| for (i = 0; i < dst_height; i++) |
| { |
| for (j = 0; j < dst_width; j++) |
| { |
| vx_coordinates2df_t *coord_ptr = &(ptr_w[i * stride + j]); |
| coord_ptr->x = (vx_float32)j; |
| coord_ptr->y = (vx_float32)i; |
| } |
| } |
| |
| VX_CALL(vxCopyRemapPatch(map, &rect, stride_y, ptr_w, VX_TYPE_COORDINATES2DF, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST)); |
| ct_free_mem(ptr_w); |
| |
| graph = vxCreateGraph(context); |
| ASSERT_VX_OBJECT(graph, VX_TYPE_GRAPH); |
| |
| node = vxRemapNode(graph, input, map, interp, output); |
| ASSERT_VX_OBJECT(node, VX_TYPE_NODE); |
| VX_CALL(vxQueryRemap(map, attr_name[0], &attr_val[0], sizeof(attr_val[0]))); |
| if (attr_val[0] != src_width) |
| { |
| CT_FAIL("check for remap attribute VX_REMAP_SOURCE_WIDTH failed\n"); |
| } |
| VX_CALL(vxQueryRemap(map, attr_name[1], &attr_val[1], sizeof(attr_val[1]))); |
| if (attr_val[1] != src_height) |
| { |
| CT_FAIL("check for remap attribute VX_REMAP_SOURCE_HEIGHT failed\n"); |
| } |
| VX_CALL(vxQueryRemap(map, attr_name[2], &attr_val[2], sizeof(attr_val[2]))); |
| if (attr_val[2] != dst_width) |
| { |
| CT_FAIL("check for remap attribute VX_REMAP_DESTINATION_WIDTH failed\n"); |
| } |
| VX_CALL(vxQueryRemap(map, attr_name[3], &attr_val[3], sizeof(attr_val[3]))); |
| if (attr_val[3] != dst_height) |
| { |
| CT_FAIL("check for remap attribute VX_REMAP_DESTINATION_HEIGHT failed\n"); |
| } |
| |
| VX_CALL(vxReleaseNode(&node)); |
| VX_CALL(vxReleaseGraph(&graph)); |
| VX_CALL(vxReleaseImage(&output)); |
| VX_CALL(vxReleaseRemap(&map)); |
| VX_CALL(vxReleaseImage(&input)); |
| |
| ASSERT(node == 0); |
| ASSERT(graph == 0); |
| ASSERT(output == 0); |
| ASSERT(map == 0); |
| ASSERT(input == 0); |
| } |
| |
| #define SRC_WIDTH 128 |
| #define SRC_HEIGHT 128 |
| |
| #define VX_MAP_IDENT 0 |
| #define VX_MAP_SCALE 1 |
| #define VX_MAP_SCALE_ROTATE 2 |
| #define VX_MAP_RANDOM 3 |
| |
| #define VX_NN_AREA_SIZE 1.5 |
| #define VX_BILINEAR_TOLERANCE 1 |
| |
| static CT_Image remap_read_image_8u(const char* fileName, int width, int height) |
| { |
| CT_Image image = NULL; |
| |
| image = ct_read_image(fileName, 1); |
| ASSERT_(return 0, image); |
| ASSERT_(return 0, image->format == VX_DF_IMAGE_U8); |
| |
| return image; |
| } |
| |
| static CT_Image remap_generate_random(const char* fileName, int width, int height) |
| { |
| CT_Image image; |
| |
| ASSERT_NO_FAILURE_(return 0, |
| image = ct_allocate_ct_image_random(width, height, VX_DF_IMAGE_U8, &CT()->seed_, 0, 256)); |
| |
| return image; |
| } |
| |
| #define RND_FLT(low, high) (vx_float32)CT_RNG_NEXT_REAL(CT()->seed_, low, high); |
| |
| static vx_remap remap_generate_map(vx_context context, int src_width, int src_height, int dst_width, int dst_height, int type) |
| { |
| vx_uint32 i; |
| vx_uint32 j; |
| vx_float32 x; |
| vx_float32 y; |
| vx_remap map = 0; |
| |
| map = vxCreateRemap(context, src_width, src_height, dst_width, dst_height); |
| if (vxGetStatus((vx_reference)map) == VX_SUCCESS) |
| { |
| vx_float32 mat[3][2]; |
| vx_float32 angle, scale_x, scale_y, cos_a, sin_a; |
| if (VX_MAP_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_MAP_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_MAP_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); |
| } |
| |
| |
| vx_rectangle_t rect = { 0, 0, dst_width, dst_height}; |
| vx_size stride = dst_width; |
| vx_size stride_y = sizeof(vx_coordinates2df_t) * (stride); |
| vx_size size = stride * dst_height; |
| vx_coordinates2df_t *ptr_w = ct_calloc(size, sizeof(vx_coordinates2df_t)); |
| ASSERT_(return 0, ptr_w); |
| |
| for (i = 0; i < (vx_uint32)dst_height; i++) |
| { |
| for (j = 0; j < (vx_uint32)dst_width; j++) |
| { |
| x = j * mat[0][0] + i * mat[1][0] + mat[2][0]; |
| y = j * mat[0][1] + i * mat[1][1] + mat[2][1]; |
| vx_coordinates2df_t *coord_ptr = &(ptr_w[i * stride + j]); |
| coord_ptr->x = x; |
| coord_ptr->y = y; |
| } |
| } |
| |
| vxCopyRemapPatch(map, &rect, stride_y, ptr_w, VX_TYPE_COORDINATES2DF, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); |
| ct_free_mem(ptr_w); |
| } |
| |
| return map; |
| } |
| |
| |
| static int remap_check_pixel(CT_Image input, CT_Image output, int x, int y, vx_float32 _x0, |
| vx_float32 _y0, vx_enum interp_type, vx_border_t border, vx_remap map, vx_bool do_report) |
| { |
| vx_float64 x0, y0, xlower, ylower, s, t; |
| vx_int32 xi, yi; |
| int candidate; |
| vx_uint8 res = *CT_IMAGE_DATA_PTR_8U(output, x, y); |
| |
| x0 = (vx_float64)_x0; |
| y0 = (vx_float64)_y0; |
| |
| 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 (0 <= xi && 0 <= yi && xi < (vx_int32)input->width && yi < (vx_int32)input->height) |
| { |
| candidate = *CT_IMAGE_DATA_PTR_8U(input, xi, yi); |
| } |
| else if (VX_BORDER_CONSTANT == border.mode) |
| { |
| candidate = border.constant_value.U8; |
| } |
| else if (VX_BORDER_REPLICATE == border.mode) |
| { |
| candidate = CT_IMAGE_DATA_REPLICATE_8U(input, xi, yi); |
| } |
| else |
| { |
| candidate = -1; |
| } |
| if (candidate == -1 || candidate == res) |
| return 0; |
| } |
| } |
| if (do_report) |
| CT_FAIL_(return 1, "Check failed for pixel (%d, %d): %d", x, y, (int)res); |
| else |
| return 1; |
| } |
| 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 >= 0 && yi >= 0 && xi < (vx_int32)input->width - 1 && yi < (vx_int32)input->height - 1) |
| { |
| 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) |
| { |
| candidate = (int)((1. - s) * (1. - t) * (vx_float64)CT_IMAGE_DATA_CONSTANT_8U(input, xi , yi , border.constant_value.U8) + |
| s * (1. - t) * (vx_float64)CT_IMAGE_DATA_CONSTANT_8U(input, xi + 1, yi , border.constant_value.U8) + |
| (1. - s) * t * (vx_float64)CT_IMAGE_DATA_CONSTANT_8U(input, xi , yi + 1, border.constant_value.U8) + |
| s * t * (vx_float64)CT_IMAGE_DATA_CONSTANT_8U(input, xi + 1, yi + 1, border.constant_value.U8)); |
| } |
| else if (VX_BORDER_REPLICATE == border.mode) |
| { |
| candidate = (int)((1. - s) * (1. - t) * (vx_float64)CT_IMAGE_DATA_REPLICATE_8U(input, xi , yi ) + |
| s * (1. - t) * (vx_float64)CT_IMAGE_DATA_REPLICATE_8U(input, xi + 1, yi ) + |
| (1. - s) * t * (vx_float64)CT_IMAGE_DATA_REPLICATE_8U(input, xi , yi + 1) + |
| s * t * (vx_float64)CT_IMAGE_DATA_REPLICATE_8U(input, xi + 1, yi + 1)); |
| } |
| if (candidate == -1 || (abs(candidate - res) <= VX_BILINEAR_TOLERANCE)) |
| return 0; |
| return 1; |
| } |
| if (do_report) |
| CT_FAIL_(return 1, "Interpolation type undefined"); |
| else |
| return 1; |
| } |
| |
| static void remap_validate(CT_Image input, CT_Image output, vx_enum interp_type, vx_border_t border, vx_remap map) |
| { |
| vx_uint32 err_count = 0; |
| |
| ASSERT(output != NULL); |
| ASSERT(output->format == VX_DF_IMAGE_U8); |
| ASSERT(output->width > 0); |
| ASSERT(output->height > 0); |
| { |
| vx_rectangle_t rect = { 0, 0, output->width, output->height}; |
| vx_size stride = output->width; |
| vx_size stride_y = sizeof(vx_coordinates2df_t) * (stride); |
| vx_size size = stride * output->height; |
| vx_coordinates2df_t *ptr_r = ct_calloc(size, sizeof(vx_coordinates2df_t)); |
| ASSERT(ptr_r); |
| vxCopyRemapPatch(map, &rect, stride_y, ptr_r, VX_TYPE_COORDINATES2DF, VX_READ_ONLY, VX_MEMORY_TYPE_HOST); |
| |
| uint32_t x, y; |
| for (y = 0; y < output->height; y++) { |
| for (x = 0; x < output->width; x++) { |
| uint8_t* dst_data = CT_IMAGE_DATA_PTR_8U(output, x, y); (void)dst_data; |
| { |
| vx_coordinates2df_t *coord_ptr = &(ptr_r[y * stride + x]); |
| ASSERT_NO_FAILURE(err_count += remap_check_pixel(input, output, x, y, coord_ptr->x, coord_ptr->y, |
| interp_type, border, map, vx_true_e)); |
| } |
| } |
| } |
| ct_free_mem(ptr_r); |
| } |
| |
| if (10 * err_count > output->width * output->height) |
| CT_FAIL_(return, "Check failed for %d pixels", err_count); |
| } |
| |
| static vx_bool remap_is_equal(CT_Image input, CT_Image output, vx_enum interp_type, vx_border_t border, vx_remap map) |
| { |
| if( (output != NULL) && |
| (output->format == VX_DF_IMAGE_U8) && |
| (output->width > 0) && |
| (output->height > 0)) |
| { |
| vx_rectangle_t rect = { 0, 0, output->width, output->height}; |
| vx_size stride = output->width; |
| vx_size stride_y = sizeof(vx_coordinates2df_t) * (stride); |
| vx_size size = stride * output->height; |
| vx_coordinates2df_t *ptr_r = ct_calloc(size, sizeof(vx_coordinates2df_t)); |
| ASSERT_(return vx_false_e, ptr_r); |
| vxCopyRemapPatch(map, &rect, stride_y, ptr_r, VX_TYPE_COORDINATES2DF, VX_READ_ONLY, VX_MEMORY_TYPE_HOST); |
| |
| uint32_t x, y; |
| for (y = 0; y < output->height; y++) { |
| for (x = 0; x < output->width; x++) { |
| uint8_t* dst_data = CT_IMAGE_DATA_PTR_8U(output, x, y); (void)dst_data; |
| { |
| vx_coordinates2df_t *coord_ptr = &(ptr_r[y * stride + x]); |
| if (0 != remap_check_pixel(input, output, x, y, coord_ptr->x, coord_ptr->y, |
| interp_type, border, map, vx_false_e)) |
| { |
| ct_free_mem(ptr_r); |
| return vx_false_e; |
| } |
| } |
| } |
| } |
| ct_free_mem(ptr_r); |
| return vx_true_e; |
| } |
| else |
| { |
| return vx_false_e; |
| } |
| } |
| |
| static void remap_check(CT_Image input, CT_Image output, vx_enum interp_type, vx_border_t border, vx_remap map) |
| { |
| 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) ); |
| |
| remap_validate(input, output, interp_type, border, map); |
| if (CT_HasFailure()) |
| { |
| printf("=== INPUT ===\n"); |
| ct_dump_image_info(input); |
| printf("=== OUTPUT ===\n"); |
| ct_dump_image_info(output); |
| } |
| } |
| |
| static void remap_check_param(CT_Image input, CT_Image output, vx_enum interp_type, vx_border_t border, vx_remap map) |
| { |
| 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) || |
| (border.mode == VX_BORDER_REPLICATE) ); |
| } |
| |
| typedef struct { |
| const char* testName; |
| CT_Image(*generator)(const char* fileName, int width, int height); |
| const char* fileName; |
| int width, height; |
| vx_border_t border; |
| vx_enum border_policy; |
| vx_enum interp_type; |
| int map_type; |
| } Arg; |
| |
| #define ADD_VX_BORDERS_REMAP_FULL(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_REMAP_SMALL(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "/VX_BORDER_UNDEFINED", __VA_ARGS__, { VX_BORDER_UNDEFINED, {{ 0 }} })), \ |
| CT_EXPAND(nextmacro(testArgName "/VX_BORDER_CONSTANT=127", __VA_ARGS__, { VX_BORDER_CONSTANT, {{ 127 }} })), \ |
| CT_EXPAND(nextmacro(testArgName "/VX_BORDER_REPLICATE", __VA_ARGS__, { VX_BORDER_REPLICATE, {{ 0 }} })) |
| |
| #define ADD_VX_BORDERS_POLICY(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "/DEFAULT_TO_UNDEFINED", __VA_ARGS__, VX_BORDER_POLICY_DEFAULT_TO_UNDEFINED)), \ |
| CT_EXPAND(nextmacro(testArgName "/RETURN_ERROR", __VA_ARGS__, VX_BORDER_POLICY_RETURN_ERROR)) |
| |
| #define ADD_VX_BORDERS_NO_POLICY(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "", __VA_ARGS__, (vx_enum)0)) |
| |
| #define ADD_VX_INTERP_TYPE_REMAP(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_INTERPOLATION_TYPE_BILINEAR(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "/VX_INTERPOLATION_BILINEAR", __VA_ARGS__, VX_INTERPOLATION_BILINEAR )) |
| |
| #define ADD_VX_MAP_PARAM_REMAP_FULL(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "/VX_MAP_IDENT", __VA_ARGS__, VX_MAP_IDENT)), \ |
| CT_EXPAND(nextmacro(testArgName "/VX_MAP_SCALE", __VA_ARGS__, VX_MAP_SCALE)), \ |
| CT_EXPAND(nextmacro(testArgName "/VX_MAP_SCALE_ROTATE", __VA_ARGS__, VX_MAP_SCALE_ROTATE)), \ |
| CT_EXPAND(nextmacro(testArgName "/VX_MAP_RANDOM", __VA_ARGS__, VX_MAP_RANDOM)) |
| |
| #define ADD_VX_MAP_PARAM_REMAP_SMALL(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "/VX_MAP_IDENT", __VA_ARGS__, VX_MAP_IDENT)) |
| |
| #define REMAP_PARAMETERS \ |
| CT_GENERATE_PARAMETERS("random", ADD_SIZE_SMALL_SET, ADD_VX_BORDERS_REMAP_FULL, ADD_VX_BORDERS_NO_POLICY, ADD_VX_INTERPOLATION_TYPE_NEAREST_NEIGHBOR, ADD_VX_MAP_PARAM_REMAP_FULL, ARG, remap_generate_random, NULL), \ |
| CT_GENERATE_PARAMETERS("lena", ADD_SIZE_SMALL_SET, ADD_VX_BORDERS_REMAP_FULL, ADD_VX_BORDERS_NO_POLICY, ADD_VX_INTERP_TYPE_REMAP, ADD_VX_MAP_PARAM_REMAP_FULL, ARG, remap_read_image_8u, "lena.bmp") |
| |
| #define POLICY_PARAMETERS \ |
| CT_GENERATE_PARAMETERS("random", ADD_SIZE_SMALL_SET, ADD_VX_BORDERS_REMAP_SMALL, ADD_VX_BORDERS_POLICY, ADD_VX_INTERPOLATION_TYPE_NEAREST_NEIGHBOR, ADD_VX_MAP_PARAM_REMAP_SMALL, ARG, remap_generate_random, NULL) |
| |
| TEST_WITH_ARG(Remap, testGraphProcessing, Arg, |
| REMAP_PARAMETERS |
| ) |
| { |
| vx_context context = context_->vx_context_; |
| vx_graph graph = 0; |
| vx_node node = 0; |
| vx_image input_image = 0, output_image = 0; |
| vx_remap map = 0; |
| |
| CT_Image input = NULL, output = NULL; |
| |
| vx_border_t border = arg_->border; |
| |
| ASSERT_NO_FAILURE(input = arg_->generator(arg_->fileName, SRC_WIDTH, SRC_HEIGHT)); |
| ASSERT_NO_FAILURE(output = ct_allocate_image(arg_->width, arg_->height, VX_DF_IMAGE_U8)); |
| |
| 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_VX_OBJECT(map = remap_generate_map(context, input->width, input->height, arg_->width, arg_->height, arg_->map_type), VX_TYPE_REMAP); |
| |
| ASSERT_VX_OBJECT(graph = vxCreateGraph(context), VX_TYPE_GRAPH); |
| |
| ASSERT_VX_OBJECT(node = vxRemapNode(graph, input_image, map, 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(remap_check(input, output, arg_->interp_type, arg_->border, map)); |
| |
| VX_CALL(vxReleaseNode(&node)); |
| VX_CALL(vxReleaseGraph(&graph)); |
| VX_CALL(vxReleaseRemap(&map)); |
| VX_CALL(vxReleaseImage(&output_image)); |
| VX_CALL(vxReleaseImage(&input_image)); |
| |
| ASSERT(node == 0); |
| ASSERT(graph == 0); |
| ASSERT(map == 0); |
| ASSERT(output_image == 0); |
| ASSERT(input_image == 0); |
| } |
| |
| TEST_WITH_ARG(Remap, testImmediateProcessing, Arg, |
| REMAP_PARAMETERS |
| ) |
| { |
| vx_context context = context_->vx_context_; |
| vx_image input_image = 0, output_image = 0; |
| vx_remap map = 0; |
| |
| CT_Image input = NULL, output = NULL; |
| |
| vx_border_t border = arg_->border; |
| |
| ASSERT_NO_FAILURE(input = arg_->generator(arg_->fileName, SRC_WIDTH, SRC_HEIGHT)); |
| ASSERT_NO_FAILURE(output = ct_allocate_image(arg_->width, arg_->height, VX_DF_IMAGE_U8)); |
| |
| 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_VX_OBJECT(map = remap_generate_map(context, input->width, input->height, arg_->width, arg_->height, arg_->map_type), VX_TYPE_REMAP); |
| |
| VX_CALL(vxSetContextAttribute(context, VX_CONTEXT_IMMEDIATE_BORDER, &border, sizeof(border))); |
| |
| VX_CALL(vxuRemap(context, input_image, map, arg_->interp_type, output_image)); |
| |
| ASSERT_NO_FAILURE(output = ct_image_from_vx_image(output_image)); |
| |
| ASSERT_NO_FAILURE(remap_check(input, output, arg_->interp_type, arg_->border, map)); |
| |
| VX_CALL(vxReleaseRemap(&map)); |
| VX_CALL(vxReleaseImage(&output_image)); |
| VX_CALL(vxReleaseImage(&input_image)); |
| |
| ASSERT(map == 0); |
| ASSERT(output_image == 0); |
| ASSERT(input_image == 0); |
| } |
| |
| TEST_WITH_ARG(Remap, testImmediatePolicy, Arg, |
| POLICY_PARAMETERS |
| ) |
| { |
| vx_context context = context_->vx_context_; |
| vx_image input_image = 0, output_image = 0; |
| vx_remap map = 0; |
| |
| CT_Image input = NULL, output = NULL; |
| |
| vx_border_t border = arg_->border; |
| vx_enum border_policy = arg_->border_policy; |
| vx_enum actual_policy = border_policy; |
| |
| vx_status expected_status = VX_SUCCESS; |
| vx_status status = VX_SUCCESS; |
| vx_border_t checked_border; |
| |
| ASSERT_NO_FAILURE(input = arg_->generator(arg_->fileName, SRC_WIDTH, SRC_HEIGHT)); |
| ASSERT_NO_FAILURE(output = ct_allocate_image(arg_->width, arg_->height, VX_DF_IMAGE_U8)); |
| |
| 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_VX_OBJECT(map = remap_generate_map(context, input->width, input->height, arg_->width, arg_->height, arg_->map_type), VX_TYPE_REMAP); |
| |
| VX_CALL(vxSetContextAttribute(context, VX_CONTEXT_IMMEDIATE_BORDER, &border, sizeof(border))); |
| |
| /* Now VX_CONTEXT_IMMEDIATE_BORDER_POLICY is readonly */ |
| /* VX_CALL(vxSetContextAttribute(context, VX_CONTEXT_IMMEDIATE_BORDER_POLICY, &border_policy, sizeof(border_policy))); */ |
| VX_CALL(vxQueryContext(context, VX_CONTEXT_IMMEDIATE_BORDER_POLICY, &actual_policy, sizeof(actual_policy))); |
| border_policy = actual_policy; |
| |
| status = vxuRemap(context, input_image, map, arg_->interp_type, output_image); |
| |
| checked_border = border; |
| if (border.mode == VX_BORDER_REPLICATE) |
| { |
| checked_border.mode = VX_BORDER_UNDEFINED; |
| switch (border_policy) |
| { |
| case VX_BORDER_POLICY_DEFAULT_TO_UNDEFINED: |
| expected_status = VX_SUCCESS; |
| break; |
| case VX_BORDER_POLICY_RETURN_ERROR: |
| expected_status = VX_ERROR_NOT_SUPPORTED; |
| break; |
| default: |
| expected_status = VX_FAILURE; |
| break; |
| } |
| } |
| else |
| { |
| expected_status = VX_SUCCESS; |
| } |
| |
| if (status == VX_SUCCESS) |
| { |
| ASSERT_NO_FAILURE(output = ct_image_from_vx_image(output_image)); |
| |
| if ((border.mode == VX_BORDER_REPLICATE) && (checked_border.mode != border.mode)) |
| { |
| /* In case of VX_BORDER_POLICY_DEFAULT_TO_UNDEFINED vxu function can return VX_SUCCESS in both cases |
| * a) it supports VX_BORDER_REPLICATE, and VX_BORDER_REPLICATE actually used; |
| * b) it doesn't support VX_BORDER_REPLICATE, and VX_BORDER_UNDEFINED actually used instead. |
| * Using API we can't distingish the cases, so we must check both |
| */ |
| vx_bool equal = vx_false_e; |
| ASSERT_NO_FAILURE(remap_check_param(input, output, arg_->interp_type, border, map)); |
| equal = remap_is_equal(input, output, arg_->interp_type, border, map); |
| if (equal == vx_false_e) |
| equal = remap_is_equal(input, output, arg_->interp_type, checked_border, map); |
| if (equal == vx_false_e) |
| ASSERT_NO_FAILURE(remap_check(input, output, arg_->interp_type, border, map)); |
| } |
| else |
| { |
| ASSERT_NO_FAILURE(remap_check(input, output, arg_->interp_type, border, map)); |
| } |
| } |
| else |
| { |
| ASSERT_EQ_VX_STATUS(expected_status, status); |
| } |
| |
| VX_CALL(vxReleaseRemap(&map)); |
| VX_CALL(vxReleaseImage(&output_image)); |
| VX_CALL(vxReleaseImage(&input_image)); |
| |
| ASSERT(map == 0); |
| ASSERT(output_image == 0); |
| ASSERT(input_image == 0); |
| } |
| |
| TEST(Remap, testNodeVirtualCreation) |
| { |
| vx_context context = context_->vx_context_; |
| vx_uint32 src_width; |
| vx_uint32 src_height; |
| vx_uint32 dst_width; |
| vx_uint32 dst_height; |
| vx_remap map = 0; |
| vx_graph graph = 0; |
| |
| src_width = 16; |
| src_height = 32; |
| dst_width = 128; |
| dst_height = 64; |
| |
| graph = vxCreateGraph(context); |
| ASSERT_VX_OBJECT(graph, VX_TYPE_GRAPH); |
| |
| map = vxCreateVirtualRemap(graph, src_width, src_height, dst_width, dst_height); |
| ASSERT_VX_OBJECT(map, VX_TYPE_REMAP); |
| |
| VX_CALL(vxReleaseGraph(&graph)); |
| VX_CALL(vxReleaseRemap(&map)); |
| |
| ASSERT(graph == 0); |
| ASSERT(map == 0); |
| } |
| |
| /* ******************vxCopyRemapPatch tests*****************/ |
| TESTCASE(vxCopyRemapPatch, CT_VXContext, ct_setup_vx_context, 0) |
| |
| TEST(vxCopyRemapPatch, testCopyRandomReamp) |
| { |
| vx_context context = context_->vx_context_; |
| vx_image input_image = 0, output_image = 0; |
| vx_remap map = 0; |
| |
| CT_Image input = NULL, output = NULL; |
| |
| vx_border_t border; |
| border.mode = VX_BORDER_UNDEFINED; |
| |
| vx_size src_width = 16; |
| vx_size src_height = 32; |
| vx_size dst_width = 128; |
| vx_size dst_height = 64; |
| |
| //first: Create 'input' and 'output' images no need to have them big . |
| // Initialize 'input' with some values(preferably different for each pixel). |
| // Initialize 'output' with 0. |
| ASSERT_NO_FAILURE(input = remap_generate_random("remap", src_width, src_height)); |
| ASSERT_NO_FAILURE(output = ct_allocate_image(dst_width, dst_height, VX_DF_IMAGE_U8)); |
| |
| //second: Create a remap object and initialize the remap object with some values(copy 'WRITE'), |
| // preferably different for each cooridinate |
| // Read the remap object (copy 'READ') into a buffer different form the one use for the WRITE, and check that it's OK |
| // (if not different, the READ could do nothing and have correct result) |
| 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_VX_OBJECT(map = remap_generate_map(context, input->width, input->height, output->width, output->height, VX_MAP_IDENT), VX_TYPE_REMAP); |
| VX_CALL(vxSetContextAttribute(context, VX_CONTEXT_IMMEDIATE_BORDER, &border, sizeof(border))); |
| |
| //third: Execute a graph with a 'remap' node |
| VX_CALL(vxuRemap(context, input_image, map, VX_INTERPOLATION_NEAREST_NEIGHBOR, output_image)); |
| ASSERT_NO_FAILURE(output = ct_image_from_vx_image(output_image)); |
| |
| //fourth: Check that the content of the 'output' image is consistent with the input image |
| // and the values copied into the remap object |
| ASSERT_NO_FAILURE(remap_check(input, output, VX_INTERPOLATION_NEAREST_NEIGHBOR, border, map)); |
| |
| VX_CALL(vxReleaseRemap(&map)); |
| VX_CALL(vxReleaseImage(&output_image)); |
| VX_CALL(vxReleaseImage(&input_image)); |
| |
| ASSERT(map == 0); |
| ASSERT(output_image == 0); |
| ASSERT(input_image == 0); |
| } |
| |
| /* *****************vxMapRemapPatch tests*******************************/ |
| TESTCASE(vxMapRemapPatch, CT_VXContext, ct_setup_vx_context, 0) |
| |
| static void remap_validate_for_map(CT_Image input, CT_Image output, vx_enum interp_type, vx_border_t border, vx_remap map) |
| { |
| vx_uint32 err_count = 0; |
| |
| ASSERT(output != NULL); |
| ASSERT(output->format == VX_DF_IMAGE_U8); |
| ASSERT(output->width > 0); |
| ASSERT(output->height > 0); |
| { |
| vx_rectangle_t rect = { 0, 0, output->width, output->height}; |
| |
| vx_size map_stride_y = 0; |
| vx_coordinates2df_t *ptr_r = 0; |
| vx_map_id map_id; |
| vxMapRemapPatch(map, &rect, &map_id, &map_stride_y, (void **)&ptr_r, VX_TYPE_COORDINATES2DF, VX_READ_ONLY, VX_MEMORY_TYPE_HOST); |
| |
| uint32_t x, y; |
| for (y = 0; y < output->height; y++) { |
| for (x = 0; x < output->width; x++) { |
| uint8_t* dst_data = CT_IMAGE_DATA_PTR_8U(output, x, y); (void)dst_data; |
| { |
| vx_coordinates2df_t *coord_ptr = (vx_coordinates2df_t *)( |
| ((vx_uint8 *)ptr_r) + |
| x*sizeof(vx_coordinates2df_t) + |
| y * map_stride_y /* map in bytes */ |
| ); |
| ASSERT_NO_FAILURE(err_count += remap_check_pixel(input, output, x, y, coord_ptr->x, coord_ptr->y, |
| interp_type, border, map, vx_true_e)); |
| } |
| } |
| } |
| |
| vxUnmapRemapPatch(map, map_id); |
| } |
| |
| if (10 * err_count > output->width * output->height) |
| CT_FAIL_(return, "Check failed for %d pixels", err_count); |
| } |
| |
| TEST(vxMapRemapPatch, testMapRandomRemap) |
| { |
| vx_context context = context_->vx_context_; |
| vx_image input_image = 0, output_image = 0; |
| vx_remap map = 0; |
| |
| CT_Image input = NULL, output = NULL; |
| |
| vx_border_t border; |
| border.mode = VX_BORDER_UNDEFINED; |
| |
| vx_size src_width = 16; |
| vx_size src_height = 32; |
| vx_size dst_width = 128; |
| vx_size dst_height = 64; |
| |
| //first: Create 'input' and 'output' images no need to have them big . |
| // Initialize 'input' with some values(preferably different for each pixel). |
| // Initialize 'output' with 0. |
| ASSERT_NO_FAILURE(input = remap_generate_random("remap", src_width, src_height)); |
| ASSERT_NO_FAILURE(output = ct_allocate_image(dst_width, dst_height, VX_DF_IMAGE_U8)); |
| |
| //second: Create a remap object and initialize the remap object with some values(copy 'WRITE'), |
| // preferably different for each cooridinate |
| // Read the remap object (copy 'READ') into a buffer different form the one use for the WRITE, and check that it's OK |
| // (if not different, the READ could do nothing and have correct result) |
| 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_VX_OBJECT(map = remap_generate_map(context, input->width, input->height, output->width, output->height, VX_MAP_IDENT), VX_TYPE_REMAP); |
| VX_CALL(vxSetContextAttribute(context, VX_CONTEXT_IMMEDIATE_BORDER, &border, sizeof(border))); |
| |
| //third: Execute a graph with a 'remap' node |
| VX_CALL(vxuRemap(context, input_image, map, VX_INTERPOLATION_NEAREST_NEIGHBOR, output_image)); |
| ASSERT_NO_FAILURE(output = ct_image_from_vx_image(output_image)); |
| |
| //fourth: Check that the content of the 'output' image is consistent with the input image |
| // and the values copied into the remap object |
| ASSERT_NO_FAILURE(remap_validate_for_map(input, output, VX_INTERPOLATION_NEAREST_NEIGHBOR, border, map)); |
| |
| VX_CALL(vxReleaseRemap(&map)); |
| VX_CALL(vxReleaseImage(&output_image)); |
| VX_CALL(vxReleaseImage(&input_image)); |
| |
| ASSERT(map == 0); |
| ASSERT(output_image == 0); |
| ASSERT(input_image == 0); |
| } |
| |
| TESTCASE_TESTS(Remap, |
| testNodeCreation, |
| testGraphProcessing, |
| testImmediateProcessing, |
| testImmediatePolicy, |
| testNodeVirtualCreation |
| ) |
| |
| TESTCASE_TESTS(vxCopyRemapPatch, testCopyRandomReamp) |
| TESTCASE_TESTS(vxMapRemapPatch, testMapRandomRemap) |
| |