blob: 9cc50aa889e57b4135e20fd5d240ef214db9f937 [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 "test_engine/test.h"
#include <VX/vx.h>
#include <VX/vxu.h>
#include <string.h>
#include "shared_functions.h"
#define MAX_POINTS 100
TESTCASE(OptFlowPyrLK, CT_VXContext, ct_setup_vx_context, 0)
static vx_array own_create_keypoint_array(vx_context context, vx_size count, vx_keypoint_t* keypoints)
{
vx_array arr = 0;
ASSERT_VX_OBJECT_(return 0, arr = vxCreateArray(context, VX_TYPE_KEYPOINT, count), VX_TYPE_ARRAY);
#if 0
{
vx_size i;
vx_size stride = 0;
void* ptr = 0;
VX_CALL_(return 0, vxAccessArrayRange(arr, 0, count, &stride, &ptr, VX_WRITE_ONLY));
for (i = 0; i < count; i++)
{
vx_keypoint_t* k = (vx_keypoint_t*)(((char*)ptr) + i * stride);
memcpy(k, &keypoints[i], sizeof(vx_keypoint_t));
}
VX_CALL_(return 0, vxCommitArrayRange(arr, 0, count, ptr));
}
#else
VX_CALL_(return 0, vxAddArrayItems(arr, count, keypoints, sizeof(vx_keypoint_t)));
#endif
return arr;
}
TEST(OptFlowPyrLK, testNodeCreation)
{
vx_context context = context_->vx_context_;
vx_image src_image[2] = {0, 0};
vx_pyramid src_pyr[2] = {0, 0};
vx_keypoint_t kp[] = {
{10, 10, 1, 0, 0, 1, 0},
{20, 10, 1, 0, 0, 1, 0},
{20, 20, 1, 0, 0, 1, 0}
};
vx_array old_points_arr = 0, new_points_arr = 0;
vx_float32 eps = 0.01f;
vx_uint32 num_iter = 10;
vx_bool use_estimations = vx_true_e;
vx_scalar vx_eps = 0, vx_num_iter = 0, vx_use_estimations = 0;
vx_size winSize = 5;
vx_graph graph = 0;
vx_node src_pyr_node[2] = {0, 0}, node = 0;
ASSERT_VX_OBJECT(src_image[0] = vxCreateImage(context, 128, 128, VX_DF_IMAGE_U8), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(src_image[1] = vxCreateImage(context, 128, 128, VX_DF_IMAGE_U8), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(old_points_arr = own_create_keypoint_array(context, sizeof(kp) / sizeof(kp[0]), kp), VX_TYPE_ARRAY);
ASSERT_VX_OBJECT(new_points_arr = vxCreateArray(context, VX_TYPE_KEYPOINT, sizeof(kp) / sizeof(kp[0])), VX_TYPE_ARRAY);
ASSERT_VX_OBJECT(vx_eps = vxCreateScalar(context, VX_TYPE_FLOAT32, &eps), VX_TYPE_SCALAR);
ASSERT_VX_OBJECT(vx_num_iter = vxCreateScalar(context, VX_TYPE_UINT32, &num_iter), VX_TYPE_SCALAR);
ASSERT_VX_OBJECT(vx_use_estimations = vxCreateScalar(context, VX_TYPE_BOOL, &use_estimations), VX_TYPE_SCALAR);
ASSERT_VX_OBJECT(graph = vxCreateGraph(context), VX_TYPE_GRAPH);
ASSERT_VX_OBJECT(src_pyr[0] = vxCreateVirtualPyramid(graph, 4, VX_SCALE_PYRAMID_HALF, 0, 0, VX_DF_IMAGE_VIRT), VX_TYPE_PYRAMID);
ASSERT_VX_OBJECT(src_pyr[1] = vxCreateVirtualPyramid(graph, 4, VX_SCALE_PYRAMID_HALF, 0, 0, VX_DF_IMAGE_VIRT), VX_TYPE_PYRAMID);
ASSERT_VX_OBJECT(src_pyr_node[0] = vxGaussianPyramidNode(graph, src_image[0], src_pyr[0]), VX_TYPE_NODE);
ASSERT_VX_OBJECT(src_pyr_node[1] = vxGaussianPyramidNode(graph, src_image[1], src_pyr[1]), VX_TYPE_NODE);
ASSERT_VX_OBJECT(node = vxOpticalFlowPyrLKNode(graph, src_pyr[0], src_pyr[1],
old_points_arr, old_points_arr, new_points_arr,
VX_TERM_CRITERIA_BOTH, vx_eps, vx_num_iter, vx_use_estimations,
winSize), VX_TYPE_NODE);
VX_CALL(vxVerifyGraph(graph));
VX_CALL(vxProcessGraph(graph));
VX_CALL(vxReleaseNode(&node));
VX_CALL(vxReleaseNode(&src_pyr_node[0]));
VX_CALL(vxReleaseNode(&src_pyr_node[1]));
VX_CALL(vxReleaseGraph(&graph));
VX_CALL(vxReleaseScalar(&vx_eps));
VX_CALL(vxReleaseScalar(&vx_num_iter));
VX_CALL(vxReleaseScalar(&vx_use_estimations));
VX_CALL(vxReleaseArray(&old_points_arr));
VX_CALL(vxReleaseArray(&new_points_arr));
VX_CALL(vxReleasePyramid(&src_pyr[0]));
VX_CALL(vxReleasePyramid(&src_pyr[1]));
VX_CALL(vxReleaseImage(&src_image[0]));
VX_CALL(vxReleaseImage(&src_image[1]));
}
static CT_Image optflow_pyrlk_read_image(const char* fileName, int width, int height)
{
CT_Image image = NULL;
ASSERT_(return 0, width == 0 && height == 0);
image = ct_read_image(fileName, 1);
ASSERT_(return 0, image);
ASSERT_(return 0, image->format == VX_DF_IMAGE_U8);
return image;
}
static vx_size own_read_keypoints(const char* fileName, vx_keypoint_t** p_old_points, vx_keypoint_t** p_new_points)
{
size_t sz = 0;
void* buf = 0;
char file[MAXPATHLENGTH];
sz = snprintf(file, MAXPATHLENGTH, "%s/%s", ct_get_test_file_path(), fileName);
ASSERT_(return 0, (sz < MAXPATHLENGTH));
#if 1
FILE* f = fopen(file, "rb");
ASSERT_(return 0, f);
fseek(f, 0, SEEK_END);
sz = ftell(f);
fseek(f, 0, SEEK_SET);
ASSERT_(return 0, buf = ct_alloc_mem(sz + 1));
ASSERT_(return 0, sz == fread(buf, 1, sz, f));
fclose(f); f = NULL;
((char*)buf)[sz] = 0;
#else
sz = ...
buf = ...
#endif
ASSERT_(return 0, *p_old_points = ct_alloc_mem(sizeof(vx_keypoint_t) * MAX_POINTS));
ASSERT_(return 0, *p_new_points = ct_alloc_mem(sizeof(vx_keypoint_t) * MAX_POINTS));
{
int num = 0;
char* pos = buf;
char* next = 0;
while(pos && (next = strchr(pos, '\n')))
{
int id = 0, status = 0;
float x1, y1, x2, y2;
int res;
*next = 0;
res = sscanf(pos, "%d %d %g %g %g %g", &id, &status, &x1, &y1, &x2, &y2);
pos = next + 1;
if (res == 6)
{
(*p_old_points)[num].x = (vx_int32)x1;
(*p_old_points)[num].y = (vx_int32)y1;
(*p_old_points)[num].strength = 1;
(*p_old_points)[num].scale = 0;
(*p_old_points)[num].orientation = 0;
(*p_old_points)[num].tracking_status = 1;
(*p_old_points)[num].error = 0;
(*p_new_points)[num].x = (vx_int32)x2;
(*p_new_points)[num].y = (vx_int32)y2;
(*p_new_points)[num].strength = 1;
(*p_new_points)[num].scale = 0;
(*p_new_points)[num].orientation = 0;
(*p_new_points)[num].tracking_status = status;
(*p_new_points)[num].error = 0;
num++;
}
else
break;
}
ct_free_mem(buf);
return num;
}
}
static void own_keypoints_check(vx_size num_points,
vx_keypoint_t* old_points, vx_keypoint_t* new_points_ref, vx_keypoint_t* new_points)
{
vx_size i;
int num_valid_points = 0;
int num_lost = 0;
int num_errors = 0;
int num_tracked_points = 0;
for (i = 0; i < num_points; i++)
{
vx_int32 dx, dy;
if (new_points_ref[i].tracking_status == 0)
continue;
num_valid_points++;
if (new_points[i].tracking_status == 0)
{
num_lost++;
continue;
}
num_tracked_points++;
dx = new_points_ref[i].x - new_points[i].x;
dy = new_points_ref[i].y - new_points[i].y;
if ((dx * dx + dy * dy) > 2 * 2)
{
num_errors++;
}
}
if (num_lost > (int)(num_valid_points * 0.05f))
CT_ADD_FAILURE("Too many lost points: %d (threshold %d)\n",
num_lost, (int)(num_valid_points * 0.05f));
if (num_errors > (int)(num_tracked_points * 0.10f))
CT_ADD_FAILURE("Too many bad points: %d (threshold %d, both tracked points %d)\n",
num_errors, (int)(num_tracked_points * 0.10f), num_tracked_points);
#if 0
if (CT_HasFailure())
{
for (i = 0; i < num_points; i++)
{
printf("i=%d status = %d->%d x = %d -> %d ? %d y = %d -> %d ? %d\n", (int)i,
new_points_ref[i].tracking_status, new_points[i].tracking_status,
old_points[i].x, new_points_ref[i].x, new_points[i].x,
old_points[i].y, new_points_ref[i].y, new_points[i].y);
}
}
#endif
}
typedef struct {
const char* testName;
CT_Image (*generator)(const char* fileName, int width, int height);
const char* src1_fileName;
const char* src2_fileName;
const char* points_fileName;
vx_size winSize;
int useReferencePyramid;
} Arg;
#define PARAMETERS \
ARG("case1/5x5/ReferencePyramid", optflow_pyrlk_read_image, "optflow_00.bmp", "optflow_01.bmp", "optflow_pyrlk_5x5.txt", 5, 1), \
ARG("case1/9x9/ReferencePyramid", optflow_pyrlk_read_image, "optflow_00.bmp", "optflow_01.bmp", "optflow_pyrlk_9x9.txt", 9, 1), \
ARG("DISABLED_case1/5x5", optflow_pyrlk_read_image, "optflow_00.bmp", "optflow_01.bmp", "optflow_pyrlk_5x5.txt", 5, 0), \
ARG("DISABLED_case1/9x9", optflow_pyrlk_read_image, "optflow_00.bmp", "optflow_01.bmp", "optflow_pyrlk_9x9.txt", 9, 0), \
TEST_WITH_ARG(OptFlowPyrLK, testGraphProcessing, Arg,
PARAMETERS
)
{
vx_context context = context_->vx_context_;
vx_image src_image[2] = { 0, 0 };
vx_pyramid src_pyr[2] = { 0, 0 };
vx_array old_points_arr = 0;
vx_array new_points_arr = 0;
vx_float32 eps_val = 0.001f;
vx_uint32 num_iter_val = 100;
vx_bool use_estimations_val = vx_true_e;
vx_scalar eps = 0;
vx_scalar num_iter = 0;
vx_scalar use_estimations = 0;
vx_size winSize = arg_->winSize;
vx_graph graph = 0;
vx_node src_pyr_node[2] = { 0, 0 };
vx_node node = 0;
vx_size num_points = 0;
vx_keypoint_t* old_points = 0;
vx_keypoint_t* new_points_ref = 0;
vx_keypoint_t* new_points = 0;
vx_size new_points_size = 0;
vx_size max_window_dim = 0;
CT_Image src_ct_image[2] = {0, 0};
VX_CALL(vxQueryContext(context, VX_CONTEXT_OPTICAL_FLOW_MAX_WINDOW_DIMENSION, &max_window_dim, sizeof(max_window_dim)));
if (winSize > max_window_dim)
{
printf("%d window dim is not supported. Skip test\n", (int)winSize);
return;
}
ASSERT_NO_FAILURE(src_ct_image[0] = arg_->generator(arg_->src1_fileName, 0, 0));
ASSERT_NO_FAILURE(src_ct_image[1] = arg_->generator(arg_->src2_fileName, 0, 0));
ASSERT_VX_OBJECT(src_image[0] = ct_image_to_vx_image(src_ct_image[0], context), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(src_image[1] = ct_image_to_vx_image(src_ct_image[1], context), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(src_pyr[0] = vxCreatePyramid(context, 4, VX_SCALE_PYRAMID_HALF, src_ct_image[0]->width, src_ct_image[0]->height, VX_DF_IMAGE_U8), VX_TYPE_PYRAMID);
ASSERT_VX_OBJECT(src_pyr[1] = vxCreatePyramid(context, 4, VX_SCALE_PYRAMID_HALF, src_ct_image[0]->width, src_ct_image[0]->height, VX_DF_IMAGE_U8), VX_TYPE_PYRAMID);
ASSERT_NO_FAILURE(num_points = own_read_keypoints(arg_->points_fileName, &old_points, &new_points_ref));
ASSERT_VX_OBJECT(old_points_arr = own_create_keypoint_array(context, num_points, old_points), VX_TYPE_ARRAY);
ASSERT_VX_OBJECT(new_points_arr = vxCreateArray(context, VX_TYPE_KEYPOINT, num_points), VX_TYPE_ARRAY);
ASSERT_VX_OBJECT(eps = vxCreateScalar(context, VX_TYPE_FLOAT32, &eps_val), VX_TYPE_SCALAR);
ASSERT_VX_OBJECT(num_iter = vxCreateScalar(context, VX_TYPE_UINT32, &num_iter_val), VX_TYPE_SCALAR);
ASSERT_VX_OBJECT(use_estimations = vxCreateScalar(context, VX_TYPE_BOOL, &use_estimations_val), VX_TYPE_SCALAR);
ASSERT_VX_OBJECT(graph = vxCreateGraph(context), VX_TYPE_GRAPH);
if (arg_->useReferencePyramid)
{
vx_border_t border = { VX_BORDER_REPLICATE };
ASSERT_NO_FAILURE(gaussian_pyramid_fill_reference(src_ct_image[0], src_pyr[0], 4, VX_SCALE_PYRAMID_HALF, border));
ASSERT_NO_FAILURE(gaussian_pyramid_fill_reference(src_ct_image[1], src_pyr[1], 4, VX_SCALE_PYRAMID_HALF, border));
}
else
{
#if 0
ASSERT_VX_OBJECT(src_pyr_node[0] = vxGaussianPyramidNode(graph, src_image[0], src_pyr[0]), VX_TYPE_NODE);
ASSERT_VX_OBJECT(src_pyr_node[1] = vxGaussianPyramidNode(graph, src_image[1], src_pyr[1]), VX_TYPE_NODE);
#else
VX_CALL(vxuGaussianPyramid(context, src_image[0], src_pyr[0]));
VX_CALL(vxuGaussianPyramid(context, src_image[1], src_pyr[1]));
#endif
}
ASSERT_VX_OBJECT(node = vxOpticalFlowPyrLKNode(
graph,
src_pyr[0], src_pyr[1],
old_points_arr, old_points_arr, new_points_arr,
VX_TERM_CRITERIA_BOTH, eps, num_iter, use_estimations, winSize), VX_TYPE_NODE);
VX_CALL(vxVerifyGraph(graph));
VX_CALL(vxProcessGraph(graph));
VX_CALL(vxProcessGraph(graph)); // it is ok to call processing twice, isn't it?
ASSERT(VX_TYPE_KEYPOINT == ct_read_array(new_points_arr, (void**)&new_points, 0, &new_points_size, 0));
ASSERT(new_points_size == num_points);
ASSERT_NO_FAILURE(own_keypoints_check(num_points, old_points, new_points_ref, new_points));
ct_free_mem(new_points);
ct_free_mem(new_points_ref);
ct_free_mem(old_points);
VX_CALL(vxReleaseNode(&node));
if(src_pyr_node[0])
VX_CALL(vxReleaseNode(&src_pyr_node[0]));
if(src_pyr_node[1])
VX_CALL(vxReleaseNode(&src_pyr_node[1]));
VX_CALL(vxReleaseGraph(&graph));
VX_CALL(vxReleaseScalar(&eps));
VX_CALL(vxReleaseScalar(&num_iter));
VX_CALL(vxReleaseScalar(&use_estimations));
VX_CALL(vxReleaseArray(&old_points_arr));
VX_CALL(vxReleaseArray(&new_points_arr));
VX_CALL(vxReleasePyramid(&src_pyr[0]));
VX_CALL(vxReleasePyramid(&src_pyr[1]));
VX_CALL(vxReleaseImage(&src_image[0]));
VX_CALL(vxReleaseImage(&src_image[1]));
}
TEST_WITH_ARG(OptFlowPyrLK, testImmediateProcessing, Arg,
PARAMETERS
)
{
vx_context context = context_->vx_context_;
vx_image src_image[2] = {0, 0};
vx_pyramid src_pyr[2] = {0, 0};
vx_array old_points_arr = 0;
vx_array new_points_arr = 0;
vx_float32 eps_val = 0.001f;
vx_uint32 num_iter_val = 100;
vx_bool use_estimations_val = vx_true_e;
vx_scalar eps = 0;
vx_scalar num_iter = 0;
vx_scalar use_estimations = 0;
vx_size winSize = arg_->winSize;
vx_size num_points = 0;
vx_keypoint_t* old_points = 0;
vx_keypoint_t* new_points_ref = 0;
vx_keypoint_t* new_points = 0;
vx_size new_points_size = 0;
vx_size max_window_dim = 0;
CT_Image src_ct_image[2] = {0, 0};
VX_CALL(vxQueryContext(context, VX_CONTEXT_OPTICAL_FLOW_MAX_WINDOW_DIMENSION, &max_window_dim, sizeof(max_window_dim)));
if (winSize > max_window_dim)
{
printf("%d window dim is not supported. Skip test\n", (int)winSize);
return;
}
ASSERT_NO_FAILURE(src_ct_image[0] = arg_->generator(arg_->src1_fileName, 0, 0));
ASSERT_NO_FAILURE(src_ct_image[1] = arg_->generator(arg_->src2_fileName, 0, 0));
ASSERT_VX_OBJECT(src_image[0] = ct_image_to_vx_image(src_ct_image[0], context), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(src_image[1] = ct_image_to_vx_image(src_ct_image[1], context), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(src_pyr[0] = vxCreatePyramid(context, 4, VX_SCALE_PYRAMID_HALF, src_ct_image[0]->width, src_ct_image[0]->height, VX_DF_IMAGE_U8), VX_TYPE_PYRAMID);
ASSERT_VX_OBJECT(src_pyr[1] = vxCreatePyramid(context, 4, VX_SCALE_PYRAMID_HALF, src_ct_image[0]->width, src_ct_image[0]->height, VX_DF_IMAGE_U8), VX_TYPE_PYRAMID);
ASSERT_NO_FAILURE(num_points = own_read_keypoints(arg_->points_fileName, &old_points, &new_points_ref));
ASSERT_VX_OBJECT(old_points_arr = own_create_keypoint_array(context, num_points, old_points), VX_TYPE_ARRAY);
ASSERT_VX_OBJECT(new_points_arr = vxCreateArray(context, VX_TYPE_KEYPOINT, num_points), VX_TYPE_ARRAY);
ASSERT_VX_OBJECT(eps = vxCreateScalar(context, VX_TYPE_FLOAT32, &eps_val), VX_TYPE_SCALAR);
ASSERT_VX_OBJECT(num_iter = vxCreateScalar(context, VX_TYPE_UINT32, &num_iter_val), VX_TYPE_SCALAR);
ASSERT_VX_OBJECT(use_estimations = vxCreateScalar(context, VX_TYPE_BOOL, &use_estimations_val), VX_TYPE_SCALAR);
if (arg_->useReferencePyramid)
{
vx_border_t border = { VX_BORDER_REPLICATE };
ASSERT_NO_FAILURE(gaussian_pyramid_fill_reference(src_ct_image[0], src_pyr[0], 4, VX_SCALE_PYRAMID_HALF, border));
ASSERT_NO_FAILURE(gaussian_pyramid_fill_reference(src_ct_image[1], src_pyr[1], 4, VX_SCALE_PYRAMID_HALF, border));
}
else
{
VX_CALL(vxuGaussianPyramid(context, src_image[0], src_pyr[0]));
VX_CALL(vxuGaussianPyramid(context, src_image[1], src_pyr[1]));
}
VX_CALL(vxuOpticalFlowPyrLK(
context,
src_pyr[0], src_pyr[1],
old_points_arr, old_points_arr, new_points_arr,
VX_TERM_CRITERIA_BOTH, eps, num_iter, use_estimations, winSize));
ASSERT(VX_TYPE_KEYPOINT == ct_read_array(new_points_arr, (void**)&new_points, 0, &new_points_size, 0));
ASSERT(new_points_size == num_points);
ASSERT_NO_FAILURE(own_keypoints_check(num_points, old_points, new_points_ref, new_points));
ct_free_mem(new_points);
ct_free_mem(new_points_ref);
ct_free_mem(old_points);
VX_CALL(vxReleaseScalar(&eps));
VX_CALL(vxReleaseScalar(&num_iter));
VX_CALL(vxReleaseScalar(&use_estimations));
VX_CALL(vxReleaseArray(&old_points_arr));
VX_CALL(vxReleaseArray(&new_points_arr));
VX_CALL(vxReleasePyramid(&src_pyr[0]));
VX_CALL(vxReleasePyramid(&src_pyr[1]));
VX_CALL(vxReleaseImage(&src_image[0]));
VX_CALL(vxReleaseImage(&src_image[1]));
}
TESTCASE_TESTS(OptFlowPyrLK,
testNodeCreation,
testGraphProcessing,
testImmediateProcessing
)
#endif //OPENVX_USE_ENHANCED_VISION || OPENVX_CONFORMANCE_VISION