Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3352 lines
104 KiB
3352 lines
104 KiB
/*M/////////////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
|
// |
|
// By downloading, copying, installing or using the software you agree to this license. |
|
// If you do not agree to this license, do not download, install, |
|
// copy or use the software. |
|
// |
|
// |
|
// Intel License Agreement |
|
// For Open Source Computer Vision Library |
|
// |
|
// Copyright (C) 2000, Intel Corporation, all rights reserved. |
|
// Third party copyrights are property of their respective owners. |
|
// |
|
// Redistribution and use in source and binary forms, with or without modification, |
|
// are permitted provided that the following conditions are met: |
|
// |
|
// * Redistribution's of source code must retain the above copyright notice, |
|
// this list of conditions and the following disclaimer. |
|
// |
|
// * Redistribution's in binary form must reproduce the above copyright notice, |
|
// this list of conditions and the following disclaimer in the documentation |
|
// and/or other materials provided with the distribution. |
|
// |
|
// * The name of Intel Corporation may not be used to endorse or promote products |
|
// derived from this software without specific prior written permission. |
|
// |
|
// This software is provided by the copyright holders and contributors "as is" and |
|
// any express or implied warranties, including, but not limited to, the implied |
|
// warranties of merchantability and fitness for a particular purpose are disclaimed. |
|
// In no event shall the Intel Corporation or contributors be liable for any direct, |
|
// indirect, incidental, special, exemplary, or consequential damages |
|
// (including, but not limited to, procurement of substitute goods or services; |
|
// loss of use, data, or profits; or business interruption) however caused |
|
// and on any theory of liability, whether in contract, strict liability, |
|
// or tort (including negligence or otherwise) arising in any way out of |
|
// the use of this software, even if advised of the possibility of such damage. |
|
// |
|
//M*/ |
|
|
|
////////////////////////////////////////////////////////////////////////////////////////// |
|
/////////////////// tests for matrix operations and math functions /////////////////////// |
|
////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
#include "cxcoretest.h" |
|
#include <float.h> |
|
#include <math.h> |
|
|
|
/// !!! NOTE !!! These tests happily avoid overflow cases & out-of-range arguments |
|
/// so that output arrays contain neigher Inf's nor Nan's. |
|
/// Handling such cases would require special modification of check function |
|
/// (validate_test_results) => TBD. |
|
/// Also, need some logarithmic-scale generation of input data. Right now it is done (in some tests) |
|
/// by generating min/max boundaries for random data in logarimithic scale, but |
|
/// within the same test case all the input array elements are of the same order. |
|
|
|
static const CvSize math_sizes[] = {{10,1}, {100,1}, {10000,1}, {-1,-1}}; |
|
static const int math_depths[] = { CV_32F, CV_64F, -1 }; |
|
static const char* math_param_names[] = { "size", "depth", 0 }; |
|
|
|
static const CvSize matrix_sizes[] = {{3,3}, {4,4}, {10,10}, {30,30}, {100,100}, {500,500}, {-1,-1}}; |
|
|
|
class CxCore_MathTestImpl : public CvArrTest |
|
{ |
|
public: |
|
CxCore_MathTestImpl( const char* test_name, const char* test_funcs ); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
double get_success_error_level( int /*test_case_idx*/, int i, int j ); |
|
bool test_nd; |
|
}; |
|
|
|
|
|
CxCore_MathTestImpl::CxCore_MathTestImpl( const char* test_name, const char* test_funcs ) |
|
: CvArrTest( test_name, test_funcs, "" ) |
|
{ |
|
optional_mask = false; |
|
|
|
test_array[INPUT].push(NULL); |
|
test_array[OUTPUT].push(NULL); |
|
test_array[REF_OUTPUT].push(NULL); |
|
|
|
default_timing_param_names = math_param_names; |
|
|
|
size_list = math_sizes; |
|
whole_size_list = 0; |
|
depth_list = math_depths; |
|
cn_list = 0; |
|
test_nd = false; |
|
} |
|
|
|
|
|
double CxCore_MathTestImpl::get_success_error_level( int /*test_case_idx*/, int i, int j ) |
|
{ |
|
return CV_MAT_DEPTH(test_mat[i][j].type) == CV_32F ? FLT_EPSILON*128 : DBL_EPSILON*1024; |
|
} |
|
|
|
|
|
void CxCore_MathTestImpl::get_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int depth = cvTsRandInt(rng)%2 + CV_32F; |
|
int cn = cvTsRandInt(rng) % 4 + 1, type = CV_MAKETYPE(depth, cn); |
|
int i, j; |
|
CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
|
|
for( i = 0; i < max_arr; i++ ) |
|
{ |
|
int count = test_array[i].size(); |
|
for( j = 0; j < count; j++ ) |
|
types[i][j] = type; |
|
} |
|
test_nd = cvTsRandInt(rng)%3 == 0; |
|
} |
|
|
|
CxCore_MathTestImpl math_test( "math", "" ); |
|
|
|
|
|
class CxCore_MathTest : public CxCore_MathTestImpl |
|
{ |
|
public: |
|
CxCore_MathTest( const char* test_name, const char* test_funcs ); |
|
}; |
|
|
|
|
|
CxCore_MathTest::CxCore_MathTest( const char* test_name, const char* test_funcs ) |
|
: CxCore_MathTestImpl( test_name, test_funcs ) |
|
{ |
|
size_list = 0; |
|
depth_list = 0; |
|
} |
|
|
|
|
|
////////// exp ///////////// |
|
class CxCore_ExpTest : public CxCore_MathTest |
|
{ |
|
public: |
|
CxCore_ExpTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high ); |
|
double get_success_error_level( int /*test_case_idx*/, int i, int j ); |
|
int prepare_test_case( int test_case ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
int out_type; |
|
}; |
|
|
|
|
|
CxCore_ExpTest::CxCore_ExpTest() |
|
: CxCore_MathTest( "math-exp", "cvExp" ) |
|
{ |
|
out_type = 0; |
|
} |
|
|
|
|
|
double CxCore_ExpTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) |
|
{ |
|
int in_depth = CV_MAT_DEPTH(test_mat[INPUT][0].type); |
|
int out_depth = CV_MAT_DEPTH(test_mat[OUTPUT][0].type); |
|
int min_depth = MIN(in_depth, out_depth); |
|
return min_depth == CV_32F ? 1e-5 : 1e-8; |
|
} |
|
|
|
|
|
void CxCore_ExpTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CxCore_MathTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
out_type = types[OUTPUT][0]; |
|
/*if( CV_MAT_DEPTH(types[INPUT][0]) == CV_32F && (cvRandInt(ts->get_rng()) & 3) == 0 ) |
|
types[OUTPUT][0] = types[REF_OUTPUT][0] = |
|
out_type = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK)|CV_64F;*/ |
|
} |
|
|
|
void CxCore_ExpTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ) |
|
{ |
|
double l = cvTsRandReal(ts->get_rng())*10+1; |
|
double u = cvTsRandReal(ts->get_rng())*10+1; |
|
l *= -l; |
|
u *= u; |
|
*low = cvScalarAll(l); |
|
*high = cvScalarAll(CV_MAT_DEPTH(out_type)==CV_64F? u : u*0.5); |
|
} |
|
|
|
int CxCore_ExpTest::prepare_test_case( int test_case ) |
|
{ |
|
int code = CxCore_MathTest::prepare_test_case(test_case); |
|
if( code < 0 ) |
|
return code; |
|
|
|
CvRNG* rng = ts->get_rng(); |
|
|
|
int i, j, k, count = cvTsRandInt(rng) % 10; |
|
CvMat* src = &test_mat[INPUT][0]; |
|
int depth = CV_MAT_DEPTH(src->type); |
|
|
|
// add some extremal values |
|
for( k = 0; k < count; k++ ) |
|
{ |
|
i = cvTsRandInt(rng) % src->rows; |
|
j = cvTsRandInt(rng) % (src->cols*CV_MAT_CN(src->type)); |
|
int sign = cvTsRandInt(rng) % 2 ? 1 : -1; |
|
if( depth == CV_32F ) |
|
((float*)(src->data.ptr + src->step*i))[j] = FLT_MAX*sign; |
|
else |
|
((double*)(src->data.ptr + src->step*i))[j] = DBL_MAX*sign; |
|
} |
|
|
|
return code; |
|
} |
|
|
|
|
|
void CxCore_ExpTest::run_func() |
|
{ |
|
if(!test_nd) |
|
cvExp( test_array[INPUT][0], test_array[OUTPUT][0] ); |
|
else |
|
{ |
|
cv::MatND a = cv::cvarrToMatND(test_array[INPUT][0]); |
|
cv::MatND b = cv::cvarrToMatND(test_array[OUTPUT][0]); |
|
cv::exp(a, b); |
|
} |
|
} |
|
|
|
|
|
void CxCore_ExpTest::prepare_to_validation( int /*test_case_idx*/ ) |
|
{ |
|
CvMat* a = &test_mat[INPUT][0]; |
|
CvMat* b = &test_mat[REF_OUTPUT][0]; |
|
|
|
int a_depth = CV_MAT_DEPTH(a->type); |
|
int b_depth = CV_MAT_DEPTH(b->type); |
|
int ncols = test_mat[INPUT][0].cols*CV_MAT_CN(a->type); |
|
int i, j; |
|
|
|
for( i = 0; i < a->rows; i++ ) |
|
{ |
|
uchar* a_data = a->data.ptr + i*a->step; |
|
uchar* b_data = b->data.ptr + i*b->step; |
|
|
|
if( a_depth == CV_32F && b_depth == CV_32F ) |
|
{ |
|
for( j = 0; j < ncols; j++ ) |
|
((float*)b_data)[j] = (float)exp((double)((float*)a_data)[j]); |
|
} |
|
else if( a_depth == CV_32F && b_depth == CV_64F ) |
|
{ |
|
for( j = 0; j < ncols; j++ ) |
|
((double*)b_data)[j] = exp((double)((float*)a_data)[j]); |
|
} |
|
else |
|
{ |
|
assert( a_depth == CV_64F && b_depth == CV_64F ); |
|
for( j = 0; j < ncols; j++ ) |
|
((double*)b_data)[j] = exp(((double*)a_data)[j]); |
|
} |
|
} |
|
} |
|
|
|
CxCore_ExpTest exp_test; |
|
|
|
|
|
////////// log ///////////// |
|
class CxCore_LogTest : public CxCore_MathTest |
|
{ |
|
public: |
|
CxCore_LogTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
}; |
|
|
|
|
|
CxCore_LogTest::CxCore_LogTest() |
|
: CxCore_MathTest( "math-log", "cvLog" ) |
|
{ |
|
} |
|
|
|
|
|
void CxCore_LogTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CxCore_MathTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
/*if( CV_MAT_DEPTH(types[INPUT][0]) == CV_32F && (cvRandInt(ts->get_rng()) & 3) == 0 ) |
|
types[INPUT][0] = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK)|CV_64F;*/ |
|
} |
|
|
|
|
|
void CxCore_LogTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ) |
|
{ |
|
double l = cvTsRandReal(ts->get_rng())*15-5; |
|
double u = cvTsRandReal(ts->get_rng())*15-5; |
|
double t; |
|
l = exp(l); |
|
u = exp(u); |
|
if( l > u ) |
|
CV_SWAP( l, u, t ); |
|
*low = cvScalarAll(l); |
|
*high = cvScalarAll(u); |
|
} |
|
|
|
|
|
void CxCore_LogTest::run_func() |
|
{ |
|
if(!test_nd) |
|
cvLog( test_array[INPUT][0], test_array[OUTPUT][0] ); |
|
else |
|
{ |
|
cv::MatND a = cv::cvarrToMatND(test_array[INPUT][0]); |
|
cv::MatND b = cv::cvarrToMatND(test_array[OUTPUT][0]); |
|
cv::log(a, b); |
|
} |
|
} |
|
|
|
|
|
void CxCore_LogTest::prepare_to_validation( int /*test_case_idx*/ ) |
|
{ |
|
CvMat* a = &test_mat[INPUT][0]; |
|
CvMat* b = &test_mat[REF_OUTPUT][0]; |
|
|
|
int a_depth = CV_MAT_DEPTH(a->type); |
|
int b_depth = CV_MAT_DEPTH(b->type); |
|
int ncols = test_mat[INPUT][0].cols*CV_MAT_CN(a->type); |
|
int i, j; |
|
|
|
for( i = 0; i < a->rows; i++ ) |
|
{ |
|
uchar* a_data = a->data.ptr + i*a->step; |
|
uchar* b_data = b->data.ptr + i*b->step; |
|
|
|
if( a_depth == CV_32F && b_depth == CV_32F ) |
|
{ |
|
for( j = 0; j < ncols; j++ ) |
|
((float*)b_data)[j] = (float)log((double)((float*)a_data)[j]); |
|
} |
|
else if( a_depth == CV_64F && b_depth == CV_32F ) |
|
{ |
|
for( j = 0; j < ncols; j++ ) |
|
((float*)b_data)[j] = (float)log(((double*)a_data)[j]); |
|
} |
|
else |
|
{ |
|
assert( a_depth == CV_64F && b_depth == CV_64F ); |
|
for( j = 0; j < ncols; j++ ) |
|
((double*)b_data)[j] = log(((double*)a_data)[j]); |
|
} |
|
} |
|
} |
|
|
|
CxCore_LogTest log_test; |
|
|
|
|
|
////////// pow ///////////// |
|
|
|
static const double math_pow_values[] = { 2., 5., 0.5, -0.5, 1./3, -1./3, CV_PI }; |
|
static const char* math_pow_param_names[] = { "size", "power", "depth", 0 }; |
|
static const int math_pow_depths[] = { CV_8U, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, -1 }; |
|
|
|
class CxCore_PowTest : public CxCore_MathTest |
|
{ |
|
public: |
|
CxCore_PowTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
int write_default_params( CvFileStorage* fs ); |
|
void print_timing_params( int test_case_idx, char* ptr, int params_left ); |
|
void run_func(); |
|
int prepare_test_case( int test_case_idx ); |
|
void prepare_to_validation( int test_case_idx ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
double power; |
|
}; |
|
|
|
|
|
CxCore_PowTest::CxCore_PowTest() |
|
: CxCore_MathTest( "math-pow", "cvPow" ) |
|
{ |
|
power = 0; |
|
default_timing_param_names = math_pow_param_names; |
|
depth_list = math_pow_depths; |
|
} |
|
|
|
|
|
void CxCore_PowTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int depth = cvTsRandInt(rng) % (CV_64F+1); |
|
int cn = cvTsRandInt(rng) % 4 + 1; |
|
int i, j; |
|
CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
depth += depth == CV_8S; |
|
|
|
if( depth < CV_32F || cvTsRandInt(rng)%8 == 0 ) |
|
// integer power |
|
power = (int)(cvTsRandInt(rng)%21 - 10); |
|
else |
|
{ |
|
i = cvTsRandInt(rng)%17; |
|
power = i == 16 ? 1./3 : i == 15 ? 0.5 : i == 14 ? -0.5 : cvTsRandReal(rng)*10 - 5; |
|
} |
|
|
|
for( i = 0; i < max_arr; i++ ) |
|
{ |
|
int count = test_array[i].size(); |
|
int type = CV_MAKETYPE(depth, cn); |
|
for( j = 0; j < count; j++ ) |
|
types[i][j] = type; |
|
} |
|
test_nd = cvTsRandInt(rng)%3 == 0; |
|
} |
|
|
|
|
|
void CxCore_PowTest::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CxCore_MathTest::get_timing_test_array_types_and_sizes( test_case_idx, |
|
sizes, types, whole_sizes, are_images ); |
|
power = cvReadReal( find_timing_param( "power" ), 0.2 ); |
|
} |
|
|
|
|
|
int CxCore_PowTest::write_default_params( CvFileStorage* fs ) |
|
{ |
|
int i, code = CxCore_MathTest::write_default_params(fs); |
|
if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE ) |
|
return code; |
|
start_write_param( fs ); |
|
cvStartWriteStruct( fs, "power", CV_NODE_SEQ + CV_NODE_FLOW ); |
|
for( i = 0; i < CV_DIM(math_pow_values); i++ ) |
|
cvWriteReal( fs, 0, math_pow_values[i] ); |
|
cvEndWriteStruct(fs); |
|
return code; |
|
} |
|
|
|
|
|
int CxCore_PowTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = CxCore_MathTest::prepare_test_case( test_case_idx ); |
|
if( code > 0 && ts->get_testing_mode() == CvTS::TIMING_MODE ) |
|
{ |
|
if( cvRound(power) != power && CV_MAT_DEPTH(test_mat[INPUT][0].type) < CV_32F ) |
|
return 0; |
|
} |
|
return code; |
|
} |
|
|
|
|
|
void CxCore_PowTest::print_timing_params( int test_case_idx, char* ptr, int params_left ) |
|
{ |
|
sprintf( ptr, "%g,", power ); |
|
ptr += strlen(ptr); |
|
params_left--; |
|
CxCore_MathTest::print_timing_params( test_case_idx, ptr, params_left ); |
|
} |
|
|
|
|
|
double CxCore_PowTest::get_success_error_level( int test_case_idx, int i, int j ) |
|
{ |
|
int type = cvGetElemType( test_array[i][j] ); |
|
if( CV_MAT_DEPTH(type) < CV_32F ) |
|
return power == cvRound(power) && power >= 0 ? 0 : 1; |
|
else |
|
return CxCore_MathTest::get_success_error_level( test_case_idx, i, j ); |
|
} |
|
|
|
|
|
void CxCore_PowTest::get_minmax_bounds( int /*i*/, int /*j*/, int type, CvScalar* low, CvScalar* high ) |
|
{ |
|
double l, u = cvTsRandInt(ts->get_rng())%1000 + 1; |
|
if( power > 0 ) |
|
{ |
|
double mval = cvTsMaxVal(type); |
|
double u1 = pow(mval,1./power)*2; |
|
u = MIN(u,u1); |
|
} |
|
|
|
l = power == cvRound(power) ? -u : FLT_EPSILON; |
|
*low = cvScalarAll(l); |
|
*high = cvScalarAll(u); |
|
} |
|
|
|
|
|
void CxCore_PowTest::run_func() |
|
{ |
|
if(!test_nd) |
|
{ |
|
if( fabs(power-1./3) <= DBL_EPSILON && CV_MAT_DEPTH(test_mat[INPUT][0].type) == CV_32F ) |
|
{ |
|
cv::Mat a(&test_mat[INPUT][0]), b(&test_mat[OUTPUT][0]); |
|
|
|
a = a.reshape(1); |
|
b = b.reshape(1); |
|
for( int i = 0; i < a.rows; i++ ) |
|
{ |
|
b.at<float>(i,0) = (float)fabs(cvCbrt(a.at<float>(i,0))); |
|
for( int j = 1; j < a.cols; j++ ) |
|
b.at<float>(i,j) = (float)fabs(cv::cubeRoot(a.at<float>(i,j))); |
|
} |
|
} |
|
else |
|
cvPow( test_array[INPUT][0], test_array[OUTPUT][0], power ); |
|
} |
|
else |
|
{ |
|
cv::MatND a = cv::cvarrToMatND(test_array[INPUT][0]); |
|
cv::MatND b = cv::cvarrToMatND(test_array[OUTPUT][0]); |
|
if(power == 0.5) |
|
cv::sqrt(a, b); |
|
else |
|
cv::pow(a, power, b); |
|
} |
|
} |
|
|
|
|
|
inline static int ipow( int a, int power ) |
|
{ |
|
int b = 1; |
|
while( power > 0 ) |
|
{ |
|
if( power&1 ) |
|
b *= a, power--; |
|
else |
|
a *= a, power >>= 1; |
|
} |
|
return b; |
|
} |
|
|
|
|
|
inline static double ipow( double a, int power ) |
|
{ |
|
double b = 1.; |
|
while( power > 0 ) |
|
{ |
|
if( power&1 ) |
|
b *= a, power--; |
|
else |
|
a *= a, power >>= 1; |
|
} |
|
return b; |
|
} |
|
|
|
|
|
void CxCore_PowTest::prepare_to_validation( int /*test_case_idx*/ ) |
|
{ |
|
CvMat* a = &test_mat[INPUT][0]; |
|
CvMat* b = &test_mat[REF_OUTPUT][0]; |
|
|
|
int depth = CV_MAT_DEPTH(a->type); |
|
int ncols = test_mat[INPUT][0].cols*CV_MAT_CN(a->type); |
|
int ipower = cvRound(power), apower = abs(ipower); |
|
int i, j; |
|
|
|
for( i = 0; i < a->rows; i++ ) |
|
{ |
|
uchar* a_data = a->data.ptr + i*a->step; |
|
uchar* b_data = b->data.ptr + i*b->step; |
|
|
|
switch( depth ) |
|
{ |
|
case CV_8U: |
|
if( ipower < 0 ) |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
int val = ((uchar*)a_data)[j]; |
|
((uchar*)b_data)[j] = (uchar)(val <= 1 ? val : |
|
val == 2 && ipower == -1 ? 1 : 0); |
|
} |
|
else |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
int val = ((uchar*)a_data)[j]; |
|
val = ipow( val, ipower ); |
|
((uchar*)b_data)[j] = CV_CAST_8U(val); |
|
} |
|
break; |
|
case CV_8S: |
|
if( ipower < 0 ) |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
int val = ((char*)a_data)[j]; |
|
((char*)b_data)[j] = (char)((val&~1)==0 ? val : |
|
val ==-1 ? 1-2*(ipower&1) : |
|
val == 2 && ipower == -1 ? 1 : 0); |
|
} |
|
else |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
int val = ((char*)a_data)[j]; |
|
val = ipow( val, ipower ); |
|
((char*)b_data)[j] = CV_CAST_8S(val); |
|
} |
|
break; |
|
case CV_16U: |
|
if( ipower < 0 ) |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
int val = ((ushort*)a_data)[j]; |
|
((ushort*)b_data)[j] = (ushort)((val&~1)==0 ? val : |
|
val ==-1 ? 1-2*(ipower&1) : |
|
val == 2 && ipower == -1 ? 1 : 0); |
|
} |
|
else |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
int val = ((ushort*)a_data)[j]; |
|
val = ipow( val, ipower ); |
|
((ushort*)b_data)[j] = CV_CAST_16U(val); |
|
} |
|
break; |
|
case CV_16S: |
|
if( ipower < 0 ) |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
int val = ((short*)a_data)[j]; |
|
((short*)b_data)[j] = (short)((val&~1)==0 ? val : |
|
val ==-1 ? 1-2*(ipower&1) : |
|
val == 2 && ipower == -1 ? 1 : 0); |
|
} |
|
else |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
int val = ((short*)a_data)[j]; |
|
val = ipow( val, ipower ); |
|
((short*)b_data)[j] = CV_CAST_16S(val); |
|
} |
|
break; |
|
case CV_32S: |
|
if( ipower < 0 ) |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
int val = ((int*)a_data)[j]; |
|
((int*)b_data)[j] = (val&~1)==0 ? val : |
|
val ==-1 ? 1-2*(ipower&1) : |
|
val == 2 && ipower == -1 ? 1 : 0; |
|
} |
|
else |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
int val = ((int*)a_data)[j]; |
|
val = ipow( val, ipower ); |
|
((int*)b_data)[j] = val; |
|
} |
|
break; |
|
case CV_32F: |
|
if( power != ipower ) |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
double val = ((float*)a_data)[j]; |
|
val = pow( fabs(val), power ); |
|
((float*)b_data)[j] = CV_CAST_32F(val); |
|
} |
|
else |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
double val = ((float*)a_data)[j]; |
|
if( ipower < 0 ) |
|
val = 1./val; |
|
val = ipow( val, apower ); |
|
((float*)b_data)[j] = (float)val; |
|
} |
|
break; |
|
case CV_64F: |
|
if( power != ipower ) |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
double val = ((double*)a_data)[j]; |
|
val = pow( fabs(val), power ); |
|
((double*)b_data)[j] = CV_CAST_64F(val); |
|
} |
|
else |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
double val = ((double*)a_data)[j]; |
|
if( ipower < 0 ) |
|
val = 1./val; |
|
val = ipow( val, apower ); |
|
((double*)b_data)[j] = (double)val; |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
|
|
CxCore_PowTest pow_test; |
|
|
|
|
|
|
|
////////// cart2polar ///////////// |
|
class CxCore_CartToPolarTest : public CxCore_MathTest |
|
{ |
|
public: |
|
CxCore_CartToPolarTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
int use_degrees; |
|
}; |
|
|
|
|
|
CxCore_CartToPolarTest::CxCore_CartToPolarTest() |
|
: CxCore_MathTest( "math-cart2polar", "cvCartToPolar" ) |
|
{ |
|
use_degrees = 0; |
|
test_array[INPUT].push(NULL); |
|
test_array[OUTPUT].push(NULL); |
|
test_array[REF_OUTPUT].push(NULL); |
|
} |
|
|
|
|
|
void CxCore_CartToPolarTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
CxCore_MathTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
|
|
use_degrees = cvTsRandInt(rng) & 1; |
|
if( cvTsRandInt(rng) % 4 == 0 ) // check missing magnitude/angle cases |
|
{ |
|
int idx = cvTsRandInt(rng) & 1; |
|
sizes[OUTPUT][idx] = sizes[REF_OUTPUT][idx] = cvSize(0,0); |
|
} |
|
} |
|
|
|
|
|
void CxCore_CartToPolarTest::run_func() |
|
{ |
|
if(!test_nd) |
|
{ |
|
cvCartToPolar( test_array[INPUT][0], test_array[INPUT][1], |
|
test_array[OUTPUT][0], test_array[OUTPUT][1], use_degrees ); |
|
} |
|
else |
|
{ |
|
cv::Mat X = cv::cvarrToMat(test_array[INPUT][0]); |
|
cv::Mat Y = cv::cvarrToMat(test_array[INPUT][1]); |
|
cv::Mat mag = test_array[OUTPUT][0] ? cv::cvarrToMat(test_array[OUTPUT][0]) : cv::Mat(); |
|
cv::Mat ph = test_array[OUTPUT][1] ? cv::cvarrToMat(test_array[OUTPUT][1]) : cv::Mat(); |
|
if(!mag.data) |
|
cv::phase(X, Y, ph, use_degrees != 0); |
|
else if(!ph.data) |
|
cv::magnitude(X, Y, mag); |
|
else |
|
cv::cartToPolar(X, Y, mag, ph, use_degrees != 0); |
|
} |
|
} |
|
|
|
|
|
double CxCore_CartToPolarTest::get_success_error_level( int test_case_idx, int i, int j ) |
|
{ |
|
return j == 1 ? 0.5*(use_degrees ? 1 : CV_PI/180.) : |
|
CxCore_MathTest::get_success_error_level( test_case_idx, i, j ); |
|
} |
|
|
|
|
|
void CxCore_CartToPolarTest::prepare_to_validation( int /*test_case_idx*/ ) |
|
{ |
|
CvMat* x = &test_mat[INPUT][0]; |
|
CvMat* y = &test_mat[INPUT][1]; |
|
CvMat* mag = test_array[REF_OUTPUT][0] ? &test_mat[REF_OUTPUT][0] : 0; |
|
CvMat* angle = test_array[REF_OUTPUT][1] ? &test_mat[REF_OUTPUT][1] : 0; |
|
double C = use_degrees ? 180./CV_PI : 1.; |
|
|
|
int depth = CV_MAT_DEPTH(x->type); |
|
int ncols = x->cols*CV_MAT_CN(x->type); |
|
int i, j; |
|
|
|
for( i = 0; i < x->rows; i++ ) |
|
{ |
|
uchar* x_data = x->data.ptr + i*x->step; |
|
uchar* y_data = y->data.ptr + i*y->step; |
|
uchar* mag_data = mag ? mag->data.ptr + i*mag->step : 0; |
|
uchar* angle_data = angle ? angle->data.ptr + i*angle->step : 0; |
|
|
|
if( depth == CV_32F ) |
|
{ |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
double xval = ((float*)x_data)[j]; |
|
double yval = ((float*)y_data)[j]; |
|
|
|
if( mag_data ) |
|
((float*)mag_data)[j] = (float)sqrt(xval*xval + yval*yval); |
|
if( angle_data ) |
|
{ |
|
double a = atan2( yval, xval ); |
|
if( a < 0 ) |
|
a += CV_PI*2; |
|
a *= C; |
|
((float*)angle_data)[j] = (float)a; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
assert( depth == CV_64F ); |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
double xval = ((double*)x_data)[j]; |
|
double yval = ((double*)y_data)[j]; |
|
|
|
if( mag_data ) |
|
((double*)mag_data)[j] = sqrt(xval*xval + yval*yval); |
|
if( angle_data ) |
|
{ |
|
double a = atan2( yval, xval ); |
|
if( a < 0 ) |
|
a += CV_PI*2; |
|
a *= C; |
|
((double*)angle_data)[j] = a; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if( angle ) |
|
{ |
|
// hack: increase angle value by 1 (so that alpha becomes 1+alpha) |
|
// to hide large relative errors in case of very small angles |
|
cvTsAdd( &test_mat[OUTPUT][1], cvScalarAll(1.), 0, cvScalarAll(0.), |
|
cvScalarAll(1.), &test_mat[OUTPUT][1], 0 ); |
|
cvTsAdd( &test_mat[REF_OUTPUT][1], cvScalarAll(1.), 0, cvScalarAll(0.), |
|
cvScalarAll(1.), &test_mat[REF_OUTPUT][1], 0 ); |
|
} |
|
} |
|
|
|
CxCore_CartToPolarTest cart2polar_test; |
|
|
|
|
|
|
|
////////// polar2cart ///////////// |
|
class CxCore_PolarToCartTest : public CxCore_MathTest |
|
{ |
|
public: |
|
CxCore_PolarToCartTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
int use_degrees; |
|
}; |
|
|
|
|
|
CxCore_PolarToCartTest::CxCore_PolarToCartTest() |
|
: CxCore_MathTest( "math-polar2cart", "cvPolarToCart" ) |
|
{ |
|
use_degrees = 0; |
|
test_array[INPUT].push(NULL); |
|
test_array[OUTPUT].push(NULL); |
|
test_array[REF_OUTPUT].push(NULL); |
|
} |
|
|
|
|
|
void CxCore_PolarToCartTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
CxCore_MathTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
|
|
use_degrees = cvTsRandInt(rng) & 1; |
|
if( cvTsRandInt(rng) % 4 == 0 ) // check missing magnitude case |
|
sizes[INPUT][1] = cvSize(0,0); |
|
|
|
if( cvTsRandInt(rng) % 4 == 0 ) // check missing x/y cases |
|
{ |
|
int idx = cvTsRandInt(rng) & 1; |
|
sizes[OUTPUT][idx] = sizes[REF_OUTPUT][idx] = cvSize(0,0); |
|
} |
|
} |
|
|
|
|
|
void CxCore_PolarToCartTest::run_func() |
|
{ |
|
if(!test_nd) |
|
{ |
|
cvPolarToCart( test_array[INPUT][1], test_array[INPUT][0], |
|
test_array[OUTPUT][0], test_array[OUTPUT][1], use_degrees ); |
|
} |
|
else |
|
{ |
|
cv::Mat X = test_array[OUTPUT][0] ? cv::cvarrToMat(test_array[OUTPUT][0]) : cv::Mat(); |
|
cv::Mat Y = test_array[OUTPUT][1] ? cv::cvarrToMat(test_array[OUTPUT][1]) : cv::Mat(); |
|
cv::Mat mag = test_array[INPUT][1] ? cv::cvarrToMat(test_array[INPUT][1]) : cv::Mat(); |
|
cv::Mat ph = test_array[INPUT][0] ? cv::cvarrToMat(test_array[INPUT][0]) : cv::Mat(); |
|
cv::polarToCart(mag, ph, X, Y, use_degrees != 0); |
|
} |
|
} |
|
|
|
|
|
double CxCore_PolarToCartTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) |
|
{ |
|
return FLT_EPSILON*100; |
|
} |
|
|
|
|
|
void CxCore_PolarToCartTest::prepare_to_validation( int /*test_case_idx*/ ) |
|
{ |
|
CvMat* x = test_array[REF_OUTPUT][0] ? &test_mat[REF_OUTPUT][0] : 0; |
|
CvMat* y = test_array[REF_OUTPUT][1] ? &test_mat[REF_OUTPUT][1] : 0; |
|
CvMat* angle = &test_mat[INPUT][0]; |
|
CvMat* mag = test_array[INPUT][1] ? &test_mat[INPUT][1] : 0; |
|
double C = use_degrees ? CV_PI/180. : 1.; |
|
|
|
int depth = CV_MAT_DEPTH(angle->type); |
|
int ncols = angle->cols*CV_MAT_CN(angle->type); |
|
int i, j; |
|
|
|
for( i = 0; i < angle->rows; i++ ) |
|
{ |
|
uchar* x_data = x ? x->data.ptr + i*x->step : 0; |
|
uchar* y_data = y ? y->data.ptr + i*y->step : 0; |
|
uchar* mag_data = mag ? mag->data.ptr + i*mag->step : 0; |
|
uchar* angle_data = angle->data.ptr + i*angle->step; |
|
|
|
if( depth == CV_32F ) |
|
{ |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
double a = ((float*)angle_data)[j]*C; |
|
double m = mag_data ? ((float*)mag_data)[j] : 1.; |
|
|
|
if( x_data ) |
|
((float*)x_data)[j] = (float)(m*cos(a)); |
|
if( y_data ) |
|
((float*)y_data)[j] = (float)(m*sin(a)); |
|
} |
|
} |
|
else |
|
{ |
|
assert( depth == CV_64F ); |
|
for( j = 0; j < ncols; j++ ) |
|
{ |
|
double a = ((double*)angle_data)[j]*C; |
|
double m = mag_data ? ((double*)mag_data)[j] : 1.; |
|
|
|
if( x_data ) |
|
((double*)x_data)[j] = m*cos(a); |
|
if( y_data ) |
|
((double*)y_data)[j] = m*sin(a); |
|
} |
|
} |
|
} |
|
} |
|
|
|
CxCore_PolarToCartTest polar2cart_test; |
|
|
|
///////////////////////////////////////// matrix tests //////////////////////////////////////////// |
|
|
|
static const int matrix_all_depths[] = { CV_8U, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, -1 }; |
|
|
|
class CxCore_MatrixTestImpl : public CvArrTest |
|
{ |
|
public: |
|
CxCore_MatrixTestImpl( const char* test_name, const char* test_funcs, int in_count, int out_count, |
|
bool allow_int, bool scalar_output, int max_cn ); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
bool allow_int; |
|
bool scalar_output; |
|
int max_cn; |
|
}; |
|
|
|
|
|
CxCore_MatrixTestImpl::CxCore_MatrixTestImpl( const char* test_name, const char* test_funcs, |
|
int in_count, int out_count, |
|
bool _allow_int, bool _scalar_output, int _max_cn ) |
|
: CvArrTest( test_name, test_funcs, "" ), |
|
allow_int(_allow_int), scalar_output(_scalar_output), max_cn(_max_cn) |
|
{ |
|
int i; |
|
for( i = 0; i < in_count; i++ ) |
|
test_array[INPUT].push(NULL); |
|
|
|
for( i = 0; i < out_count; i++ ) |
|
{ |
|
test_array[OUTPUT].push(NULL); |
|
test_array[REF_OUTPUT].push(NULL); |
|
} |
|
|
|
element_wise_relative_error = false; |
|
|
|
default_timing_param_names = math_param_names; |
|
|
|
size_list = (CvSize*)matrix_sizes; |
|
whole_size_list = 0; |
|
depth_list = (int*)math_depths; |
|
cn_list = 0; |
|
} |
|
|
|
|
|
void CxCore_MatrixTestImpl::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int depth = cvTsRandInt(rng) % (allow_int ? CV_64F+1 : 2); |
|
int cn = cvTsRandInt(rng) % max_cn + 1; |
|
int i, j; |
|
|
|
if( allow_int ) |
|
depth += depth == CV_8S; |
|
else |
|
depth += CV_32F; |
|
|
|
CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
|
|
for( i = 0; i < max_arr; i++ ) |
|
{ |
|
int count = test_array[i].size(); |
|
int flag = (i == OUTPUT || i == REF_OUTPUT) && scalar_output; |
|
int type = !flag ? CV_MAKETYPE(depth, cn) : CV_64FC1; |
|
|
|
for( j = 0; j < count; j++ ) |
|
{ |
|
types[i][j] = type; |
|
if( flag ) |
|
sizes[i][j] = cvSize( 4, 1 ); |
|
} |
|
} |
|
} |
|
|
|
|
|
void CxCore_MatrixTestImpl::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CvArrTest::get_timing_test_array_types_and_sizes( test_case_idx, |
|
sizes, types, whole_sizes, are_images ); |
|
if( scalar_output ) |
|
{ |
|
types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1; |
|
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize( 4, 1 ); |
|
whole_sizes[OUTPUT][0] = whole_sizes[REF_OUTPUT][0] = cvSize( 4, 1 ); |
|
} |
|
} |
|
|
|
|
|
double CxCore_MatrixTestImpl::get_success_error_level( int test_case_idx, int i, int j ) |
|
{ |
|
int input_depth = CV_MAT_DEPTH(cvGetElemType( test_array[INPUT][0] )); |
|
double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ? |
|
5e-5 : 1e-10; |
|
double output_precision = CvArrTest::get_success_error_level( test_case_idx, i, j ); |
|
return MAX(input_precision, output_precision); |
|
} |
|
|
|
CxCore_MatrixTestImpl matrix_test( "matrix", "", 0, 0, false, false, 0 ); |
|
|
|
|
|
class CxCore_MatrixTest : public CxCore_MatrixTestImpl |
|
{ |
|
public: |
|
CxCore_MatrixTest( const char* test_name, const char* test_funcs, int in_count, int out_count, |
|
bool allow_int, bool scalar_output, int max_cn ); |
|
}; |
|
|
|
|
|
CxCore_MatrixTest::CxCore_MatrixTest( const char* test_name, const char* test_funcs, |
|
int in_count, int out_count, bool _allow_int, |
|
bool _scalar_output, int _max_cn ) |
|
: CxCore_MatrixTestImpl( test_name, test_funcs, in_count, out_count, |
|
_allow_int, _scalar_output, _max_cn ) |
|
{ |
|
size_list = 0; |
|
depth_list = 0; |
|
} |
|
|
|
|
|
///////////////// Trace ///////////////////// |
|
|
|
class CxCore_TraceTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_TraceTest(); |
|
protected: |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
}; |
|
|
|
|
|
CxCore_TraceTest::CxCore_TraceTest() : |
|
CxCore_MatrixTest( "matrix-trace", "cvTrace", 1, 1, true, true, 4 ) |
|
{ |
|
} |
|
|
|
|
|
void CxCore_TraceTest::run_func() |
|
{ |
|
*((CvScalar*)(test_mat[OUTPUT][0].data.db)) = cvTrace(test_array[INPUT][0]); |
|
} |
|
|
|
|
|
void CxCore_TraceTest::prepare_to_validation( int ) |
|
{ |
|
CvMat* mat = &test_mat[INPUT][0]; |
|
int i, j, count = MIN( mat->rows, mat->cols ); |
|
CvScalar trace = {{0,0,0,0}}; |
|
|
|
for( i = 0; i < count; i++ ) |
|
{ |
|
CvScalar el = cvGet2D( mat, i, i ); |
|
for( j = 0; j < 4; j++ ) |
|
trace.val[j] += el.val[j]; |
|
} |
|
|
|
*((CvScalar*)(test_mat[REF_OUTPUT][0].data.db)) = trace; |
|
} |
|
|
|
CxCore_TraceTest trace_test; |
|
|
|
|
|
///////// dotproduct ////////// |
|
|
|
class CxCore_DotProductTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_DotProductTest(); |
|
protected: |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
}; |
|
|
|
|
|
CxCore_DotProductTest::CxCore_DotProductTest() : |
|
CxCore_MatrixTest( "matrix-dotproduct", "cvDotProduct", 2, 1, true, true, 4 ) |
|
{ |
|
depth_list = matrix_all_depths; |
|
} |
|
|
|
|
|
void CxCore_DotProductTest::run_func() |
|
{ |
|
*((CvScalar*)(test_mat[OUTPUT][0].data.ptr)) = |
|
cvRealScalar(cvDotProduct( test_array[INPUT][0], test_array[INPUT][1] )); |
|
} |
|
|
|
|
|
void CxCore_DotProductTest::prepare_to_validation( int ) |
|
{ |
|
*((CvScalar*)(test_mat[REF_OUTPUT][0].data.ptr)) = |
|
cvRealScalar(cvTsCrossCorr( &test_mat[INPUT][0], &test_mat[INPUT][1] )); |
|
} |
|
|
|
CxCore_DotProductTest dotproduct_test; |
|
|
|
|
|
///////// crossproduct ////////// |
|
|
|
static const CvSize cross_product_sizes[] = {{3,1}, {-1,-1}}; |
|
|
|
class CxCore_CrossProductTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_CrossProductTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
}; |
|
|
|
|
|
CxCore_CrossProductTest::CxCore_CrossProductTest() : |
|
CxCore_MatrixTest( "matrix-crossproduct", "cvCrossProduct", 2, 1, false, false, 1 ) |
|
{ |
|
size_list = cross_product_sizes; |
|
} |
|
|
|
|
|
void CxCore_CrossProductTest::get_test_array_types_and_sizes( int /*test_case_idx*/, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int depth = cvTsRandInt(rng) % 2 + CV_32F; |
|
int cn = cvTsRandInt(rng) & 1 ? 3 : 1, type = CV_MAKETYPE(depth, cn); |
|
CvSize sz; |
|
|
|
types[INPUT][0] = types[INPUT][1] = types[OUTPUT][0] = types[REF_OUTPUT][0] = type; |
|
|
|
if( cn == 3 ) |
|
sz = cvSize(1,1); |
|
else if( cvTsRandInt(rng) & 1 ) |
|
sz = cvSize(3,1); |
|
else |
|
sz = cvSize(1,3); |
|
|
|
sizes[INPUT][0] = sizes[INPUT][1] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz; |
|
} |
|
|
|
|
|
void CxCore_CrossProductTest::run_func() |
|
{ |
|
cvCrossProduct( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0] ); |
|
} |
|
|
|
|
|
void CxCore_CrossProductTest::prepare_to_validation( int ) |
|
{ |
|
CvScalar a = {{0,0,0,0}}, b = {{0,0,0,0}}, c = {{0,0,0,0}}; |
|
|
|
if( test_mat[INPUT][0].rows > 1 ) |
|
{ |
|
a.val[0] = cvGetReal2D( &test_mat[INPUT][0], 0, 0 ); |
|
a.val[1] = cvGetReal2D( &test_mat[INPUT][0], 1, 0 ); |
|
a.val[2] = cvGetReal2D( &test_mat[INPUT][0], 2, 0 ); |
|
|
|
b.val[0] = cvGetReal2D( &test_mat[INPUT][1], 0, 0 ); |
|
b.val[1] = cvGetReal2D( &test_mat[INPUT][1], 1, 0 ); |
|
b.val[2] = cvGetReal2D( &test_mat[INPUT][1], 2, 0 ); |
|
} |
|
else if( test_mat[INPUT][0].cols > 1 ) |
|
{ |
|
a.val[0] = cvGetReal1D( &test_mat[INPUT][0], 0 ); |
|
a.val[1] = cvGetReal1D( &test_mat[INPUT][0], 1 ); |
|
a.val[2] = cvGetReal1D( &test_mat[INPUT][0], 2 ); |
|
|
|
b.val[0] = cvGetReal1D( &test_mat[INPUT][1], 0 ); |
|
b.val[1] = cvGetReal1D( &test_mat[INPUT][1], 1 ); |
|
b.val[2] = cvGetReal1D( &test_mat[INPUT][1], 2 ); |
|
} |
|
else |
|
{ |
|
a = cvGet1D( &test_mat[INPUT][0], 0 ); |
|
b = cvGet1D( &test_mat[INPUT][1], 0 ); |
|
} |
|
|
|
c.val[2] = a.val[0]*b.val[1] - a.val[1]*b.val[0]; |
|
c.val[1] = -a.val[0]*b.val[2] + a.val[2]*b.val[0]; |
|
c.val[0] = a.val[1]*b.val[2] - a.val[2]*b.val[1]; |
|
|
|
if( test_mat[REF_OUTPUT][0].rows > 1 ) |
|
{ |
|
cvSetReal2D( &test_mat[REF_OUTPUT][0], 0, 0, c.val[0] ); |
|
cvSetReal2D( &test_mat[REF_OUTPUT][0], 1, 0, c.val[1] ); |
|
cvSetReal2D( &test_mat[REF_OUTPUT][0], 2, 0, c.val[2] ); |
|
} |
|
else if( test_mat[REF_OUTPUT][0].cols > 1 ) |
|
{ |
|
cvSetReal1D( &test_mat[REF_OUTPUT][0], 0, c.val[0] ); |
|
cvSetReal1D( &test_mat[REF_OUTPUT][0], 1, c.val[1] ); |
|
cvSetReal1D( &test_mat[REF_OUTPUT][0], 2, c.val[2] ); |
|
} |
|
else |
|
{ |
|
cvSet1D( &test_mat[REF_OUTPUT][0], 0, c ); |
|
} |
|
} |
|
|
|
CxCore_CrossProductTest crossproduct_test; |
|
|
|
|
|
///////////////// scaleadd ///////////////////// |
|
|
|
class CxCore_ScaleAddTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_ScaleAddTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
int prepare_test_case( int test_case_idx ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
CvScalar alpha; |
|
bool test_nd; |
|
}; |
|
|
|
CxCore_ScaleAddTest::CxCore_ScaleAddTest() : |
|
CxCore_MatrixTest( "matrix-scaleadd", "cvScaleAdd", 3, 1, false, false, 4 ) |
|
{ |
|
alpha = cvScalarAll(0); |
|
test_nd = false; |
|
} |
|
|
|
|
|
void CxCore_ScaleAddTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
sizes[INPUT][2] = cvSize(1,1); |
|
types[INPUT][2] &= CV_MAT_DEPTH_MASK; |
|
test_nd = cvTsRandInt(ts->get_rng()) % 2 != 0; |
|
} |
|
|
|
|
|
void CxCore_ScaleAddTest::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types, |
|
whole_sizes, are_images ); |
|
sizes[INPUT][2] = cvSize(1,1); |
|
types[INPUT][2] &= CV_MAT_DEPTH_MASK; |
|
} |
|
|
|
|
|
int CxCore_ScaleAddTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = CxCore_MatrixTest::prepare_test_case( test_case_idx ); |
|
if( code > 0 ) |
|
alpha = cvGet1D( &test_mat[INPUT][2], 0 ); |
|
if( test_nd ) |
|
alpha.val[1] = 0; |
|
return code; |
|
} |
|
|
|
|
|
void CxCore_ScaleAddTest::run_func() |
|
{ |
|
if(!test_nd) |
|
cvScaleAdd( test_array[INPUT][0], alpha, test_array[INPUT][1], test_array[OUTPUT][0] ); |
|
else |
|
{ |
|
cv::MatND c = cv::cvarrToMatND(test_array[OUTPUT][0]); |
|
cv::scaleAdd( cv::cvarrToMatND(test_array[INPUT][0]), alpha.val[0], |
|
cv::cvarrToMatND(test_array[INPUT][1]), c); |
|
} |
|
} |
|
|
|
|
|
void CxCore_ScaleAddTest::prepare_to_validation( int ) |
|
{ |
|
cvTsAdd( &test_mat[INPUT][0], cvScalarAll(alpha.val[0]), |
|
&test_mat[INPUT][1], cvScalarAll(1.), |
|
cvScalarAll(0.), &test_mat[REF_OUTPUT][0], 0 ); |
|
} |
|
|
|
CxCore_ScaleAddTest scaleadd_test; |
|
|
|
|
|
///////////////// gemm ///////////////////// |
|
|
|
static const char* matrix_gemm_param_names[] = { "size", "add_c", "mul_type", "depth", 0 }; |
|
static const char* matrix_gemm_mul_types[] = { "AB", "AtB", "ABt", "AtBt", 0 }; |
|
static const int matrix_gemm_add_c_flags[] = { 0, 1 }; |
|
|
|
class CxCore_GEMMTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_GEMMTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
int write_default_params( CvFileStorage* fs ); |
|
void print_timing_params( int test_case_idx, char* ptr, int params_left ); |
|
int prepare_test_case( int test_case_idx ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
int tabc_flag; |
|
double alpha, beta; |
|
}; |
|
|
|
CxCore_GEMMTest::CxCore_GEMMTest() : |
|
CxCore_MatrixTest( "matrix-gemm", "cvGEMM", 5, 1, false, false, 2 ) |
|
{ |
|
test_case_count = 100; |
|
max_log_array_size = 10; |
|
default_timing_param_names = matrix_gemm_param_names; |
|
alpha = beta = 0; |
|
} |
|
|
|
|
|
void CxCore_GEMMTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
CvSize sizeA; |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
sizeA = sizes[INPUT][0]; |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
sizes[INPUT][0] = sizeA; |
|
sizes[INPUT][2] = sizes[INPUT][3] = cvSize(1,1); |
|
types[INPUT][2] = types[INPUT][3] &= ~CV_MAT_CN_MASK; |
|
|
|
tabc_flag = cvTsRandInt(rng) & 7; |
|
|
|
switch( tabc_flag & (CV_GEMM_A_T|CV_GEMM_B_T) ) |
|
{ |
|
case 0: |
|
sizes[INPUT][1].height = sizes[INPUT][0].width; |
|
sizes[OUTPUT][0].height = sizes[INPUT][0].height; |
|
sizes[OUTPUT][0].width = sizes[INPUT][1].width; |
|
break; |
|
case CV_GEMM_B_T: |
|
sizes[INPUT][1].width = sizes[INPUT][0].width; |
|
sizes[OUTPUT][0].height = sizes[INPUT][0].height; |
|
sizes[OUTPUT][0].width = sizes[INPUT][1].height; |
|
break; |
|
case CV_GEMM_A_T: |
|
sizes[INPUT][1].height = sizes[INPUT][0].height; |
|
sizes[OUTPUT][0].height = sizes[INPUT][0].width; |
|
sizes[OUTPUT][0].width = sizes[INPUT][1].width; |
|
break; |
|
case CV_GEMM_A_T | CV_GEMM_B_T: |
|
sizes[INPUT][1].width = sizes[INPUT][0].height; |
|
sizes[OUTPUT][0].height = sizes[INPUT][0].width; |
|
sizes[OUTPUT][0].width = sizes[INPUT][1].height; |
|
break; |
|
} |
|
|
|
sizes[REF_OUTPUT][0] = sizes[OUTPUT][0]; |
|
|
|
if( cvTsRandInt(rng) & 1 ) |
|
sizes[INPUT][4] = cvSize(0,0); |
|
else if( !(tabc_flag & CV_GEMM_C_T) ) |
|
sizes[INPUT][4] = sizes[OUTPUT][0]; |
|
else |
|
{ |
|
sizes[INPUT][4].width = sizes[OUTPUT][0].height; |
|
sizes[INPUT][4].height = sizes[OUTPUT][0].width; |
|
} |
|
} |
|
|
|
|
|
void CxCore_GEMMTest::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx, |
|
sizes, types, whole_sizes, are_images ); |
|
const char* mul_type = cvReadString( find_timing_param("mul_type"), "AB" ); |
|
if( strcmp( mul_type, "AtB" ) == 0 ) |
|
tabc_flag = CV_GEMM_A_T; |
|
else if( strcmp( mul_type, "ABt" ) == 0 ) |
|
tabc_flag = CV_GEMM_B_T; |
|
else if( strcmp( mul_type, "AtBt" ) == 0 ) |
|
tabc_flag = CV_GEMM_A_T + CV_GEMM_B_T; |
|
else |
|
tabc_flag = 0; |
|
|
|
if( cvReadInt( find_timing_param( "add_c" ), 0 ) == 0 ) |
|
sizes[INPUT][4] = cvSize(0,0); |
|
} |
|
|
|
|
|
int CxCore_GEMMTest::write_default_params( CvFileStorage* fs ) |
|
{ |
|
int code = CxCore_MatrixTest::write_default_params(fs); |
|
if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE ) |
|
return code; |
|
write_string_list( fs, "mul_type", matrix_gemm_mul_types ); |
|
write_int_list( fs, "add_c", matrix_gemm_add_c_flags, CV_DIM(matrix_gemm_add_c_flags) ); |
|
return code; |
|
} |
|
|
|
|
|
void CxCore_GEMMTest::print_timing_params( int test_case_idx, char* ptr, int params_left ) |
|
{ |
|
sprintf( ptr, "%s%s,%s,", |
|
tabc_flag & CV_GEMM_A_T ? "At" : "A", |
|
tabc_flag & CV_GEMM_B_T ? "Bt" : "B", |
|
test_array[INPUT][4] ? "plusC" : "" ); |
|
ptr += strlen(ptr); |
|
params_left -= 2; |
|
CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left ); |
|
} |
|
|
|
|
|
int CxCore_GEMMTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = CxCore_MatrixTest::prepare_test_case( test_case_idx ); |
|
if( code > 0 ) |
|
{ |
|
alpha = cvmGet( &test_mat[INPUT][2], 0, 0 ); |
|
beta = cvmGet( &test_mat[INPUT][3], 0, 0 ); |
|
} |
|
return code; |
|
} |
|
|
|
|
|
void CxCore_GEMMTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ) |
|
{ |
|
*low = cvScalarAll(-10.); |
|
*high = cvScalarAll(10.); |
|
} |
|
|
|
|
|
void CxCore_GEMMTest::run_func() |
|
{ |
|
cvGEMM( test_array[INPUT][0], test_array[INPUT][1], alpha, |
|
test_array[INPUT][4], beta, test_array[OUTPUT][0], tabc_flag ); |
|
} |
|
|
|
|
|
void CxCore_GEMMTest::prepare_to_validation( int ) |
|
{ |
|
cvTsGEMM( &test_mat[INPUT][0], &test_mat[INPUT][1], alpha, |
|
test_array[INPUT][4] ? &test_mat[INPUT][4] : 0, |
|
beta, &test_mat[REF_OUTPUT][0], tabc_flag ); |
|
} |
|
|
|
CxCore_GEMMTest gemm_test; |
|
|
|
|
|
///////////////// multransposed ///////////////////// |
|
|
|
static const char* matrix_multrans_param_names[] = { "size", "use_delta", "mul_type", "depth", 0 }; |
|
static const int matrix_multrans_use_delta_flags[] = { 0, 1 }; |
|
static const char* matrix_multrans_mul_types[] = { "AAt", "AtA", 0 }; |
|
|
|
class CxCore_MulTransposedTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_MulTransposedTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
int write_default_params( CvFileStorage* fs ); |
|
void print_timing_params( int test_case_idx, char* ptr, int params_left ); |
|
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
int order; |
|
}; |
|
|
|
|
|
CxCore_MulTransposedTest::CxCore_MulTransposedTest() : |
|
CxCore_MatrixTest( "matrix-multransposed", "cvMulTransposed, cvRepeat", 2, 1, false, false, 1 ) |
|
{ |
|
test_case_count = 100; |
|
order = 0; |
|
test_array[TEMP].push(NULL); |
|
default_timing_param_names = matrix_multrans_param_names; |
|
} |
|
|
|
|
|
void CxCore_MulTransposedTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int bits = cvTsRandInt(rng); |
|
int src_type = cvTsRandInt(rng) % 5; |
|
int dst_type = cvTsRandInt(rng) % 2; |
|
|
|
src_type = src_type == 0 ? CV_8U : src_type == 1 ? CV_16U : src_type == 2 ? CV_16S : |
|
src_type == 3 ? CV_32F : CV_64F; |
|
dst_type = dst_type == 0 ? CV_32F : CV_64F; |
|
dst_type = MAX( dst_type, src_type ); |
|
|
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
|
|
if( bits & 1 ) |
|
sizes[INPUT][1] = cvSize(0,0); |
|
else |
|
{ |
|
sizes[INPUT][1] = sizes[INPUT][0]; |
|
if( bits & 2 ) |
|
sizes[INPUT][1].height = 1; |
|
if( bits & 4 ) |
|
sizes[INPUT][1].width = 1; |
|
} |
|
|
|
sizes[TEMP][0] = sizes[INPUT][0]; |
|
types[INPUT][0] = src_type; |
|
types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][1] = types[TEMP][0] = dst_type; |
|
|
|
order = (bits & 8) != 0; |
|
sizes[OUTPUT][0].width = sizes[OUTPUT][0].height = order == 0 ? |
|
sizes[INPUT][0].height : sizes[INPUT][0].width; |
|
sizes[REF_OUTPUT][0] = sizes[OUTPUT][0]; |
|
} |
|
|
|
|
|
void CxCore_MulTransposedTest::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx, |
|
sizes, types, whole_sizes, are_images ); |
|
const char* mul_type = cvReadString( find_timing_param("mul_type"), "AAt" ); |
|
order = strcmp( mul_type, "AtA" ) == 0; |
|
|
|
if( cvReadInt( find_timing_param( "use_delta" ), 0 ) == 0 ) |
|
sizes[INPUT][1] = cvSize(0,0); |
|
} |
|
|
|
|
|
int CxCore_MulTransposedTest::write_default_params( CvFileStorage* fs ) |
|
{ |
|
int code = CxCore_MatrixTest::write_default_params(fs); |
|
if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE ) |
|
return code; |
|
write_string_list( fs, "mul_type", matrix_multrans_mul_types ); |
|
write_int_list( fs, "use_delta", matrix_multrans_use_delta_flags, |
|
CV_DIM(matrix_multrans_use_delta_flags) ); |
|
return code; |
|
} |
|
|
|
|
|
void CxCore_MulTransposedTest::print_timing_params( int test_case_idx, char* ptr, int params_left ) |
|
{ |
|
sprintf( ptr, "%s,%s,", order == 0 ? "AAt" : "AtA", test_array[INPUT][1] ? "delta" : "" ); |
|
ptr += strlen(ptr); |
|
params_left -= 2; |
|
CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left ); |
|
} |
|
|
|
|
|
void CxCore_MulTransposedTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ) |
|
{ |
|
*low = cvScalarAll(-10.); |
|
*high = cvScalarAll(10.); |
|
} |
|
|
|
|
|
void CxCore_MulTransposedTest::run_func() |
|
{ |
|
cvMulTransposed( test_array[INPUT][0], test_array[OUTPUT][0], |
|
order, test_array[INPUT][1] ); |
|
} |
|
|
|
|
|
void CxCore_MulTransposedTest::prepare_to_validation( int ) |
|
{ |
|
CvMat* delta = test_array[INPUT][1] ? &test_mat[INPUT][1] : 0; |
|
if( delta ) |
|
{ |
|
if( test_mat[INPUT][1].rows < test_mat[INPUT][0].rows || |
|
test_mat[INPUT][1].cols < test_mat[INPUT][0].cols ) |
|
{ |
|
cvRepeat( delta, &test_mat[TEMP][0] ); |
|
delta = &test_mat[TEMP][0]; |
|
} |
|
cvTsAdd( &test_mat[INPUT][0], cvScalarAll(1.), delta, cvScalarAll(-1.), |
|
cvScalarAll(0.), &test_mat[TEMP][0], 0 ); |
|
} |
|
else |
|
cvTsConvert( &test_mat[INPUT][0], &test_mat[TEMP][0] ); |
|
delta = &test_mat[TEMP][0]; |
|
|
|
cvTsGEMM( delta, delta, 1., 0, 0, &test_mat[REF_OUTPUT][0], order == 0 ? CV_GEMM_B_T : CV_GEMM_A_T ); |
|
} |
|
|
|
CxCore_MulTransposedTest multransposed_test; |
|
|
|
|
|
///////////////// Transform ///////////////////// |
|
|
|
static const CvSize matrix_transform_sizes[] = {{10,10}, {100,100}, {720,480}, {-1,-1}}; |
|
static const CvSize matrix_transform_whole_sizes[] = {{10,10}, {720,480}, {720,480}, {-1,-1}}; |
|
static const int matrix_transform_channels[] = { 2, 3, 4, -1 }; |
|
static const char* matrix_transform_param_names[] = { "size", "channels", "depth", 0 }; |
|
|
|
class CxCore_TransformTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_TransformTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
int prepare_test_case( int test_case_idx ); |
|
void print_timing_params( int test_case_idx, char* ptr, int params_left ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
|
|
double scale; |
|
bool diagMtx; |
|
}; |
|
|
|
|
|
CxCore_TransformTest::CxCore_TransformTest() : |
|
CxCore_MatrixTest( "matrix-transform", "cvTransform", 3, 1, true, false, 4 ) |
|
{ |
|
default_timing_param_names = matrix_transform_param_names; |
|
cn_list = matrix_transform_channels; |
|
depth_list = matrix_all_depths; |
|
size_list = matrix_transform_sizes; |
|
whole_size_list = matrix_transform_whole_sizes; |
|
} |
|
|
|
|
|
void CxCore_TransformTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int bits = cvTsRandInt(rng); |
|
int depth, dst_cn, mat_cols, mattype; |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
|
|
mat_cols = CV_MAT_CN(types[INPUT][0]); |
|
depth = CV_MAT_DEPTH(types[INPUT][0]); |
|
dst_cn = cvTsRandInt(rng) % 4 + 1; |
|
types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, dst_cn); |
|
|
|
mattype = depth < CV_32S ? CV_32F : depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F; |
|
types[INPUT][1] = mattype; |
|
types[INPUT][2] = CV_MAKETYPE(mattype, dst_cn); |
|
|
|
scale = 1./((cvTsRandInt(rng)%4)*50+1); |
|
|
|
if( bits & 2 ) |
|
{ |
|
sizes[INPUT][2] = cvSize(0,0); |
|
mat_cols += (bits & 4) != 0; |
|
} |
|
else if( bits & 4 ) |
|
sizes[INPUT][2] = cvSize(1,1); |
|
else |
|
{ |
|
if( bits & 8 ) |
|
sizes[INPUT][2] = cvSize(dst_cn,1); |
|
else |
|
sizes[INPUT][2] = cvSize(1,dst_cn); |
|
types[INPUT][2] &= ~CV_MAT_CN_MASK; |
|
} |
|
diagMtx = (bits & 16) != 0; |
|
|
|
sizes[INPUT][1] = cvSize(mat_cols,dst_cn); |
|
} |
|
|
|
|
|
void CxCore_TransformTest::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx, |
|
sizes, types, whole_sizes, are_images ); |
|
int cn = CV_MAT_CN(types[INPUT][0]); |
|
sizes[INPUT][1] = cvSize(cn + (cn < 4), cn); |
|
sizes[INPUT][2] = cvSize(0,0); |
|
types[INPUT][1] = types[INPUT][2] = CV_64FC1; |
|
scale = 1./1000; |
|
} |
|
|
|
int CxCore_TransformTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = CxCore_MatrixTest::prepare_test_case( test_case_idx ); |
|
if( code > 0 ) |
|
{ |
|
cvTsAdd(&test_mat[INPUT][1], cvScalarAll(scale), &test_mat[INPUT][1], |
|
cvScalarAll(0), cvScalarAll(0), &test_mat[INPUT][1], 0 ); |
|
if(diagMtx) |
|
{ |
|
CvMat* w = cvCloneMat(&test_mat[INPUT][1]); |
|
cvSetIdentity(w, cvScalarAll(1)); |
|
cvMul(w, &test_mat[INPUT][1], &test_mat[INPUT][1]); |
|
cvReleaseMat(&w); |
|
} |
|
} |
|
return code; |
|
} |
|
|
|
void CxCore_TransformTest::print_timing_params( int test_case_idx, char* ptr, int params_left ) |
|
{ |
|
CvSize size = cvGetMatSize(&test_mat[INPUT][1]); |
|
sprintf( ptr, "matrix=%dx%d,", size.height, size.width ); |
|
ptr += strlen(ptr); |
|
params_left--; |
|
CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left ); |
|
} |
|
|
|
|
|
double CxCore_TransformTest::get_success_error_level( int test_case_idx, int i, int j ) |
|
{ |
|
int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type); |
|
return depth <= CV_8S ? 1 : depth <= CV_32S ? 8 : |
|
CxCore_MatrixTest::get_success_error_level( test_case_idx, i, j ); |
|
} |
|
|
|
void CxCore_TransformTest::run_func() |
|
{ |
|
cvTransform( test_array[INPUT][0], test_array[OUTPUT][0], &test_mat[INPUT][1], |
|
test_array[INPUT][2] ? &test_mat[INPUT][2] : 0); |
|
} |
|
|
|
|
|
void CxCore_TransformTest::prepare_to_validation( int ) |
|
{ |
|
CvMat* transmat = &test_mat[INPUT][1]; |
|
CvMat* shift = test_array[INPUT][2] ? &test_mat[INPUT][2] : 0; |
|
|
|
cvTsTransform( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0], transmat, shift ); |
|
} |
|
|
|
//CxCore_TransformTest transform_test; |
|
|
|
|
|
///////////////// PerspectiveTransform ///////////////////// |
|
|
|
static const int matrix_perspective_transform_channels[] = { 2, 3, -1 }; |
|
|
|
class CxCore_PerspectiveTransformTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_PerspectiveTransformTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
}; |
|
|
|
|
|
CxCore_PerspectiveTransformTest::CxCore_PerspectiveTransformTest() : |
|
CxCore_MatrixTest( "matrix-perspective", "cvPerspectiveTransform", 2, 1, false, false, 2 ) |
|
{ |
|
default_timing_param_names = matrix_transform_param_names; |
|
cn_list = matrix_perspective_transform_channels; |
|
size_list = matrix_transform_sizes; |
|
whole_size_list = matrix_transform_whole_sizes; |
|
} |
|
|
|
|
|
void CxCore_PerspectiveTransformTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int bits = cvTsRandInt(rng); |
|
int depth, cn, mattype; |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
|
|
cn = CV_MAT_CN(types[INPUT][0]) + 1; |
|
depth = CV_MAT_DEPTH(types[INPUT][0]); |
|
types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn); |
|
|
|
mattype = depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F; |
|
types[INPUT][1] = mattype; |
|
sizes[INPUT][1] = cvSize(cn + 1, cn + 1); |
|
} |
|
|
|
|
|
double CxCore_PerspectiveTransformTest::get_success_error_level( int test_case_idx, int i, int j ) |
|
{ |
|
int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type); |
|
return depth == CV_32F ? 1e-4 : depth == CV_64F ? 1e-8 : |
|
CxCore_MatrixTest::get_success_error_level(test_case_idx, i, j); |
|
} |
|
|
|
|
|
void CxCore_PerspectiveTransformTest::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx, |
|
sizes, types, whole_sizes, are_images ); |
|
int cn = CV_MAT_CN(types[INPUT][0]); |
|
sizes[INPUT][1] = cvSize(cn + 1, cn + 1); |
|
types[INPUT][1] = CV_64FC1; |
|
} |
|
|
|
|
|
void CxCore_PerspectiveTransformTest::run_func() |
|
{ |
|
cvPerspectiveTransform( test_array[INPUT][0], test_array[OUTPUT][0], &test_mat[INPUT][1] ); |
|
} |
|
|
|
|
|
static void cvTsPerspectiveTransform( const CvArr* _src, CvArr* _dst, const CvMat* transmat ) |
|
{ |
|
int i, j, cols; |
|
int cn, depth, mat_depth; |
|
CvMat astub, bstub, *a, *b; |
|
double mat[16], *buf; |
|
|
|
a = cvGetMat( _src, &astub, 0, 0 ); |
|
b = cvGetMat( _dst, &bstub, 0, 0 ); |
|
|
|
cn = CV_MAT_CN(a->type); |
|
depth = CV_MAT_DEPTH(a->type); |
|
mat_depth = CV_MAT_DEPTH(transmat->type); |
|
cols = transmat->cols; |
|
|
|
// prepare cn x (cn + 1) transform matrix |
|
if( mat_depth == CV_32F ) |
|
{ |
|
for( i = 0; i < transmat->rows; i++ ) |
|
for( j = 0; j < cols; j++ ) |
|
mat[i*cols + j] = ((float*)(transmat->data.ptr + transmat->step*i))[j]; |
|
} |
|
else |
|
{ |
|
assert( mat_depth == CV_64F ); |
|
for( i = 0; i < transmat->rows; i++ ) |
|
for( j = 0; j < cols; j++ ) |
|
mat[i*cols + j] = ((double*)(transmat->data.ptr + transmat->step*i))[j]; |
|
} |
|
|
|
// transform data |
|
cols = a->cols * cn; |
|
buf = (double*)cvStackAlloc( cols * sizeof(double) ); |
|
|
|
for( i = 0; i < a->rows; i++ ) |
|
{ |
|
uchar* src = a->data.ptr + i*a->step; |
|
uchar* dst = b->data.ptr + i*b->step; |
|
|
|
switch( depth ) |
|
{ |
|
case CV_32F: |
|
for( j = 0; j < cols; j++ ) |
|
buf[j] = ((float*)src)[j]; |
|
break; |
|
case CV_64F: |
|
for( j = 0; j < cols; j++ ) |
|
buf[j] = ((double*)src)[j]; |
|
break; |
|
default: |
|
assert(0); |
|
} |
|
|
|
switch( cn ) |
|
{ |
|
case 2: |
|
for( j = 0; j < cols; j += 2 ) |
|
{ |
|
double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + mat[2]; |
|
double t1 = buf[j]*mat[3] + buf[j+1]*mat[4] + mat[5]; |
|
double w = buf[j]*mat[6] + buf[j+1]*mat[7] + mat[8]; |
|
w = w ? 1./w : 0; |
|
buf[j] = t0*w; |
|
buf[j+1] = t1*w; |
|
} |
|
break; |
|
case 3: |
|
for( j = 0; j < cols; j += 3 ) |
|
{ |
|
double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + buf[j+2]*mat[2] + mat[3]; |
|
double t1 = buf[j]*mat[4] + buf[j+1]*mat[5] + buf[j+2]*mat[6] + mat[7]; |
|
double t2 = buf[j]*mat[8] + buf[j+1]*mat[9] + buf[j+2]*mat[10] + mat[11]; |
|
double w = buf[j]*mat[12] + buf[j+1]*mat[13] + buf[j+2]*mat[14] + mat[15]; |
|
w = w ? 1./w : 0; |
|
buf[j] = t0*w; |
|
buf[j+1] = t1*w; |
|
buf[j+2] = t2*w; |
|
} |
|
break; |
|
default: |
|
assert(0); |
|
} |
|
|
|
switch( depth ) |
|
{ |
|
case CV_32F: |
|
for( j = 0; j < cols; j++ ) |
|
((float*)dst)[j] = (float)buf[j]; |
|
break; |
|
case CV_64F: |
|
for( j = 0; j < cols; j++ ) |
|
((double*)dst)[j] = buf[j]; |
|
break; |
|
default: |
|
assert(0); |
|
} |
|
} |
|
} |
|
|
|
|
|
void CxCore_PerspectiveTransformTest::prepare_to_validation( int ) |
|
{ |
|
CvMat* transmat = &test_mat[INPUT][1]; |
|
cvTsPerspectiveTransform( test_array[INPUT][0], test_array[REF_OUTPUT][0], transmat ); |
|
} |
|
|
|
CxCore_PerspectiveTransformTest perspective_test; |
|
|
|
|
|
///////////////// Mahalanobis ///////////////////// |
|
|
|
class CxCore_MahalanobisTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_MahalanobisTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
int prepare_test_case( int test_case_idx ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
}; |
|
|
|
|
|
CxCore_MahalanobisTest::CxCore_MahalanobisTest() : |
|
CxCore_MatrixTest( "matrix-mahalanobis", "cvMahalanobis", 3, 1, false, true, 1 ) |
|
{ |
|
test_case_count = 100; |
|
test_array[TEMP].push(NULL); |
|
test_array[TEMP].push(NULL); |
|
test_array[TEMP].push(NULL); |
|
} |
|
|
|
|
|
void CxCore_MahalanobisTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
|
|
if( cvTsRandInt(rng) & 1 ) |
|
sizes[INPUT][0].width = sizes[INPUT][1].width = 1; |
|
else |
|
sizes[INPUT][0].height = sizes[INPUT][1].height = 1; |
|
|
|
sizes[TEMP][0] = sizes[TEMP][1] = sizes[INPUT][0]; |
|
sizes[INPUT][2].width = sizes[INPUT][2].height = sizes[INPUT][0].width + sizes[INPUT][0].height - 1; |
|
sizes[TEMP][2] = sizes[INPUT][2]; |
|
types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0]; |
|
} |
|
|
|
|
|
void CxCore_MahalanobisTest::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx, |
|
sizes, types, whole_sizes, are_images ); |
|
sizes[INPUT][0].height = sizes[INPUT][1].height = 1; |
|
} |
|
|
|
|
|
int CxCore_MahalanobisTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = CxCore_MatrixTest::prepare_test_case( test_case_idx ); |
|
if( code > 0 && ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE ) |
|
{ |
|
// make sure that the inverted "covariation" matrix is symmetrix and positively defined. |
|
cvTsGEMM( &test_mat[INPUT][2], &test_mat[INPUT][2], 1., 0, 0., &test_mat[TEMP][2], CV_GEMM_B_T ); |
|
cvTsCopy( &test_mat[TEMP][2], &test_mat[INPUT][2] ); |
|
} |
|
|
|
return code; |
|
} |
|
|
|
|
|
void CxCore_MahalanobisTest::run_func() |
|
{ |
|
*((CvScalar*)(test_mat[OUTPUT][0].data.db)) = |
|
cvRealScalar(cvMahalanobis(test_array[INPUT][0], test_array[INPUT][1], test_array[INPUT][2])); |
|
} |
|
|
|
void CxCore_MahalanobisTest::prepare_to_validation( int ) |
|
{ |
|
cvTsAdd( &test_mat[INPUT][0], cvScalarAll(1.), |
|
&test_mat[INPUT][1], cvScalarAll(-1.), |
|
cvScalarAll(0.), &test_mat[TEMP][0], 0 ); |
|
if( test_mat[INPUT][0].rows == 1 ) |
|
cvTsGEMM( &test_mat[TEMP][0], &test_mat[INPUT][2], 1., |
|
0, 0., &test_mat[TEMP][1], 0 ); |
|
else |
|
cvTsGEMM( &test_mat[INPUT][2], &test_mat[TEMP][0], 1., |
|
0, 0., &test_mat[TEMP][1], 0 ); |
|
|
|
*((CvScalar*)(test_mat[REF_OUTPUT][0].data.db)) = |
|
cvRealScalar(sqrt(cvTsCrossCorr(&test_mat[TEMP][0], &test_mat[TEMP][1]))); |
|
} |
|
|
|
CxCore_MahalanobisTest mahalanobis_test; |
|
|
|
|
|
///////////////// covarmatrix ///////////////////// |
|
|
|
class CxCore_CovarMatrixTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_CovarMatrixTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
int prepare_test_case( int test_case_idx ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
CvTestPtrVec temp_hdrs; |
|
uchar* hdr_data; |
|
int flags, t_flag, len, count; |
|
bool are_images; |
|
}; |
|
|
|
|
|
CxCore_CovarMatrixTest::CxCore_CovarMatrixTest() : |
|
CxCore_MatrixTest( "matrix-covar", "cvCalcCovarMatrix", 1, 1, true, false, 1 ), |
|
flags(0), t_flag(0), are_images(false) |
|
{ |
|
test_case_count = 100; |
|
test_array[INPUT_OUTPUT].push(NULL); |
|
test_array[REF_INPUT_OUTPUT].push(NULL); |
|
test_array[TEMP].push(NULL); |
|
test_array[TEMP].push(NULL); |
|
|
|
support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE; |
|
} |
|
|
|
|
|
void CxCore_CovarMatrixTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int bits = cvTsRandInt(rng); |
|
int i, single_matrix; |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
|
|
flags = bits & (CV_COVAR_NORMAL | CV_COVAR_USE_AVG | CV_COVAR_SCALE | CV_COVAR_ROWS ); |
|
single_matrix = flags & CV_COVAR_ROWS; |
|
t_flag = (bits & 256) != 0; |
|
|
|
const int min_count = 2; |
|
|
|
if( !t_flag ) |
|
{ |
|
len = sizes[INPUT][0].width; |
|
count = sizes[INPUT][0].height; |
|
count = MAX(count, min_count); |
|
sizes[INPUT][0] = cvSize(len, count); |
|
} |
|
else |
|
{ |
|
len = sizes[INPUT][0].height; |
|
count = sizes[INPUT][0].width; |
|
count = MAX(count, min_count); |
|
sizes[INPUT][0] = cvSize(count, len); |
|
} |
|
|
|
if( single_matrix && t_flag ) |
|
flags = (flags & ~CV_COVAR_ROWS) | CV_COVAR_COLS; |
|
|
|
if( CV_MAT_DEPTH(types[INPUT][0]) == CV_32S ) |
|
types[INPUT][0] = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK) | CV_32F; |
|
|
|
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = flags & CV_COVAR_NORMAL ? cvSize(len,len) : cvSize(count,count); |
|
sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = !t_flag ? cvSize(len,1) : cvSize(1,len); |
|
sizes[TEMP][0] = sizes[INPUT][0]; |
|
|
|
types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = |
|
types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0] = |
|
CV_MAT_DEPTH(types[INPUT][0]) == CV_64F || (bits & 512) ? CV_64F : CV_32F; |
|
|
|
are_images = (bits & 1024) != 0; |
|
for( i = 0; i < (single_matrix ? 1 : count); i++ ) |
|
temp_hdrs.push(NULL); |
|
} |
|
|
|
|
|
int CxCore_CovarMatrixTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = CxCore_MatrixTest::prepare_test_case( test_case_idx ); |
|
if( code > 0 ) |
|
{ |
|
int i; |
|
int single_matrix = flags & (CV_COVAR_ROWS|CV_COVAR_COLS); |
|
int hdr_size = are_images ? sizeof(IplImage) : sizeof(CvMat); |
|
|
|
hdr_data = (uchar*)cvAlloc( count*hdr_size ); |
|
if( single_matrix ) |
|
{ |
|
if( !are_images ) |
|
*((CvMat*)hdr_data) = test_mat[INPUT][0]; |
|
else |
|
cvGetImage( &test_mat[INPUT][0], (IplImage*)hdr_data ); |
|
temp_hdrs[0] = hdr_data; |
|
} |
|
else |
|
for( i = 0; i < count; i++ ) |
|
{ |
|
CvMat part; |
|
void* ptr = hdr_data + i*hdr_size; |
|
|
|
if( !t_flag ) |
|
cvGetRow( &test_mat[INPUT][0], &part, i ); |
|
else |
|
cvGetCol( &test_mat[INPUT][0], &part, i ); |
|
|
|
if( !are_images ) |
|
*((CvMat*)ptr) = part; |
|
else |
|
cvGetImage( &part, (IplImage*)ptr ); |
|
|
|
temp_hdrs[i] = ptr; |
|
} |
|
} |
|
|
|
return code; |
|
} |
|
|
|
|
|
void CxCore_CovarMatrixTest::run_func() |
|
{ |
|
cvCalcCovarMatrix( (const void**)&temp_hdrs[0], count, |
|
test_array[OUTPUT][0], test_array[INPUT_OUTPUT][0], flags ); |
|
} |
|
|
|
|
|
void CxCore_CovarMatrixTest::prepare_to_validation( int ) |
|
{ |
|
CvMat* avg = &test_mat[REF_INPUT_OUTPUT][0]; |
|
double scale = 1.; |
|
|
|
if( !(flags & CV_COVAR_USE_AVG) ) |
|
{ |
|
int i; |
|
cvTsZero( avg ); |
|
|
|
for( i = 0; i < count; i++ ) |
|
{ |
|
CvMat stub, *vec = 0; |
|
if( flags & CV_COVAR_ROWS ) |
|
vec = cvGetRow( temp_hdrs[0], &stub, i ); |
|
else if( flags & CV_COVAR_COLS ) |
|
vec = cvGetCol( temp_hdrs[0], &stub, i ); |
|
else |
|
vec = cvGetMat( temp_hdrs[i], &stub ); |
|
|
|
cvTsAdd( avg, cvScalarAll(1.), vec, |
|
cvScalarAll(1.), cvScalarAll(0.), avg, 0 ); |
|
} |
|
|
|
cvTsAdd( avg, cvScalarAll(1./count), 0, |
|
cvScalarAll(0.), cvScalarAll(0.), avg, 0 ); |
|
} |
|
|
|
if( flags & CV_COVAR_SCALE ) |
|
{ |
|
scale = 1./count; |
|
} |
|
|
|
cvRepeat( avg, &test_mat[TEMP][0] ); |
|
cvTsAdd( &test_mat[INPUT][0], cvScalarAll(1.), |
|
&test_mat[TEMP][0], cvScalarAll(-1.), |
|
cvScalarAll(0.), &test_mat[TEMP][0], 0 ); |
|
|
|
cvTsGEMM( &test_mat[TEMP][0], &test_mat[TEMP][0], |
|
scale, 0, 0., &test_mat[REF_OUTPUT][0], |
|
t_flag ^ ((flags & CV_COVAR_NORMAL) != 0) ? |
|
CV_GEMM_A_T : CV_GEMM_B_T ); |
|
|
|
cvFree( &hdr_data ); |
|
temp_hdrs.clear(); |
|
} |
|
|
|
CxCore_CovarMatrixTest covarmatrix_test; |
|
|
|
|
|
static void cvTsFloodWithZeros( CvMat* mat, CvRNG* rng ) |
|
{ |
|
int k, total = mat->rows*mat->cols; |
|
int zero_total = cvTsRandInt(rng) % total; |
|
assert( CV_MAT_TYPE(mat->type) == CV_32FC1 || |
|
CV_MAT_TYPE(mat->type) == CV_64FC1 ); |
|
|
|
for( k = 0; k < zero_total; k++ ) |
|
{ |
|
int i = cvTsRandInt(rng) % mat->rows; |
|
int j = cvTsRandInt(rng) % mat->cols; |
|
uchar* row = mat->data.ptr + mat->step*i; |
|
|
|
if( CV_MAT_DEPTH(mat->type) == CV_32FC1 ) |
|
((float*)row)[j] = 0.f; |
|
else |
|
((double*)row)[j] = 0.; |
|
} |
|
} |
|
|
|
|
|
///////////////// determinant ///////////////////// |
|
|
|
class CxCore_DetTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_DetTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ); |
|
int prepare_test_case( int test_case_idx ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
}; |
|
|
|
|
|
CxCore_DetTest::CxCore_DetTest() : |
|
CxCore_MatrixTest( "matrix-det", "cvDet", 1, 1, false, true, 1 ) |
|
{ |
|
test_case_count = 100; |
|
max_log_array_size = 7; |
|
test_array[TEMP].push(NULL); |
|
} |
|
|
|
|
|
void CxCore_DetTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
|
|
sizes[INPUT][0].width = sizes[INPUT][0].height = sizes[INPUT][0].height; |
|
sizes[TEMP][0] = sizes[INPUT][0]; |
|
types[TEMP][0] = CV_64FC1; |
|
} |
|
|
|
|
|
void CxCore_DetTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ) |
|
{ |
|
*low = cvScalarAll(-2.); |
|
*high = cvScalarAll(2.); |
|
} |
|
|
|
|
|
double CxCore_DetTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) |
|
{ |
|
return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-2 : 1e-5; |
|
} |
|
|
|
|
|
int CxCore_DetTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = CxCore_MatrixTest::prepare_test_case( test_case_idx ); |
|
if( code > 0 ) |
|
cvTsFloodWithZeros( &test_mat[INPUT][0], ts->get_rng() ); |
|
|
|
return code; |
|
} |
|
|
|
|
|
void CxCore_DetTest::run_func() |
|
{ |
|
*((CvScalar*)(test_mat[OUTPUT][0].data.db)) = cvRealScalar(cvDet(test_array[INPUT][0])); |
|
} |
|
|
|
|
|
// LU method that chooses the optimal in a column pivot element |
|
static double cvTsLU( CvMat* a, CvMat* b=NULL, CvMat* x=NULL, int* rank=0 ) |
|
{ |
|
int i, j, k, N = a->rows, N1 = a->cols, Nm = MIN(N, N1), step = a->step/sizeof(double); |
|
int M = b ? b->cols : 0, b_step = b ? b->step/sizeof(double) : 0; |
|
int x_step = x ? x->step/sizeof(double) : 0; |
|
double *a0 = a->data.db, *b0 = b ? b->data.db : 0; |
|
double *x0 = x ? x->data.db : 0; |
|
double t, det = 1.; |
|
assert( CV_MAT_TYPE(a->type) == CV_64FC1 && |
|
(!b || CV_ARE_TYPES_EQ(a,b)) && (!x || CV_ARE_TYPES_EQ(a,x))); |
|
|
|
for( i = 0; i < Nm; i++ ) |
|
{ |
|
double max_val = fabs(a0[i*step + i]); |
|
double *a1, *a2, *b1 = 0, *b2 = 0; |
|
k = i; |
|
|
|
for( j = i+1; j < N; j++ ) |
|
{ |
|
t = fabs(a0[j*step + i]); |
|
if( max_val < t ) |
|
{ |
|
max_val = t; |
|
k = j; |
|
} |
|
} |
|
|
|
if( k != i ) |
|
{ |
|
for( j = i; j < N1; j++ ) |
|
CV_SWAP( a0[i*step + j], a0[k*step + j], t ); |
|
|
|
for( j = 0; j < M; j++ ) |
|
CV_SWAP( b0[i*b_step + j], b0[k*b_step + j], t ); |
|
det = -det; |
|
} |
|
|
|
if( max_val == 0 ) |
|
{ |
|
if( rank ) |
|
*rank = i; |
|
return 0.; |
|
} |
|
|
|
a1 = a0 + i*step; |
|
a2 = a1 + step; |
|
b1 = b0 + i*b_step; |
|
b2 = b1 + b_step; |
|
|
|
for( j = i+1; j < N; j++, a2 += step, b2 += b_step ) |
|
{ |
|
t = a2[i]/a1[i]; |
|
for( k = i+1; k < N1; k++ ) |
|
a2[k] -= t*a1[k]; |
|
|
|
for( k = 0; k < M; k++ ) |
|
b2[k] -= t*b1[k]; |
|
} |
|
|
|
det *= a1[i]; |
|
} |
|
|
|
if( x ) |
|
{ |
|
assert( b ); |
|
|
|
for( i = N-1; i >= 0; i-- ) |
|
{ |
|
double* a1 = a0 + i*step; |
|
double* b1 = b0 + i*b_step; |
|
for( j = 0; j < M; j++ ) |
|
{ |
|
t = b1[j]; |
|
for( k = i+1; k < N1; k++ ) |
|
t -= a1[k]*x0[k*x_step + j]; |
|
x0[i*x_step + j] = t/a1[i]; |
|
} |
|
} |
|
} |
|
|
|
if( rank ) |
|
*rank = i; |
|
return det; |
|
} |
|
|
|
|
|
void CxCore_DetTest::prepare_to_validation( int ) |
|
{ |
|
if( !CV_ARE_TYPES_EQ( &test_mat[INPUT][0], &test_mat[TEMP][0] )) |
|
cvTsConvert( &test_mat[INPUT][0], &test_mat[TEMP][0] ); |
|
else |
|
cvTsCopy( &test_mat[INPUT][0], &test_mat[TEMP][0], 0 ); |
|
|
|
*((CvScalar*)(test_mat[REF_OUTPUT][0].data.db)) = cvRealScalar(cvTsLU(&test_mat[TEMP][0], 0, 0)); |
|
} |
|
|
|
CxCore_DetTest det_test; |
|
|
|
|
|
|
|
///////////////// invert ///////////////////// |
|
|
|
static const char* matrix_solve_invert_param_names[] = { "size", "method", "depth", 0 }; |
|
static const char* matrix_solve_invert_methods[] = { "LU", "SVD", 0 }; |
|
|
|
class CxCore_InvertTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_InvertTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
int write_default_params( CvFileStorage* fs ); |
|
void print_timing_params( int test_case_idx, char* ptr, int params_left ); |
|
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
int prepare_test_case( int test_case_idx ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
int method, rank; |
|
double result; |
|
}; |
|
|
|
|
|
CxCore_InvertTest::CxCore_InvertTest() : |
|
CxCore_MatrixTest( "matrix-invert", "cvInvert, cvSVD, cvSVBkSb", 1, 1, false, false, 1 ), method(0), rank(0), result(0.) |
|
{ |
|
test_case_count = 100; |
|
max_log_array_size = 7; |
|
test_array[TEMP].push(NULL); |
|
test_array[TEMP].push(NULL); |
|
|
|
default_timing_param_names = matrix_solve_invert_param_names; |
|
} |
|
|
|
|
|
void CxCore_InvertTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int bits = cvTsRandInt(rng); |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height ); |
|
|
|
if( (bits & 3) == 0 ) |
|
{ |
|
method = CV_SVD; |
|
if( bits & 4 ) |
|
{ |
|
sizes[INPUT][0] = cvSize(min_size, min_size); |
|
if( bits & 16 ) |
|
method = CV_CHOLESKY; |
|
} |
|
} |
|
else |
|
{ |
|
method = CV_LU; |
|
sizes[INPUT][0] = cvSize(min_size, min_size); |
|
} |
|
|
|
sizes[TEMP][0].width = sizes[INPUT][0].height; |
|
sizes[TEMP][0].height = sizes[INPUT][0].width; |
|
sizes[TEMP][1] = sizes[INPUT][0]; |
|
types[TEMP][0] = types[INPUT][0]; |
|
types[TEMP][1] = CV_64FC1; |
|
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(min_size, min_size); |
|
} |
|
|
|
|
|
void CxCore_InvertTest::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx, |
|
sizes, types, whole_sizes, are_images ); |
|
const char* method_str = cvReadString( find_timing_param("method"), "LU" ); |
|
method = strcmp( method_str, "LU" ) == 0 ? CV_LU : CV_SVD; |
|
} |
|
|
|
|
|
int CxCore_InvertTest::write_default_params( CvFileStorage* fs ) |
|
{ |
|
int code = CxCore_MatrixTest::write_default_params(fs); |
|
if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE ) |
|
return code; |
|
write_string_list( fs, "method", matrix_solve_invert_methods ); |
|
return code; |
|
} |
|
|
|
|
|
void CxCore_InvertTest::print_timing_params( int test_case_idx, char* ptr, int params_left ) |
|
{ |
|
sprintf( ptr, "%s,", method == CV_LU ? "LU" : "SVD" ); |
|
ptr += strlen(ptr); |
|
params_left--; |
|
CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left ); |
|
} |
|
|
|
|
|
double CxCore_InvertTest::get_success_error_level( int /*test_case_idx*/, int, int ) |
|
{ |
|
return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 1e-2 : 1e-7; |
|
} |
|
|
|
int CxCore_InvertTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = CxCore_MatrixTest::prepare_test_case( test_case_idx ); |
|
if( code > 0 ) |
|
{ |
|
cvTsFloodWithZeros( &test_mat[INPUT][0], ts->get_rng() ); |
|
|
|
if( method == CV_CHOLESKY ) |
|
{ |
|
cvTsGEMM( &test_mat[INPUT][0], &test_mat[INPUT][0], 1., |
|
0, 0., &test_mat[TEMP][0], CV_GEMM_B_T ); |
|
cvTsCopy( &test_mat[TEMP][0], &test_mat[INPUT][0] ); |
|
} |
|
} |
|
|
|
return code; |
|
} |
|
|
|
|
|
|
|
void CxCore_InvertTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ) |
|
{ |
|
*low = cvScalarAll(-1.); |
|
*high = cvScalarAll(1.); |
|
} |
|
|
|
|
|
void CxCore_InvertTest::run_func() |
|
{ |
|
result = cvInvert(test_array[INPUT][0], test_array[TEMP][0], method); |
|
} |
|
|
|
|
|
static double cvTsSVDet( CvMat* mat, double* ratio ) |
|
{ |
|
int type = CV_MAT_TYPE(mat->type); |
|
int i, nm = MIN( mat->rows, mat->cols ); |
|
CvMat* w = cvCreateMat( nm, 1, type ); |
|
double det = 1.; |
|
|
|
cvSVD( mat, w, 0, 0, 0 ); |
|
|
|
if( type == CV_32FC1 ) |
|
{ |
|
for( i = 0; i < nm; i++ ) |
|
det *= w->data.fl[i]; |
|
*ratio = w->data.fl[nm-1] < FLT_EPSILON ? FLT_MAX : w->data.fl[nm-1]/w->data.fl[0]; |
|
} |
|
else |
|
{ |
|
for( i = 0; i < nm; i++ ) |
|
det *= w->data.db[i]; |
|
*ratio = w->data.db[nm-1] < FLT_EPSILON ? DBL_MAX : w->data.db[nm-1]/w->data.db[0]; |
|
} |
|
|
|
cvReleaseMat( &w ); |
|
return det; |
|
} |
|
|
|
void CxCore_InvertTest::prepare_to_validation( int ) |
|
{ |
|
CvMat* input = &test_mat[INPUT][0]; |
|
double ratio = 0, det = cvTsSVDet( input, &ratio ); |
|
double threshold = (CV_MAT_DEPTH(input->type) == CV_32F ? FLT_EPSILON : DBL_EPSILON)*1000; |
|
|
|
if( CV_MAT_TYPE(input->type) == CV_32FC1 ) |
|
cvTsConvert( input, &test_mat[TEMP][1] ); |
|
else |
|
cvTsCopy( input, &test_mat[TEMP][1], 0 ); |
|
|
|
if( det < threshold || |
|
((method == CV_LU || method == CV_CHOLESKY) && (result == 0 || ratio < threshold)) || |
|
((method == CV_SVD || method == CV_SVD_SYM) && result < threshold) ) |
|
{ |
|
cvTsZero( &test_mat[OUTPUT][0] ); |
|
cvTsZero( &test_mat[REF_OUTPUT][0] ); |
|
//cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.), cvScalarAll(fabs(det)>1e-3), |
|
// &test_mat[REF_OUTPUT][0], 0 ); |
|
return; |
|
} |
|
|
|
if( input->rows >= input->cols ) |
|
cvTsGEMM( &test_mat[TEMP][0], input, 1., 0, 0., &test_mat[OUTPUT][0], 0 ); |
|
else |
|
cvTsGEMM( input, &test_mat[TEMP][0], 1., 0, 0., &test_mat[OUTPUT][0], 0 ); |
|
|
|
cvTsSetIdentity( &test_mat[REF_OUTPUT][0], cvScalarAll(1.) ); |
|
} |
|
|
|
//CxCore_InvertTest invert_test; |
|
|
|
|
|
///////////////// solve ///////////////////// |
|
|
|
class CxCore_SolveTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_SolveTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
int write_default_params( CvFileStorage* fs ); |
|
void print_timing_params( int test_case_idx, char* ptr, int params_left ); |
|
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
int prepare_test_case( int test_case_idx ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
int method, rank; |
|
double result; |
|
}; |
|
|
|
|
|
CxCore_SolveTest::CxCore_SolveTest() : |
|
CxCore_MatrixTest( "matrix-solve", "cvSolve, cvSVD, cvSVBkSb", 2, 1, false, false, 1 ), method(0), rank(0), result(0.) |
|
{ |
|
test_case_count = 100; |
|
max_log_array_size = 7; |
|
test_array[TEMP].push(NULL); |
|
test_array[TEMP].push(NULL); |
|
|
|
default_timing_param_names = matrix_solve_invert_param_names; |
|
} |
|
|
|
|
|
void CxCore_SolveTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int bits = cvTsRandInt(rng); |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
CvSize in_sz = sizes[INPUT][0]; |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
sizes[INPUT][0] = in_sz; |
|
int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height ); |
|
|
|
if( (bits & 3) == 0 ) |
|
{ |
|
method = CV_SVD; |
|
if( bits & 4 ) |
|
{ |
|
sizes[INPUT][0] = cvSize(min_size, min_size); |
|
/*if( bits & 8 ) |
|
method = CV_SVD_SYM;*/ |
|
} |
|
} |
|
else |
|
{ |
|
method = CV_LU; |
|
sizes[INPUT][0] = cvSize(min_size, min_size); |
|
} |
|
|
|
sizes[INPUT][1].height = sizes[INPUT][0].height; |
|
sizes[TEMP][0].width = sizes[INPUT][1].width; |
|
sizes[TEMP][0].height = sizes[INPUT][0].width; |
|
sizes[TEMP][1] = sizes[INPUT][0]; |
|
types[TEMP][0] = types[INPUT][0]; |
|
types[TEMP][1] = CV_64FC1; |
|
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(sizes[INPUT][1].width, min_size); |
|
} |
|
|
|
void CxCore_SolveTest::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx, |
|
sizes, types, whole_sizes, are_images ); |
|
const char* method_str = cvReadString( find_timing_param("method"), "LU" ); |
|
sizes[INPUT][1].width = sizes[TEMP][0].width = sizes[OUTPUT][0].width = sizes[REF_OUTPUT][0].width = 1; |
|
method = strcmp( method_str, "LU" ) == 0 ? CV_LU : CV_SVD; |
|
} |
|
|
|
|
|
int CxCore_SolveTest::write_default_params( CvFileStorage* fs ) |
|
{ |
|
int code = CxCore_MatrixTest::write_default_params(fs); |
|
if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE ) |
|
return code; |
|
write_string_list( fs, "method", matrix_solve_invert_methods ); |
|
return code; |
|
} |
|
|
|
|
|
void CxCore_SolveTest::print_timing_params( int test_case_idx, char* ptr, int params_left ) |
|
{ |
|
sprintf( ptr, "%s,", method == CV_LU ? "LU" : "SVD" ); |
|
ptr += strlen(ptr); |
|
params_left--; |
|
CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left ); |
|
} |
|
|
|
|
|
int CxCore_SolveTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = CxCore_MatrixTest::prepare_test_case( test_case_idx ); |
|
|
|
/*if( method == CV_SVD_SYM ) |
|
{ |
|
cvTsGEMM( test_array[INPUT][0], test_array[INPUT][0], 1., |
|
0, 0., test_array[TEMP][0], CV_GEMM_B_T ); |
|
cvTsCopy( test_array[TEMP][0], test_array[INPUT][0] ); |
|
}*/ |
|
|
|
return code; |
|
} |
|
|
|
|
|
void CxCore_SolveTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ) |
|
{ |
|
*low = cvScalarAll(-1.); |
|
*high = cvScalarAll(1.); |
|
} |
|
|
|
|
|
double CxCore_SolveTest::get_success_error_level( int /*test_case_idx*/, int, int ) |
|
{ |
|
return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 1e-2 : 1e-8; |
|
} |
|
|
|
|
|
void CxCore_SolveTest::run_func() |
|
{ |
|
result = cvSolve(test_array[INPUT][0], test_array[INPUT][1], test_array[TEMP][0], method); |
|
} |
|
|
|
void CxCore_SolveTest::prepare_to_validation( int ) |
|
{ |
|
//int rank = test_mat[REF_OUTPUT][0].rows; |
|
CvMat* dst; |
|
CvMat* input = &test_mat[INPUT][0]; |
|
|
|
if( method == CV_LU ) |
|
{ |
|
if( result == 0 ) |
|
{ |
|
if( CV_MAT_TYPE(input->type) == CV_32FC1 ) |
|
cvTsConvert( input, &test_mat[TEMP][1] ); |
|
else |
|
cvTsCopy( input, &test_mat[TEMP][1], 0 ); |
|
|
|
cvTsZero( &test_mat[OUTPUT][0] ); |
|
double det = cvTsLU( &test_mat[TEMP][1], 0, 0 ); |
|
cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.), cvScalarAll(det != 0), |
|
&test_mat[REF_OUTPUT][0], 0 ); |
|
return; |
|
} |
|
|
|
double threshold = (CV_MAT_DEPTH(input->type) == CV_32F ? FLT_EPSILON : DBL_EPSILON)*1000; |
|
double ratio = 0, det = cvTsSVDet( input, &ratio ); |
|
if( det < threshold || ratio < threshold ) |
|
{ |
|
cvTsZero( &test_mat[OUTPUT][0] ); |
|
cvTsZero( &test_mat[REF_OUTPUT][0] ); |
|
return; |
|
} |
|
} |
|
|
|
|
|
dst = input->rows <= input->cols ? &test_mat[OUTPUT][0] : &test_mat[INPUT][1]; |
|
|
|
cvTsGEMM( input, &test_mat[TEMP][0], 1., &test_mat[INPUT][1], -1., dst, 0 ); |
|
if( dst != &test_mat[OUTPUT][0] ) |
|
cvTsGEMM( input, dst, 1., 0, 0., &test_mat[OUTPUT][0], CV_GEMM_A_T ); |
|
cvTsZero( &test_mat[REF_OUTPUT][0] ); |
|
} |
|
|
|
CxCore_SolveTest solve_test; |
|
|
|
|
|
///////////////// SVD ///////////////////// |
|
|
|
static const char* matrix_svd_param_names[] = { "size", "output", "depth", 0 }; |
|
static const char* matrix_svd_output_modes[] = { "w", "all", 0 }; |
|
|
|
class CxCore_SVDTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_SVDTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
int write_default_params( CvFileStorage* fs ); |
|
void print_timing_params( int test_case_idx, char* ptr, int params_left ); |
|
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ); |
|
int prepare_test_case( int test_case_idx ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
int flags; |
|
bool have_u, have_v, symmetric, compact, vector_w; |
|
}; |
|
|
|
|
|
CxCore_SVDTest::CxCore_SVDTest() : |
|
CxCore_MatrixTest( "matrix-svd", "cvSVD", 1, 4, false, false, 1 ), |
|
flags(0), have_u(false), have_v(false), symmetric(false), compact(false), vector_w(false) |
|
{ |
|
test_case_count = 100; |
|
test_array[TEMP].push(NULL); |
|
test_array[TEMP].push(NULL); |
|
test_array[TEMP].push(NULL); |
|
test_array[TEMP].push(NULL); |
|
|
|
default_timing_param_names = matrix_svd_param_names; |
|
} |
|
|
|
|
|
void CxCore_SVDTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int bits = cvTsRandInt(rng); |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
int min_size, i, m, n; |
|
|
|
min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height ); |
|
|
|
flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T); |
|
have_u = (bits & 8) != 0; |
|
have_v = (bits & 16) != 0; |
|
symmetric = (bits & 32) != 0; |
|
compact = (bits & 64) != 0; |
|
vector_w = (bits & 128) != 0; |
|
|
|
if( symmetric ) |
|
sizes[INPUT][0] = cvSize(min_size, min_size); |
|
|
|
m = sizes[INPUT][0].height; |
|
n = sizes[INPUT][0].width; |
|
|
|
if( compact ) |
|
sizes[TEMP][0] = cvSize(min_size, min_size); |
|
else |
|
sizes[TEMP][0] = sizes[INPUT][0]; |
|
sizes[TEMP][3] = cvSize(0,0); |
|
|
|
if( vector_w ) |
|
{ |
|
sizes[TEMP][3] = sizes[TEMP][0]; |
|
if( bits & 256 ) |
|
sizes[TEMP][0] = cvSize(1, min_size); |
|
else |
|
sizes[TEMP][0] = cvSize(min_size, 1); |
|
} |
|
|
|
if( have_u ) |
|
{ |
|
sizes[TEMP][1] = compact ? cvSize(min_size, m) : cvSize(m, m); |
|
|
|
if( flags & CV_SVD_U_T ) |
|
CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i ); |
|
} |
|
else |
|
sizes[TEMP][1] = cvSize(0,0); |
|
|
|
if( have_v ) |
|
{ |
|
sizes[TEMP][2] = compact ? cvSize(n, min_size) : cvSize(n, n); |
|
|
|
if( !(flags & CV_SVD_V_T) ) |
|
CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i ); |
|
} |
|
else |
|
sizes[TEMP][2] = cvSize(0,0); |
|
|
|
types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[TEMP][3] = types[INPUT][0]; |
|
types[OUTPUT][0] = types[OUTPUT][1] = types[OUTPUT][2] = types[INPUT][0]; |
|
types[OUTPUT][3] = CV_8UC1; |
|
sizes[OUTPUT][0] = !have_u || !have_v ? cvSize(0,0) : sizes[INPUT][0]; |
|
sizes[OUTPUT][1] = !have_u ? cvSize(0,0) : compact ? cvSize(min_size,min_size) : cvSize(m,m); |
|
sizes[OUTPUT][2] = !have_v ? cvSize(0,0) : compact ? cvSize(min_size,min_size) : cvSize(n,n); |
|
sizes[OUTPUT][3] = cvSize(min_size,1); |
|
|
|
for( i = 0; i < 4; i++ ) |
|
{ |
|
sizes[REF_OUTPUT][i] = sizes[OUTPUT][i]; |
|
types[REF_OUTPUT][i] = types[OUTPUT][i]; |
|
} |
|
} |
|
|
|
|
|
void CxCore_SVDTest::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx, |
|
sizes, types, whole_sizes, are_images ); |
|
const char* output_str = cvReadString( find_timing_param("output"), "all" ); |
|
bool need_all = strcmp( output_str, "all" ) == 0; |
|
int i, count = test_array[OUTPUT].size(); |
|
vector_w = true; |
|
symmetric = false; |
|
compact = true; |
|
sizes[TEMP][0] = cvSize(1,sizes[INPUT][0].height); |
|
if( need_all ) |
|
{ |
|
have_u = have_v = true; |
|
} |
|
else |
|
{ |
|
have_u = have_v = false; |
|
sizes[TEMP][1] = sizes[TEMP][2] = cvSize(0,0); |
|
} |
|
|
|
flags = CV_SVD_U_T + CV_SVD_V_T; |
|
for( i = 0; i < count; i++ ) |
|
sizes[OUTPUT][i] = sizes[REF_OUTPUT][i] = cvSize(0,0); |
|
sizes[OUTPUT][0] = cvSize(1,1); |
|
} |
|
|
|
|
|
int CxCore_SVDTest::write_default_params( CvFileStorage* fs ) |
|
{ |
|
int code = CxCore_MatrixTest::write_default_params(fs); |
|
if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE ) |
|
return code; |
|
write_string_list( fs, "output", matrix_svd_output_modes ); |
|
return code; |
|
} |
|
|
|
|
|
void CxCore_SVDTest::print_timing_params( int test_case_idx, char* ptr, int params_left ) |
|
{ |
|
sprintf( ptr, "%s,", have_u ? "all" : "w" ); |
|
ptr += strlen(ptr); |
|
params_left--; |
|
CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left ); |
|
} |
|
|
|
|
|
int CxCore_SVDTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = CxCore_MatrixTest::prepare_test_case( test_case_idx ); |
|
if( code > 0 ) |
|
{ |
|
CvMat* input = &test_mat[INPUT][0]; |
|
cvTsFloodWithZeros( input, ts->get_rng() ); |
|
|
|
if( symmetric && (have_u || have_v) ) |
|
{ |
|
CvMat* temp = &test_mat[TEMP][have_u ? 1 : 2]; |
|
cvTsGEMM( input, input, 1., |
|
0, 0., temp, CV_GEMM_B_T ); |
|
cvTsCopy( temp, input ); |
|
} |
|
|
|
if( (flags & CV_SVD_MODIFY_A) && test_array[OUTPUT][0] ) |
|
cvTsCopy( input, &test_mat[OUTPUT][0] ); |
|
} |
|
|
|
return code; |
|
} |
|
|
|
|
|
void CxCore_SVDTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ) |
|
{ |
|
*low = cvScalarAll(-2.); |
|
*high = cvScalarAll(2.); |
|
} |
|
|
|
double CxCore_SVDTest::get_success_error_level( int test_case_idx, int i, int j ) |
|
{ |
|
int input_depth = CV_MAT_DEPTH(cvGetElemType( test_array[INPUT][0] )); |
|
double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ? |
|
5e-5 : 5e-11; |
|
double output_precision = CvArrTest::get_success_error_level( test_case_idx, i, j ); |
|
return MAX(input_precision, output_precision); |
|
} |
|
|
|
void CxCore_SVDTest::run_func() |
|
{ |
|
CvArr* src = test_array[!(flags & CV_SVD_MODIFY_A) ? INPUT : OUTPUT][0]; |
|
if( !src ) |
|
src = test_array[INPUT][0]; |
|
cvSVD( src, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags ); |
|
} |
|
|
|
|
|
void CxCore_SVDTest::prepare_to_validation( int ) |
|
{ |
|
CvMat* input = &test_mat[INPUT][0]; |
|
int m = input->rows, n = input->cols, min_size = MIN(m, n); |
|
CvMat *src, *dst, *w; |
|
double prev = 0, threshold = CV_MAT_TYPE(input->type) == CV_32FC1 ? FLT_EPSILON : DBL_EPSILON; |
|
int i, j = 0, step; |
|
|
|
if( have_u ) |
|
{ |
|
src = &test_mat[TEMP][1]; |
|
dst = &test_mat[OUTPUT][1]; |
|
cvTsGEMM( src, src, 1., 0, 0., dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T ); |
|
cvTsSetIdentity( &test_mat[REF_OUTPUT][1], cvScalarAll(1.) ); |
|
} |
|
|
|
if( have_v ) |
|
{ |
|
src = &test_mat[TEMP][2]; |
|
dst = &test_mat[OUTPUT][2]; |
|
cvTsGEMM( src, src, 1., 0, 0., dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T ); |
|
cvTsSetIdentity( &test_mat[REF_OUTPUT][2], cvScalarAll(1.) ); |
|
} |
|
|
|
w = &test_mat[TEMP][0]; |
|
step = w->rows == 1 ? 1 : w->step/CV_ELEM_SIZE(w->type); |
|
for( i = 0; i < min_size; i++ ) |
|
{ |
|
double norm = 0, aii; |
|
uchar* row_ptr; |
|
if( w->rows > 1 && w->cols > 1 ) |
|
{ |
|
CvMat row; |
|
cvGetRow( w, &row, i ); |
|
norm = cvNorm( &row, 0, CV_L1 ); |
|
j = i; |
|
row_ptr = row.data.ptr; |
|
} |
|
else |
|
{ |
|
row_ptr = w->data.ptr; |
|
j = i*step; |
|
} |
|
|
|
aii = CV_MAT_TYPE(w->type) == CV_32FC1 ? |
|
(double)((float*)row_ptr)[j] : ((double*)row_ptr)[j]; |
|
if( w->rows == 1 || w->cols == 1 ) |
|
norm = aii; |
|
norm = fabs(norm - aii); |
|
test_mat[OUTPUT][3].data.ptr[i] = aii >= 0 && norm < threshold && (i == 0 || aii <= prev); |
|
prev = aii; |
|
} |
|
|
|
cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.), |
|
cvScalarAll(1.), &test_mat[REF_OUTPUT][3], 0 ); |
|
|
|
if( have_u && have_v ) |
|
{ |
|
if( vector_w ) |
|
{ |
|
cvTsZero( &test_mat[TEMP][3] ); |
|
for( i = 0; i < min_size; i++ ) |
|
{ |
|
double val = cvGetReal1D( w, i ); |
|
cvSetReal2D( &test_mat[TEMP][3], i, i, val ); |
|
} |
|
w = &test_mat[TEMP][3]; |
|
} |
|
|
|
if( m >= n ) |
|
{ |
|
cvTsGEMM( &test_mat[TEMP][1], w, 1., 0, 0., &test_mat[REF_OUTPUT][0], |
|
flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 ); |
|
cvTsGEMM( &test_mat[REF_OUTPUT][0], &test_mat[TEMP][2], 1., 0, 0., |
|
&test_mat[OUTPUT][0], flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T ); |
|
} |
|
else |
|
{ |
|
cvTsGEMM( w, &test_mat[TEMP][2], 1., 0, 0., &test_mat[REF_OUTPUT][0], |
|
flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T ); |
|
cvTsGEMM( &test_mat[TEMP][1], &test_mat[REF_OUTPUT][0], 1., 0, 0., |
|
&test_mat[OUTPUT][0], flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 ); |
|
} |
|
|
|
cvTsCopy( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0], 0 ); |
|
} |
|
} |
|
|
|
|
|
CxCore_SVDTest svd_test; |
|
|
|
|
|
///////////////// SVBkSb ///////////////////// |
|
|
|
class CxCore_SVBkSbTest : public CxCore_MatrixTest |
|
{ |
|
public: |
|
CxCore_SVBkSbTest(); |
|
protected: |
|
void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ); |
|
void get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ); |
|
double get_success_error_level( int test_case_idx, int i, int j ); |
|
void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ); |
|
int prepare_test_case( int test_case_idx ); |
|
void run_func(); |
|
void prepare_to_validation( int test_case_idx ); |
|
int flags; |
|
bool have_b, symmetric, compact, vector_w; |
|
}; |
|
|
|
|
|
CxCore_SVBkSbTest::CxCore_SVBkSbTest() : |
|
CxCore_MatrixTest( "matrix-svbksb", "cvSVBkSb", 2, 1, false, false, 1 ), |
|
flags(0), have_b(false), symmetric(false), compact(false), vector_w(false) |
|
{ |
|
test_case_count = 100; |
|
test_array[TEMP].push(NULL); |
|
test_array[TEMP].push(NULL); |
|
test_array[TEMP].push(NULL); |
|
} |
|
|
|
|
|
void CxCore_SVBkSbTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types ) |
|
{ |
|
CvRNG* rng = ts->get_rng(); |
|
int bits = cvTsRandInt(rng); |
|
CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); |
|
int min_size, i, m, n; |
|
CvSize b_size; |
|
|
|
min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height ); |
|
|
|
flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T); |
|
have_b = (bits & 16) != 0; |
|
symmetric = (bits & 32) != 0; |
|
compact = (bits & 64) != 0; |
|
vector_w = (bits & 128) != 0; |
|
|
|
if( symmetric ) |
|
sizes[INPUT][0] = cvSize(min_size, min_size); |
|
|
|
m = sizes[INPUT][0].height; |
|
n = sizes[INPUT][0].width; |
|
|
|
sizes[INPUT][1] = cvSize(0,0); |
|
b_size = cvSize(m,m); |
|
if( have_b ) |
|
{ |
|
sizes[INPUT][1].height = sizes[INPUT][0].height; |
|
sizes[INPUT][1].width = cvTsRandInt(rng) % 100 + 1; |
|
b_size = sizes[INPUT][1]; |
|
} |
|
|
|
if( compact ) |
|
sizes[TEMP][0] = cvSize(min_size, min_size); |
|
else |
|
sizes[TEMP][0] = sizes[INPUT][0]; |
|
|
|
if( vector_w ) |
|
{ |
|
if( bits & 256 ) |
|
sizes[TEMP][0] = cvSize(1, min_size); |
|
else |
|
sizes[TEMP][0] = cvSize(min_size, 1); |
|
} |
|
|
|
sizes[TEMP][1] = compact ? cvSize(min_size, m) : cvSize(m, m); |
|
|
|
if( flags & CV_SVD_U_T ) |
|
CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i ); |
|
|
|
sizes[TEMP][2] = compact ? cvSize(n, min_size) : cvSize(n, n); |
|
|
|
if( !(flags & CV_SVD_V_T) ) |
|
CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i ); |
|
|
|
types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0]; |
|
types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][0]; |
|
sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize( b_size.width, n ); |
|
} |
|
|
|
|
|
void CxCore_SVBkSbTest::get_timing_test_array_types_and_sizes( int test_case_idx, |
|
CvSize** sizes, int** types, |
|
CvSize** whole_sizes, bool* are_images ) |
|
{ |
|
CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx, |
|
sizes, types, whole_sizes, are_images ); |
|
have_b = true; |
|
vector_w = true; |
|
compact = true; |
|
sizes[TEMP][0] = cvSize(1,sizes[INPUT][0].height); |
|
sizes[INPUT][1] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(1,sizes[INPUT][0].height); |
|
flags = CV_SVD_U_T + CV_SVD_V_T; |
|
} |
|
|
|
|
|
int CxCore_SVBkSbTest::prepare_test_case( int test_case_idx ) |
|
{ |
|
int code = CxCore_MatrixTest::prepare_test_case( test_case_idx ); |
|
if( code > 0 ) |
|
{ |
|
CvMat* input = &test_mat[INPUT][0]; |
|
cvTsFloodWithZeros( input, ts->get_rng() ); |
|
|
|
if( symmetric ) |
|
{ |
|
CvMat* temp = &test_mat[TEMP][1]; |
|
cvTsGEMM( input, input, 1., 0, 0., temp, CV_GEMM_B_T ); |
|
cvTsCopy( temp, input ); |
|
} |
|
|
|
cvSVD( input, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags ); |
|
} |
|
|
|
return code; |
|
} |
|
|
|
|
|
void CxCore_SVBkSbTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high ) |
|
{ |
|
*low = cvScalarAll(-2.); |
|
*high = cvScalarAll(2.); |
|
} |
|
|
|
|
|
double CxCore_SVBkSbTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) |
|
{ |
|
return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-3 : 1e-7; |
|
} |
|
|
|
|
|
void CxCore_SVBkSbTest::run_func() |
|
{ |
|
cvSVBkSb( test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], |
|
test_array[INPUT][1], test_array[OUTPUT][0], flags ); |
|
} |
|
|
|
|
|
void CxCore_SVBkSbTest::prepare_to_validation( int ) |
|
{ |
|
CvMat* input = &test_mat[INPUT][0]; |
|
int i, m = input->rows, n = input->cols, min_size = MIN(m, n), nb; |
|
bool is_float = CV_MAT_DEPTH(input->type) == CV_32F; |
|
CvSize w_size = compact ? cvSize(min_size,min_size) : cvSize(m,n); |
|
CvMat* w = &test_mat[TEMP][0]; |
|
CvMat* wdb = cvCreateMat( w_size.height, w_size.width, CV_64FC1 ); |
|
// use exactly the same threshold as in icvSVD... , |
|
// so the changes in the library and here should be synchronized. |
|
double threshold = cvSum( w ).val[0]*2*(is_float ? FLT_EPSILON : DBL_EPSILON); |
|
CvMat *u, *v, *b, *t0, *t1; |
|
|
|
cvTsZero(wdb); |
|
for( i = 0; i < min_size; i++ ) |
|
{ |
|
double wii = vector_w ? cvGetReal1D(w,i) : cvGetReal2D(w,i,i); |
|
cvSetReal2D( wdb, i, i, wii > threshold ? 1./wii : 0. ); |
|
} |
|
|
|
u = &test_mat[TEMP][1]; |
|
v = &test_mat[TEMP][2]; |
|
b = 0; |
|
nb = m; |
|
|
|
if( test_array[INPUT][1] ) |
|
{ |
|
b = &test_mat[INPUT][1]; |
|
nb = b->cols; |
|
} |
|
|
|
if( is_float ) |
|
{ |
|
u = cvCreateMat( u->rows, u->cols, CV_64F ); |
|
cvTsConvert( &test_mat[TEMP][1], u ); |
|
if( b ) |
|
{ |
|
b = cvCreateMat( b->rows, b->cols, CV_64F ); |
|
cvTsConvert( &test_mat[INPUT][1], b ); |
|
} |
|
} |
|
|
|
t0 = cvCreateMat( wdb->cols, nb, CV_64F ); |
|
|
|
if( b ) |
|
cvTsGEMM( u, b, 1., 0, 0., t0, !(flags & CV_SVD_U_T) ? CV_GEMM_A_T : 0 ); |
|
else if( flags & CV_SVD_U_T ) |
|
cvTsCopy( u, t0 ); |
|
else |
|
cvTsTranspose( u, t0 ); |
|
|
|
if( is_float ) |
|
{ |
|
cvReleaseMat( &b ); |
|
|
|
if( !symmetric ) |
|
{ |
|
cvReleaseMat( &u ); |
|
v = cvCreateMat( v->rows, v->cols, CV_64F ); |
|
} |
|
else |
|
{ |
|
v = u; |
|
u = 0; |
|
} |
|
cvTsConvert( &test_mat[TEMP][2], v ); |
|
} |
|
|
|
t1 = cvCreateMat( wdb->rows, nb, CV_64F ); |
|
cvTsGEMM( wdb, t0, 1, 0, 0, t1, 0 ); |
|
|
|
if( !is_float || !symmetric ) |
|
{ |
|
cvReleaseMat( &t0 ); |
|
t0 = !is_float ? &test_mat[REF_OUTPUT][0] : cvCreateMat( test_mat[REF_OUTPUT][0].rows, nb, CV_64F ); |
|
} |
|
|
|
cvTsGEMM( v, t1, 1, 0, 0, t0, flags & CV_SVD_V_T ? CV_GEMM_A_T : 0 ); |
|
cvReleaseMat( &t1 ); |
|
|
|
if( t0 != &test_mat[REF_OUTPUT][0] ) |
|
{ |
|
cvTsConvert( t0, &test_mat[REF_OUTPUT][0] ); |
|
cvReleaseMat( &t0 ); |
|
} |
|
|
|
if( v != &test_mat[TEMP][2] ) |
|
cvReleaseMat( &v ); |
|
|
|
cvReleaseMat( &wdb ); |
|
} |
|
|
|
|
|
CxCore_SVBkSbTest svbksb_test; |
|
|
|
|
|
// TODO: eigenvv, invsqrt, cbrt, fastarctan, (round, floor, ceil(?)), |
|
|
|
/* End of file. */ |
|
|
|
|