Commit 6f44457d authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

the combined cxts + gtest

parent 23e83f8f
if(BUILD_SHARED_LIBS)
add_definitions(-DGTEST_CREATE_SHARED_LIBRARY=1)
endif()
define_opencv_module(ts opencv_core)
#ifndef __OPENCV_GTESTCV_HPP__
#define __OPENCV_GTESTCV_HPP__
#include "opencv2/ts/ts_gtest.h"
#include "opencv2/core/core.hpp"
namespace cvtest
{
using std::vector;
using std::string;
using cv::RNG;
using cv::Mat;
using cv::Scalar;
using cv::Size;
using cv::Point;
using cv::Rect;
class CV_EXPORTS TS;
enum
{
TYPE_MASK_8U = 1 << CV_8U,
TYPE_MASK_8S = 1 << CV_8S,
TYPE_MASK_16U = 1 << CV_16U,
TYPE_MASK_16S = 1 << CV_16S,
TYPE_MASK_32S = 1 << CV_32S,
TYPE_MASK_32F = 1 << CV_32F,
TYPE_MASK_64F = 1 << CV_64F,
TYPE_MASK_ALL = (TYPE_MASK_64F<<1)-1,
TYPE_MASK_ALL_BUT_8S = TYPE_MASK_ALL & ~TYPE_MASK_8S,
TYPE_MASK_FLT = TYPE_MASK_32F + TYPE_MASK_64F
};
CV_EXPORTS int64 readSeed(const char* str);
CV_EXPORTS void randUni( RNG& rng, Mat& a, const Scalar& param1, const Scalar& param2 );
inline unsigned randInt( RNG& rng )
{
return (unsigned)rng;
}
inline double randReal( RNG& rng )
{
return (double)rng;
}
CV_EXPORTS const char* getTypeName( int type );
CV_EXPORTS int typeByName( const char* type_name );
CV_EXPORTS string vec2str(const string& sep, const int* v, size_t nelems);
inline int clipInt( int val, int min_val, int max_val )
{
if( val < min_val )
val = min_val;
if( val > max_val )
val = max_val;
return val;
}
CV_EXPORTS double getMinVal(int depth);
CV_EXPORTS double getMaxVal(int depth);
CV_EXPORTS Size randomSize(RNG& rng, double maxSizeLog);
CV_EXPORTS void randomSize(RNG& rng, int minDims, int maxDims, double maxSizeLog, vector<int>& sz);
CV_EXPORTS int randomType(RNG& rng, int typeMask, int minChannels, int maxChannels);
CV_EXPORTS Mat randomMat(RNG& rng, Size size, int type, double minVal, double maxVal, bool useRoi);
CV_EXPORTS Mat randomMat(RNG& rng, const vector<int>& size, int type, double minVal, double maxVal, bool useRoi);
CV_EXPORTS void add(const Mat& a, double alpha, const Mat& b, double beta,
Scalar gamma, Mat& c, int ctype, bool calcAbs=false);
CV_EXPORTS void multiply(const Mat& a, const Mat& b, Mat& c, double alpha=1);
CV_EXPORTS void divide(const Mat& a, const Mat& b, Mat& c, double alpha=1);
CV_EXPORTS void convert(const Mat& src, Mat& dst, int dtype, double alpha=1, double beta=0);
CV_EXPORTS void copy(const Mat& src, Mat& dst, const Mat& mask=Mat(), bool invertMask=false);
CV_EXPORTS void set(Mat& dst, const Scalar& gamma, const Mat& mask=Mat());
// working with multi-channel arrays
CV_EXPORTS void extract( const Mat& a, Mat& plane, int coi );
CV_EXPORTS void insert( const Mat& plane, Mat& a, int coi );
// checks that the array does not have NaNs and/or Infs and all the elements are
// within [min_val,max_val). idx is the index of the first "bad" element.
CV_EXPORTS int check( const Mat& data, double min_val, double max_val, vector<int>* idx );
// modifies values that are close to zero
CV_EXPORTS void patchZeros( Mat& mat, double level );
CV_EXPORTS void transpose(const Mat& src, Mat& dst);
CV_EXPORTS void erode(const Mat& src, Mat& dst, const Mat& _kernel, Point anchor=Point(-1,-1),
int borderType=IPL_BORDER_CONSTANT, const Scalar& borderValue=Scalar());
CV_EXPORTS void dilate(const Mat& src, Mat& dst, const Mat& _kernel, Point anchor=Point(-1,-1),
int borderType=IPL_BORDER_CONSTANT, const Scalar& borderValue=Scalar());
CV_EXPORTS void filter2D(const Mat& src, Mat& dst, int ddepth, const Mat& kernel,
Point anchor, double delta, int borderType,
const Scalar& borderValue=Scalar());
CV_EXPORTS void copyMakeBorder(const Mat& src, Mat& dst, int top, int bottom, int left, int right,
int borderType, const Scalar& borderValue=Scalar());
CV_EXPORTS Mat calcSobelKernel2D( int dx, int dy, int apertureSize, int origin=0 );
CV_EXPORTS Mat calcLaplaceKernel2D( int aperture_size );
CV_EXPORTS void initUndistortMap( const Mat& a, const Mat& k, Size sz, Mat& mapx, Mat& mapy );
CV_EXPORTS void minMaxLoc(const Mat& src, double* minval, double* maxval,
vector<int>* minloc, vector<int>* maxloc, const Mat& mask=Mat());
CV_EXPORTS double norm(const Mat& src, int normType, const Mat& mask=Mat());
CV_EXPORTS double norm(const Mat& src1, const Mat& src2, int normType, const Mat& mask=Mat());
CV_EXPORTS Scalar mean(const Mat& src, const Mat& mask=Mat());
CV_EXPORTS bool cmpUlps(const Mat& data, const Mat& refdata, int expMaxDiff, double* realMaxDiff, vector<int>* idx);
// compares two arrays. max_diff is the maximum actual difference,
// success_err_level is maximum allowed difference, idx is the index of the first
// element for which difference is >success_err_level
// (or index of element with the maximum difference)
CV_EXPORTS int cmpEps( const Mat& data, const Mat& refdata, double* max_diff,
double success_err_level, vector<int>* idx,
bool element_wise_relative_error );
// a wrapper for the previous function. in case of error prints the message to log file.
CV_EXPORTS int cmpEps2( TS* ts, const Mat& data, const Mat& refdata, double success_err_level,
bool element_wise_relative_error, const char* desc );
CV_EXPORTS int cmpEps2_64f( TS* ts, const double* val, const double* refval, int len,
double eps, const char* param_name );
CV_EXPORTS void logicOp(const Mat& src1, const Mat& src2, Mat& dst, char c);
CV_EXPORTS void logicOp(const Mat& src, const Scalar& s, Mat& dst, char c);
CV_EXPORTS void min(const Mat& src1, const Mat& src2, Mat& dst);
CV_EXPORTS void min(const Mat& src, double s, Mat& dst);
CV_EXPORTS void max(const Mat& src1, const Mat& src2, Mat& dst);
CV_EXPORTS void max(const Mat& src, double s, Mat& dst);
CV_EXPORTS void compare(const Mat& src1, const Mat& src2, Mat& dst, int cmpop);
CV_EXPORTS void compare(const Mat& src, double s, Mat& dst, int cmpop);
CV_EXPORTS void gemm(const Mat& src1, const Mat& src2, double alpha,
const Mat& src3, double beta, Mat& dst, int flags);
CV_EXPORTS void transform( const Mat& src, Mat& dst, const Mat& transmat, const Mat& shift );
CV_EXPORTS double crossCorr(const Mat& src1, const Mat& src2);
struct CV_EXPORTS MatInfo
{
MatInfo(const Mat& _m) : m(&_m) {}
const Mat* m;
};
CV_EXPORTS std::ostream& operator << (std::ostream& out, const MatInfo& m);
struct CV_EXPORTS MatComparator
{
public:
MatComparator(double maxdiff, int context);
::testing::AssertionResult operator()(const char* expr1, const char* expr2,
const Mat& m1, const Mat& m2);
double maxdiff;
double realmaxdiff;
vector<int> loc0;
int context;
};
class BaseTest;
class TS;
class CV_EXPORTS BaseTest
{
public:
// constructor(s) and destructor
BaseTest();
virtual ~BaseTest();
// the main procedure of the test
virtual void run( int start_from );
// the wrapper for run that cares of exceptions
virtual void safe_run( int start_from=0 );
const string& get_name() const { return name; }
// returns true if and only if the different test cases do not depend on each other
// (so that test system could get right to a problematic test case)
virtual bool can_do_fast_forward();
// deallocates all the memory.
// called by init() (before initialization) and by the destructor
virtual void clear();
protected:
int test_case_count; // the total number of test cases
// read test params
virtual int read_params( CvFileStorage* fs );
// returns the number of tests or -1 if it is unknown a-priori
virtual int get_test_case_count();
// prepares data for the next test case. rng seed is updated by the function
virtual int prepare_test_case( int test_case_idx );
// checks if the test output is valid and accurate
virtual int validate_test_results( int test_case_idx );
// calls the tested function. the method is called from run_test_case()
virtual void run_func(); // runs tested func(s)
// updates progress bar
virtual int update_progress( int progress, int test_case_idx, int count, double dt );
// finds test parameter
const CvFileNode* find_param( CvFileStorage* fs, const char* param_name );
// name of the test (it is possible to locate a test by its name)
string name;
// pointer to the system that includes the test
TS* ts;
};
/*****************************************************************************************\
* Information about a failed test *
\*****************************************************************************************/
struct TestInfo
{
TestInfo();
// pointer to the test
BaseTest* test;
// failure code (CV_FAIL*)
int code;
// seed value right before the data for the failed test case is prepared.
uint64 rng_seed;
// seed value right before running the test
uint64 rng_seed0;
// index of test case, can be then passed to BaseTest::proceed_to_test_case()
int test_case_idx;
};
/*****************************************************************************************\
* Base Class for test system *
\*****************************************************************************************/
// common parameters:
struct CV_EXPORTS TSParams
{
TSParams();
// RNG seed, passed to and updated by every test executed.
uint64 rng_seed;
// whether to use IPP, MKL etc. or not
bool use_optimized;
// extensivity of the tests, scale factor for test_case_count
double test_case_count_scale;
};
class CV_EXPORTS TS
{
public:
// constructor(s) and destructor
TS();
virtual ~TS();
enum
{
NUL=0,
SUMMARY_IDX=0,
SUMMARY=1 << SUMMARY_IDX,
LOG_IDX=1,
LOG=1 << LOG_IDX,
CSV_IDX=2,
CSV=1 << CSV_IDX,
CONSOLE_IDX=3,
CONSOLE=1 << CONSOLE_IDX,
MAX_IDX=4
};
static TS* ptr();
// initialize test system before running the first test
virtual void init( const string& modulename );
// low-level printing functions that are used by individual tests and by the system itself
virtual void printf( int streams, const char* fmt, ... );
virtual void vprintf( int streams, const char* fmt, va_list arglist );
// updates the context: current test, test case, rng state
virtual void update_context( BaseTest* test, int test_case_idx, bool update_ts_context );
const TestInfo* get_current_test_info() { return &current_test_info; }
// sets information about a failed test
virtual void set_failed_test_info( int fail_code );
virtual void set_gtest_status();
// test error codes
enum
{
// everything is Ok
OK=0,
// generic error: stub value to be used
// temporarily if the error's cause is unknown
FAIL_GENERIC=-1,
// the test is missing some essential data to proceed further
FAIL_MISSING_TEST_DATA=-2,
// the tested function raised an error via cxcore error handler
FAIL_ERROR_IN_CALLED_FUNC=-3,
// an exception has been raised;
// for memory and arithmetic exception
// there are two specialized codes (see below...)
FAIL_EXCEPTION=-4,
// a memory exception
// (access violation, access to missed page, stack overflow etc.)
FAIL_MEMORY_EXCEPTION=-5,
// arithmetic exception (overflow, division by zero etc.)
FAIL_ARITHM_EXCEPTION=-6,
// the tested function corrupted memory (no exception have been raised)
FAIL_MEMORY_CORRUPTION_BEGIN=-7,
FAIL_MEMORY_CORRUPTION_END=-8,
// the tested function (or test ifself) do not deallocate some memory
FAIL_MEMORY_LEAK=-9,
// the tested function returned invalid object, e.g. matrix, containing NaNs,
// structure with NULL or out-of-range fields (while it should not)
FAIL_INVALID_OUTPUT=-10,
// the tested function returned valid object, but it does not match to
// the original (or produced by the test) object
FAIL_MISMATCH=-11,
// the tested function returned valid object (a single number or numerical array),
// but it differs too much from the original (or produced by the test) object
FAIL_BAD_ACCURACY=-12,
// the tested function hung. Sometimes, can be determined by unexpectedly long
// processing time (in this case there should be possibility to interrupt such a function
FAIL_HANG=-13,
// unexpected responce on passing bad arguments to the tested function
// (the function crashed, proceed succesfully (while it should not), or returned
// error code that is different from what is expected)
FAIL_BAD_ARG_CHECK=-14,
// the test data (in whole or for the particular test case) is invalid
FAIL_INVALID_TEST_DATA=-15,
// the test has been skipped because it is not in the selected subset of the tests to run,
// because it has been run already within the same run with the same parameters, or because
// of some other reason and this is not considered as an error.
// Normally TS::run() (or overrided method in the derived class) takes care of what
// needs to be run, so this code should not occur.
SKIPPED=1
};
// get file storage
CvFileStorage* get_file_storage();
// get RNG to generate random input data for a test
RNG& get_rng() { return rng; }
// returns the current error code
int get_err_code() { return current_test_info.code; }
// returns the test extensivity scale
double get_test_case_count_scale() { return params.test_case_count_scale; }
const string& get_data_path() const { return data_path; }
// returns textual description of failure code
static string str_from_code( int code );
protected:
// these are allocated within a test to try keep them valid in case of stack corruption
RNG rng;
// information about the current test
TestInfo current_test_info;
// the path to data files used by tests
string data_path;
TSParams params;
std::string output_buf[MAX_IDX];
};
/*****************************************************************************************\
* Subclass of BaseTest for testing functions that process dense arrays *
\*****************************************************************************************/
class CV_EXPORTS ArrayTest : public BaseTest
{
public:
// constructor(s) and destructor
ArrayTest();
virtual ~ArrayTest();
virtual void clear();
protected:
virtual int read_params( CvFileStorage* fs );
virtual int prepare_test_case( int test_case_idx );
virtual int validate_test_results( int test_case_idx );
virtual void prepare_to_validation( int test_case_idx );
virtual void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
virtual void fill_array( int test_case_idx, int i, int j, Mat& arr );
virtual void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
virtual double get_success_error_level( int test_case_idx, int i, int j );
bool cvmat_allowed;
bool iplimage_allowed;
bool optional_mask;
bool element_wise_relative_error;
int min_log_array_size;
int max_log_array_size;
enum { INPUT, INPUT_OUTPUT, OUTPUT, REF_INPUT_OUTPUT, REF_OUTPUT, TEMP, MASK, MAX_ARR };
vector<vector<void*> > test_array;
vector<vector<Mat> > test_mat;
float buf[4];
};
class CV_EXPORTS BadArgTest : public BaseTest
{
public:
// constructor(s) and destructor
BadArgTest();
virtual ~BadArgTest();
protected:
virtual int run_test_case( int expected_code, const string& descr );
virtual void run_func(void) = 0;
int test_case_idx;
int progress;
double t, freq;
template<class F>
int run_test_case( int expected_code, const string& _descr, F f)
{
double new_t = (double)cv::getTickCount(), dt;
if( test_case_idx < 0 )
{
test_case_idx = 0;
progress = 0;
dt = 0;
}
else
{
dt = (new_t - t)/(freq*1000);
t = new_t;
}
progress = update_progress(progress, test_case_idx, 0, dt);
int errcount = 0;
bool thrown = false;
const char* descr = _descr.c_str() ? _descr.c_str() : "";
try
{
f();
}
catch(const cv::Exception& e)
{
thrown = true;
if( e.code != expected_code )
{
ts->printf(TS::LOG, "%s (test case #%d): the error code %d is different from the expected %d\n",
descr, test_case_idx, e.code, expected_code);
errcount = 1;
}
}
catch(...)
{
thrown = true;
ts->printf(TS::LOG, "%s (test case #%d): unknown exception was thrown (the function has likely crashed)\n",
descr, test_case_idx);
errcount = 1;
}
if(!thrown)
{
ts->printf(TS::LOG, "%s (test case #%d): no expected exception was thrown\n",
descr, test_case_idx);
errcount = 1;
}
test_case_idx++;
return errcount;
}
};
struct CV_EXPORTS DefaultRngAuto
{
const uint64 old_state;
DefaultRngAuto() : old_state(cv::theRNG().state) { cv::theRNG().state = (uint64)-1; }
~DefaultRngAuto() { cv::theRNG().state = old_state; }
DefaultRngAuto& operator=(const DefaultRngAuto&);
};
}
// fills c with zeros
CV_EXPORTS void cvTsZero( CvMat* c, const CvMat* mask=0 );
// copies a to b (whole matrix or only the selected region)
CV_EXPORTS void cvTsCopy( const CvMat* a, CvMat* b, const CvMat* mask=0 );
// converts one array to another
CV_EXPORTS void cvTsConvert( const CvMat* src, CvMat* dst );
CV_EXPORTS void cvTsGEMM( const CvMat* a, const CvMat* b, double alpha,
const CvMat* c, double beta, CvMat* d, int flags );
#define CV_TEST_MAIN(resourcesubdir) \
int main(int argc, char **argv) \
{ \
cvtest::TS::ptr()->init(resourcesubdir); \
::testing::InitGoogleTest(&argc, argv); \
return RUN_ALL_TESTS(); \
}
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
#include "precomp.hpp"
/*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*/
#include "precomp.hpp"
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
#include <io.h>
#include <windows.h>
#ifdef _MSC_VER
#include <eh.h>
#endif
#else
#include <unistd.h>
#endif
namespace cvtest
{
/*****************************************************************************************\
* Exception and memory handlers *
\*****************************************************************************************/
// a few platform-dependent declarations
#if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
#ifdef _MSC_VER
static void setSEHTranslator( unsigned int /*u*/, EXCEPTION_POINTERS* pExp )
{
int code = TS::FAIL_EXCEPTION;
switch( pExp->ExceptionRecord->ExceptionCode )
{
case EXCEPTION_ACCESS_VIOLATION:
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
case EXCEPTION_DATATYPE_MISALIGNMENT:
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_STACK_OVERFLOW:
case EXCEPTION_IN_PAGE_ERROR:
code = TS::FAIL_MEMORY_EXCEPTION;
break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_FLT_INEXACT_RESULT:
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_UNDERFLOW:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_OVERFLOW:
code = TS::FAIL_ARITHM_EXCEPTION;
break;
case EXCEPTION_BREAKPOINT:
case EXCEPTION_ILLEGAL_INSTRUCTION:
case EXCEPTION_INVALID_DISPOSITION:
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
case EXCEPTION_PRIV_INSTRUCTION:
case EXCEPTION_SINGLE_STEP:
code = TS::FAIL_EXCEPTION;
}
throw code;
}
#endif
#else
#include <signal.h>
#include <setjmp.h>
static const int tsSigId[] = { SIGSEGV, SIGBUS, SIGFPE, SIGILL, SIGABRT, -1 };
static jmp_buf tsJmpMark;
void signalHandler( int sig_code )
{
int code = TS::FAIL_EXCEPTION;
switch( sig_code )
{
case SIGFPE:
code = TS::FAIL_ARITHM_EXCEPTION;
break;
case SIGSEGV:
case SIGBUS:
code = TS::FAIL_ARITHM_EXCEPTION;
break;
case SIGILL:
code = TS::FAIL_EXCEPTION;
}
longjmp( tsJmpMark, code );
}
#endif
// reads 16-digit hexadecimal number (i.e. 64-bit integer)
int64 readSeed( const char* str )
{
int64 val = 0;
if( str && strlen(str) == 16 )
{
for( int i = 0; str[i]; i++ )
{
int c = tolower(str[i]);
if( !isxdigit(c) )
return 0;
val = val * 16 +
(str[i] < 'a' ? str[i] - '0' : str[i] - 'a' + 10);
}
}
return val;
}
/*****************************************************************************************\
* Base Class for Tests *
\*****************************************************************************************/
BaseTest::BaseTest()
{
ts = TS::ptr();
test_case_count = -1;
}
BaseTest::~BaseTest()
{
clear();
}
void BaseTest::clear()
{
}
const CvFileNode* BaseTest::find_param( CvFileStorage* fs, const char* param_name )
{
CvFileNode* node = cvGetFileNodeByName(fs, 0, get_name().c_str());
return node ? cvGetFileNodeByName( fs, node, param_name ) : 0;
}
int BaseTest::read_params( CvFileStorage* )
{
return 0;
}
bool BaseTest::can_do_fast_forward()
{
return true;
}
void BaseTest::safe_run( int start_from )
{
read_params( ts->get_file_storage() );
ts->update_context( 0, -1, true );
ts->update_context( this, -1, true );
if( !::testing::GTEST_FLAG(catch_exceptions) )
run( start_from );
else
{
try
{
#if !defined WIN32 && !defined _WIN32
int _code = setjmp( tsJmpMark );
if( !_code )
run( start_from );
else
throw _code;
#else
run( start_from );
#endif
}
catch (const cv::Exception& exc)
{
const char* errorStr = cvErrorStr(exc.code);
char buf[1 << 16];
sprintf( buf, "OpenCV Error: %s (%s) in %s, file %s, line %d",
errorStr, exc.err.c_str(), exc.func.size() > 0 ?
exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line );
ts->printf(TS::LOG, "%s\n", buf);
ts->set_failed_test_info( TS::FAIL_ERROR_IN_CALLED_FUNC );
}
catch (...)
{
ts->set_failed_test_info( TS::FAIL_EXCEPTION );
}
}
ts->set_gtest_status();
}
void BaseTest::run( int start_from )
{
int test_case_idx, count = get_test_case_count();
int64 t_start = cvGetTickCount();
double freq = cv::getTickFrequency();
bool ff = can_do_fast_forward();
int progress = 0, code;
int64 t1 = t_start;
for( test_case_idx = ff && start_from >= 0 ? start_from : 0;
count < 0 || test_case_idx < count; test_case_idx++ )
{
ts->update_context( this, test_case_idx, ff );
progress = update_progress( progress, test_case_idx, count, (double)(t1 - t_start)/(freq*1000) );
code = prepare_test_case( test_case_idx );
if( code < 0 || ts->get_err_code() < 0 )
return;
if( code == 0 )
continue;
run_func();
if( ts->get_err_code() < 0 )
return;
if( validate_test_results( test_case_idx ) < 0 || ts->get_err_code() < 0 )
return;
}
}
void BaseTest::run_func(void)
{
assert(0);
}
int BaseTest::get_test_case_count(void)
{
return test_case_count;
}
int BaseTest::prepare_test_case( int )
{
return 0;
}
int BaseTest::validate_test_results( int )
{
return 0;
}
int BaseTest::update_progress( int progress, int test_case_idx, int count, double dt )
{
int width = 60 - (int)get_name().size();
if( count > 0 )
{
int t = cvRound( ((double)test_case_idx * width)/count );
if( t > progress )
{
ts->printf( TS::CONSOLE, "." );
progress = t;
}
}
else if( cvRound(dt) > progress )
{
ts->printf( TS::CONSOLE, "." );
progress = cvRound(dt);
}
return progress;
}
BadArgTest::BadArgTest()
{
progress = -1;
test_case_idx = -1;
freq = cv::getTickFrequency();
}
BadArgTest::~BadArgTest(void)
{
}
int BadArgTest::run_test_case( int expected_code, const string& _descr )
{
double new_t = (double)cv::getTickCount(), dt;
if( test_case_idx < 0 )
{
test_case_idx = 0;
progress = 0;
dt = 0;
}
else
{
dt = (new_t - t)/(freq*1000);
t = new_t;
}
progress = update_progress(progress, test_case_idx, 0, dt);
int errcount = 0;
bool thrown = false;
const char* descr = _descr.c_str() ? _descr.c_str() : "";
try
{
run_func();
}
catch(const cv::Exception& e)
{
thrown = true;
if( e.code != expected_code )
{
ts->printf(TS::LOG, "%s (test case #%d): the error code %d is different from the expected %d\n",
descr, test_case_idx, e.code, expected_code);
errcount = 1;
}
}
catch(...)
{
thrown = true;
ts->printf(TS::LOG, "%s (test case #%d): unknown exception was thrown (the function has likely crashed)\n",
descr, test_case_idx);
errcount = 1;
}
if(!thrown)
{
ts->printf(TS::LOG, "%s (test case #%d): no expected exception was thrown\n",
descr, test_case_idx);
errcount = 1;
}
test_case_idx++;
return errcount;
}
/*****************************************************************************************\
* Base Class for Test System *
\*****************************************************************************************/
/******************************** Constructors/Destructors ******************************/
TSParams::TSParams()
{
rng_seed = (uint64)-1;
use_optimized = true;
test_case_count_scale = 1;
}
TestInfo::TestInfo()
{
test = 0;
code = 0;
rng_seed = rng_seed0 = 0;
test_case_idx = -1;
}
TS::TS()
{
} // ctor
TS::~TS()
{
} // dtor
string TS::str_from_code( int code )
{
switch( code )
{
case OK: return "Ok";
case FAIL_GENERIC: return "Generic/Unknown";
case FAIL_MISSING_TEST_DATA: return "No test data";
case FAIL_INVALID_TEST_DATA: return "Invalid test data";
case FAIL_ERROR_IN_CALLED_FUNC: return "cvError invoked";
case FAIL_EXCEPTION: return "Hardware/OS exception";
case FAIL_MEMORY_EXCEPTION: return "Invalid memory access";
case FAIL_ARITHM_EXCEPTION: return "Arithmetic exception";
case FAIL_MEMORY_CORRUPTION_BEGIN: return "Corrupted memblock (beginning)";
case FAIL_MEMORY_CORRUPTION_END: return "Corrupted memblock (end)";
case FAIL_MEMORY_LEAK: return "Memory leak";
case FAIL_INVALID_OUTPUT: return "Invalid function output";
case FAIL_MISMATCH: return "Unexpected output";
case FAIL_BAD_ACCURACY: return "Bad accuracy";
case FAIL_HANG: return "Infinite loop(?)";
case FAIL_BAD_ARG_CHECK: return "Incorrect handling of bad arguments";
default:
;
}
return "Generic/Unknown";
}
/************************************** Running tests **********************************/
void TS::init( const string& modulename )
{
char* datapath_dir = getenv("OPENCV_TEST_DATA_PATH");
if( datapath_dir )
{
char buf[1024];
size_t l = strlen(datapath_dir);
bool haveSlash = l > 0 && (datapath_dir[l-1] == '/' || datapath_dir[l-1] == '\\');
sprintf( buf, "%s%s%s/", datapath_dir, haveSlash ? "" : "/", modulename.c_str() );
data_path = string(buf);
}
if( ::testing::GTEST_FLAG(catch_exceptions) )
{
cvSetErrMode( CV_ErrModeParent );
cvRedirectError( cvStdErrReport );
#if defined WIN32 || defined _WIN32
#ifdef _MSC_VER
_set_se_translator( SEHTranslator );
#endif
#else
for( int i = 0; tsSigId[i] >= 0; i++ )
signal( tsSigId[i], signalHandler );
#endif
}
else
{
cvSetErrMode( CV_ErrModeLeaf );
cvRedirectError( cvGuiBoxReport );
#if defined WIN32 || defined _WIN32
#ifdef _MSC_VER
_set_se_translator( 0 );
#endif
#else
for( int i = 0; tsSigId[i] >= 0; i++ )
signal( tsSigId[i], SIG_DFL );
#endif
}
if( params.use_optimized == 0 )
cv::setUseOptimized(false);
rng = RNG(params.rng_seed);
}
void TS::set_gtest_status()
{
int code = get_err_code();
if( code >= 0 )
return SUCCEED();
char seedstr[32];
sprintf(seedstr, "%08x%08x", (unsigned)(current_test_info.rng_seed>>32),
(unsigned)(current_test_info.rng_seed));
string logs = "";
if( !output_buf[SUMMARY_IDX].empty() )
logs += "\n-----------------------------------\n\tSUM: " + output_buf[SUMMARY_IDX];
if( !output_buf[LOG_IDX].empty() )
logs += "\n-----------------------------------\n\tLOG: " + output_buf[LOG_IDX];
if( !output_buf[CONSOLE_IDX].empty() )
logs += "\n-----------------------------------\n\tCONSOLE: " + output_buf[CONSOLE_IDX];
logs += "\n-----------------------------------\n";
FAIL() << "\n\tfailure reason: " << str_from_code(code) <<
"\n\ttest case #" << current_test_info.test_case_idx <<
"\n\tseed: " << seedstr << logs;
}
CvFileStorage* TS::get_file_storage() { return 0; }
void TS::update_context( BaseTest* test, int test_case_idx, bool update_ts_context )
{
if( current_test_info.test != test )
{
for( int i = 0; i <= CONSOLE_IDX; i++ )
output_buf[i] = string();
rng = RNG(params.rng_seed);
current_test_info.rng_seed0 = current_test_info.rng_seed = rng.state;
}
current_test_info.test = test;
current_test_info.test_case_idx = test_case_idx;
current_test_info.code = 0;
cvSetErrStatus( CV_StsOk );
if( update_ts_context )
current_test_info.rng_seed = rng.state;
}
void TS::set_failed_test_info( int fail_code )
{
if( current_test_info.code >= 0 )
current_test_info.code = fail_code;
}
#if defined _MSC_VER && _MSC_VER < 1400
#undef vsnprintf
#define vsnprintf _vsnprintf
#endif
void TS::vprintf( int streams, const char* fmt, va_list l )
{
char str[1 << 14];
vsnprintf( str, sizeof(str)-1, fmt, l );
for( int i = 0; i < MAX_IDX; i++ )
if( (streams & (1 << i)) )
{
output_buf[i] += std::string(str);
// in the new GTest-based framework we do not use
// any output files (except for the automatically generated xml report).
// if a test fails, all the buffers are printed, so we do not want to duplicate the information and
// thus only add the new information to a single buffer and return from the function.
break;
}
}
void TS::printf( int streams, const char* fmt, ... )
{
if( streams )
{
va_list l;
va_start( l, fmt );
vprintf( streams, fmt, l );
va_end( l );
}
}
TS ts;
TS* TS::ptr() { return &ts; }
}
/* End of file. */
/*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*/
#include "precomp.hpp"
namespace cvtest
{
static const int default_test_case_count = 500;
static const int default_max_log_array_size = 9;
ArrayTest::ArrayTest()
{
test_case_count = default_test_case_count;
iplimage_allowed = true;
cvmat_allowed = true;
optional_mask = false;
min_log_array_size = 0;
max_log_array_size = default_max_log_array_size;
element_wise_relative_error = true;
test_array.resize(MAX_ARR);
}
ArrayTest::~ArrayTest()
{
clear();
}
void ArrayTest::clear()
{
for( size_t i = 0; i < test_array.size(); i++ )
{
for( size_t j = 0; j < test_array[i].size(); j++ )
cvRelease( &test_array[i][j] );
}
BaseTest::clear();
}
int ArrayTest::read_params( CvFileStorage* fs )
{
int code = BaseTest::read_params( fs );
if( code < 0 )
return code;
min_log_array_size = cvReadInt( find_param( fs, "min_log_array_size" ), min_log_array_size );
max_log_array_size = cvReadInt( find_param( fs, "max_log_array_size" ), max_log_array_size );
test_case_count = cvReadInt( find_param( fs, "test_case_count" ), test_case_count );
test_case_count = cvRound( test_case_count*ts->get_test_case_count_scale() );
min_log_array_size = clipInt( min_log_array_size, 0, 20 );
max_log_array_size = clipInt( max_log_array_size, min_log_array_size, 20 );
test_case_count = clipInt( test_case_count, 0, 100000 );
return code;
}
void ArrayTest::get_test_array_types_and_sizes( int /*test_case_idx*/, vector<vector<Size> >& sizes, vector<vector<int> >& types )
{
RNG& rng = ts->get_rng();
Size size;
double val;
size_t i, j;
val = randReal(rng) * (max_log_array_size - min_log_array_size) + min_log_array_size;
size.width = cvRound( exp(val*CV_LOG2) );
val = randReal(rng) * (max_log_array_size - min_log_array_size) + min_log_array_size;
size.height = cvRound( exp(val*CV_LOG2) );
for( i = 0; i < test_array.size(); i++ )
{
size_t sizei = test_array[i].size();
for( j = 0; j < sizei; j++ )
{
sizes[i][j] = size;
types[i][j] = CV_8UC1;
}
}
}
static const int icvTsTypeToDepth[] =
{
IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U, IPL_DEPTH_16S,
IPL_DEPTH_32S, IPL_DEPTH_32F, IPL_DEPTH_64F
};
int ArrayTest::prepare_test_case( int test_case_idx )
{
int code = 1;
size_t max_arr = test_array.size();
vector<vector<Size> > sizes(max_arr);
vector<vector<Size> > whole_sizes(max_arr);
vector<vector<int> > types(max_arr);
size_t i, j;
RNG& rng = ts->get_rng();
bool is_image = false;
for( i = 0; i < max_arr; i++ )
{
size_t sizei = std::max(test_array[i].size(), (size_t)1);
sizes[i].resize(sizei);
types[i].resize(sizei);
whole_sizes[i].resize(sizei);
}
get_test_array_types_and_sizes( test_case_idx, sizes, types );
for( i = 0; i < max_arr; i++ )
{
size_t sizei = test_array[i].size();
for( j = 0; j < sizei; j++ )
{
unsigned t = randInt(rng);
bool create_mask = true, use_roi = false;
CvSize size = sizes[i][j], whole_size = size;
CvRect roi = {0,0,0,0};
is_image = !cvmat_allowed ? true : iplimage_allowed ? (t & 1) != 0 : false;
create_mask = (t & 6) == 0; // ~ each of 3 tests will use mask
use_roi = (t & 8) != 0;
if( use_roi )
{
whole_size.width += randInt(rng) % 10;
whole_size.height += randInt(rng) % 10;
}
cvRelease( &test_array[i][j] );
if( size.width > 0 && size.height > 0 &&
types[i][j] >= 0 && (i != MASK || create_mask) )
{
if( use_roi )
{
roi.width = size.width;
roi.height = size.height;
if( whole_size.width > size.width )
roi.x = randInt(rng) % (whole_size.width - size.width);
if( whole_size.height > size.height )
roi.y = randInt(rng) % (whole_size.height - size.height);
}
if( is_image )
{
test_array[i][j] = cvCreateImage( whole_size,
icvTsTypeToDepth[CV_MAT_DEPTH(types[i][j])], CV_MAT_CN(types[i][j]) );
if( use_roi )
cvSetImageROI( (IplImage*)test_array[i][j], roi );
}
else
{
test_array[i][j] = cvCreateMat( whole_size.height, whole_size.width, types[i][j] );
if( use_roi )
{
CvMat submat, *mat = (CvMat*)test_array[i][j];
cvGetSubRect( test_array[i][j], &submat, roi );
submat.refcount = mat->refcount;
*mat = submat;
}
}
}
}
}
test_mat.resize(test_array.size());
for( i = 0; i < max_arr; i++ )
{
size_t sizei = test_array[i].size();
test_mat[i].resize(sizei);
for( j = 0; j < sizei; j++ )
{
CvArr* arr = test_array[i][j];
test_mat[i][j] = cv::cvarrToMat(arr);
if( !test_mat[i][j].empty() )
fill_array( test_case_idx, i, j, test_mat[i][j] );
}
}
return code;
}
void ArrayTest::get_minmax_bounds( int i, int /*j*/, int type, Scalar& low, Scalar& high )
{
double l, u;
int depth = CV_MAT_DEPTH(type);
if( i == MASK )
{
l = -2;
u = 2;
}
else if( depth < CV_32S )
{
l = getMinVal(type);
u = getMaxVal(type);
}
else
{
u = depth == CV_32S ? 1000000 : 1000.;
l = -u;
}
low = Scalar::all(l);
high = Scalar::all(u);
}
void ArrayTest::fill_array( int /*test_case_idx*/, int i, int j, Mat& arr )
{
if( i == REF_INPUT_OUTPUT )
cvtest::copy( test_mat[INPUT_OUTPUT][j], arr, Mat() );
else if( i == INPUT || i == INPUT_OUTPUT || i == MASK )
{
Scalar low, high;
get_minmax_bounds( i, j, arr.type(), low, high );
randUni( ts->get_rng(), arr, low, high );
}
}
double ArrayTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
{
int elem_depth = CV_MAT_DEPTH(cvGetElemType(test_array[i][j]));
assert( i == OUTPUT || i == INPUT_OUTPUT );
return elem_depth < CV_32F ? 0 : elem_depth == CV_32F ? FLT_EPSILON*100: DBL_EPSILON*5000;
}
void ArrayTest::prepare_to_validation( int /*test_case_idx*/ )
{
assert(0);
}
int ArrayTest::validate_test_results( int test_case_idx )
{
static const char* arr_names[] = { "input", "input/output", "output",
"ref input/output", "ref output",
"temporary", "mask" };
size_t i, j;
prepare_to_validation( test_case_idx );
for( i = 0; i < 2; i++ )
{
int i0 = i == 0 ? OUTPUT : INPUT_OUTPUT;
int i1 = i == 0 ? REF_OUTPUT : REF_INPUT_OUTPUT;
size_t sizei = test_array[i0].size();
assert( sizei == test_array[i1].size() );
for( j = 0; j < sizei; j++ )
{
double err_level;
vector<int> idx;
double max_diff = 0;
int code;
char msg[100];
if( !test_array[i1][j] )
continue;
err_level = get_success_error_level( test_case_idx, i0, j );
code = cmpEps( test_mat[i0][j], test_mat[i1][j], &max_diff, err_level, &idx, element_wise_relative_error );
switch( code )
{
case -1:
sprintf( msg, "Too big difference (=%g)", max_diff );
code = TS::FAIL_BAD_ACCURACY;
break;
case -2:
strcpy( msg, "Invalid output" );
code = TS::FAIL_INVALID_OUTPUT;
break;
case -3:
strcpy( msg, "Invalid output in the reference array" );
code = TS::FAIL_INVALID_OUTPUT;
break;
default:
continue;
}
string idxstr = vec2str(", ", &idx[0], idx.size());
ts->printf( TS::LOG, "%s in %s array %d at (%s)", msg, arr_names[i0], j, idxstr.c_str() );
for( i0 = 0; i0 < (int)test_array.size(); i0++ )
{
size_t sizei0 = test_array[i0].size();
if( i0 == REF_INPUT_OUTPUT || i0 == OUTPUT || i0 == TEMP )
continue;
for( i1 = 0; i1 < (int)sizei0; i1++ )
{
const Mat& arr = test_mat[i0][i1];
if( !arr.empty() )
{
string sizestr = vec2str(", ", &arr.size[0], arr.dims);
ts->printf( TS::LOG, "%s array %d type=%sC%d, size=(%s)\n",
arr_names[i0], i1, getTypeName(arr.depth()),
arr.channels(), sizestr.c_str() );
}
}
}
ts->set_failed_test_info( code );
return code;
}
}
return 0;
}
}
/* End of file. */
#include "precomp.hpp"
#include <float.h>
#include <limits.h>
using namespace cv;
namespace cvtest
{
const char* getTypeName( int type )
{
static const char* type_names[] = { "8u", "8s", "16u", "16s", "32s", "32f", "64f", "ptr" };
return type_names[CV_MAT_DEPTH(type)];
}
int typeByName( const char* name )
{
int i;
for( i = 0; i < CV_DEPTH_MAX; i++ )
if( strcmp(name, getTypeName(i)) == 0 )
return i;
return -1;
}
string vec2str( const string& sep, const int* v, size_t nelems )
{
char buf[32];
string result = "";
for( size_t i = 0; i < nelems; i++ )
{
sprintf(buf, "%d", v[i]);
result += string(buf);
if( i < nelems - 1 )
result += sep;
}
return result;
}
Size randomSize(RNG& rng, double maxSizeLog)
{
double width_log = rng.uniform(0., maxSizeLog);
double height_log = rng.uniform(0., maxSizeLog - width_log);
if( (unsigned)rng % 2 != 0 )
std::swap(width_log, height_log);
Size sz;
sz.width = cvRound(exp(width_log));
sz.height = cvRound(exp(height_log));
return sz;
}
void randomSize(RNG& rng, int minDims, int maxDims, double maxSizeLog, vector<int>& sz)
{
int i, dims = rng.uniform(minDims, maxDims+1);
sz.resize(dims);
for( i = 0; i < dims; i++ )
{
double v = rng.uniform(0., maxSizeLog);
maxSizeLog -= v;
sz[i] = cvRound(exp(v));
}
for( i = 0; i < dims; i++ )
{
int j = rng.uniform(0, dims);
int k = rng.uniform(0, dims);
std::swap(sz[j], sz[k]);
}
}
int randomType(RNG& rng, int typeMask, int minChannels, int maxChannels)
{
int channels = rng.uniform(minChannels, maxChannels+1);
int depth = 0;
CV_Assert((typeMask & TYPE_MASK_ALL) != 0);
for(;;)
{
depth = rng.uniform(CV_8U, CV_64F+1);
if( ((1 << depth) & typeMask) != 0 )
break;
}
return CV_MAKETYPE(depth, channels);
}
double getMinVal(int depth)
{
depth = CV_MAT_DEPTH(depth);
double val = depth == CV_8U ? 0 : depth == CV_8S ? SCHAR_MIN : depth == CV_16U ? 0 :
depth == CV_16S ? SHRT_MIN : depth == CV_32S ? INT_MIN :
depth == CV_32F ? -FLT_MAX : depth == CV_64F ? -DBL_MAX : -1;
CV_Assert(val != -1);
return val;
}
double getMaxVal(int depth)
{
depth = CV_MAT_DEPTH(depth);
double val = depth == CV_8U ? UCHAR_MAX : depth == CV_8S ? SCHAR_MAX : depth == CV_16U ? USHRT_MAX :
depth == CV_16S ? SHRT_MAX : depth == CV_32S ? INT_MAX :
depth == CV_32F ? FLT_MAX : depth == CV_64F ? DBL_MAX : -1;
CV_Assert(val != -1);
return val;
}
Mat randomMat(RNG& rng, Size size, int type, double minVal, double maxVal, bool useRoi)
{
Size size0 = size;
if( useRoi )
{
size0.width += std::max(rng.uniform(0, 10) - 5, 0);
size0.height += std::max(rng.uniform(0, 10) - 5, 0);
}
Mat m(size0, type);
rng.fill(m, RNG::UNIFORM, Scalar::all(minVal), Scalar::all(maxVal));
if( size0 == size )
return m;
return m(Rect((size0.width-size.width)/2, (size0.height-size.height)/2, size.width, size.height));
}
Mat randomMat(RNG& rng, const vector<int>& size, int type, double minVal, double maxVal, bool useRoi)
{
int i, dims = (int)size.size();
vector<int> size0(dims);
vector<Range> r(dims);
bool eqsize = true;
for( i = 0; i < dims; i++ )
{
size0[i] = size[i];
r[i] = Range::all();
if( useRoi )
{
size0[i] += std::max(rng.uniform(0, 5) - 2, 0);
r[i] = Range((size0[i] - size[i])/2, (size0[i] - size[i])/2 + size[i]);
}
eqsize = eqsize && size[i] == size0[i];
}
Mat m(dims, &size0[0], type);
rng.fill(m, RNG::UNIFORM, Scalar::all(minVal), Scalar::all(maxVal));
if( eqsize )
return m;
return m(&r[0]);
}
void add(const Mat& _a, double alpha, const Mat& _b, double beta,
Scalar gamma, Mat& c, int ctype, bool calcAbs)
{
Mat a = _a, b = _b;
if( a.empty() || alpha == 0 )
{
// both alpha and beta can be 0, but at least one of a and b must be non-empty array,
// otherwise we do not know the size of the output (and may be type of the output, when ctype<0)
CV_Assert( !a.empty() || !b.empty() );
if( !b.empty() )
{
a = b;
alpha = beta;
b = Mat();
beta = 0;
}
}
if( b.empty() || beta == 0 )
{
b = Mat();
beta = 0;
}
else
CV_Assert(a.size == b.size);
if( ctype < 0 )
ctype = a.depth();
ctype = CV_MAKETYPE(CV_MAT_DEPTH(ctype), a.channels());
c.create(a.dims, &a.size[0], ctype);
const Mat *arrays[] = {&a, &b, &c, 0};
Mat planes[3], buf[3];
NAryMatIterator it(arrays, planes);
int i, nplanes = it.nplanes, cn=a.channels();
size_t total = planes[0].total(), maxsize = std::min((size_t)12*12*std::max(12/cn, 1), total);
CV_Assert(planes[0].rows == 1);
buf[0].create(1, (int)maxsize, CV_64FC(cn));
if(!b.empty())
buf[1].create(1, maxsize, CV_64FC(cn));
buf[2].create(1, maxsize, CV_64FC(cn));
scalarToRawData(gamma, buf[2].data, CV_64FC(cn), (int)(maxsize*cn));
for( i = 0; i < nplanes; i++, ++it)
{
for( size_t j = 0; j < total; j += maxsize )
{
size_t j2 = std::min(j + maxsize, total);
Mat apart0 = planes[0].colRange((int)j, (int)j2);
Mat cpart0 = planes[2].colRange((int)j, (int)j2);
Mat apart = buf[0].colRange(0, (int)(j2 - j));
apart0.convertTo(apart, apart.type(), alpha);
size_t k, n = (j2 - j)*cn;
double* aptr = (double*)apart.data;
const double* gptr = (const double*)buf[2].data;
if( b.empty() )
{
for( k = 0; k < n; k++ )
aptr[k] += gptr[k];
}
else
{
Mat bpart0 = planes[1].colRange((int)j, (int)j2);
Mat bpart = buf[1].colRange(0, (int)(j2 - j));
bpart0.convertTo(bpart, bpart.type(), beta);
const double* bptr = (const double*)bpart.data;
for( k = 0; k < n; k++ )
aptr[k] += bptr[k] + gptr[k];
}
if( calcAbs )
for( k = 0; k < n; k++ )
aptr[k] = fabs(aptr[k]);
apart.convertTo(cpart0, cpart0.type(), 1, 0);
}
}
}
template<typename _Tp1, typename _Tp2> inline void
convert_(const _Tp1* src, _Tp2* dst, size_t total, double alpha, double beta)
{
size_t i;
if( alpha == 1 && beta == 0 )
for( i = 0; i < total; i++ )
dst[i] = saturate_cast<_Tp2>(src[i]);
else if( beta == 0 )
for( i = 0; i < total; i++ )
dst[i] = saturate_cast<_Tp2>(src[i]*alpha);
else
for( i = 0; i < total; i++ )
dst[i] = saturate_cast<_Tp2>(src[i]*alpha + beta);
}
template<typename _Tp> inline void
convertTo(const _Tp* src, void* dst, int dtype, size_t total, double alpha, double beta)
{
switch( CV_MAT_DEPTH(dtype) )
{
case CV_8U:
convert_(src, (uchar*)dst, total, alpha, beta);
break;
case CV_8S:
convert_(src, (schar*)dst, total, alpha, beta);
break;
case CV_16U:
convert_(src, (ushort*)dst, total, alpha, beta);
break;
case CV_16S:
convert_(src, (short*)dst, total, alpha, beta);
break;
case CV_32S:
convert_(src, (int*)dst, total, alpha, beta);
break;
case CV_32F:
convert_(src, (float*)dst, total, alpha, beta);
break;
case CV_64F:
convert_(src, (double*)dst, total, alpha, beta);
break;
default:
CV_Assert(0);
}
}
void convert(const Mat& src, Mat& dst, int dtype, double alpha, double beta)
{
dtype = CV_MAKETYPE(CV_MAT_DEPTH(dtype), src.channels());
dst.create(src.dims, &src.size[0], dtype);
if( alpha == 0 )
{
set( dst, Scalar::all(beta) );
return;
}
if( dtype == src.type() && alpha == 1 && beta == 0 )
{
copy( src, dst );
return;
}
const Mat *arrays[]={&src, &dst, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total()*planes[0].channels();
int i, nplanes = it.nplanes;
for( i = 0; i < nplanes; i++, ++it)
{
const uchar* sptr = planes[0].data;
uchar* dptr = planes[1].data;
switch( src.depth() )
{
case CV_8U:
convertTo((const uchar*)sptr, dptr, dtype, total, alpha, beta);
break;
case CV_8S:
convertTo((const schar*)sptr, dptr, dtype, total, alpha, beta);
break;
case CV_16U:
convertTo((const ushort*)sptr, dptr, dtype, total, alpha, beta);
break;
case CV_16S:
convertTo((const short*)sptr, dptr, dtype, total, alpha, beta);
break;
case CV_32S:
convertTo((const int*)sptr, dptr, dtype, total, alpha, beta);
break;
case CV_32F:
convertTo((const float*)sptr, dptr, dtype, total, alpha, beta);
break;
case CV_64F:
convertTo((const double*)sptr, dptr, dtype, total, alpha, beta);
break;
}
}
}
void copy(const Mat& src, Mat& dst, const Mat& mask, bool invertMask)
{
dst.create(src.dims, &src.size[0], src.type());
if(mask.empty())
{
const Mat* arrays[] = {&src, &dst, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
int i, nplanes = it.nplanes;
size_t planeSize = planes[0].total()*src.elemSize();
for( i = 0; i < nplanes; i++, ++it )
memcpy(planes[1].data, planes[0].data, planeSize);
return;
}
CV_Assert( src.size == mask.size && mask.type() == CV_8U );
const Mat *arrays[]={&src, &dst, &mask, 0};
Mat planes[3];
NAryMatIterator it(arrays, planes);
size_t j, k, elemSize = src.elemSize(), total = planes[0].total();
int i, nplanes = it.nplanes;
for( i = 0; i < nplanes; i++, ++it)
{
const uchar* sptr = planes[0].data;
uchar* dptr = planes[1].data;
const uchar* mptr = planes[2].data;
for( j = 0; j < total; j++, sptr += elemSize, dptr += elemSize )
{
if( (mptr[j] != 0) ^ invertMask )
for( k = 0; k < elemSize; k++ )
dptr[k] = sptr[k];
}
}
}
void set(Mat& dst, const Scalar& gamma, const Mat& mask)
{
double buf[12];
scalarToRawData(gamma, &buf, dst.type(), dst.channels());
const uchar* gptr = (const uchar*)&buf[0];
if(mask.empty())
{
const Mat* arrays[] = {&dst, 0};
Mat plane;
NAryMatIterator it(arrays, &plane);
int i, nplanes = it.nplanes;
size_t j, k, elemSize = dst.elemSize(), planeSize = plane.total()*elemSize;
for( k = 1; k < elemSize; k++ )
if( gptr[k] != gptr[0] )
break;
bool uniform = k >= elemSize;
for( i = 0; i < nplanes; i++, ++it )
{
uchar* dptr = plane.data;
if( uniform )
memset( dptr, gptr[0], planeSize );
else if( i == 0 )
{
for( j = 0; j < planeSize; j += elemSize, dptr += elemSize )
for( k = 0; k < elemSize; k++ )
dptr[k] = gptr[k];
}
else
memcpy(dptr, dst.data, planeSize);
}
return;
}
CV_Assert( dst.size == mask.size && mask.type() == CV_8U );
const Mat *arrays[]={&dst, &mask, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t j, k, elemSize = dst.elemSize(), total = planes[0].total();
int i, nplanes = it.nplanes;
for( i = 0; i < nplanes; i++, ++it)
{
uchar* dptr = planes[0].data;
const uchar* mptr = planes[1].data;
for( j = 0; j < total; j++, dptr += elemSize )
{
if( mptr[j] )
for( k = 0; k < elemSize; k++ )
dptr[k] = gptr[k];
}
}
}
void insert(const Mat& src, Mat& dst, int coi)
{
CV_Assert( dst.size == src.size && src.depth() == dst.depth() &&
0 <= coi && coi < dst.channels() );
const Mat* arrays[] = {&src, &dst, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
int i, nplanes = it.nplanes;
size_t j, k, size0 = src.elemSize(), size1 = dst.elemSize(), total = planes[0].total();
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr = planes[0].data;
uchar* dptr = planes[1].data + coi*size0;
for( j = 0; j < total; j++, sptr += size0, dptr += size1 )
{
for( k = 0; k < size0; k++ )
dptr[k] = sptr[k];
}
}
}
void extract(const Mat& src, Mat& dst, int coi)
{
dst.create( src.dims, &src.size[0], src.depth() );
CV_Assert( 0 <= coi && coi < src.channels() );
const Mat* arrays[] = {&src, &dst, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
int i, nplanes = it.nplanes;
size_t j, k, size0 = src.elemSize(), size1 = dst.elemSize(), total = planes[0].total();
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr = planes[0].data + coi*size1;
uchar* dptr = planes[1].data;
for( j = 0; j < total; j++, sptr += size0, dptr += size1 )
{
for( k = 0; k < size1; k++ )
dptr[k] = sptr[k];
}
}
}
void transpose(const Mat& src, Mat& dst)
{
CV_Assert(src.dims == 2);
dst.create(src.cols, src.rows, src.type());
int i, j, k, esz = (int)src.elemSize();
for( i = 0; i < dst.rows; i++ )
{
const uchar* sptr = src.ptr(0) + i*esz;
uchar* dptr = dst.ptr(i);
for( j = 0; j < dst.cols; j++, sptr += src.step[0], dptr += esz )
{
for( k = 0; k < esz; k++ )
dptr[k] = sptr[k];
}
}
}
template<typename _Tp> static void
randUniInt_(RNG& rng, _Tp* data, size_t total, int cn, const Scalar& scale, const Scalar& delta)
{
for( size_t i = 0; i < total; i += cn )
for( int k = 0; k < cn; k++ )
{
int val = cvFloor( randInt(rng)*scale[k] + delta[k] );
data[i + k] = saturate_cast<_Tp>(val);
}
}
template<typename _Tp> static void
randUniFlt_(RNG& rng, _Tp* data, size_t total, int cn, const Scalar& scale, const Scalar& delta)
{
for( size_t i = 0; i < total; i += cn )
for( int k = 0; k < cn; k++ )
{
double val = randReal(rng)*scale[k] + delta[k];
data[i + k] = saturate_cast<_Tp>(val);
}
}
void randUni( RNG& rng, Mat& a, const Scalar& param0, const Scalar& param1 )
{
Scalar scale = param0;
Scalar delta = param1;
double C = a.depth() < CV_32F ? 1./(65536.*65536.) : 1.;
for( int k = 0; k < 4; k++ )
{
double s = scale.val[k] - delta.val[k];
if( s >= 0 )
scale.val[k] = s;
else
{
delta.val[k] = scale.val[k];
scale.val[k] = -s;
}
scale.val[k] *= C;
}
const Mat *arrays[]={&a, 0};
Mat plane;
NAryMatIterator it(arrays, &plane);
int i, nplanes = it.nplanes, depth = a.depth(), cn = a.channels();
size_t total = plane.total()*cn;
for( i = 0; i < nplanes; i++, ++it )
{
switch( depth )
{
case CV_8U:
randUniInt_(rng, plane.ptr<uchar>(), total, cn, scale, delta);
break;
case CV_8S:
randUniInt_(rng, plane.ptr<schar>(), total, cn, scale, delta);
break;
case CV_16U:
randUniInt_(rng, plane.ptr<ushort>(), total, cn, scale, delta);
break;
case CV_16S:
randUniInt_(rng, plane.ptr<short>(), total, cn, scale, delta);
break;
case CV_32S:
randUniInt_(rng, plane.ptr<int>(), total, cn, scale, delta);
break;
case CV_32F:
randUniFlt_(rng, plane.ptr<float>(), total, cn, scale, delta);
break;
case CV_64F:
randUniFlt_(rng, plane.ptr<double>(), total, cn, scale, delta);
break;
default:
CV_Assert(0);
}
}
}
template<typename _Tp> static void
erode_(const Mat& src, Mat& dst, const vector<int>& ofsvec)
{
int width = dst.cols*src.channels(), n = (int)ofsvec.size();
const int* ofs = &ofsvec[0];
for( int y = 0; y < dst.rows; y++ )
{
const _Tp* sptr = src.ptr<_Tp>(y);
_Tp* dptr = dst.ptr<_Tp>(y);
for( int x = 0; x < width; x++ )
{
_Tp result = sptr[x + ofs[0]];
for( int i = 1; i < n; i++ )
result = std::min(result, sptr[x + ofs[i]]);
dptr[x] = result;
}
}
}
template<typename _Tp> static void
dilate_(const Mat& src, Mat& dst, const vector<int>& ofsvec)
{
int width = dst.cols*src.channels(), n = (int)ofsvec.size();
const int* ofs = &ofsvec[0];
for( int y = 0; y < dst.rows; y++ )
{
const _Tp* sptr = src.ptr<_Tp>(y);
_Tp* dptr = dst.ptr<_Tp>(y);
for( int x = 0; x < width; x++ )
{
_Tp result = sptr[x + ofs[0]];
for( int i = 1; i < n; i++ )
result = std::max(result, sptr[x + ofs[i]]);
dptr[x] = result;
}
}
}
void erode(const Mat& _src, Mat& dst, const Mat& _kernel, Point anchor,
int borderType, const Scalar& _borderValue)
{
//if( _src.type() == CV_16UC3 && _src.size() == Size(1, 2) )
// putchar('*');
Mat kernel = _kernel, src;
Scalar borderValue = _borderValue;
if( kernel.empty() )
kernel = Mat::ones(3, 3, CV_8U);
else
{
CV_Assert( kernel.type() == CV_8U );
}
if( anchor == Point(-1,-1) )
anchor = Point(kernel.cols/2, kernel.rows/2);
if( borderType == IPL_BORDER_CONSTANT )
borderValue = getMaxVal(src.depth());
copyMakeBorder(_src, src, anchor.y, kernel.rows - anchor.y - 1,
anchor.x, kernel.cols - anchor.x - 1,
borderType, borderValue);
dst.create( _src.size(), src.type() );
vector<int> ofs;
int step = (int)(src.step/src.elemSize1()), cn = src.channels();
for( int i = 0; i < kernel.rows; i++ )
for( int j = 0; j < kernel.cols; j++ )
if( kernel.at<uchar>(i, j) != 0 )
ofs.push_back(i*step + j*cn);
if( ofs.empty() )
ofs.push_back(anchor.y*step + anchor.x*cn);
switch( src.depth() )
{
case CV_8U:
erode_<uchar>(src, dst, ofs);
break;
case CV_8S:
erode_<schar>(src, dst, ofs);
break;
case CV_16U:
erode_<ushort>(src, dst, ofs);
break;
case CV_16S:
erode_<short>(src, dst, ofs);
break;
case CV_32S:
erode_<int>(src, dst, ofs);
break;
case CV_32F:
erode_<float>(src, dst, ofs);
break;
case CV_64F:
erode_<double>(src, dst, ofs);
break;
default:
CV_Assert(0);
}
}
void dilate(const Mat& _src, Mat& dst, const Mat& _kernel, Point anchor,
int borderType, const Scalar& _borderValue)
{
Mat kernel = _kernel, src;
Scalar borderValue = _borderValue;
if( kernel.empty() )
kernel = Mat::ones(3, 3, CV_8U);
else
{
CV_Assert( kernel.type() == CV_8U );
}
if( anchor == Point(-1,-1) )
anchor = Point(kernel.cols/2, kernel.rows/2);
if( borderType == IPL_BORDER_CONSTANT )
borderValue = getMinVal(src.depth());
copyMakeBorder(_src, src, anchor.y, kernel.rows - anchor.y - 1,
anchor.x, kernel.cols - anchor.x - 1,
borderType, borderValue);
dst.create( _src.size(), src.type() );
vector<int> ofs;
int step = (int)(src.step/src.elemSize1()), cn = src.channels();
for( int i = 0; i < kernel.rows; i++ )
for( int j = 0; j < kernel.cols; j++ )
if( kernel.at<uchar>(i, j) != 0 )
ofs.push_back(i*step + j*cn);
if( ofs.empty() )
ofs.push_back(anchor.y*step + anchor.x*cn);
switch( src.depth() )
{
case CV_8U:
dilate_<uchar>(src, dst, ofs);
break;
case CV_8S:
dilate_<schar>(src, dst, ofs);
break;
case CV_16U:
dilate_<ushort>(src, dst, ofs);
break;
case CV_16S:
dilate_<short>(src, dst, ofs);
break;
case CV_32S:
dilate_<int>(src, dst, ofs);
break;
case CV_32F:
dilate_<float>(src, dst, ofs);
break;
case CV_64F:
dilate_<double>(src, dst, ofs);
break;
default:
CV_Assert(0);
}
}
template<typename _Tp> static void
filter2D_(const Mat& src, Mat& dst, const vector<int>& ofsvec, const vector<double>& coeffvec)
{
const int* ofs = &ofsvec[0];
const double* coeff = &coeffvec[0];
int width = dst.cols*dst.channels(), ncoeffs = (int)ofsvec.size();
for( int y = 0; y < dst.rows; y++ )
{
const _Tp* sptr = src.ptr<_Tp>(y);
double* dptr = dst.ptr<double>(y);
for( int x = 0; x < width; x++ )
{
double s = 0;
for( int i = 0; i < ncoeffs; i++ )
s += sptr[x + ofs[i]]*coeff[i];
dptr[x] = s;
}
}
}
void filter2D(const Mat& _src, Mat& dst, int ddepth, const Mat& kernel,
Point anchor, double delta, int borderType, const Scalar& _borderValue)
{
Mat src, _dst;
Scalar borderValue = _borderValue;
CV_Assert( kernel.type() == CV_32F || kernel.type() == CV_64F );
if( anchor == Point(-1,-1) )
anchor = Point(kernel.cols/2, kernel.rows/2);
if( borderType == IPL_BORDER_CONSTANT )
borderValue = getMinVal(src.depth());
copyMakeBorder(_src, src, anchor.y, kernel.rows - anchor.y - 1,
anchor.x, kernel.cols - anchor.x - 1,
borderType, borderValue);
_dst.create( _src.size(), CV_MAKETYPE(CV_64F, src.channels()) );
vector<int> ofs;
vector<double> coeff(kernel.rows*kernel.cols);
Mat cmat(kernel.rows, kernel.cols, CV_64F, &coeff[0]);
convert(kernel, cmat, cmat.type());
int step = (int)(src.step/src.elemSize1()), cn = src.channels();
for( int i = 0; i < kernel.rows; i++ )
for( int j = 0; j < kernel.cols; j++ )
ofs.push_back(i*step + j*cn);
switch( src.depth() )
{
case CV_8U:
filter2D_<uchar>(src, _dst, ofs, coeff);
break;
case CV_8S:
filter2D_<schar>(src, _dst, ofs, coeff);
break;
case CV_16U:
filter2D_<ushort>(src, _dst, ofs, coeff);
break;
case CV_16S:
filter2D_<short>(src, _dst, ofs, coeff);
break;
case CV_32S:
filter2D_<int>(src, _dst, ofs, coeff);
break;
case CV_32F:
filter2D_<float>(src, _dst, ofs, coeff);
break;
case CV_64F:
filter2D_<double>(src, _dst, ofs, coeff);
break;
default:
CV_Assert(0);
}
convert(_dst, dst, ddepth, 1, delta);
}
static int borderInterpolate( int p, int len, int borderType )
{
if( (unsigned)p < (unsigned)len )
;
else if( borderType == IPL_BORDER_REPLICATE )
p = p < 0 ? 0 : len - 1;
else if( borderType == IPL_BORDER_REFLECT || borderType == IPL_BORDER_REFLECT_101 )
{
int delta = borderType == IPL_BORDER_REFLECT_101;
if( len == 1 )
return 0;
do
{
if( p < 0 )
p = -p - 1 + delta;
else
p = len - 1 - (p - len) - delta;
}
while( (unsigned)p >= (unsigned)len );
}
else if( borderType == IPL_BORDER_WRAP )
{
if( p < 0 )
p -= ((p-len+1)/len)*len;
if( p >= len )
p %= len;
}
else if( borderType == IPL_BORDER_CONSTANT )
p = -1;
else
CV_Error( CV_StsBadArg, "Unknown/unsupported border type" );
return p;
}
void copyMakeBorder(const Mat& src, Mat& dst, int top, int bottom, int left, int right,
int borderType, const Scalar& borderValue)
{
dst.create(src.rows + top + bottom, src.cols + left + right, src.type());
int i, j, k, esz = (int)src.elemSize();
int width = src.cols*esz, width1 = dst.cols*esz;
if( borderType == IPL_BORDER_CONSTANT )
{
vector<uchar> valvec((src.cols + left + right)*esz);
uchar* val = &valvec[0];
scalarToRawData(borderValue, val, src.type(), (src.cols + left + right)*src.channels());
left *= esz;
right *= esz;
for( i = 0; i < src.rows; i++ )
{
const uchar* sptr = src.ptr(i);
uchar* dptr = dst.ptr(i + top) + left;
for( j = 0; j < left; j++ )
dptr[j - left] = val[j];
if( dptr != sptr )
for( j = 0; j < width; j++ )
dptr[j] = sptr[j];
for( j = 0; j < right; j++ )
dptr[j + width] = val[j];
}
for( i = 0; i < top; i++ )
{
uchar* dptr = dst.ptr(i);
for( j = 0; j < width1; j++ )
dptr[j] = val[j];
}
for( i = 0; i < bottom; i++ )
{
uchar* dptr = dst.ptr(i + top + src.rows);
for( j = 0; j < width1; j++ )
dptr[j] = val[j];
}
}
else
{
vector<int> tabvec((left + right)*esz);
int* ltab = &tabvec[0];
int* rtab = &tabvec[left*esz];
for( i = 0; i < left; i++ )
{
j = borderInterpolate(i - left, src.cols, borderType)*esz;
for( k = 0; k < esz; k++ )
ltab[i*esz + k] = j + k;
}
for( i = 0; i < right; i++ )
{
j = borderInterpolate(src.cols + i, src.cols, borderType)*esz;
for( k = 0; k < esz; k++ )
rtab[i*esz + k] = j + k;
}
left *= esz;
right *= esz;
for( i = 0; i < src.rows; i++ )
{
const uchar* sptr = src.ptr(i);
uchar* dptr = dst.ptr(i + top);
for( j = 0; j < left; j++ )
dptr[j] = sptr[ltab[j]];
if( dptr + left != sptr )
{
for( j = 0; j < width; j++ )
dptr[j + left] = sptr[j];
}
for( j = 0; j < right; j++ )
dptr[j + left + width] = sptr[rtab[j]];
}
for( i = 0; i < top; i++ )
{
j = borderInterpolate(i - top, src.rows, borderType);
const uchar* sptr = dst.ptr(j + top);
uchar* dptr = dst.ptr(i);
for( k = 0; k < width1; k++ )
dptr[k] = sptr[k];
}
for( i = 0; i < bottom; i++ )
{
j = borderInterpolate(i + src.rows, src.rows, borderType);
const uchar* sptr = dst.ptr(j + top);
uchar* dptr = dst.ptr(i + top + src.rows);
for( k = 0; k < width1; k++ )
dptr[k] = sptr[k];
}
}
}
template<typename _Tp> static void
minMaxLoc_(const _Tp* src, size_t total, size_t startidx,
double* _minval, double* _maxval,
size_t* _minpos, size_t* _maxpos,
const uchar* mask)
{
_Tp maxval = saturate_cast<_Tp>(*_maxval), minval = saturate_cast<_Tp>(*_minval);
size_t minpos = *_minpos, maxpos = *_maxpos;
if( !mask )
{
for( size_t i = 0; i < total; i++ )
{
_Tp val = src[i];
if( minval > val )
{
minval = val;
minpos = startidx + i;
}
if( maxval < val )
{
maxval = val;
maxpos = startidx + i;
}
}
}
else
{
for( size_t i = 0; i < total; i++ )
{
_Tp val = src[i];
if( minval > val && mask[i] )
{
minval = val;
minpos = startidx + i;
}
if( maxval < val && mask[i] )
{
maxval = val;
maxpos = startidx + i;
}
}
}
*_maxval = maxval;
*_minval = minval;
*_maxpos = maxpos;
*_minpos = minpos;
}
static void setpos( const Mat& mtx, vector<int>& pos, size_t idx )
{
pos.resize(mtx.dims);
if( idx > 0 )
{
idx--;
for( int i = mtx.dims-1; i >= 0; i-- )
{
int sz = mtx.size[i]*(i == mtx.dims-1 ? mtx.channels() : 1);
pos[i] = idx % sz;
idx /= sz;
}
}
else
{
for( int i = mtx.dims-1; i >= 0; i-- )
pos[i] = -1;
}
}
void minMaxLoc(const Mat& src, double* _minval, double* _maxval,
vector<int>* _minloc, vector<int>* _maxloc,
const Mat& mask)
{
CV_Assert( src.channels() == 1 );
const Mat *arrays[]={&src, &mask, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t startidx = 1, total = planes[0].total();
int i, nplanes = it.nplanes, depth = src.depth();
double maxval = depth < CV_32F ? INT_MIN : depth == CV_32F ? -FLT_MAX : -DBL_MAX;
double minval = depth < CV_32F ? INT_MAX : depth == CV_32F ? FLT_MAX : DBL_MAX;
size_t maxidx = 0, minidx = 0;
for( i = 0; i < nplanes; i++, ++it, startidx += total )
{
const uchar* sptr = planes[0].data;
const uchar* mptr = planes[1].data;
switch( depth )
{
case CV_8U:
minMaxLoc_((const uchar*)sptr, total, startidx,
&minval, &maxval, &minidx, &maxidx, mptr);
break;
case CV_8S:
minMaxLoc_((const schar*)sptr, total, startidx,
&minval, &maxval, &minidx, &maxidx, mptr);
break;
case CV_16U:
minMaxLoc_((const ushort*)sptr, total, startidx,
&minval, &maxval, &minidx, &maxidx, mptr);
break;
case CV_16S:
minMaxLoc_((const short*)sptr, total, startidx,
&minval, &maxval, &minidx, &maxidx, mptr);
break;
case CV_32S:
minMaxLoc_((const int*)sptr, total, startidx,
&minval, &maxval, &minidx, &maxidx, mptr);
break;
case CV_32F:
minMaxLoc_((const float*)sptr, total, startidx,
&minval, &maxval, &minidx, &maxidx, mptr);
break;
case CV_64F:
minMaxLoc_((const double*)sptr, total, startidx,
&minval, &maxval, &minidx, &maxidx, mptr);
break;
default:
CV_Assert(0);
}
}
if( minidx == 0 )
minval = maxval = 0;
if( _maxval )
*_maxval = maxval;
if( _minval )
*_minval = minval;
if( _maxloc )
setpos( src, *_maxloc, maxidx );
if( _minloc )
setpos( src, *_minloc, minidx );
}
template<typename _Tp> static double
norm_(const _Tp* src, size_t total, int cn, int normType, double startval, const uchar* mask)
{
size_t i;
double result = startval;
if( !mask )
total *= cn;
if( normType == NORM_INF )
{
if( !mask )
for( i = 0; i < total; i++ )
result = std::max(result, (double)std::abs(src[i]));
else
for( int c = 0; c < cn; c++ )
{
for( i = 0; i < total; i++ )
if( mask[i] )
result = std::max(result, (double)std::abs(src[i*cn + c]));
}
}
else if( normType == NORM_L1 )
{
if( !mask )
for( i = 0; i < total; i++ )
result += std::abs(src[i]);
else
for( int c = 0; c < cn; c++ )
{
for( i = 0; i < total; i++ )
if( mask[i] )
result += std::abs(src[i*cn + c]);
}
}
else
{
if( !mask )
for( i = 0; i < total; i++ )
{
double v = src[i];
result += v*v;
}
else
for( int c = 0; c < cn; c++ )
{
for( i = 0; i < total; i++ )
if( mask[i] )
{
double v = src[i*cn + c];
result += v*v;
}
}
}
return result;
}
template<typename _Tp> static double
norm_(const _Tp* src1, const _Tp* src2, size_t total, int cn, int normType, double startval, const uchar* mask)
{
size_t i;
double result = startval;
if( !mask )
total *= cn;
if( normType == NORM_INF )
{
if( !mask )
for( i = 0; i < total; i++ )
result = std::max(result, (double)std::abs(src1[i] - src2[i]));
else
for( int c = 0; c < cn; c++ )
{
for( i = 0; i < total; i++ )
if( mask[i] )
result = std::max(result, (double)std::abs(src1[i*cn + c] - src2[i*cn + c]));
}
}
else if( normType == NORM_L1 )
{
if( !mask )
for( i = 0; i < total; i++ )
result += std::abs(src1[i] - src2[i]);
else
for( int c = 0; c < cn; c++ )
{
for( i = 0; i < total; i++ )
if( mask[i] )
result += std::abs(src1[i*cn + c] - src2[i*cn + c]);
}
}
else
{
if( !mask )
for( i = 0; i < total; i++ )
{
double v = src1[i] - src2[i];
result += v*v;
}
else
for( int c = 0; c < cn; c++ )
{
for( i = 0; i < total; i++ )
if( mask[i] )
{
double v = src1[i*cn + c] - src2[i*cn + c];
result += v*v;
}
}
}
return result;
}
double norm(const Mat& src, int normType, const Mat& mask)
{
CV_Assert( mask.empty() || (src.size == mask.size && mask.type() == CV_8U) );
CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 );
const Mat *arrays[]={&src, &mask, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total();
int i, nplanes = it.nplanes, depth = src.depth();
int cn = planes[0].channels();
double result = 0;
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr = planes[0].data;
const uchar* mptr = planes[1].data;
switch( depth )
{
case CV_8U:
result = norm_((const uchar*)sptr, total, cn, normType, result, mptr);
break;
case CV_8S:
result = norm_((const schar*)sptr, total, cn, normType, result, mptr);
break;
case CV_16U:
result = norm_((const ushort*)sptr, total, cn, normType, result, mptr);
break;
case CV_16S:
result = norm_((const short*)sptr, total, cn, normType, result, mptr);
break;
case CV_32S:
result = norm_((const int*)sptr, total, cn, normType, result, mptr);
break;
case CV_32F:
result = norm_((const float*)sptr, total, cn, normType, result, mptr);
break;
case CV_64F:
result = norm_((const double*)sptr, total, cn, normType, result, mptr);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
};
}
if( normType == NORM_L2 )
result = sqrt(result);
return result;
}
double norm(const Mat& src1, const Mat& src2, int normType, const Mat& mask)
{
CV_Assert( src1.type() == src2.type() && src1.size == src2.size );
CV_Assert( mask.empty() || (src1.size == mask.size && mask.type() == CV_8U) );
CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 );
const Mat *arrays[]={&src1, &src2, &mask, 0};
Mat planes[3];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total();
int i, nplanes = it.nplanes, depth = src1.depth();
int cn = planes[0].channels();
double result = 0;
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr1 = planes[0].data;
const uchar* sptr2 = planes[1].data;
const uchar* mptr = planes[2].data;
switch( depth )
{
case CV_8U:
result = norm_((const uchar*)sptr1, (const uchar*)sptr2, total, cn, normType, result, mptr);
break;
case CV_8S:
result = norm_((const schar*)sptr1, (const schar*)sptr2, total, cn, normType, result, mptr);
break;
case CV_16U:
result = norm_((const ushort*)sptr1, (const ushort*)sptr2, total, cn, normType, result, mptr);
break;
case CV_16S:
result = norm_((const short*)sptr1, (const short*)sptr2, total, cn, normType, result, mptr);
break;
case CV_32S:
result = norm_((const int*)sptr1, (const int*)sptr2, total, cn, normType, result, mptr);
break;
case CV_32F:
result = norm_((const float*)sptr1, (const float*)sptr2, total, cn, normType, result, mptr);
break;
case CV_64F:
result = norm_((const double*)sptr1, (const double*)sptr2, total, cn, normType, result, mptr);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
};
}
if( normType == NORM_L2 )
result = sqrt(result);
return result;
}
template<typename _Tp> static double
crossCorr_(const _Tp* src1, const _Tp* src2, size_t total)
{
double result = 0;
for( size_t i = 0; i < total; i++ )
result += (double)src1[i]*src2[i];
return result;
}
double crossCorr(const Mat& src1, const Mat& src2)
{
CV_Assert( src1.size == src2.size && src1.type() == src2.type() );
const Mat *arrays[]={&src1, &src2, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total()*planes[0].channels();
int i, nplanes = it.nplanes, depth = src1.depth();
double result = 0;
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr1 = planes[0].data;
const uchar* sptr2 = planes[1].data;
switch( depth )
{
case CV_8U:
result += crossCorr_((const uchar*)sptr1, (const uchar*)sptr2, total);
break;
case CV_8S:
result += crossCorr_((const schar*)sptr1, (const schar*)sptr2, total);
break;
case CV_16U:
result += crossCorr_((const ushort*)sptr1, (const ushort*)sptr2, total);
break;
case CV_16S:
result += crossCorr_((const short*)sptr1, (const short*)sptr2, total);
break;
case CV_32S:
result += crossCorr_((const int*)sptr1, (const int*)sptr2, total);
break;
case CV_32F:
result += crossCorr_((const float*)sptr1, (const float*)sptr2, total);
break;
case CV_64F:
result += crossCorr_((const double*)sptr1, (const double*)sptr2, total);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
};
}
return result;
}
static void
logicOp_(const uchar* src1, const uchar* src2, uchar* dst, size_t total, char c)
{
size_t i;
if( c == '&' )
for( i = 0; i < total; i++ )
dst[i] = src1[i] & src2[i];
else if( c == '|' )
for( i = 0; i < total; i++ )
dst[i] = src1[i] | src2[i];
else
for( i = 0; i < total; i++ )
dst[i] = src1[i] ^ src2[i];
}
static void
logicOpS_(const uchar* src, const uchar* scalar, uchar* dst, size_t total, char c)
{
const size_t blockSize = 96;
size_t i, j;
if( c == '&' )
for( i = 0; i < total; i += blockSize, dst += blockSize, src += blockSize )
{
size_t sz = std::min(total - i, blockSize);
for( j = 0; j < sz; j++ )
dst[j] = src[j] & scalar[j];
}
else if( c == '|' )
for( i = 0; i < total; i += blockSize, dst += blockSize, src += blockSize )
{
size_t sz = std::min(total - i, blockSize);
for( j = 0; j < sz; j++ )
dst[j] = src[j] | scalar[j];
}
else if( c == '^' )
{
for( i = 0; i < total; i += blockSize, dst += blockSize, src += blockSize )
{
size_t sz = std::min(total - i, blockSize);
for( j = 0; j < sz; j++ )
dst[j] = src[j] ^ scalar[j];
}
}
else
for( i = 0; i < total; i++ )
dst[i] = ~src[i];
}
void logicOp( const Mat& src1, const Mat& src2, Mat& dst, char op )
{
CV_Assert( op == '&' || op == '|' || op == '^' );
CV_Assert( src1.type() == src2.type() && src1.size == src2.size );
dst.create( src1.dims, &src1.size[0], src1.type() );
const Mat *arrays[]={&src1, &src2, &dst, 0};
Mat planes[3];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total()*planes[0].elemSize();
int i, nplanes = it.nplanes;
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr1 = planes[0].data;
const uchar* sptr2 = planes[1].data;
uchar* dptr = planes[2].data;
logicOp_(sptr1, sptr2, dptr, total, op);
}
}
void logicOp(const Mat& src, const Scalar& s, Mat& dst, char op)
{
CV_Assert( op == '&' || op == '|' || op == '^' || op == '~' );
dst.create( src.dims, &src.size[0], src.type() );
const Mat *arrays[]={&src, &dst, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total()*planes[0].elemSize();
int i, nplanes = it.nplanes;
double buf[12];
scalarToRawData(s, buf, src.type(), 96/planes[0].elemSize1());
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr = planes[0].data;
uchar* dptr = planes[1].data;
logicOpS_(sptr, (uchar*)&buf[0], dptr, total, op);
}
}
template<typename _Tp> static void
compare_(const _Tp* src1, const _Tp* src2, uchar* dst, size_t total, int cmpop)
{
size_t i;
switch( cmpop )
{
case CMP_LT:
for( i = 0; i < total; i++ )
dst[i] = src1[i] < src2[i] ? 255 : 0;
break;
case CMP_LE:
for( i = 0; i < total; i++ )
dst[i] = src1[i] <= src2[i] ? 255 : 0;
break;
case CMP_EQ:
for( i = 0; i < total; i++ )
dst[i] = src1[i] == src2[i] ? 255 : 0;
break;
case CMP_NE:
for( i = 0; i < total; i++ )
dst[i] = src1[i] != src2[i] ? 255 : 0;
break;
case CMP_GE:
for( i = 0; i < total; i++ )
dst[i] = src1[i] >= src2[i] ? 255 : 0;
break;
case CMP_GT:
for( i = 0; i < total; i++ )
dst[i] = src1[i] > src2[i] ? 255 : 0;
break;
default:
CV_Error(CV_StsBadArg, "Unknown comparison operation");
}
}
template<typename _Tp, typename _WTp> static void
compareS_(const _Tp* src1, _WTp value, uchar* dst, size_t total, int cmpop)
{
size_t i;
switch( cmpop )
{
case CMP_LT:
for( i = 0; i < total; i++ )
dst[i] = src1[i] < value ? 255 : 0;
break;
case CMP_LE:
for( i = 0; i < total; i++ )
dst[i] = src1[i] <= value ? 255 : 0;
break;
case CMP_EQ:
for( i = 0; i < total; i++ )
dst[i] = src1[i] == value ? 255 : 0;
break;
case CMP_NE:
for( i = 0; i < total; i++ )
dst[i] = src1[i] != value ? 255 : 0;
break;
case CMP_GE:
for( i = 0; i < total; i++ )
dst[i] = src1[i] >= value ? 255 : 0;
break;
case CMP_GT:
for( i = 0; i < total; i++ )
dst[i] = src1[i] > value ? 255 : 0;
break;
default:
CV_Error(CV_StsBadArg, "Unknown comparison operation");
}
}
void compare(const Mat& src1, const Mat& src2, Mat& dst, int cmpop)
{
CV_Assert( src1.type() == src2.type() && src1.channels() == 1 && src1.size == src2.size );
dst.create( src1.dims, &src1.size[0], CV_8U );
const Mat *arrays[]={&src1, &src2, &dst, 0};
Mat planes[3];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total();
int i, nplanes = it.nplanes, depth = src1.depth();
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr1 = planes[0].data;
const uchar* sptr2 = planes[1].data;
uchar* dptr = planes[2].data;
switch( depth )
{
case CV_8U:
compare_((const uchar*)sptr1, (const uchar*)sptr2, dptr, total, cmpop);
break;
case CV_8S:
compare_((const schar*)sptr1, (const schar*)sptr2, dptr, total, cmpop);
break;
case CV_16U:
compare_((const ushort*)sptr1, (const ushort*)sptr2, dptr, total, cmpop);
break;
case CV_16S:
compare_((const short*)sptr1, (const short*)sptr2, dptr, total, cmpop);
break;
case CV_32S:
compare_((const int*)sptr1, (const int*)sptr2, dptr, total, cmpop);
break;
case CV_32F:
compare_((const float*)sptr1, (const float*)sptr2, dptr, total, cmpop);
break;
case CV_64F:
compare_((const double*)sptr1, (const double*)sptr2, dptr, total, cmpop);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
}
}
}
void compare(const Mat& src, double value, Mat& dst, int cmpop)
{
CV_Assert( src.channels() == 1 );
dst.create( src.dims, &src.size[0], CV_8U );
const Mat *arrays[]={&src, &dst, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total();
int i, nplanes = it.nplanes, depth = src.depth();
int ivalue = saturate_cast<int>(value);
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr = planes[0].data;
uchar* dptr = planes[1].data;
switch( depth )
{
case CV_8U:
compareS_((const uchar*)sptr, ivalue, dptr, total, cmpop);
break;
case CV_8S:
compareS_((const schar*)sptr, ivalue, dptr, total, cmpop);
break;
case CV_16U:
compareS_((const ushort*)sptr, ivalue, dptr, total, cmpop);
break;
case CV_16S:
compareS_((const short*)sptr, ivalue, dptr, total, cmpop);
break;
case CV_32S:
compareS_((const int*)sptr, ivalue, dptr, total, cmpop);
break;
case CV_32F:
compareS_((const float*)sptr, value, dptr, total, cmpop);
break;
case CV_64F:
compareS_((const double*)sptr, value, dptr, total, cmpop);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
}
}
}
template<typename _Tp> static double
cmpUlpsInt_(const _Tp* src1, const _Tp* src2, size_t total, int imaxdiff,
size_t startidx, size_t& idx)
{
size_t i;
int realmaxdiff = 0;
for( i = 0; i < total; i++ )
{
int diff = std::abs(src1[i] - src2[i]);
if( realmaxdiff < diff )
{
realmaxdiff = diff;
if( diff > imaxdiff && idx == 0 )
idx = i + startidx;
}
}
return realmaxdiff;
}
template<> static double cmpUlpsInt_<int>(const int* src1, const int* src2,
size_t total, int imaxdiff,
size_t startidx, size_t& idx)
{
size_t i;
double realmaxdiff = 0;
for( i = 0; i < total; i++ )
{
double diff = fabs((double)src1[i] - (double)src2[i]);
if( realmaxdiff < diff )
{
realmaxdiff = diff;
if( diff > imaxdiff && idx == 0 )
idx = i + startidx;
}
}
return realmaxdiff;
}
template<typename _Tp> static double
cmpUlpsFlt_(const _Tp* src1, const _Tp* src2, size_t total, int imaxdiff, size_t startidx, size_t& idx)
{
const _Tp C = ((_Tp)1 << (sizeof(_Tp)*8-1)) - 1;
_Tp realmaxdiff = 0;
size_t i;
for( i = 0; i < total; i++ )
{
_Tp a = src1[i], b = src2[i];
if( a < 0 ) a ^= C; if( b < 0 ) b ^= C;
_Tp diff = std::abs(a - b);
if( realmaxdiff < diff )
{
realmaxdiff = diff;
if( diff > imaxdiff && idx == 0 )
idx = i + startidx;
}
}
return realmaxdiff;
}
bool cmpUlps(const Mat& src1, const Mat& src2, int imaxDiff, double* _realmaxdiff, vector<int>* loc)
{
CV_Assert( src1.type() == src2.type() && src1.size == src2.size );
const Mat *arrays[]={&src1, &src2, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total()*planes[0].channels();
int i, nplanes = it.nplanes, depth = src1.depth();
size_t startidx = 1, idx = 0;
if(_realmaxdiff)
*_realmaxdiff = 0;
for( i = 0; i < nplanes; i++, ++it, startidx += total )
{
const uchar* sptr1 = planes[0].data;
const uchar* sptr2 = planes[1].data;
double realmaxdiff = 0;
switch( depth )
{
case CV_8U:
realmaxdiff = cmpUlpsInt_((const uchar*)sptr1, (const uchar*)sptr2, total, imaxDiff, startidx, idx);
break;
case CV_8S:
realmaxdiff = cmpUlpsInt_((const schar*)sptr1, (const schar*)sptr2, total, imaxDiff, startidx, idx);
break;
case CV_16U:
realmaxdiff = cmpUlpsInt_((const ushort*)sptr1, (const ushort*)sptr2, total, imaxDiff, startidx, idx);
break;
case CV_16S:
realmaxdiff = cmpUlpsInt_((const short*)sptr1, (const short*)sptr2, total, imaxDiff, startidx, idx);
break;
case CV_32S:
realmaxdiff = cmpUlpsInt_((const int*)sptr1, (const int*)sptr2, total, imaxDiff, startidx, idx);
break;
case CV_32F:
realmaxdiff = cmpUlpsFlt_((const int*)sptr1, (const int*)sptr2, total, imaxDiff, startidx, idx);
break;
case CV_64F:
realmaxdiff = cmpUlpsFlt_((const int64*)sptr1, (const int64*)sptr2, total, imaxDiff, startidx, idx);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
}
if(_realmaxdiff)
*_realmaxdiff = std::max(*_realmaxdiff, realmaxdiff);
}
if(idx > 0 && loc)
setpos(src1, *loc, idx);
return idx == 0;
}
template<typename _Tp> static void
checkInt_(const _Tp* a, size_t total, int imin, int imax, size_t startidx, size_t& idx)
{
for( size_t i = 0; i < total; i++ )
{
int val = a[i];
if( val < imin || val > imax )
{
idx = i + startidx;
break;
}
}
}
template<typename _Tp> static void
checkFlt_(const _Tp* a, size_t total, double fmin, double fmax, size_t startidx, size_t& idx)
{
for( size_t i = 0; i < total; i++ )
{
double val = a[i];
if( cvIsNaN(val) || cvIsInf(val) || val < fmin || val > fmax )
{
idx = i + startidx;
break;
}
}
}
// checks that the array does not have NaNs and/or Infs and all the elements are
// within [min_val,max_val). idx is the index of the first "bad" element.
int check( const Mat& a, double fmin, double fmax, vector<int>* _idx )
{
const Mat *arrays[]={&a, 0};
Mat plane;
NAryMatIterator it(arrays, &plane);
size_t total = plane.total()*plane.channels();
int i, nplanes = it.nplanes, depth = a.depth();
size_t startidx = 1, idx = 0;
int imin = 0, imax = 0;
if( depth <= CV_32S )
{
imin = cvCeil(fmin);
imax = cvFloor(fmax);
}
for( i = 0; i < nplanes; i++, ++it, startidx += total )
{
const uchar* aptr = plane.data;
switch( depth )
{
case CV_8U:
checkInt_((const uchar*)aptr, total, imin, imax, startidx, idx);
break;
case CV_8S:
checkInt_((const schar*)aptr, total, imin, imax, startidx, idx);
break;
case CV_16U:
checkInt_((const ushort*)aptr, total, imin, imax, startidx, idx);
break;
case CV_16S:
checkInt_((const short*)aptr, total, imin, imax, startidx, idx);
break;
case CV_32S:
checkInt_((const int*)aptr, total, imin, imax, startidx, idx);
break;
case CV_32F:
checkFlt_((const float*)aptr, total, fmin, fmax, startidx, idx);
break;
case CV_64F:
checkFlt_((const double*)aptr, total, fmin, fmax, startidx, idx);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
}
if( idx != 0 )
break;
}
if(idx != 0 && _idx)
setpos(a, *_idx, idx);
return idx == 0 ? 0 : -1;
}
// compares two arrays. max_diff is the maximum actual difference,
// success_err_level is maximum allowed difference, idx is the index of the first
// element for which difference is >success_err_level
// (or index of element with the maximum difference)
int cmpEps( const Mat& arr, const Mat& refarr, double* _realmaxdiff,
double success_err_level, vector<int>* _idx,
bool element_wise_relative_error )
{
CV_Assert( arr.type() == refarr.type() && arr.size == refarr.size );
int ilevel = refarr.depth() <= CV_32S ? cvFloor(success_err_level) : 0;
int result = 0;
const Mat *arrays[]={&arr, &refarr, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total()*planes[0].channels(), j = total;
int i, nplanes = it.nplanes, depth = arr.depth();
size_t startidx = 1, idx = 0;
double realmaxdiff = 0, maxval = 0;
if(_realmaxdiff)
*_realmaxdiff = 0;
if( refarr.depth() >= CV_32F && !element_wise_relative_error )
{
maxval = cvtest::norm( refarr, NORM_INF );
maxval = MAX(maxval, 1.);
}
for( i = 0; i < nplanes; i++, ++it, startidx += total )
{
const uchar* sptr1 = planes[0].data;
const uchar* sptr2 = planes[1].data;
switch( depth )
{
case CV_8U:
realmaxdiff = cmpUlpsInt_((const uchar*)sptr1, (const uchar*)sptr2, total, ilevel, startidx, idx);
break;
case CV_8S:
realmaxdiff = cmpUlpsInt_((const schar*)sptr1, (const schar*)sptr2, total, ilevel, startidx, idx);
break;
case CV_16U:
realmaxdiff = cmpUlpsInt_((const ushort*)sptr1, (const ushort*)sptr2, total, ilevel, startidx, idx);
break;
case CV_16S:
realmaxdiff = cmpUlpsInt_((const short*)sptr1, (const short*)sptr2, total, ilevel, startidx, idx);
break;
case CV_32S:
realmaxdiff = cmpUlpsInt_((const int*)sptr1, (const int*)sptr2, total, ilevel, startidx, idx);
break;
case CV_32F:
for( j = 0; j < total; j++ )
{
double a_val = ((float*)sptr1)[j];
double b_val = ((float*)sptr2)[j];
double threshold;
if( ((int*)sptr1)[j] == ((int*)sptr2)[j] )
continue;
if( cvIsNaN(a_val) || cvIsInf(a_val) )
{
result = -2;
idx = startidx + j;
break;
}
if( cvIsNaN(b_val) || cvIsInf(b_val) )
{
result = -3;
idx = startidx + j;
break;
}
a_val = fabs(a_val - b_val);
threshold = element_wise_relative_error ? fabs(b_val) + 1 : maxval;
if( a_val > threshold*success_err_level )
{
realmaxdiff = a_val/threshold;
if( idx == 0 )
idx = startidx + j;
break;
}
}
break;
case CV_64F:
for( j = 0; j < total; j++ )
{
double a_val = ((double*)sptr1)[j];
double b_val = ((double*)sptr2)[j];
double threshold;
if( ((int64*)sptr1)[j] == ((int64*)sptr2)[j] )
continue;
if( cvIsNaN(a_val) || cvIsInf(a_val) )
{
result = -2;
idx = startidx + j;
break;
}
if( cvIsNaN(b_val) || cvIsInf(b_val) )
{
result = -3;
idx = startidx + j;
break;
}
a_val = fabs(a_val - b_val);
threshold = element_wise_relative_error ? fabs(b_val) + 1 : maxval;
if( a_val > threshold*success_err_level )
{
realmaxdiff = a_val/threshold;
idx = startidx + j;
break;
}
}
break;
default:
assert(0);
return -1;
}
if(_realmaxdiff)
*_realmaxdiff = MAX(*_realmaxdiff, realmaxdiff);
if( idx != 0 )
break;
}
if( result == 0 && idx != 0 )
result = -1;
if( result < -1 && _realmaxdiff )
*_realmaxdiff = exp(1000.);
if(idx > 0 && _idx)
setpos(arr, *_idx, idx);
return result;
}
int cmpEps2( TS* ts, const Mat& a, const Mat& b, double success_err_level,
bool element_wise_relative_error, const char* desc )
{
char msg[100];
double diff = 0;
vector<int> idx;
int code = cmpEps( a, b, &diff, success_err_level, &idx, element_wise_relative_error );
switch( code )
{
case -1:
sprintf( msg, "%s: Too big difference (=%g)", desc, diff );
code = TS::FAIL_BAD_ACCURACY;
break;
case -2:
sprintf( msg, "%s: Invalid output", desc );
code = TS::FAIL_INVALID_OUTPUT;
break;
case -3:
sprintf( msg, "%s: Invalid reference output", desc );
code = TS::FAIL_INVALID_OUTPUT;
break;
default:
;
}
if( code < 0 )
{
if( a.total() == 1 )
{
ts->printf( TS::LOG, "%s\n", msg );
}
else if( a.dims == 2 && (a.rows == 1 || a.cols == 1) )
{
ts->printf( TS::LOG, "%s at element %d\n", msg, idx[0] + idx[1] );
}
else
{
string idxstr = vec2str(", ", &idx[0], idx.size());
ts->printf( TS::LOG, "%s at (%s)\n", msg, idxstr.c_str() );
}
}
return code;
}
int cmpEps2_64f( TS* ts, const double* val, const double* refval, int len,
double eps, const char* param_name )
{
Mat _val(1, len, CV_64F, (void*)val);
Mat _refval(1, len, CV_64F, (void*)refval);
return cmpEps2( ts, _val, _refval, eps, true, param_name );
}
template<typename _Tp> static void
GEMM_(const _Tp* a_data0, int a_step, int a_delta,
const _Tp* b_data0, int b_step, int b_delta,
const _Tp* c_data0, int c_step, int c_delta,
_Tp* d_data, int d_step,
int d_rows, int d_cols, int a_cols, int cn,
double alpha, double beta)
{
for( int i = 0; i < d_rows; i++, d_data += d_step, c_data0 += c_step, a_data0 += a_step )
{
for( int j = 0; j < d_cols; j++ )
{
const _Tp* a_data = a_data0;
const _Tp* b_data = b_data0 + j*b_delta;
const _Tp* c_data = c_data0 + j*c_delta;
if( cn == 1 )
{
double s = 0;
for( int k = 0; k < a_cols; k++ )
{
s += ((double)a_data[0])*b_data[0];
a_data += a_delta;
b_data += b_step;
}
d_data[j] = (_Tp)(s*alpha + (c_data ? c_data[0]*beta : 0));
}
else
{
double s_re = 0, s_im = 0;
for( int k = 0; k < a_cols; k++ )
{
s_re += ((double)a_data[0])*b_data[0] - ((double)a_data[1])*b_data[1];
s_im += ((double)a_data[0])*b_data[1] + ((double)a_data[1])*b_data[0];
a_data += a_delta;
b_data += b_step;
}
s_re *= alpha;
s_im *= alpha;
if( c_data )
{
s_re += c_data[0]*beta;
s_im += c_data[1]*beta;
}
d_data[j*2] = (_Tp)s_re;
d_data[j*2+1] = (_Tp)s_im;
}
}
}
}
void gemm( const Mat& _a, const Mat& _b, double alpha,
const Mat& _c, double beta, Mat& d, int flags )
{
Mat a = _a, b = _b, c = _c;
if( a.data == d.data )
a = a.clone();
if( b.data == d.data )
b = b.clone();
if( !c.empty() && c.data == d.data && (flags & cv::GEMM_3_T) )
c = c.clone();
int a_rows = a.rows, a_cols = a.cols, b_rows = b.rows, b_cols = b.cols;
int cn = a.channels();
int a_step = (int)a.step1(), a_delta = cn;
int b_step = (int)b.step1(), b_delta = cn;
int c_rows = 0, c_cols = 0, c_step = 0, c_delta = 0;
CV_Assert( a.type() == b.type() && a.dims == 2 && b.dims == 2 && cn <= 2 );
if( flags & cv::GEMM_1_T )
{
std::swap( a_rows, a_cols );
std::swap( a_step, a_delta );
}
if( flags & cv::GEMM_2_T )
{
std::swap( b_rows, b_cols );
std::swap( b_step, b_delta );
}
if( !c.empty() )
{
c_rows = c.rows;
c_cols = c.cols;
c_step = (int)c.step1();
c_delta = cn;
if( flags & cv::GEMM_3_T )
{
std::swap( c_rows, c_cols );
std::swap( c_step, c_delta );
}
CV_Assert( c.dims == 2 && c.type() == a.type() && c_rows == a_rows && c_cols == b_cols );
}
d.create(a_rows, b_cols, a.type());
if( a.depth() == CV_32F )
GEMM_(a.ptr<float>(), a_step, a_delta, b.ptr<float>(), b_step, b_delta,
!c.empty() ? c.ptr<float>() : 0, c_step, c_delta, d.ptr<float>(),
d.step1(), a_rows, b_cols, a_cols, cn, alpha, beta );
else
GEMM_(a.ptr<double>(), a_step, a_delta, b.ptr<double>(), b_step, b_delta,
!c.empty() ? c.ptr<double>() : 0, c_step, c_delta, d.ptr<double>(),
d.step1(), a_rows, b_cols, a_cols, cn, alpha, beta );
}
double cvTsCrossCorr( const CvMat* a, const CvMat* b )
{
int i, j;
int cn, ncols;
double s = 0;
cn = CV_MAT_CN(a->type);
ncols = a->cols*cn;
assert( CV_ARE_SIZES_EQ( a, b ) && CV_ARE_TYPES_EQ( a, b ) );
for( i = 0; i < a->rows; i++ )
{
uchar* a_data = a->data.ptr + a->step*i;
uchar* b_data = b->data.ptr + b->step*i;
switch( CV_MAT_DEPTH(a->type) )
{
case CV_8U:
for( j = 0; j < ncols; j++ )
s += ((uchar*)a_data)[j]*((uchar*)b_data)[j];
break;
case CV_8S:
for( j = 0; j < ncols; j++ )
s += ((schar*)a_data)[j]*((schar*)b_data)[j];
break;
case CV_16U:
for( j = 0; j < ncols; j++ )
s += (double)((ushort*)a_data)[j]*((ushort*)b_data)[j];
break;
case CV_16S:
for( j = 0; j < ncols; j++ )
s += ((short*)a_data)[j]*((short*)b_data)[j];
break;
case CV_32S:
for( j = 0; j < ncols; j++ )
s += ((double)((int*)a_data)[j])*((int*)b_data)[j];
break;
case CV_32F:
for( j = 0; j < ncols; j++ )
s += ((double)((float*)a_data)[j])*((float*)b_data)[j];
break;
case CV_64F:
for( j = 0; j < ncols; j++ )
s += ((double*)a_data)[j]*((double*)b_data)[j];
break;
default:
assert(0);
return log(-1.);
}
}
return s;
}
template<typename _Tp> static void
transform_(const _Tp* sptr, _Tp* dptr, size_t total, int scn, int dcn, const double* mat)
{
for( size_t i = 0; i < total; i++, sptr += scn, dptr += dcn )
{
for( int j = 0; j < dcn; j++ )
{
double s = mat[j*(scn + 1) + scn];
for( int k = 0; k < scn; k++ )
s += mat[j*(scn + 1) + k]*sptr[k];
dptr[j] = saturate_cast<_Tp>(s);
}
}
}
void transform( const Mat& src, Mat& dst, const Mat& transmat, const Mat& _shift )
{
double mat[20];
int scn = src.channels();
int dcn = dst.channels();
int depth = src.depth();
int mattype = transmat.depth();
Mat shift = _shift.reshape(1, 0);
bool haveShift = !shift.empty();
CV_Assert( scn <= 4 && dcn <= 4 &&
(mattype == CV_32F || mattype == CV_64F) &&
(!haveShift || (shift.type() == mattype && (shift.rows == 1 || shift.cols == 1))) );
// prepare cn x (cn + 1) transform matrix
if( mattype == CV_32F )
{
for( int i = 0; i < transmat.rows; i++ )
{
mat[i*(scn+1)+scn] = 0.;
for( int j = 0; j < transmat.cols; j++ )
mat[i*(scn+1)+j] = transmat.at<float>(i,j);
if( haveShift )
mat[i*(scn+1)+scn] = shift.at<float>(i);
}
}
else
{
for( int i = 0; i < transmat.rows; i++ )
{
mat[i*(scn+1)+scn] = 0.;
for( int j = 0; j < transmat.cols; j++ )
mat[i*(scn+1)+j] = transmat.at<double>(i,j);
if( haveShift )
mat[i*(scn+1)+scn] = shift.at<double>(i);
}
}
const Mat *arrays[]={&src, &dst, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total();
int i, nplanes = it.nplanes;
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr = planes[0].data;
uchar* dptr = planes[1].data;
switch( depth )
{
case CV_8U:
transform_((const uchar*)sptr, (uchar*)dptr, total, scn, dcn, mat);
break;
case CV_8S:
transform_((const schar*)sptr, (schar*)dptr, total, scn, dcn, mat);
break;
case CV_16U:
transform_((const ushort*)sptr, (ushort*)dptr, total, scn, dcn, mat);
break;
case CV_16S:
transform_((const short*)sptr, (short*)dptr, total, scn, dcn, mat);
break;
case CV_32S:
transform_((const int*)sptr, (int*)dptr, total, scn, dcn, mat);
break;
case CV_32F:
transform_((const float*)sptr, (float*)dptr, total, scn, dcn, mat);
break;
case CV_64F:
transform_((const double*)sptr, (double*)dptr, total, scn, dcn, mat);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
}
}
}
template<typename _Tp> static void
minmax_(const _Tp* src1, const _Tp* src2, _Tp* dst, size_t total, char op)
{
if( op == 'M' )
for( size_t i = 0; i < total; i++ )
dst[i] = std::max(src1[i], src2[i]);
else
for( size_t i = 0; i < total; i++ )
dst[i] = std::min(src1[i], src2[i]);
}
static void minmax(const Mat& src1, const Mat& src2, Mat& dst, char op)
{
dst.create(src1.dims, src1.size, src1.type());
CV_Assert( src1.type() == src2.type() && src1.size == src2.size );
const Mat *arrays[]={&src1, &src2, &dst, 0};
Mat planes[3];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total()*planes[0].channels();
int i, nplanes = it.nplanes, depth = src1.depth();
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr1 = planes[0].data;
const uchar* sptr2 = planes[1].data;
uchar* dptr = planes[2].data;
switch( depth )
{
case CV_8U:
minmax_((const uchar*)sptr1, (const uchar*)sptr2, (uchar*)dptr, total, op);
break;
case CV_8S:
minmax_((const schar*)sptr1, (const schar*)sptr2, (schar*)dptr, total, op);
break;
case CV_16U:
minmax_((const ushort*)sptr1, (const ushort*)sptr2, (ushort*)dptr, total, op);
break;
case CV_16S:
minmax_((const short*)sptr1, (const short*)sptr2, (short*)dptr, total, op);
break;
case CV_32S:
minmax_((const int*)sptr1, (const int*)sptr2, (int*)dptr, total, op);
break;
case CV_32F:
minmax_((const float*)sptr1, (const float*)sptr2, (float*)dptr, total, op);
break;
case CV_64F:
minmax_((const double*)sptr1, (const double*)sptr2, (double*)dptr, total, op);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
}
}
}
void min(const Mat& src1, const Mat& src2, Mat& dst)
{
minmax( src1, src2, dst, 'm' );
}
void max(const Mat& src1, const Mat& src2, Mat& dst)
{
minmax( src1, src2, dst, 'M' );
}
template<typename _Tp> static void
minmax_(const _Tp* src1, _Tp val, _Tp* dst, size_t total, char op)
{
if( op == 'M' )
for( size_t i = 0; i < total; i++ )
dst[i] = std::max(src1[i], val);
else
for( size_t i = 0; i < total; i++ )
dst[i] = std::min(src1[i], val);
}
static void minmax(const Mat& src1, double val, Mat& dst, char op)
{
dst.create(src1.dims, src1.size, src1.type());
const Mat *arrays[]={&src1, &dst, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total()*planes[0].channels();
int i, nplanes = it.nplanes, depth = src1.depth();
int ival = saturate_cast<int>(val);
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr1 = planes[0].data;
uchar* dptr = planes[1].data;
switch( depth )
{
case CV_8U:
minmax_((const uchar*)sptr1, saturate_cast<uchar>(ival), (uchar*)dptr, total, op);
break;
case CV_8S:
minmax_((const schar*)sptr1, saturate_cast<schar>(ival), (schar*)dptr, total, op);
break;
case CV_16U:
minmax_((const ushort*)sptr1, saturate_cast<ushort>(ival), (ushort*)dptr, total, op);
break;
case CV_16S:
minmax_((const short*)sptr1, saturate_cast<short>(ival), (short*)dptr, total, op);
break;
case CV_32S:
minmax_((const int*)sptr1, saturate_cast<int>(ival), (int*)dptr, total, op);
break;
case CV_32F:
minmax_((const float*)sptr1, saturate_cast<float>(val), (float*)dptr, total, op);
break;
case CV_64F:
minmax_((const double*)sptr1, saturate_cast<double>(val), (double*)dptr, total, op);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
}
}
}
void min(const Mat& src1, double val, Mat& dst)
{
minmax( src1, val, dst, 'm' );
}
void max(const Mat& src1, double val, Mat& dst)
{
minmax( src1, val, dst, 'M' );
}
template<typename _Tp> static void
muldiv_(const _Tp* src1, const _Tp* src2, _Tp* dst, size_t total, double scale, char op)
{
if( op == '*' )
for( size_t i = 0; i < total; i++ )
dst[i] = saturate_cast<_Tp>((scale*src1[i])*src2[i]);
else if( src1 )
for( size_t i = 0; i < total; i++ )
dst[i] = src2[i] ? saturate_cast<_Tp>((scale*src1[i])/src2[i]) : 0;
else
for( size_t i = 0; i < total; i++ )
dst[i] = src2[i] ? saturate_cast<_Tp>(scale/src2[i]) : 0;
}
static void muldiv(const Mat& src1, const Mat& src2, Mat& dst, double scale, char op)
{
dst.create(src2.dims, src2.size, src2.type());
CV_Assert( src1.empty() || (src1.type() == src2.type() && src1.size == src2.size) );
const Mat *arrays[]={&src1, &src2, &dst, 0};
Mat planes[3];
NAryMatIterator it(arrays, planes);
size_t total = planes[1].total()*planes[1].channels();
int i, nplanes = it.nplanes, depth = src2.depth();
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr1 = planes[0].data;
const uchar* sptr2 = planes[1].data;
uchar* dptr = planes[2].data;
switch( depth )
{
case CV_8U:
muldiv_((const uchar*)sptr1, (const uchar*)sptr2, (uchar*)dptr, total, scale, op);
break;
case CV_8S:
muldiv_((const schar*)sptr1, (const schar*)sptr2, (schar*)dptr, total, scale, op);
break;
case CV_16U:
muldiv_((const ushort*)sptr1, (const ushort*)sptr2, (ushort*)dptr, total, scale, op);
break;
case CV_16S:
muldiv_((const short*)sptr1, (const short*)sptr2, (short*)dptr, total, scale, op);
break;
case CV_32S:
muldiv_((const int*)sptr1, (const int*)sptr2, (int*)dptr, total, scale, op);
break;
case CV_32F:
muldiv_((const float*)sptr1, (const float*)sptr2, (float*)dptr, total, scale, op);
break;
case CV_64F:
muldiv_((const double*)sptr1, (const double*)sptr2, (double*)dptr, total, scale, op);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
}
}
}
void multiply(const Mat& src1, const Mat& src2, Mat& dst, double scale)
{
muldiv( src1, src2, dst, scale, '*' );
}
void divide(const Mat& src1, const Mat& src2, Mat& dst, double scale)
{
muldiv( src1, src2, dst, scale, '/' );
}
template<typename _Tp> static void
mean_(const _Tp* src, const uchar* mask, size_t total, int cn, Scalar& sum, int& nz)
{
if( !mask )
{
nz += (int)total;
total *= cn;
for( size_t i = 0; i < total; i += cn )
{
for( int c = 0; c < cn; c++ )
sum[c] += src[i + c];
}
}
else
{
for( size_t i = 0; i < total; i++ )
if( mask[i] )
{
nz++;
for( int c = 0; c < cn; c++ )
sum[c] += src[i*cn + c];
}
}
}
Scalar mean(const Mat& src, const Mat& mask)
{
CV_Assert(mask.empty() || (mask.type() == CV_8U && mask.size == src.size));
Scalar sum;
int nz = 0;
const Mat *arrays[]={&src, &mask, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
size_t total = planes[0].total();
int i, nplanes = it.nplanes, depth = src.depth(), cn = src.channels();
for( i = 0; i < nplanes; i++, ++it )
{
const uchar* sptr = planes[0].data;
const uchar* mptr = planes[1].data;
switch( depth )
{
case CV_8U:
mean_((const uchar*)sptr, mptr, total, cn, sum, nz);
break;
case CV_8S:
mean_((const schar*)sptr, mptr, total, cn, sum, nz);
break;
case CV_16U:
mean_((const ushort*)sptr, mptr, total, cn, sum, nz);
break;
case CV_16S:
mean_((const short*)sptr, mptr, total, cn, sum, nz);
break;
case CV_32S:
mean_((const int*)sptr, mptr, total, cn, sum, nz);
break;
case CV_32F:
mean_((const float*)sptr, mptr, total, cn, sum, nz);
break;
case CV_64F:
mean_((const double*)sptr, mptr, total, cn, sum, nz);
break;
default:
CV_Error(CV_StsUnsupportedFormat, "");
}
}
return sum * (1./std::max(nz, 1));
}
void patchZeros( Mat& mat, double level )
{
int j, ncols = mat.cols * mat.channels();
int depth = mat.depth();
CV_Assert( depth == CV_32F || depth == CV_64F );
for( int i = 0; i < mat.rows; i++ )
{
if( depth == CV_32F )
{
float* data = mat.ptr<float>(i);
for( j = 0; j < ncols; j++ )
if( fabs(data[j]) < level )
data[j] += 1;
}
else
{
double* data = mat.ptr<double>(i);
for( j = 0; j < ncols; j++ )
if( fabs(data[j]) < level )
data[j] += 1;
}
}
}
static void calcSobelKernel1D( int order, int _aperture_size, int size, vector<int>& kernel )
{
int i, j, oldval, newval;
kernel.resize(size + 1);
if( _aperture_size < 0 )
{
static const int scharr[] = { 3, 10, 3, -1, 0, 1 };
assert( size == 3 );
for( i = 0; i < size; i++ )
kernel[i] = scharr[order*3 + i];
return;
}
for( i = 1; i <= size; i++ )
kernel[i] = 0;
kernel[0] = 1;
for( i = 0; i < size - order - 1; i++ )
{
oldval = kernel[0];
for( j = 1; j <= size; j++ )
{
newval = kernel[j] + kernel[j-1];
kernel[j-1] = oldval;
oldval = newval;
}
}
for( i = 0; i < order; i++ )
{
oldval = -kernel[0];
for( j = 1; j <= size; j++ )
{
newval = kernel[j-1] - kernel[j];
kernel[j-1] = oldval;
oldval = newval;
}
}
}
Mat calcSobelKernel2D( int dx, int dy, int _aperture_size, int origin )
{
CV_Assert( (_aperture_size == -1 || (_aperture_size >= 1 && _aperture_size % 2 == 1)) &&
dx >= 0 && dy >= 0 && dx + dy <= 3 );
Size ksize = _aperture_size == -1 ? Size(3,3) : _aperture_size > 1 ?
Size(_aperture_size, _aperture_size) : dx > 0 ? Size(3, 1) : Size(1, 3);
Mat kernel(ksize, CV_32F);
vector<int> kx, ky;
calcSobelKernel1D( dx, _aperture_size, ksize.width, kx );
calcSobelKernel1D( dy, _aperture_size, ksize.height, ky );
for( int i = 0; i < kernel.rows; i++ )
{
float ay = (float)ky[i]*(origin && (dy & 1) ? -1 : 1);
for( int j = 0; j < kernel.cols; j++ )
kernel.at<float>(i, j) = kx[j]*ay;
}
return kernel;
}
Mat calcLaplaceKernel2D( int aperture_size )
{
int ksize = aperture_size == 1 ? 3 : aperture_size;
Mat kernel(ksize, ksize, CV_32F);
vector<int> kx, ky;
calcSobelKernel1D( 2, aperture_size, ksize, kx );
if( aperture_size > 1 )
calcSobelKernel1D( 0, aperture_size, ksize, ky );
else
{
ky.resize(3);
ky[0] = ky[2] = 0; ky[1] = 1;
}
for( int i = 0; i < ksize; i++ )
for( int j = 0; j < ksize; j++ )
kernel.at<float>(i, j) = kx[j]*ky[i] + kx[i]*ky[j];
return kernel;
}
void initUndistortMap( const Mat& _a0, const Mat& _k0, Size sz, Mat& _mapx, Mat& _mapy )
{
_mapx.create(sz, CV_32F);
_mapy.create(sz, CV_32F);
double a[9], k[5]={0,0,0,0,0};
Mat _a(3, 3, CV_64F, a);
Mat _k(_k0.rows,_k0.cols, CV_MAKETYPE(CV_64F,_k0.channels()),k);
double fx, fy, cx, cy, ifx, ify, cxn, cyn;
_a0.convertTo(_a, CV_64F);
_k0.convertTo(_k, CV_64F);
fx = a[0]; fy = a[4]; cx = a[2]; cy = a[5];
ifx = 1./fx; ify = 1./fy;
cxn = cx;
cyn = cy;
for( int v = 0; v < sz.height; v++ )
{
for( int u = 0; u < sz.width; u++ )
{
double x = (u - cxn)*ifx;
double y = (v - cyn)*ify;
double x2 = x*x, y2 = y*y;
double r2 = x2 + y2;
double cdist = 1 + (k[0] + (k[1] + k[4]*r2)*r2)*r2;
double x1 = x*cdist + k[2]*2*x*y + k[3]*(r2 + 2*x2);
double y1 = y*cdist + k[3]*2*x*y + k[2]*(r2 + 2*y2);
_mapy.at<float>(v, u) = (float)(y1*fy + cy);
_mapx.at<float>(v, u) = (float)(x1*fx + cx);
}
}
}
std::ostream& operator << (std::ostream& out, const MatInfo& m)
{
if( !m.m || m.m->empty() )
out << "<Empty>";
else
{
static const char* depthstr[] = {"8u", "8s", "16u", "16s", "32s", "32f", "64f", "?"};
out << depthstr[m.m->depth()] << "C" << m.m->channels() << " " << m.m->dims << "-dim (";
for( int i = 0; i < m.m->dims; i++ )
out << m.m->size[i] << (i < m.m->dims-1 ? " x " : ")");
}
return out;
}
static Mat getSubArray(const Mat& m, int border, vector<int>& ofs0, vector<int>& ofs)
{
ofs.resize(ofs0.size());
if( border < 0 )
{
std::copy(ofs0.begin(), ofs0.end(), ofs.begin());
return m;
}
int i, d = m.dims;
CV_Assert(d == (int)ofs.size());
vector<Range> r(d);
for( i = 0; i < d; i++ )
{
r[i].start = std::max(0, ofs0[i] - border);
r[i].end = std::min(ofs0[i] + 1 + border, m.size[i]);
ofs[i] = std::min(ofs0[i], border);
}
return m(&r[0]);
}
template<typename _Tp, typename _WTp> static void
writeElems(std::ostream& out, const void* data, int nelems, int starpos)
{
for(int i = 0; i < nelems; i++)
{
if( i == starpos )
out << "*";
out << (_WTp)((_Tp*)data)[i];
if( i == starpos )
out << "*";
out << (i+1 < nelems ? ", " : "");
}
}
static void writeElems(std::ostream& out, const void* data, int nelems, int depth, int starpos)
{
if(depth == CV_8U)
writeElems<uchar, int>(out, data, nelems, starpos);
else if(depth == CV_8S)
writeElems<schar, int>(out, data, nelems, starpos);
else if(depth == CV_16U)
writeElems<ushort, int>(out, data, nelems, starpos);
else if(depth == CV_16S)
writeElems<short, int>(out, data, nelems, starpos);
else if(depth == CV_32S)
writeElems<int, int>(out, data, nelems, starpos);
else if(depth == CV_32F)
{
std::streamsize pp = out.precision();
out.precision(8);
writeElems<float, float>(out, data, nelems, starpos);
out.precision(pp);
}
else if(depth == CV_64F)
{
std::streamsize pp = out.precision();
out.precision(16);
writeElems<double, double>(out, data, nelems, starpos);
out.precision(pp);
}
else
CV_Error(CV_StsUnsupportedFormat, "");
}
struct MatPart
{
MatPart(const Mat& _m, const vector<int>* _loc)
: m(&_m), loc(_loc) {}
const Mat* m;
const vector<int>* loc;
};
static std::ostream& operator << (std::ostream& out, const MatPart& m)
{
CV_Assert( !m.loc || ((int)m.loc->size() == m.m->dims && m.m->dims <= 2) );
if( !m.loc )
out << *m.m;
else
{
int i, depth = m.m->depth(), cn = m.m->channels(), width = m.m->cols*cn;
for( i = 0; i < m.m->rows; i++ )
{
writeElems(out, m.m->ptr(i), width, depth, i == (*m.loc)[0] ? (*m.loc)[1] : -1);
out << (i < m.m->rows-1 ? ";\n" : "");
}
}
return out;
}
MatComparator::MatComparator(double _maxdiff, int _context)
: maxdiff(_maxdiff), context(_context) {}
::testing::AssertionResult
MatComparator::operator()(const char* expr1, const char* expr2,
const Mat& m1, const Mat& m2)
{
if( m1.type() != m2.type() || m1.size != m2.size )
return ::testing::AssertionFailure()
<< "The reference and the actual output arrays have different type or size:\n"
<< expr1 << " ~ " << MatInfo(m1) << "\n"
<< expr2 << " ~ " << MatInfo(m2) << "\n";
//bool ok = cvtest::cmpUlps(m1, m2, maxdiff, &realmaxdiff, &loc0);
int code = cmpEps( m1, m2, &realmaxdiff, maxdiff, &loc0, true);
if(code >= 0)
return ::testing::AssertionSuccess();
Mat m[] = {m1.reshape(1,0), m2.reshape(1,0)};
int dims = m[0].dims;
vector<int> loc;
int border = dims <= 2 ? context : 0;
Mat m1part, m2part;
if( border == 0 )
{
loc = loc0;
m1part = Mat(1, 1, m[0].depth(), m[0].ptr(&loc[0]));
m2part = Mat(1, 1, m[1].depth(), m[1].ptr(&loc[0]));
}
else
{
m1part = getSubArray(m[0], border, loc0, loc);
m2part = getSubArray(m[1], border, loc0, loc);
}
return ::testing::AssertionFailure()
<< "too big relative difference (" << realmaxdiff << " > "
<< maxdiff << ") between "
<< MatInfo(m1) << " '" << expr1 << "' and '" << expr2 << "' at " << Mat(loc0) << ".\n\n"
<< "'" << expr1 << "': " << MatPart(m1part, border > 0 ? &loc : 0) << ".\n\n"
<< "'" << expr2 << "': " << MatPart(m2part, border > 0 ? &loc : 0) << ".\n";
}
}
void cvTsConvert( const CvMat* src, CvMat* dst )
{
Mat _src = cvarrToMat(src), _dst = cvarrToMat(dst);
cvtest::convert(_src, _dst, _dst.depth());
}
void cvTsZero( CvMat* dst, const CvMat* mask )
{
Mat _dst = cvarrToMat(dst), _mask = mask ? cvarrToMat(mask) : Mat();
cvtest::set(_dst, Scalar::all(0), _mask);
}
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment