| /* |
| * 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. |
| */ |
| |
| #ifdef OPENVX_USE_ENHANCED_VISION |
| |
| #include "test_engine/test.h" |
| |
| #include <VX/vx_types.h> |
| #include <VX/vx_khr_nn.h> |
| #include <VX/vxu.h> |
| |
| #include <assert.h> |
| #include <limits.h> |
| #include <math.h> |
| #include <float.h> |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| |
| #define DEBUG_TEST_TENSOR_ENABLE_PRINTF 0 |
| #define DEBUG_TEST_TENSOR_CONTINUE_AFTER_ERROR 0 |
| #define DEBUG_TEST_TENSOR_BEYOND_FOUR_DIMS 1 |
| |
| #define TEST_TENSOR_NUM_ITERATIONS 10 |
| #define TEST_TENSOR_MIN_DIM_SZ 1 |
| #define TEST_TENSOR_MAX_DIM_SZ 20 |
| |
| #define Q78_FIXED_POINT_POSITION 8 |
| #define MAX_TENSOR_DIMS 3 |
| |
| #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
| #define MAX(a, b) ((a) < (b) ? (b) : (a)) |
| #define CLAMP(v, lower, upper) MAX((lower), MIN((v), (upper))) |
| |
| #define MIN_TOLERANCE (0.95) |
| |
| enum TestTensorDF |
| { |
| TT_Q78, |
| TT_U8 |
| }; |
| |
| static void ownUnpackFormat( |
| enum TestTensorDF fmt, |
| /*OUT*/ vx_enum * data_type, |
| /*OUT*/ vx_uint8 * fixed_point_position, |
| /*out*/ vx_size * sizeof_data_type) |
| { |
| switch(fmt) |
| { |
| case TT_Q78: |
| *data_type = VX_TYPE_INT16; |
| *fixed_point_position = Q78_FIXED_POINT_POSITION; |
| *sizeof_data_type = sizeof(vx_int16); |
| break; |
| case TT_U8: |
| *data_type = VX_TYPE_UINT8; |
| *fixed_point_position = 0; |
| *sizeof_data_type = sizeof(vx_uint8); |
| break; |
| default: |
| assert(0); |
| } |
| } |
| |
| static void ownFillRandData( |
| enum TestTensorDF fmt, |
| uint64_t * rng, |
| size_t count, |
| /*OUT*/ void * data) |
| { |
| switch(fmt) |
| { |
| case TT_Q78: |
| for(size_t i = 0; i < count; ++i) |
| ((vx_int16*)data)[i] = (vx_int16)CT_RNG_NEXT_INT(*rng, INT16_MIN, INT16_MAX+1); |
| break; |
| case TT_U8: |
| for(size_t i = 0; i < count; ++i) |
| ((vx_uint8*)data)[i] = (vx_uint8)CT_RNG_NEXT_INT(*rng, 0, UINT8_MAX+1); |
| break; |
| default: |
| assert(0); |
| } |
| } |
| |
| #define COLOR_WEIGHT_SIZE_PER_CHANNEL 256 |
| |
| static void getMinMax(const void* src, const vx_size* src_strides, const vx_size* dims, vx_size num_of_dims, |
| vx_int16 *max_value, vx_int16 *min_value) |
| { |
| vx_int16 maxVal = INT16_MIN; |
| vx_int16 minVal = INT16_MAX; |
| if (num_of_dims == 2) |
| { |
| for (vx_uint32 y = 0; y < dims[1]; y++) |
| { |
| for (vx_uint32 x = 0; x < dims[0]; x++) |
| { |
| vx_uint32 offset = y * src_strides[1] + x * src_strides[0]; |
| vx_int16 val = *(vx_int16 *)((vx_int8 *)src + offset); |
| if (val > maxVal) |
| { |
| maxVal = val; |
| } |
| if (val < minVal) |
| { |
| minVal = val; |
| } |
| } |
| } |
| *max_value = maxVal; |
| *min_value = minVal; |
| } |
| else if (num_of_dims == 3) |
| { |
| for (vx_uint32 y = 0; y < dims[2]; y++) |
| { |
| for (vx_uint32 x = 0; x < dims[1]; x++) |
| { |
| for (vx_uint32 z = 0; z < dims[0]; z++) |
| { |
| vx_uint32 offset = y * src_strides[2] + x * src_strides[1] + z * src_strides[0]; |
| vx_int16 val = *(vx_int16 *)((vx_int8 *)src + offset); |
| if (val > maxVal) |
| { |
| maxVal = val; |
| } |
| if (val < minVal) |
| { |
| minVal = val; |
| } |
| } |
| } |
| } |
| *max_value = maxVal; |
| *min_value = minVal; |
| } |
| } |
| |
| static void releaseRes(void *pData) |
| { |
| if (NULL != pData) |
| { |
| ct_free_mem(pData); |
| } |
| return; |
| } |
| |
| static vx_status calcColorWeight(vx_uint8 cn, vx_float64 gauss_color_coeff, vx_float32 **color_weight) |
| { |
| vx_float32 *tmp_weight = (vx_float32 *)ct_alloc_mem(cn * COLOR_WEIGHT_SIZE_PER_CHANNEL * sizeof(vx_float32)); |
| if (NULL == tmp_weight) |
| { |
| return VX_ERROR_NO_MEMORY; |
| } |
| |
| for (vx_int32 i = 0; i < (cn * COLOR_WEIGHT_SIZE_PER_CHANNEL); i++) |
| { |
| tmp_weight[i] = (vx_float32)exp(i * i * gauss_color_coeff); |
| } |
| |
| *color_weight = tmp_weight; |
| |
| return VX_SUCCESS; |
| } |
| |
| static vx_status calcSpaceWeight(vx_int32 diameter, vx_float64 gauss_space_coeff, vx_float32 **space_weight) |
| { |
| vx_int32 radius = diameter / 2; |
| vx_float32 *tmp_weight = (vx_float32 *)ct_alloc_mem(diameter * diameter * sizeof(vx_float32)); |
| if (NULL == tmp_weight) |
| { |
| return VX_ERROR_NO_MEMORY; |
| } |
| |
| for (vx_int32 i = -radius; i <= radius; i++) |
| { |
| vx_int32 j = -radius; |
| for (; j <= radius; j++) |
| { |
| vx_float64 r = sqrt((vx_float64)i * i + (vx_float64)j * j); |
| if (r > radius) |
| { |
| continue; |
| } |
| tmp_weight[(i + radius) * diameter + (j + radius)] = (vx_float32)exp(r * r * gauss_space_coeff); |
| } |
| } |
| |
| *space_weight = tmp_weight; |
| |
| return VX_SUCCESS; |
| } |
| |
| |
| static void ownCheckBilateralFilterResult( |
| const void * in_ptr, const vx_size * in_dims, const vx_size * in_strides, |
| enum TestTensorDF fmt, |
| vx_size dim_num, |
| int diameter, |
| float sigmaSpace, |
| float sigmaColor, |
| void * out_ptr, const vx_size * out_dims, const vx_size * out_strides, |
| vx_border_t border) |
| { |
| vx_status status = VX_SUCCESS; |
| vx_float32 tolerance = 0.0; |
| vx_float32 total_num = 0.0; |
| vx_float32 equal_num = 0.0; |
| vx_int32 y = 0, x = 0; |
| vx_int32 low_x, low_y, high_x, high_y; |
| vx_int32 radius_y, radius_x; |
| vx_float32 scale_index = 0; |
| vx_int32 radius = diameter / 2; |
| vx_enum border_mode = border.mode; |
| vx_int16 out = 0, ref = 0; |
| |
| vx_float32 *color_weight = NULL; |
| vx_float32 *space_weight = NULL; |
| vx_uint8 cn = dim_num == 2 ? 1 : 3; |
| |
| vx_float64 gauss_color_coeff = -0.5/(sigmaColor*sigmaColor); |
| vx_float64 gauss_space_coeff = -0.5/(sigmaSpace*sigmaSpace); |
| |
| if (border.mode == VX_BORDER_UNDEFINED) |
| { |
| low_x = radius; |
| high_x = (in_dims[dim_num - 2] >= radius) ? in_dims[dim_num - 2] - radius : 0; |
| low_y = radius; |
| high_y = (in_dims[dim_num - 1] >= radius) ? in_dims[dim_num - 1] - radius : 0; |
| } |
| else |
| { |
| low_x = 0; |
| high_x = in_dims[dim_num - 2]; |
| low_y = 0; |
| high_y = in_dims[dim_num - 1]; |
| } |
| |
| if (fmt == TT_Q78) |
| { |
| vx_int16 minVal = -1; |
| vx_int16 maxVal = 1; |
| getMinMax(in_ptr, in_strides, in_dims, dim_num, &maxVal, &minVal); |
| if ((vx_float32)(abs(maxVal - minVal)) < FLT_EPSILON) |
| { |
| if (dim_num == 2) |
| { |
| for (y = low_y; y < high_y; y++) |
| { |
| for (x = low_x; x < high_x; x++) |
| { |
| out = *((vx_int16 *)((vx_uint8 *)out_ptr + y * in_strides[1] + x * in_strides[0])); |
| ref = *((vx_int16 *)((vx_uint8 *)in_ptr + y * in_strides[1] + x * in_strides[0])); |
| if (out == ref) |
| { |
| equal_num += 1; |
| } |
| total_num += 1; |
| } |
| } |
| tolerance = (equal_num / total_num); |
| ASSERT(tolerance >= MIN_TOLERANCE); |
| return; |
| } |
| else if (dim_num == 3) |
| { |
| for (y = low_y; y < high_y; y++) |
| { |
| for (x = low_x; x < high_x; x++) |
| { |
| out = *(vx_int16 *)((vx_uint8 *)out_ptr + y * out_strides[2] + x * out_strides[1] + 0 * out_strides[0]); |
| ref = *(vx_int16 *)((vx_uint8 *)in_ptr + y * in_strides[2] + x * in_strides[1] + 0 * in_strides[0]); |
| if (out == ref) |
| { |
| equal_num += 1; |
| } |
| out = *(vx_int16 *)((vx_uint8 *)out_ptr + y * out_strides[2] + x * out_strides[1] + 1 * out_strides[0]); |
| ref = *(vx_int16 *)((vx_uint8 *)in_ptr + y * in_strides[2] + x * in_strides[1] + 1 * in_strides[0]); |
| if (out == ref) |
| { |
| equal_num += 1; |
| } |
| out = *(vx_int16 *)((vx_uint8 *)out_ptr + y * out_strides[2] + x * out_strides[1] + 2 * out_strides[0]); |
| ref = *(vx_int16 *)((vx_uint8 *)in_ptr + y * in_strides[2] + x * in_strides[1] + 2 * in_strides[0]); |
| if (out == ref) |
| { |
| equal_num += 1; |
| } |
| total_num += 3; |
| } |
| } |
| tolerance = (equal_num / total_num); |
| ASSERT(tolerance >= MIN_TOLERANCE); |
| return; |
| } |
| |
| ASSERT(tolerance >= MIN_TOLERANCE); |
| return; |
| } |
| |
| //calculation color weight |
| vx_int32 kExpNumBinsPerChannel = 1 << 12; |
| vx_float32 lastExpVal = 1.f; |
| vx_float32 len; |
| vx_int32 kExpNumBins; |
| len = (vx_float32)(maxVal - minVal) * cn; |
| kExpNumBins = kExpNumBinsPerChannel * cn; |
| color_weight = (vx_float32 *)ct_alloc_mem((kExpNumBins + 2) * sizeof(vx_float32)); |
| if (NULL == color_weight) |
| { |
| ASSERT(tolerance >= MIN_TOLERANCE); |
| return; |
| } |
| scale_index = kExpNumBins / len; |
| for (vx_uint32 i = 0; i < (kExpNumBins + 2); i++) |
| { |
| if (lastExpVal > 0.f) |
| { |
| vx_float64 val = i / scale_index; |
| color_weight[i] = (vx_float32)exp(val * val * gauss_color_coeff); |
| lastExpVal = color_weight[i]; |
| } |
| else |
| { |
| color_weight[i] = 0.f; |
| } |
| } |
| } |
| else if (fmt == TT_U8) |
| { |
| (void)calcColorWeight(cn, gauss_color_coeff, &color_weight); |
| } |
| status = calcSpaceWeight(diameter, gauss_space_coeff, &space_weight); |
| if (status != VX_SUCCESS) |
| { |
| releaseRes(color_weight); |
| releaseRes(space_weight); |
| } |
| |
| if (dim_num == 2) |
| { |
| for (y = low_y; y < high_y; y++) |
| { |
| for (x = low_x; x < high_x; x++) |
| { |
| vx_int16 value = 0; |
| if (fmt == TT_U8) |
| { |
| out = *((vx_uint8 *)out_ptr + y * out_strides[1] + x * out_strides[0]); |
| value = *((vx_uint8 *)in_ptr + y * in_strides[1] + x * in_strides[0]); |
| } |
| else if (fmt == TT_Q78) |
| { |
| out = *((vx_int16 *)((vx_uint8 *)out_ptr + y * out_strides[1] + x * out_strides[0])); |
| value = *((vx_int16 *)((vx_uint8 *)in_ptr + y * in_strides[1] + x * in_strides[0])); |
| } |
| |
| vx_float32 sum = 0, wsum = 0; |
| //kernel filter |
| for (radius_y = -radius; radius_y <= radius; radius_y++) |
| { |
| for (radius_x = -radius; radius_x <= radius; radius_x++) |
| { |
| vx_float64 r = sqrt((vx_float64)radius_y * radius_y + (vx_float64)radius_x * radius_x); |
| if (r > radius) |
| { |
| continue; |
| } |
| vx_int32 neighbor_x = x + radius_x; |
| vx_int32 neighbor_y = y + radius_y; |
| vx_int16 neighborVal = 0; |
| if (border_mode == VX_BORDER_REPLICATE) |
| { |
| vx_int32 tmpx = neighbor_x < 0 ? 0 : (neighbor_x >((vx_int32)in_dims[0] - 1) ? ((vx_int32)in_dims[0] - 1) : neighbor_x); |
| vx_int32 tmpy = neighbor_y < 0 ? 0 : (neighbor_y >((vx_int32)in_dims[1] - 1) ? ((vx_int32)in_dims[1] - 1) : neighbor_y); |
| if (fmt == TT_U8) |
| { |
| neighborVal = *((vx_uint8 *)in_ptr + tmpy * in_strides[1] + tmpx * in_strides[0]); |
| } |
| else if (fmt == TT_Q78) |
| { |
| neighborVal = *((vx_int16 *)((vx_uint8 *)in_ptr + tmpy * in_strides[1] + tmpx * in_strides[0])); |
| } |
| } |
| else if (border_mode == VX_BORDER_CONSTANT) |
| { |
| vx_int32 tmpx = neighbor_x < 0 ? 0 : (neighbor_x >((vx_int32)in_dims[0] - 1) ? ((vx_int32)in_dims[0] - 1) : neighbor_x); |
| vx_int32 tmpy = neighbor_y < 0 ? 0 : (neighbor_y >((vx_int32)in_dims[1] - 1) ? ((vx_int32)in_dims[1] - 1) : neighbor_y); |
| if (neighbor_x < 0 || neighbor_y < 0) |
| { |
| if (fmt == TT_U8) |
| { |
| neighborVal = border.constant_value.U8; |
| } |
| else if (fmt == TT_Q78) |
| { |
| neighborVal = border.constant_value.S16; |
| } |
| } |
| else |
| { |
| if (fmt == TT_U8) |
| { |
| neighborVal = *((vx_uint8 *)in_ptr + tmpy * in_strides[1] + tmpx * in_strides[0]); |
| } |
| else if (fmt == TT_Q78) |
| { |
| neighborVal = *((vx_int16 *)((vx_uint8 *)in_ptr + tmpy * in_strides[1] + tmpx * in_strides[0])); |
| } |
| } |
| } |
| |
| vx_float32 w = 0; |
| if (fmt == TT_U8) |
| { |
| w = space_weight[(radius_y + radius) * diameter + (radius_x + radius)] * |
| color_weight[abs(neighborVal - value)]; |
| } |
| else if (fmt == TT_Q78) |
| { |
| vx_float32 alpha = abs(neighborVal - value) * scale_index; |
| vx_int32 idx = (vx_int32)floorf(alpha); |
| alpha -= idx; |
| w = space_weight[(radius_y + radius) * diameter + (radius_x + radius)] * |
| (color_weight[idx] + alpha * (color_weight[idx + 1] - color_weight[idx])); |
| } |
| sum += neighborVal * w; |
| wsum += w; |
| } |
| } |
| |
| if (fmt == TT_U8) |
| { |
| ref = (vx_uint8)roundf(sum / wsum); |
| } |
| else if (fmt == TT_Q78) |
| { |
| ref = (vx_int16)roundf(sum / wsum); |
| } |
| |
| total_num += 1; |
| |
| if (ref == out) |
| { |
| equal_num += 1; |
| } |
| } |
| } |
| } |
| else if (dim_num == 3) |
| { |
| for (y = low_y; y < high_y; y++) |
| { |
| for (x = low_x; x < high_x; x++) |
| { |
| vx_int16 b0 = 0, g0 = 0, r0 = 0; |
| vx_int16 outb = 0, outg = 0, outr = 0; |
| if (fmt == TT_U8) |
| { |
| outb = *((vx_uint8 *)out_ptr + y * out_strides[2] + x * out_strides[1] + 0 * out_strides[0]); |
| outg = *((vx_uint8 *)out_ptr + y * out_strides[2] + x * out_strides[1] + 1 * out_strides[0]); |
| outr = *((vx_uint8 *)out_ptr + y * out_strides[2] + x * out_strides[1] + 2 * out_strides[0]); |
| b0 = *((vx_uint8 *)in_ptr + y * in_strides[2] + x * in_strides[1] + 0 * in_strides[0]); |
| g0 = *((vx_uint8 *)in_ptr + y * in_strides[2] + x * in_strides[1] + 1 * in_strides[0]); |
| r0 = *((vx_uint8 *)in_ptr + y * in_strides[2] + x * in_strides[1] + 2 * in_strides[0]); |
| } |
| else if (fmt == TT_Q78) |
| { |
| outb = *((vx_int16 *)((vx_uint8 *)out_ptr + y * out_strides[2] + x * out_strides[1] + 0 * out_strides[0])); |
| outg = *((vx_int16 *)((vx_uint8 *)out_ptr + y * out_strides[2] + x * out_strides[1] + 1 * out_strides[0])); |
| outr = *((vx_int16 *)((vx_uint8 *)out_ptr + y * out_strides[2] + x * out_strides[1] + 2 * out_strides[0])); |
| b0 = *((vx_int16 *)((vx_uint8 *)in_ptr + y * in_strides[2] + x * in_strides[1] + 0 * in_strides[0])); |
| g0 = *((vx_int16 *)((vx_uint8 *)in_ptr + y * in_strides[2] + x * in_strides[1] + 1 * in_strides[0])); |
| r0 = *((vx_int16 *)((vx_uint8 *)in_ptr + y * in_strides[2] + x * in_strides[1] + 2 * in_strides[0])); |
| } |
| vx_float32 sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0; |
| //kernel filter |
| for (radius_y = -radius; radius_y <= radius; radius_y++) |
| { |
| for (radius_x = -radius; radius_x <= radius; radius_x++) |
| { |
| vx_float64 dist = sqrt((vx_float64)radius_y * radius_y + (vx_float64)radius_x * radius_x); |
| if (dist > radius) |
| { |
| continue; |
| } |
| vx_int32 neighbor_x = x + radius_x; |
| vx_int32 neighbor_y = y + radius_y; |
| vx_int16 b = 0, g = 0, r = 0; |
| if (border_mode == VX_BORDER_REPLICATE) |
| { |
| vx_int32 tmpx = neighbor_x < 0 ? 0 : (neighbor_x >((vx_int32)in_dims[1] - 1) ? ((vx_int32)in_dims[1] - 1) : neighbor_x); |
| vx_int32 tmpy = neighbor_y < 0 ? 0 : (neighbor_y >((vx_int32)in_dims[2] - 1) ? ((vx_int32)in_dims[2] - 1) : neighbor_y); |
| if (fmt == TT_U8) |
| { |
| b = *((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 0 * in_strides[0]); |
| g = *((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 1 * in_strides[0]); |
| r = *((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 2 * in_strides[0]); |
| } |
| else if (fmt == TT_Q78) |
| { |
| b = *((vx_int16 *)((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 0 * in_strides[0])); |
| g = *((vx_int16 *)((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 1 * in_strides[0])); |
| r = *((vx_int16 *)((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 2 * in_strides[0])); |
| } |
| } |
| else if (border_mode == VX_BORDER_CONSTANT) |
| { |
| vx_int32 tmpx = neighbor_x < 0 ? 0 : (neighbor_x >((vx_int32)in_dims[1] - 1) ? ((vx_int32)in_dims[1] - 1) : neighbor_x); |
| vx_int32 tmpy = neighbor_y < 0 ? 0 : (neighbor_y >((vx_int32)in_dims[2] - 1) ? ((vx_int32)in_dims[2] - 1) : neighbor_y); |
| if (neighbor_x < 0 || neighbor_y < 0) |
| { |
| if (fmt == TT_U8) |
| { |
| b = g = r = border.constant_value.U8; |
| } |
| else if (fmt == TT_Q78) |
| { |
| b = g = r = border.constant_value.S16; |
| } |
| } |
| else |
| { |
| if (fmt == TT_U8) |
| { |
| b = *((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 0 * in_strides[0]); |
| g = *((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 1 * in_strides[0]); |
| r = *((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 2 * in_strides[0]); |
| } |
| else if (fmt == TT_Q78) |
| { |
| b = *((vx_int16 *)((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 0 * in_strides[0])); |
| g = *((vx_int16 *)((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 1 * in_strides[0])); |
| r = *((vx_int16 *)((vx_uint8 *)in_ptr + tmpy * in_strides[2] + tmpx * in_strides[1] + 2 * in_strides[0])); |
| } |
| } |
| } |
| |
| vx_float32 w = 0; |
| if (fmt == TT_U8) |
| { |
| w = space_weight[(radius_y + radius) * diameter + (radius_x + radius)] * |
| color_weight[abs(b - b0) + abs(g - g0) + abs(r - r0)]; |
| } |
| else if (fmt == TT_Q78) |
| { |
| vx_float32 alpha = (abs(b- b0) + abs(g - g0) + abs(r - r0)) * scale_index; |
| vx_int32 idx = (vx_int32)floorf(alpha); |
| alpha -= idx; |
| w = space_weight[(radius_y + radius) * diameter + (radius_x + radius)] * |
| (color_weight[idx] + alpha * (color_weight[idx + 1] - color_weight[idx])); |
| } |
| sum_b += b * w; |
| sum_g += g * w; |
| sum_r += r * w; |
| wsum += w; |
| } |
| } |
| |
| vx_int16 refb = 0, refg = 0, refr = 0; |
| if (fmt == TT_U8) |
| { |
| refb = (vx_uint8)roundf(sum_b / wsum); |
| refg = (vx_uint8)roundf(sum_g / wsum); |
| refr = (vx_uint8)roundf(sum_r / wsum); |
| } |
| else if (fmt == TT_Q78) |
| { |
| refb = (vx_int16)roundf(sum_b / wsum); |
| refg = (vx_int16)roundf(sum_g / wsum); |
| refr = (vx_int16)roundf(sum_r / wsum); |
| } |
| |
| total_num += 3; |
| |
| if (refb == outb) |
| { |
| equal_num += 1; |
| } |
| if (refg == outg) |
| { |
| equal_num += 1; |
| } |
| if (refr == outr) |
| { |
| equal_num += 1; |
| } |
| } |
| } |
| } |
| |
| tolerance = (equal_num / total_num); |
| |
| ASSERT(tolerance >= MIN_TOLERANCE); |
| |
| releaseRes(color_weight); |
| releaseRes(space_weight); |
| } |
| |
| /**************************************************************************** |
| * * |
| * Test vxBilateralFilterNode * |
| * * |
| ***************************************************************************/ |
| |
| TESTCASE(BilateralFilter, CT_VXContext, ct_setup_vx_context, 0) |
| |
| static void* bilateral_generate_random(int width, int height, int cn, enum TestTensorDF tensor_fmt) |
| { |
| vx_enum data_type = VX_TYPE_UINT8; |
| vx_uint8 fixed_point_position = 0; |
| vx_size sizeof_data_type = sizeof(vx_uint8); |
| size_t count = 0; |
| uint64_t rng; |
| { |
| uint64_t * seed = &CT()->seed_; |
| //ASSERT(!!seed); |
| CT_RNG_INIT(rng, *seed); |
| } |
| |
| ownUnpackFormat(tensor_fmt, &data_type, &fixed_point_position, &sizeof_data_type); |
| |
| count = width * height * cn; |
| void *data = ct_alloc_mem(count * sizeof_data_type); |
| if (data != NULL) |
| { |
| ownFillRandData(tensor_fmt, &rng, count, data); |
| } |
| |
| return data; |
| } |
| |
| typedef struct { |
| const char* testName; |
| void* (*generator)(int width, int height, int cn, enum TestTensorDF tensor_fmt); |
| const char* fileName; |
| vx_border_t border; |
| int width, height; |
| int cn; |
| int diameter; |
| float sigmaSpace; |
| float sigmaColor; |
| enum TestTensorDF tensor_fmt; |
| } bilateral_arg; |
| |
| #define BILATERAL_FILTER_BORDERS(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "/VX_BORDER_REPLICATE", __VA_ARGS__, { VX_BORDER_REPLICATE, {{ 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 BILATERAL_CHANNEL(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "/channel=1", __VA_ARGS__, 1)), \ |
| CT_EXPAND(nextmacro(testArgName "/channel=3", __VA_ARGS__, 3)) |
| |
| #define BILATERAL_DIAMETER(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "/diameter=5", __VA_ARGS__, 5)), \ |
| CT_EXPAND(nextmacro(testArgName "/diameter=7", __VA_ARGS__, 7)), \ |
| CT_EXPAND(nextmacro(testArgName "/diameter=9", __VA_ARGS__, 9)) \ |
| |
| #define BILATERAL_SPACE_WEIGHT(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "/sigmaSpace=10", __VA_ARGS__, 10)) |
| |
| #define BILATERAL_COLOR_WEIGHT(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "/sigmaColor=5", __VA_ARGS__, 5)) |
| |
| #define BILATERAL_FORMAT(testArgName, nextmacro, ...) \ |
| CT_EXPAND(nextmacro(testArgName "/TT_U8", __VA_ARGS__, TT_U8)), \ |
| CT_EXPAND(nextmacro(testArgName "/TT_Q78", __VA_ARGS__, TT_Q78)) |
| |
| #define BILATERAL_PARAMETERS \ |
| CT_GENERATE_PARAMETERS("randam", BILATERAL_FILTER_BORDERS, ADD_SIZE_SMALL_SET, BILATERAL_CHANNEL, BILATERAL_DIAMETER, BILATERAL_SPACE_WEIGHT, BILATERAL_COLOR_WEIGHT, BILATERAL_FORMAT, ARG, bilateral_generate_random, NULL) |
| |
| TEST_WITH_ARG(BilateralFilter, testGraphProcessing, bilateral_arg, |
| BILATERAL_PARAMETERS |
| ) |
| { |
| vx_context context = context_->vx_context_; |
| const enum TestTensorDF src_fmt = arg_->tensor_fmt; |
| const enum TestTensorDF dst_fmt = arg_->tensor_fmt; |
| assert(src_fmt == TT_Q78 || src_fmt == TT_U8); |
| assert(dst_fmt == TT_Q78 || dst_fmt == TT_U8); |
| const vx_border_t border = arg_->border; |
| const int diameter = arg_->diameter; |
| const float sigmaSpace = arg_->sigmaSpace; |
| const float sigmaColor = arg_->sigmaColor; |
| const int cn = arg_->cn; |
| const int width = arg_->width; |
| const int height = arg_->height; |
| vx_size num_of_dims = 2; |
| |
| vx_enum src_data_type = 0; |
| vx_enum dst_data_type = 0; |
| vx_uint8 src_fixed_point_position = 0; |
| vx_uint8 dst_fixed_point_position= 0; |
| vx_size src_sizeof_data_type = 1; |
| vx_size dst_sizeof_data_type = 1; |
| ownUnpackFormat(src_fmt, &src_data_type, &src_fixed_point_position, &src_sizeof_data_type); |
| ownUnpackFormat(dst_fmt, &dst_data_type, &dst_fixed_point_position, &dst_sizeof_data_type); |
| |
| if (cn == 3) |
| { |
| num_of_dims = 3; |
| } |
| |
| size_t * const tensor_dims = ct_alloc_mem(sizeof(*tensor_dims) * num_of_dims); |
| size_t * const src_tensor_strides = ct_alloc_mem(sizeof(*src_tensor_strides) * num_of_dims); |
| size_t * const dst_tensor_strides = ct_alloc_mem(sizeof(*dst_tensor_strides) * num_of_dims); |
| ASSERT(tensor_dims && src_tensor_strides && dst_tensor_strides); |
| |
| if (num_of_dims == 3) |
| { |
| tensor_dims[0] = 3; |
| tensor_dims[1] = width; |
| tensor_dims[2] = height; |
| |
| src_tensor_strides[0] = src_sizeof_data_type; |
| src_tensor_strides[1] = tensor_dims[0] * src_tensor_strides[0]; |
| src_tensor_strides[2] = tensor_dims[1] * src_tensor_strides[1]; |
| |
| dst_tensor_strides[0] = src_tensor_strides[0]; |
| dst_tensor_strides[1] = src_tensor_strides[1]; |
| dst_tensor_strides[2] = src_tensor_strides[2]; |
| } |
| else |
| { |
| tensor_dims[0] = width; |
| tensor_dims[1] = height; |
| |
| src_tensor_strides[0] = src_sizeof_data_type; |
| src_tensor_strides[1] = tensor_dims[0] * src_tensor_strides[0]; |
| |
| dst_tensor_strides[0] = src_tensor_strides[0]; |
| dst_tensor_strides[1] = src_tensor_strides[1]; |
| } |
| |
| const size_t dst_tensor_bytes = tensor_dims[num_of_dims-1] * dst_tensor_strides[num_of_dims-1]; |
| |
| vx_tensor src_tensor = vxCreateTensor(context, num_of_dims, tensor_dims, src_data_type, src_fixed_point_position); |
| vx_tensor dst_tensor = vxCreateTensor(context, num_of_dims, tensor_dims, dst_data_type, dst_fixed_point_position); |
| |
| void * const dst_data = ct_alloc_mem(dst_tensor_bytes); |
| vx_size *view_start = (vx_size *)ct_alloc_mem(num_of_dims * sizeof(vx_size)); |
| memset(view_start, 0, num_of_dims * sizeof(vx_size)); |
| |
| void *src_data = NULL; |
| src_data = arg_->generator(arg_->width, arg_->height, arg_->cn, arg_->tensor_fmt); |
| VX_CALL(vxCopyTensorPatch(src_tensor, num_of_dims, view_start, tensor_dims, src_tensor_strides, src_data, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST)); |
| vx_graph graph = vxCreateGraph(context); |
| ASSERT_VX_OBJECT(graph, VX_TYPE_GRAPH); |
| |
| vx_node node = vxBilateralFilterNode(graph, src_tensor, diameter, sigmaSpace, sigmaColor, dst_tensor); |
| |
| ASSERT_VX_OBJECT(node, VX_TYPE_NODE); |
| VX_CALL(vxSetNodeAttribute(node, VX_NODE_BORDER, &border, sizeof(border))); |
| VX_CALL(vxReleaseNode(&node)); |
| EXPECT_EQ_PTR(NULL, node); |
| |
| VX_CALL(vxVerifyGraph(graph)); |
| VX_CALL(vxProcessGraph(graph)); |
| |
| VX_CALL(vxReleaseGraph(&graph)); |
| EXPECT_EQ_PTR(NULL, graph); |
| |
| VX_CALL(vxCopyTensorPatch(dst_tensor, num_of_dims, view_start, tensor_dims, dst_tensor_strides, dst_data, VX_READ_ONLY, VX_MEMORY_TYPE_HOST)); |
| |
| ownCheckBilateralFilterResult( |
| src_data, tensor_dims, src_tensor_strides, |
| dst_fmt, |
| num_of_dims, |
| diameter, |
| sigmaSpace, |
| sigmaColor, |
| dst_data, tensor_dims, dst_tensor_strides, |
| border); |
| |
| VX_CALL(vxReleaseTensor(&src_tensor)); |
| VX_CALL(vxReleaseTensor(&dst_tensor)); |
| EXPECT_EQ_PTR(NULL, src_tensor); |
| EXPECT_EQ_PTR(NULL, dst_tensor); |
| |
| ct_free_mem(src_data); |
| ct_free_mem(dst_data); |
| ct_free_mem(view_start); |
| ct_free_mem(tensor_dims); |
| ct_free_mem(src_tensor_strides); |
| ct_free_mem(dst_tensor_strides); |
| } |
| |
| TEST_WITH_ARG(BilateralFilter, testImmediateProcessing, bilateral_arg, |
| BILATERAL_PARAMETERS |
| ) |
| { |
| vx_context context = context_->vx_context_; |
| const enum TestTensorDF src_fmt = arg_->tensor_fmt; |
| const enum TestTensorDF dst_fmt = arg_->tensor_fmt; |
| assert(src_fmt == TT_Q78 || src_fmt == TT_U8); |
| assert(dst_fmt == TT_Q78 || dst_fmt == TT_U8); |
| const vx_border_t border = arg_->border; |
| const int diameter = arg_->diameter; |
| const float sigmaSpace = arg_->sigmaSpace; |
| const float sigmaColor = arg_->sigmaColor; |
| const int cn = arg_->cn; |
| const int width = arg_->width; |
| const int height = arg_->height; |
| vx_size num_of_dims = 2; |
| |
| vx_enum src_data_type = 0; |
| vx_enum dst_data_type = 0; |
| vx_uint8 src_fixed_point_position = 0; |
| vx_uint8 dst_fixed_point_position = 0; |
| vx_size src_sizeof_data_type = 1; |
| vx_size dst_sizeof_data_type = 1; |
| ownUnpackFormat(src_fmt, &src_data_type, &src_fixed_point_position, &src_sizeof_data_type); |
| ownUnpackFormat(dst_fmt, &dst_data_type, &dst_fixed_point_position, &dst_sizeof_data_type); |
| |
| if (cn == 3) |
| { |
| num_of_dims = 3; |
| } |
| |
| size_t * const tensor_dims = ct_alloc_mem(sizeof(*tensor_dims) * num_of_dims); |
| size_t * const src_tensor_strides = ct_alloc_mem(sizeof(*src_tensor_strides) * num_of_dims); |
| size_t * const dst_tensor_strides = ct_alloc_mem(sizeof(*dst_tensor_strides) * num_of_dims); |
| ASSERT(tensor_dims && src_tensor_strides && dst_tensor_strides); |
| |
| if (num_of_dims == 3) |
| { |
| tensor_dims[0] = 3; |
| tensor_dims[1] = width; |
| tensor_dims[2] = height; |
| |
| src_tensor_strides[0] = src_sizeof_data_type; |
| src_tensor_strides[1] = tensor_dims[0] * src_tensor_strides[0]; |
| src_tensor_strides[2] = tensor_dims[1] * src_tensor_strides[1]; |
| |
| dst_tensor_strides[0] = src_tensor_strides[0]; |
| dst_tensor_strides[1] = src_tensor_strides[1]; |
| dst_tensor_strides[2] = src_tensor_strides[2]; |
| } |
| else |
| { |
| tensor_dims[0] = width; |
| tensor_dims[1] = height; |
| |
| src_tensor_strides[0] = src_sizeof_data_type; |
| src_tensor_strides[1] = tensor_dims[0] * src_tensor_strides[0]; |
| |
| dst_tensor_strides[0] = src_tensor_strides[0]; |
| dst_tensor_strides[1] = src_tensor_strides[1]; |
| } |
| |
| const size_t dst_tensor_bytes = tensor_dims[num_of_dims-1] * dst_tensor_strides[num_of_dims-1]; |
| |
| vx_tensor src_tensor = vxCreateTensor(context, num_of_dims, tensor_dims, src_data_type, src_fixed_point_position); |
| vx_tensor dst_tensor = vxCreateTensor(context, num_of_dims, tensor_dims, dst_data_type, dst_fixed_point_position); |
| |
| void * const dst_data = ct_alloc_mem(dst_tensor_bytes); |
| vx_size *view_start = (vx_size *)ct_alloc_mem(num_of_dims * sizeof(vx_size)); |
| memset(view_start, 0, num_of_dims * sizeof(vx_size)); |
| |
| void *src_data = NULL; |
| src_data = arg_->generator(arg_->width, arg_->height, arg_->cn, arg_->tensor_fmt); |
| VX_CALL(vxCopyTensorPatch(src_tensor, num_of_dims, view_start, tensor_dims, src_tensor_strides, src_data, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST)); |
| |
| VX_CALL(vxSetContextAttribute(context, VX_CONTEXT_IMMEDIATE_BORDER, &border, sizeof(border))); |
| VX_CALL(vxuBilateralFilter(context, src_tensor, diameter, sigmaSpace, sigmaColor, dst_tensor)); |
| |
| VX_CALL(vxCopyTensorPatch(dst_tensor, num_of_dims, view_start, tensor_dims, dst_tensor_strides, dst_data, VX_READ_ONLY, VX_MEMORY_TYPE_HOST)); |
| |
| ownCheckBilateralFilterResult( |
| src_data, tensor_dims, src_tensor_strides, |
| dst_fmt, |
| num_of_dims, |
| diameter, |
| sigmaSpace, |
| sigmaColor, |
| dst_data, tensor_dims, dst_tensor_strides, |
| border); |
| |
| VX_CALL(vxReleaseTensor(&src_tensor)); |
| VX_CALL(vxReleaseTensor(&dst_tensor)); |
| EXPECT_EQ_PTR(NULL, src_tensor); |
| EXPECT_EQ_PTR(NULL, dst_tensor); |
| |
| ct_free_mem(src_data); |
| ct_free_mem(dst_data); |
| ct_free_mem(view_start); |
| ct_free_mem(tensor_dims); |
| ct_free_mem(src_tensor_strides); |
| ct_free_mem(dst_tensor_strides); |
| } |
| |
| |
| |
| TEST(BilateralFilter, testNodeCreation) |
| { |
| const vx_context context = context_->vx_context_; |
| |
| const enum TestTensorDF src_fmt = TT_Q78; |
| const enum TestTensorDF dst_fmt = TT_Q78; |
| |
| const int diameter = 5; |
| const float sigmaSpace = 1; |
| const float sigmaValues = 1; |
| |
| vx_size max_dims = 0; |
| { |
| VX_CALL(vxQueryContext(context, VX_CONTEXT_MAX_TENSOR_DIMS, &max_dims, sizeof(max_dims))); |
| ASSERT(max_dims > 3); |
| if(!DEBUG_TEST_TENSOR_BEYOND_FOUR_DIMS) max_dims = 4; else max_dims = MIN(max_dims, MAX_TENSOR_DIMS); |
| } |
| |
| uint64_t rng; |
| { |
| uint64_t * seed = &CT()->seed_; |
| ASSERT(!!seed); |
| CT_RNG_INIT(rng, *seed); |
| } |
| |
| vx_enum src_data_type; |
| vx_enum dst_data_type; |
| vx_uint8 src_fixed_point_position; |
| vx_uint8 dst_fixed_point_position; |
| vx_size src_sizeof_data_type; |
| vx_size dst_sizeof_data_type; |
| ownUnpackFormat(src_fmt, &src_data_type, &src_fixed_point_position, &src_sizeof_data_type); |
| ownUnpackFormat(dst_fmt, &dst_data_type, &dst_fixed_point_position, &dst_sizeof_data_type); |
| |
| size_t * const tensor_dims = ct_alloc_mem(sizeof(*tensor_dims) * max_dims); |
| size_t * const src_tensor_strides = ct_alloc_mem(sizeof(*src_tensor_strides) * max_dims); |
| size_t * const dst_tensor_strides = ct_alloc_mem(sizeof(*dst_tensor_strides) * max_dims); |
| ASSERT(tensor_dims && src_tensor_strides && dst_tensor_strides); |
| |
| // The input data a vx_tensor. maximum 3 dimension and minimum 2. |
| for (vx_size dims = 2; dims <= max_dims; ++dims) |
| for (int iter = 0; iter < TEST_TENSOR_NUM_ITERATIONS; ++iter) |
| { |
| if (DEBUG_TEST_TENSOR_ENABLE_PRINTF) |
| { |
| printf("dims #: %zu,\titer #: %d\n", dims, iter); |
| fflush(stdout); |
| } |
| |
| for (vx_size i = 0; i < dims; ++i) |
| { |
| tensor_dims[i] = (size_t)CT_RNG_NEXT_INT(rng, TEST_TENSOR_MIN_DIM_SZ, TEST_TENSOR_MAX_DIM_SZ+1); |
| |
| src_tensor_strides[i] = i ? src_tensor_strides[i-1] * tensor_dims[i-1] : src_sizeof_data_type; |
| dst_tensor_strides[i] = i ? dst_tensor_strides[i-1] * tensor_dims[i-1] : dst_sizeof_data_type; |
| } |
| |
| vx_tensor src_tensor = vxCreateTensor(context, dims, tensor_dims, src_data_type, src_fixed_point_position); |
| vx_tensor dst_tensor = vxCreateTensor(context, dims, tensor_dims, dst_data_type, dst_fixed_point_position); |
| ASSERT_VX_OBJECT(src_tensor, VX_TYPE_TENSOR); |
| ASSERT_VX_OBJECT(dst_tensor, VX_TYPE_TENSOR); |
| |
| const size_t src_tensor_bytes = tensor_dims[dims-1] * src_tensor_strides[dims-1]; |
| const size_t dst_tensor_bytes = tensor_dims[dims-1] * dst_tensor_strides[dims-1]; |
| const size_t count = src_tensor_bytes / src_sizeof_data_type; |
| |
| if (DEBUG_TEST_TENSOR_ENABLE_PRINTF) |
| { |
| printf("\tconfig: {\n"); |
| printf("\t tensor_dims: { "); for (size_t i = 0; i < dims; ++i) { printf("%zu, ", tensor_dims[i]); } printf(" }, \n"); |
| printf("\t }\n"); |
| } |
| |
| void * const src_data = ct_alloc_mem(src_tensor_bytes); |
| void * const dst_data = ct_alloc_mem(dst_tensor_bytes); |
| ASSERT(src_data && dst_data); |
| |
| { |
| ownFillRandData(src_fmt, &rng, count, src_data); |
| |
| vx_size view_start[MAX_TENSOR_DIMS] = { 0 }; |
| VX_CALL(vxCopyTensorPatch(src_tensor, dims, view_start, tensor_dims, src_tensor_strides, src_data, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST)); |
| } |
| |
| { |
| vx_graph graph = vxCreateGraph(context); |
| ASSERT_VX_OBJECT(graph, VX_TYPE_GRAPH); |
| |
| vx_node node = vxBilateralFilterNode(graph, src_tensor, diameter, sigmaSpace, sigmaValues, dst_tensor); |
| |
| ASSERT_VX_OBJECT(node, VX_TYPE_NODE); |
| VX_CALL(vxReleaseNode(&node)); |
| EXPECT_EQ_PTR(NULL, node); |
| |
| VX_CALL(vxVerifyGraph(graph)); |
| |
| VX_CALL(vxReleaseGraph(&graph)); |
| EXPECT_EQ_PTR(NULL, graph); |
| } |
| |
| VX_CALL(vxReleaseTensor(&src_tensor)); |
| VX_CALL(vxReleaseTensor(&dst_tensor)); |
| EXPECT_EQ_PTR(NULL, src_tensor); |
| EXPECT_EQ_PTR(NULL, dst_tensor); |
| |
| ct_free_mem(src_data); |
| ct_free_mem(dst_data); |
| } |
| |
| ct_free_mem(tensor_dims); |
| ct_free_mem(src_tensor_strides); |
| ct_free_mem(dst_tensor_strides); |
| } |
| |
| TESTCASE_TESTS(BilateralFilter, |
| testNodeCreation, |
| testGraphProcessing, |
| testImmediateProcessing |
| ); |
| |
| #endif //OPENVX_USE_ENHANCED_VISION |