blob: 3a25bc49d762a5e4c486a3fa33edda9fc6a062ec [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 <stdlib.h>
#include <limits.h>
#include <VX/vx.h>
#include <VX/vxu.h>
#include "test_engine/test.h"
static void reference_mean_stddev(CT_Image src, vx_float32* _mean, vx_float32* _stddev)
{
ASSERT(src);
ASSERT(src->width > 0 && src->height > 0);
uint32_t x, y, width = src->width, height = src->height, shift_x_u1;
uint32_t npix, stride;
double sum = 0, sqsum = 0;
int format = src->format;
npix = width * height;
stride = ct_stride_bytes(src);
shift_x_u1 = src->roi.x % 8; // Bit shift for U1 images with ROIs
#define CASE_MEANSTDDEV(format, type, acctype) \
case format: \
{ \
acctype s = 0, s2 = 0; \
for ( y = 0; y < height; y++ ) \
{ \
const type* ptr = (const type*)(src->data.y + stride * y); \
for ( x = 0; x < width; x++ ) \
{ \
type val; \
if (format == VX_DF_IMAGE_U1) \
{ \
uint32_t x_shiftd = x + shift_x_u1; \
val = (ptr[x_shiftd / 8] & (1 << (x_shiftd % 8))) >> (x_shiftd % 8); \
} \
else \
{ \
val = ptr[x]; \
} \
s += val; \
s2 += (acctype)val * val; \
} \
} \
sum = (double)s; \
sqsum = (double)s2; \
} \
break
switch (format)
{
CASE_MEANSTDDEV(VX_DF_IMAGE_U1, uint8_t, uint64_t);
CASE_MEANSTDDEV(VX_DF_IMAGE_U8, uint8_t, uint64_t);
default:
FAIL("Unsupported image format: (%d)", &src->format);
}
*_mean = (vx_float32)(sum / npix);
sqsum = (sqsum / npix) - (sum / npix) * (sum / npix);
*_stddev = (vx_float32)sqrt(CT_MAX(sqsum, 0.));
}
TESTCASE(MeanStdDev, CT_VXContext, ct_setup_vx_context, 0)
typedef struct {
const char* name;
int mode;
vx_df_image format;
} format_arg;
#define MEANSTDDEV_TEST_CASE_U8(imm) { #imm, CT_##imm##_MODE, VX_DF_IMAGE_U8}
#define MEANSTDDEV_TEST_CASE_U1(imm) {"_U1_/" #imm, CT_##imm##_MODE, VX_DF_IMAGE_U1}
TEST_WITH_ARG(MeanStdDev, testOnRandom, format_arg,
MEANSTDDEV_TEST_CASE_U8(Immediate),
MEANSTDDEV_TEST_CASE_U8(Graph),
MEANSTDDEV_TEST_CASE_U1(Immediate),
MEANSTDDEV_TEST_CASE_U1(Graph),
)
{
double mean_tolerance = 1e-4;
double stddev_tolerance = 1e-4;
int format = arg_->format;
int mode = arg_->mode;
vx_image src;
CT_Image src0;
vx_node node = 0;
vx_graph graph = 0;
vx_scalar mean_s, stddev_s;
vx_context context = context_->vx_context_;
int iter, niters = 100;
uint64_t rng;
vx_float32 mean0 = 0.f, stddev0 = 0.f, mean = 0.f, stddev = 0.f;
int a = 0, b = (format == VX_DF_IMAGE_U1) ? 2 : 256;
rng = CT()->seed_;
mean_tolerance *= b;
stddev_tolerance *= b;
mean_s = vxCreateScalar(context, VX_TYPE_FLOAT32, &mean);
ASSERT_VX_OBJECT(mean_s, VX_TYPE_SCALAR);
stddev_s = vxCreateScalar(context, VX_TYPE_FLOAT32, &stddev);
ASSERT_VX_OBJECT(stddev_s, VX_TYPE_SCALAR);
for( iter = 0; iter < niters; iter++ )
{
double mean_diff, stddev_diff;
int width = ct_roundf(ct_log_rng(&rng, 0, 10));
int height = ct_roundf(ct_log_rng(&rng, 0, 10));
width = CT_MAX(width, 1);
height = CT_MAX(height, 1);
if( !ct_check_any_size() )
{
width = CT_MIN((width + 7) & -8, 640);
height = CT_MIN((height + 7) & -8, 480);
}
if (format == VX_DF_IMAGE_U1)
{
width = ((width + 7) / 8) * 8; // Width must be multiple of 8 for U1 images
}
ct_update_progress(iter, niters);
src0 = ct_allocate_ct_image_random(width, height, format, &rng, a, b);
reference_mean_stddev(src0, &mean0, &stddev0);
src = ct_image_to_vx_image(src0, context);
if( mode == CT_Immediate_MODE )
{
ASSERT_EQ_VX_STATUS(VX_SUCCESS, vxuMeanStdDev(context, src, &mean, &stddev));
}
else
{
graph = vxCreateGraph(context);
ASSERT_VX_OBJECT(graph, VX_TYPE_GRAPH);
node = vxMeanStdDevNode(graph, src, mean_s, stddev_s);
ASSERT_VX_OBJECT(node, VX_TYPE_NODE);
VX_CALL(vxVerifyGraph(graph));
VX_CALL(vxProcessGraph(graph));
VX_CALL(vxCopyScalar(mean_s, &mean, VX_READ_ONLY, VX_MEMORY_TYPE_HOST));
VX_CALL(vxCopyScalar(stddev_s, &stddev, VX_READ_ONLY, VX_MEMORY_TYPE_HOST));
}
mean_diff = fabs(mean - mean0);
stddev_diff = fabs(stddev - stddev0);
if( mean_diff > mean_tolerance ||
stddev_diff > stddev_tolerance )
{
CT_RecordFailureAtFormat("Test case %d. width=%d, height=%d,\n"
"\tExpected: mean=%.5g, stddev=%.5g\n"
"\tActual: mean=%.5g (diff=%.5g %s %.5g), stddev=%.5f (diff=%.5g %s %.5g)\n",
__FUNCTION__, __FILE__, __LINE__,
iter, width, height,
mean0, stddev0,
mean, mean_diff, mean_diff > mean_tolerance ? ">" : "<=", mean_tolerance,
stddev, stddev_diff, stddev_diff > stddev_tolerance ? ">" : "<=", stddev_tolerance);
break;
}
VX_CALL(vxReleaseImage(&src));
if(node)
VX_CALL(vxReleaseNode(&node));
if(graph)
VX_CALL(vxReleaseGraph(&graph));
ASSERT(node == 0 && graph == 0);
CT_CollectGarbage(CT_GC_IMAGE);
}
VX_CALL(vxReleaseScalar(&mean_s));
VX_CALL(vxReleaseScalar(&stddev_s));
}
typedef struct {
const char* name;
int mode;
vx_df_image format;
vx_rectangle_t region_shift;
} format_region_arg;
#define MEANSTDDEV_REGION_TEST_CASE_U8(imm, shrink) \
{ #imm "/RegionShrink=" #shrink, CT_##imm##_MODE, VX_DF_IMAGE_U8, {shrink, shrink, -shrink, -shrink}}
#define MEANSTDDEV_REGION_TEST_CASE_U1(imm, shrink) \
{"_U1_/" #imm "/RegionShrink=" #shrink, CT_##imm##_MODE, VX_DF_IMAGE_U1, {shrink, shrink, -shrink, -shrink}}
TEST_WITH_ARG(MeanStdDev, testOnRandomWithValidRegion, format_region_arg,
MEANSTDDEV_REGION_TEST_CASE_U8(Immediate, 1),
MEANSTDDEV_REGION_TEST_CASE_U8(Immediate, 7),
MEANSTDDEV_REGION_TEST_CASE_U1(Immediate, 1),
MEANSTDDEV_REGION_TEST_CASE_U1(Immediate, 7),
)
{
double mean_tolerance = 1e-4;
double stddev_tolerance = 1e-4;
int format = arg_->format;
vx_image src;
CT_Image src0;
vx_scalar mean_s, stddev_s;
vx_context context = context_->vx_context_;
int iter, niters = 100;
uint64_t rng;
vx_float32 mean0 = 0.f, stddev0 = 0.f, mean = 0.f, stddev = 0.f;
int a = 0, b = (format == VX_DF_IMAGE_U1) ? 2 : 256;
vx_rectangle_t rect = {0, 0, 0, 0}, rect_shft = arg_->region_shift;
rng = CT()->seed_;
mean_tolerance *= b;
stddev_tolerance *= b;
mean_s = vxCreateScalar(context, VX_TYPE_FLOAT32, &mean);
ASSERT_VX_OBJECT(mean_s, VX_TYPE_SCALAR);
stddev_s = vxCreateScalar(context, VX_TYPE_FLOAT32, &stddev);
ASSERT_VX_OBJECT(stddev_s, VX_TYPE_SCALAR);
for( iter = 0; iter < niters; iter++ )
{
double mean_diff, stddev_diff;
int width = ct_roundf(ct_log_rng(&rng, 0, 10));
int height = ct_roundf(ct_log_rng(&rng, 0, 10));
width = CT_MAX(width, 15); // Max region shrink is 7 on each side -> minimum size is 15
height = CT_MAX(height, 15);
if( !ct_check_any_size() )
{
width = CT_MIN((width + 7) & -8, 640);
height = CT_MIN((height + 7) & -8, 480);
}
if (format == VX_DF_IMAGE_U1)
{
width = ((width + 7) / 8) * 8; // Width must be multiple of 8 for U1 images
}
ct_update_progress(iter, niters);
ASSERT_NO_FAILURE(src0 = ct_allocate_ct_image_random(width, height, format, &rng, a, b));
ASSERT_VX_OBJECT(src = ct_image_to_vx_image(src0, context), VX_TYPE_IMAGE);
ASSERT_NO_FAILURE(ct_adjust_roi(src0, rect_shft.start_x, rect_shft.start_y, -rect_shft.end_x, -rect_shft.end_y));
reference_mean_stddev(src0, &mean0, &stddev0);
ASSERT_NO_FAILURE(vxGetValidRegionImage(src, &rect));
ALTERRECTANGLE(rect, rect_shft.start_x, rect_shft.start_y, rect_shft.end_x, rect_shft.end_y);
ASSERT_NO_FAILURE(vxSetImageValidRectangle(src, &rect));
ASSERT_EQ_VX_STATUS(VX_SUCCESS, vxuMeanStdDev(context, src, &mean, &stddev));
mean_diff = fabs(mean - mean0);
stddev_diff = fabs(stddev - stddev0);
if( mean_diff > mean_tolerance ||
stddev_diff > stddev_tolerance )
{
CT_RecordFailureAtFormat("Test case %d. width=%d, height=%d,\n"
"\tExpected: mean=%.5g, stddev=%.5g\n"
"\tActual: mean=%.5g (diff=%.5g %s %.5g), stddev=%.5f (diff=%.5g %s %.5g)\n",
__FUNCTION__, __FILE__, __LINE__,
iter, width, height,
mean0, stddev0,
mean, mean_diff, mean_diff > mean_tolerance ? ">" : "<=", mean_tolerance,
stddev, stddev_diff, stddev_diff > stddev_tolerance ? ">" : "<=", stddev_tolerance);
break;
}
VX_CALL(vxReleaseImage(&src));
CT_CollectGarbage(CT_GC_IMAGE);
}
VX_CALL(vxReleaseScalar(&mean_s));
VX_CALL(vxReleaseScalar(&stddev_s));
}
TESTCASE_TESTS(MeanStdDev, testOnRandom, testOnRandomWithValidRegion)
#endif //OPENVX_USE_ENHANCED_VISION || OPENVX_CONFORMANCE_VISION