mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1944 lines
60 KiB
1944 lines
60 KiB
// This file is part of OpenCV project. |
|
// It is subject to the license terms in the LICENSE file found in the top-level directory |
|
// of this distribution and at http://opencv.org/license.html. |
|
#include "test_precomp.hpp" |
|
|
|
namespace opencv_test { namespace { |
|
|
|
class Core_ReduceTest : public cvtest::BaseTest |
|
{ |
|
public: |
|
Core_ReduceTest() {} |
|
protected: |
|
void run( int); |
|
int checkOp( const Mat& src, int dstType, int opType, const Mat& opRes, int dim ); |
|
int checkCase( int srcType, int dstType, int dim, Size sz ); |
|
int checkDim( int dim, Size sz ); |
|
int checkSize( Size sz ); |
|
}; |
|
|
|
template<class Type> |
|
void testReduce( const Mat& src, Mat& sum, Mat& avg, Mat& max, Mat& min, int dim ) |
|
{ |
|
assert( src.channels() == 1 ); |
|
if( dim == 0 ) // row |
|
{ |
|
sum.create( 1, src.cols, CV_64FC1 ); |
|
max.create( 1, src.cols, CV_64FC1 ); |
|
min.create( 1, src.cols, CV_64FC1 ); |
|
} |
|
else |
|
{ |
|
sum.create( src.rows, 1, CV_64FC1 ); |
|
max.create( src.rows, 1, CV_64FC1 ); |
|
min.create( src.rows, 1, CV_64FC1 ); |
|
} |
|
sum.setTo(Scalar(0)); |
|
max.setTo(Scalar(-DBL_MAX)); |
|
min.setTo(Scalar(DBL_MAX)); |
|
|
|
const Mat_<Type>& src_ = src; |
|
Mat_<double>& sum_ = (Mat_<double>&)sum; |
|
Mat_<double>& min_ = (Mat_<double>&)min; |
|
Mat_<double>& max_ = (Mat_<double>&)max; |
|
|
|
if( dim == 0 ) |
|
{ |
|
for( int ri = 0; ri < src.rows; ri++ ) |
|
{ |
|
for( int ci = 0; ci < src.cols; ci++ ) |
|
{ |
|
sum_(0, ci) += src_(ri, ci); |
|
max_(0, ci) = std::max( max_(0, ci), (double)src_(ri, ci) ); |
|
min_(0, ci) = std::min( min_(0, ci), (double)src_(ri, ci) ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
for( int ci = 0; ci < src.cols; ci++ ) |
|
{ |
|
for( int ri = 0; ri < src.rows; ri++ ) |
|
{ |
|
sum_(ri, 0) += src_(ri, ci); |
|
max_(ri, 0) = std::max( max_(ri, 0), (double)src_(ri, ci) ); |
|
min_(ri, 0) = std::min( min_(ri, 0), (double)src_(ri, ci) ); |
|
} |
|
} |
|
} |
|
sum.convertTo( avg, CV_64FC1 ); |
|
avg = avg * (1.0 / (dim==0 ? (double)src.rows : (double)src.cols)); |
|
} |
|
|
|
void getMatTypeStr( int type, string& str) |
|
{ |
|
str = type == CV_8UC1 ? "CV_8UC1" : |
|
type == CV_8SC1 ? "CV_8SC1" : |
|
type == CV_16UC1 ? "CV_16UC1" : |
|
type == CV_16SC1 ? "CV_16SC1" : |
|
type == CV_32SC1 ? "CV_32SC1" : |
|
type == CV_32FC1 ? "CV_32FC1" : |
|
type == CV_64FC1 ? "CV_64FC1" : "unsupported matrix type"; |
|
} |
|
|
|
int Core_ReduceTest::checkOp( const Mat& src, int dstType, int opType, const Mat& opRes, int dim ) |
|
{ |
|
int srcType = src.type(); |
|
bool support = false; |
|
if( opType == CV_REDUCE_SUM || opType == CV_REDUCE_AVG ) |
|
{ |
|
if( srcType == CV_8U && (dstType == CV_32S || dstType == CV_32F || dstType == CV_64F) ) |
|
support = true; |
|
if( srcType == CV_16U && (dstType == CV_32F || dstType == CV_64F) ) |
|
support = true; |
|
if( srcType == CV_16S && (dstType == CV_32F || dstType == CV_64F) ) |
|
support = true; |
|
if( srcType == CV_32F && (dstType == CV_32F || dstType == CV_64F) ) |
|
support = true; |
|
if( srcType == CV_64F && dstType == CV_64F) |
|
support = true; |
|
} |
|
else if( opType == CV_REDUCE_MAX ) |
|
{ |
|
if( srcType == CV_8U && dstType == CV_8U ) |
|
support = true; |
|
if( srcType == CV_32F && dstType == CV_32F ) |
|
support = true; |
|
if( srcType == CV_64F && dstType == CV_64F ) |
|
support = true; |
|
} |
|
else if( opType == CV_REDUCE_MIN ) |
|
{ |
|
if( srcType == CV_8U && dstType == CV_8U) |
|
support = true; |
|
if( srcType == CV_32F && dstType == CV_32F) |
|
support = true; |
|
if( srcType == CV_64F && dstType == CV_64F) |
|
support = true; |
|
} |
|
if( !support ) |
|
return cvtest::TS::OK; |
|
|
|
double eps = 0.0; |
|
if ( opType == CV_REDUCE_SUM || opType == CV_REDUCE_AVG ) |
|
{ |
|
if ( dstType == CV_32F ) |
|
eps = 1.e-5; |
|
else if( dstType == CV_64F ) |
|
eps = 1.e-8; |
|
else if ( dstType == CV_32S ) |
|
eps = 0.6; |
|
} |
|
|
|
assert( opRes.type() == CV_64FC1 ); |
|
Mat _dst, dst, diff; |
|
cv::reduce( src, _dst, dim, opType, dstType ); |
|
_dst.convertTo( dst, CV_64FC1 ); |
|
|
|
absdiff( opRes,dst,diff ); |
|
bool check = false; |
|
if (dstType == CV_32F || dstType == CV_64F) |
|
check = countNonZero(diff>eps*dst) > 0; |
|
else |
|
check = countNonZero(diff>eps) > 0; |
|
if( check ) |
|
{ |
|
char msg[100]; |
|
const char* opTypeStr = opType == CV_REDUCE_SUM ? "CV_REDUCE_SUM" : |
|
opType == CV_REDUCE_AVG ? "CV_REDUCE_AVG" : |
|
opType == CV_REDUCE_MAX ? "CV_REDUCE_MAX" : |
|
opType == CV_REDUCE_MIN ? "CV_REDUCE_MIN" : "unknown operation type"; |
|
string srcTypeStr, dstTypeStr; |
|
getMatTypeStr( src.type(), srcTypeStr ); |
|
getMatTypeStr( dstType, dstTypeStr ); |
|
const char* dimStr = dim == 0 ? "ROWS" : "COLS"; |
|
|
|
sprintf( msg, "bad accuracy with srcType = %s, dstType = %s, opType = %s, dim = %s", |
|
srcTypeStr.c_str(), dstTypeStr.c_str(), opTypeStr, dimStr ); |
|
ts->printf( cvtest::TS::LOG, msg ); |
|
return cvtest::TS::FAIL_BAD_ACCURACY; |
|
} |
|
return cvtest::TS::OK; |
|
} |
|
|
|
int Core_ReduceTest::checkCase( int srcType, int dstType, int dim, Size sz ) |
|
{ |
|
int code = cvtest::TS::OK, tempCode; |
|
Mat src, sum, avg, max, min; |
|
|
|
src.create( sz, srcType ); |
|
randu( src, Scalar(0), Scalar(100) ); |
|
|
|
if( srcType == CV_8UC1 ) |
|
testReduce<uchar>( src, sum, avg, max, min, dim ); |
|
else if( srcType == CV_8SC1 ) |
|
testReduce<char>( src, sum, avg, max, min, dim ); |
|
else if( srcType == CV_16UC1 ) |
|
testReduce<unsigned short int>( src, sum, avg, max, min, dim ); |
|
else if( srcType == CV_16SC1 ) |
|
testReduce<short int>( src, sum, avg, max, min, dim ); |
|
else if( srcType == CV_32SC1 ) |
|
testReduce<int>( src, sum, avg, max, min, dim ); |
|
else if( srcType == CV_32FC1 ) |
|
testReduce<float>( src, sum, avg, max, min, dim ); |
|
else if( srcType == CV_64FC1 ) |
|
testReduce<double>( src, sum, avg, max, min, dim ); |
|
else |
|
assert( 0 ); |
|
|
|
// 1. sum |
|
tempCode = checkOp( src, dstType, CV_REDUCE_SUM, sum, dim ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
// 2. avg |
|
tempCode = checkOp( src, dstType, CV_REDUCE_AVG, avg, dim ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
// 3. max |
|
tempCode = checkOp( src, dstType, CV_REDUCE_MAX, max, dim ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
// 4. min |
|
tempCode = checkOp( src, dstType, CV_REDUCE_MIN, min, dim ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
return code; |
|
} |
|
|
|
int Core_ReduceTest::checkDim( int dim, Size sz ) |
|
{ |
|
int code = cvtest::TS::OK, tempCode; |
|
|
|
// CV_8UC1 |
|
tempCode = checkCase( CV_8UC1, CV_8UC1, dim, sz ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
tempCode = checkCase( CV_8UC1, CV_32SC1, dim, sz ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
tempCode = checkCase( CV_8UC1, CV_32FC1, dim, sz ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
tempCode = checkCase( CV_8UC1, CV_64FC1, dim, sz ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
// CV_16UC1 |
|
tempCode = checkCase( CV_16UC1, CV_32FC1, dim, sz ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
tempCode = checkCase( CV_16UC1, CV_64FC1, dim, sz ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
// CV_16SC1 |
|
tempCode = checkCase( CV_16SC1, CV_32FC1, dim, sz ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
tempCode = checkCase( CV_16SC1, CV_64FC1, dim, sz ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
// CV_32FC1 |
|
tempCode = checkCase( CV_32FC1, CV_32FC1, dim, sz ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
tempCode = checkCase( CV_32FC1, CV_64FC1, dim, sz ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
// CV_64FC1 |
|
tempCode = checkCase( CV_64FC1, CV_64FC1, dim, sz ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
return code; |
|
} |
|
|
|
int Core_ReduceTest::checkSize( Size sz ) |
|
{ |
|
int code = cvtest::TS::OK, tempCode; |
|
|
|
tempCode = checkDim( 0, sz ); // rows |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
tempCode = checkDim( 1, sz ); // cols |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
return code; |
|
} |
|
|
|
void Core_ReduceTest::run( int ) |
|
{ |
|
int code = cvtest::TS::OK, tempCode; |
|
|
|
tempCode = checkSize( Size(1,1) ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
tempCode = checkSize( Size(1,100) ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
tempCode = checkSize( Size(100,1) ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
tempCode = checkSize( Size(1000,500) ); |
|
code = tempCode != cvtest::TS::OK ? tempCode : code; |
|
|
|
ts->set_failed_test_info( code ); |
|
} |
|
|
|
|
|
#define CHECK_C |
|
|
|
TEST(Core_PCA, accuracy) |
|
{ |
|
const Size sz(200, 500); |
|
|
|
double diffPrjEps, diffBackPrjEps, |
|
prjEps, backPrjEps, |
|
evalEps, evecEps; |
|
int maxComponents = 100; |
|
double retainedVariance = 0.95; |
|
Mat rPoints(sz, CV_32FC1), rTestPoints(sz, CV_32FC1); |
|
RNG rng(12345); |
|
|
|
rng.fill( rPoints, RNG::UNIFORM, Scalar::all(0.0), Scalar::all(1.0) ); |
|
rng.fill( rTestPoints, RNG::UNIFORM, Scalar::all(0.0), Scalar::all(1.0) ); |
|
|
|
PCA rPCA( rPoints, Mat(), CV_PCA_DATA_AS_ROW, maxComponents ), cPCA; |
|
|
|
// 1. check C++ PCA & ROW |
|
Mat rPrjTestPoints = rPCA.project( rTestPoints ); |
|
Mat rBackPrjTestPoints = rPCA.backProject( rPrjTestPoints ); |
|
|
|
Mat avg(1, sz.width, CV_32FC1 ); |
|
cv::reduce( rPoints, avg, 0, CV_REDUCE_AVG ); |
|
Mat Q = rPoints - repeat( avg, rPoints.rows, 1 ), Qt = Q.t(), eval, evec; |
|
Q = Qt * Q; |
|
Q = Q /(float)rPoints.rows; |
|
|
|
eigen( Q, eval, evec ); |
|
/*SVD svd(Q); |
|
evec = svd.vt; |
|
eval = svd.w;*/ |
|
|
|
Mat subEval( maxComponents, 1, eval.type(), eval.ptr() ), |
|
subEvec( maxComponents, evec.cols, evec.type(), evec.ptr() ); |
|
|
|
#ifdef CHECK_C |
|
Mat prjTestPoints, backPrjTestPoints, cPoints = rPoints.t(), cTestPoints = rTestPoints.t(); |
|
CvMat _points, _testPoints, _avg, _eval, _evec, _prjTestPoints, _backPrjTestPoints; |
|
#endif |
|
|
|
// check eigen() |
|
double eigenEps = 1e-4; |
|
double err; |
|
for(int i = 0; i < Q.rows; i++ ) |
|
{ |
|
Mat v = evec.row(i).t(); |
|
Mat Qv = Q * v; |
|
|
|
Mat lv = eval.at<float>(i,0) * v; |
|
err = cvtest::norm(Qv, lv, NORM_L2 | NORM_RELATIVE); |
|
EXPECT_LE(err, eigenEps) << "bad accuracy of eigen(); i = " << i; |
|
} |
|
// check pca eigenvalues |
|
evalEps = 1e-5, evecEps = 5e-3; |
|
err = cvtest::norm(rPCA.eigenvalues, subEval, NORM_L2 | NORM_RELATIVE); |
|
EXPECT_LE(err , evalEps) << "pca.eigenvalues is incorrect (CV_PCA_DATA_AS_ROW)"; |
|
// check pca eigenvectors |
|
for(int i = 0; i < subEvec.rows; i++) |
|
{ |
|
Mat r0 = rPCA.eigenvectors.row(i); |
|
Mat r1 = subEvec.row(i); |
|
// eigenvectors have normalized length, but both directions v and -v are valid |
|
double err1 = cvtest::norm(r0, r1, NORM_L2 | NORM_RELATIVE); |
|
double err2 = cvtest::norm(r0, -r1, NORM_L2 | NORM_RELATIVE); |
|
err = std::min(err1, err2); |
|
if (err > evecEps) |
|
{ |
|
Mat tmp; |
|
absdiff(rPCA.eigenvectors, subEvec, tmp); |
|
double mval = 0; Point mloc; |
|
minMaxLoc(tmp, 0, &mval, 0, &mloc); |
|
|
|
EXPECT_LE(err, evecEps) << "pca.eigenvectors is incorrect (CV_PCA_DATA_AS_ROW) at " << i << " " |
|
<< cv::format("max diff is %g at (i=%d, j=%d) (%g vs %g)\n", |
|
mval, mloc.y, mloc.x, rPCA.eigenvectors.at<float>(mloc.y, mloc.x), |
|
subEvec.at<float>(mloc.y, mloc.x)) |
|
<< "r0=" << r0 << std::endl |
|
<< "r1=" << r1 << std::endl |
|
<< "err1=" << err1 << " err2=" << err2 |
|
; |
|
} |
|
} |
|
|
|
prjEps = 1.265, backPrjEps = 1.265; |
|
for( int i = 0; i < rTestPoints.rows; i++ ) |
|
{ |
|
// check pca project |
|
Mat subEvec_t = subEvec.t(); |
|
Mat prj = rTestPoints.row(i) - avg; prj *= subEvec_t; |
|
err = cvtest::norm(rPrjTestPoints.row(i), prj, NORM_L2 | NORM_RELATIVE); |
|
if (err < prjEps) |
|
{ |
|
EXPECT_LE(err, prjEps) << "bad accuracy of project() (CV_PCA_DATA_AS_ROW)"; |
|
continue; |
|
} |
|
// check pca backProject |
|
Mat backPrj = rPrjTestPoints.row(i) * subEvec + avg; |
|
err = cvtest::norm(rBackPrjTestPoints.row(i), backPrj, NORM_L2 | NORM_RELATIVE); |
|
if (err > backPrjEps) |
|
{ |
|
EXPECT_LE(err, backPrjEps) << "bad accuracy of backProject() (CV_PCA_DATA_AS_ROW)"; |
|
continue; |
|
} |
|
} |
|
|
|
// 2. check C++ PCA & COL |
|
cPCA( rPoints.t(), Mat(), CV_PCA_DATA_AS_COL, maxComponents ); |
|
diffPrjEps = 1, diffBackPrjEps = 1; |
|
Mat ocvPrjTestPoints = cPCA.project(rTestPoints.t()); |
|
err = cvtest::norm(cv::abs(ocvPrjTestPoints), cv::abs(rPrjTestPoints.t()), NORM_L2 | NORM_RELATIVE); |
|
ASSERT_LE(err, diffPrjEps) << "bad accuracy of project() (CV_PCA_DATA_AS_COL)"; |
|
err = cvtest::norm(cPCA.backProject(ocvPrjTestPoints), rBackPrjTestPoints.t(), NORM_L2 | NORM_RELATIVE); |
|
ASSERT_LE(err, diffBackPrjEps) << "bad accuracy of backProject() (CV_PCA_DATA_AS_COL)"; |
|
|
|
// 3. check C++ PCA w/retainedVariance |
|
cPCA( rPoints.t(), Mat(), CV_PCA_DATA_AS_COL, retainedVariance ); |
|
diffPrjEps = 1, diffBackPrjEps = 1; |
|
Mat rvPrjTestPoints = cPCA.project(rTestPoints.t()); |
|
|
|
if( cPCA.eigenvectors.rows > maxComponents) |
|
err = cvtest::norm(cv::abs(rvPrjTestPoints.rowRange(0,maxComponents)), cv::abs(rPrjTestPoints.t()), NORM_L2 | NORM_RELATIVE); |
|
else |
|
err = cvtest::norm(cv::abs(rvPrjTestPoints), cv::abs(rPrjTestPoints.colRange(0,cPCA.eigenvectors.rows).t()), NORM_L2 | NORM_RELATIVE); |
|
|
|
ASSERT_LE(err, diffPrjEps) << "bad accuracy of project() (CV_PCA_DATA_AS_COL); retainedVariance=" << retainedVariance; |
|
err = cvtest::norm(cPCA.backProject(rvPrjTestPoints), rBackPrjTestPoints.t(), NORM_L2 | NORM_RELATIVE); |
|
ASSERT_LE(err, diffBackPrjEps) << "bad accuracy of backProject() (CV_PCA_DATA_AS_COL); retainedVariance=" << retainedVariance; |
|
|
|
#ifdef CHECK_C |
|
// 4. check C PCA & ROW |
|
_points = cvMat(rPoints); |
|
_testPoints = cvMat(rTestPoints); |
|
_avg = cvMat(avg); |
|
_eval = cvMat(eval); |
|
_evec = cvMat(evec); |
|
prjTestPoints.create(rTestPoints.rows, maxComponents, rTestPoints.type() ); |
|
backPrjTestPoints.create(rPoints.size(), rPoints.type() ); |
|
_prjTestPoints = cvMat(prjTestPoints); |
|
_backPrjTestPoints = cvMat(backPrjTestPoints); |
|
|
|
cvCalcPCA( &_points, &_avg, &_eval, &_evec, CV_PCA_DATA_AS_ROW ); |
|
cvProjectPCA( &_testPoints, &_avg, &_evec, &_prjTestPoints ); |
|
cvBackProjectPCA( &_prjTestPoints, &_avg, &_evec, &_backPrjTestPoints ); |
|
|
|
err = cvtest::norm(prjTestPoints, rPrjTestPoints, NORM_L2 | NORM_RELATIVE); |
|
ASSERT_LE(err, diffPrjEps) << "bad accuracy of cvProjectPCA() (CV_PCA_DATA_AS_ROW)"; |
|
err = cvtest::norm(backPrjTestPoints, rBackPrjTestPoints, NORM_L2 | NORM_RELATIVE); |
|
ASSERT_LE(err, diffBackPrjEps) << "bad accuracy of cvBackProjectPCA() (CV_PCA_DATA_AS_ROW)"; |
|
|
|
// 5. check C PCA & COL |
|
_points = cvMat(cPoints); |
|
_testPoints = cvMat(cTestPoints); |
|
avg = avg.t(); _avg = cvMat(avg); |
|
eval = eval.t(); _eval = cvMat(eval); |
|
evec = evec.t(); _evec = cvMat(evec); |
|
prjTestPoints = prjTestPoints.t(); _prjTestPoints = cvMat(prjTestPoints); |
|
backPrjTestPoints = backPrjTestPoints.t(); _backPrjTestPoints = cvMat(backPrjTestPoints); |
|
|
|
cvCalcPCA( &_points, &_avg, &_eval, &_evec, CV_PCA_DATA_AS_COL ); |
|
cvProjectPCA( &_testPoints, &_avg, &_evec, &_prjTestPoints ); |
|
cvBackProjectPCA( &_prjTestPoints, &_avg, &_evec, &_backPrjTestPoints ); |
|
|
|
err = cvtest::norm(cv::abs(prjTestPoints), cv::abs(rPrjTestPoints.t()), NORM_L2 | NORM_RELATIVE); |
|
ASSERT_LE(err, diffPrjEps) << "bad accuracy of cvProjectPCA() (CV_PCA_DATA_AS_COL)"; |
|
err = cvtest::norm(backPrjTestPoints, rBackPrjTestPoints.t(), NORM_L2 | NORM_RELATIVE); |
|
ASSERT_LE(err, diffBackPrjEps) << "bad accuracy of cvBackProjectPCA() (CV_PCA_DATA_AS_COL)"; |
|
#endif |
|
// Test read and write |
|
FileStorage fs( "PCA_store.yml", FileStorage::WRITE ); |
|
rPCA.write( fs ); |
|
fs.release(); |
|
|
|
PCA lPCA; |
|
fs.open( "PCA_store.yml", FileStorage::READ ); |
|
lPCA.read( fs.root() ); |
|
err = cvtest::norm(rPCA.eigenvectors, lPCA.eigenvectors, NORM_L2 | NORM_RELATIVE); |
|
EXPECT_LE(err, 0) << "bad accuracy of write/load functions (YML)"; |
|
err = cvtest::norm(rPCA.eigenvalues, lPCA.eigenvalues, NORM_L2 | NORM_RELATIVE); |
|
EXPECT_LE(err, 0) << "bad accuracy of write/load functions (YML)"; |
|
err = cvtest::norm(rPCA.mean, lPCA.mean, NORM_L2 | NORM_RELATIVE); |
|
EXPECT_LE(err, 0) << "bad accuracy of write/load functions (YML)"; |
|
} |
|
|
|
class Core_ArrayOpTest : public cvtest::BaseTest |
|
{ |
|
public: |
|
Core_ArrayOpTest(); |
|
~Core_ArrayOpTest(); |
|
protected: |
|
void run(int); |
|
}; |
|
|
|
|
|
Core_ArrayOpTest::Core_ArrayOpTest() |
|
{ |
|
} |
|
Core_ArrayOpTest::~Core_ArrayOpTest() {} |
|
|
|
static string idx2string(const int* idx, int dims) |
|
{ |
|
char buf[256]; |
|
char* ptr = buf; |
|
for( int k = 0; k < dims; k++ ) |
|
{ |
|
sprintf(ptr, "%4d ", idx[k]); |
|
ptr += strlen(ptr); |
|
} |
|
ptr[-1] = '\0'; |
|
return string(buf); |
|
} |
|
|
|
static const int* string2idx(const string& s, int* idx, int dims) |
|
{ |
|
const char* ptr = s.c_str(); |
|
for( int k = 0; k < dims; k++ ) |
|
{ |
|
int n = 0; |
|
sscanf(ptr, "%d%n", idx + k, &n); |
|
ptr += n; |
|
} |
|
return idx; |
|
} |
|
|
|
static double getValue(SparseMat& M, const int* idx, RNG& rng) |
|
{ |
|
int d = M.dims(); |
|
size_t hv = 0, *phv = 0; |
|
if( (unsigned)rng % 2 ) |
|
{ |
|
hv = d == 2 ? M.hash(idx[0], idx[1]) : |
|
d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx); |
|
phv = &hv; |
|
} |
|
|
|
const uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], false, phv) : |
|
d == 3 ? M.ptr(idx[0], idx[1], idx[2], false, phv) : |
|
M.ptr(idx, false, phv); |
|
return !ptr ? 0 : M.type() == CV_32F ? *(float*)ptr : M.type() == CV_64F ? *(double*)ptr : 0; |
|
} |
|
|
|
static double getValue(const CvSparseMat* M, const int* idx) |
|
{ |
|
int type = 0; |
|
const uchar* ptr = cvPtrND(M, idx, &type, 0); |
|
return !ptr ? 0 : type == CV_32F ? *(float*)ptr : type == CV_64F ? *(double*)ptr : 0; |
|
} |
|
|
|
static void eraseValue(SparseMat& M, const int* idx, RNG& rng) |
|
{ |
|
int d = M.dims(); |
|
size_t hv = 0, *phv = 0; |
|
if( (unsigned)rng % 2 ) |
|
{ |
|
hv = d == 2 ? M.hash(idx[0], idx[1]) : |
|
d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx); |
|
phv = &hv; |
|
} |
|
|
|
if( d == 2 ) |
|
M.erase(idx[0], idx[1], phv); |
|
else if( d == 3 ) |
|
M.erase(idx[0], idx[1], idx[2], phv); |
|
else |
|
M.erase(idx, phv); |
|
} |
|
|
|
static void eraseValue(CvSparseMat* M, const int* idx) |
|
{ |
|
cvClearND(M, idx); |
|
} |
|
|
|
static void setValue(SparseMat& M, const int* idx, double value, RNG& rng) |
|
{ |
|
int d = M.dims(); |
|
size_t hv = 0, *phv = 0; |
|
if( (unsigned)rng % 2 ) |
|
{ |
|
hv = d == 2 ? M.hash(idx[0], idx[1]) : |
|
d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx); |
|
phv = &hv; |
|
} |
|
|
|
uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], true, phv) : |
|
d == 3 ? M.ptr(idx[0], idx[1], idx[2], true, phv) : |
|
M.ptr(idx, true, phv); |
|
if( M.type() == CV_32F ) |
|
*(float*)ptr = (float)value; |
|
else if( M.type() == CV_64F ) |
|
*(double*)ptr = value; |
|
else |
|
CV_Error(CV_StsUnsupportedFormat, ""); |
|
} |
|
|
|
template<typename Pixel> |
|
struct InitializerFunctor{ |
|
/// Initializer for cv::Mat::forEach test |
|
void operator()(Pixel & pixel, const int * idx) const { |
|
pixel.x = idx[0]; |
|
pixel.y = idx[1]; |
|
pixel.z = idx[2]; |
|
} |
|
}; |
|
|
|
template<typename Pixel> |
|
struct InitializerFunctor5D{ |
|
/// Initializer for cv::Mat::forEach test (5 dimensional case) |
|
void operator()(Pixel & pixel, const int * idx) const { |
|
pixel[0] = idx[0]; |
|
pixel[1] = idx[1]; |
|
pixel[2] = idx[2]; |
|
pixel[3] = idx[3]; |
|
pixel[4] = idx[4]; |
|
} |
|
}; |
|
|
|
template<typename Pixel> |
|
struct EmptyFunctor |
|
{ |
|
void operator()(const Pixel &, const int *) const {} |
|
}; |
|
|
|
|
|
void Core_ArrayOpTest::run( int /* start_from */) |
|
{ |
|
int errcount = 0; |
|
|
|
// dense matrix operations |
|
{ |
|
int sz3[] = {5, 10, 15}; |
|
MatND A(3, sz3, CV_32F), B(3, sz3, CV_16SC4); |
|
CvMatND matA = cvMatND(A), matB = cvMatND(B); |
|
RNG rng; |
|
rng.fill(A, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10)); |
|
rng.fill(B, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10)); |
|
|
|
int idx0[] = {3,4,5}, idx1[] = {0, 9, 7}; |
|
float val0 = 130; |
|
Scalar val1(-1000, 30, 3, 8); |
|
cvSetRealND(&matA, idx0, val0); |
|
cvSetReal3D(&matA, idx1[0], idx1[1], idx1[2], -val0); |
|
cvSetND(&matB, idx0, cvScalar(val1)); |
|
cvSet3D(&matB, idx1[0], idx1[1], idx1[2], cvScalar(-val1)); |
|
Ptr<CvMatND> matC(cvCloneMatND(&matB)); |
|
|
|
if( A.at<float>(idx0[0], idx0[1], idx0[2]) != val0 || |
|
A.at<float>(idx1[0], idx1[1], idx1[2]) != -val0 || |
|
cvGetReal3D(&matA, idx0[0], idx0[1], idx0[2]) != val0 || |
|
cvGetRealND(&matA, idx1) != -val0 || |
|
|
|
Scalar(B.at<Vec4s>(idx0[0], idx0[1], idx0[2])) != val1 || |
|
Scalar(B.at<Vec4s>(idx1[0], idx1[1], idx1[2])) != -val1 || |
|
Scalar(cvGet3D(matC, idx0[0], idx0[1], idx0[2])) != val1 || |
|
Scalar(cvGetND(matC, idx1)) != -val1 ) |
|
{ |
|
ts->printf(cvtest::TS::LOG, "one of cvSetReal3D, cvSetRealND, cvSet3D, cvSetND " |
|
"or the corresponding *Get* functions is not correct\n"); |
|
errcount++; |
|
} |
|
} |
|
// test cv::Mat::forEach |
|
{ |
|
const int dims[3] = { 101, 107, 7 }; |
|
typedef cv::Point3i Pixel; |
|
|
|
cv::Mat a = cv::Mat::zeros(3, dims, CV_32SC3); |
|
InitializerFunctor<Pixel> initializer; |
|
|
|
a.forEach<Pixel>(initializer); |
|
|
|
uint64 total = 0; |
|
bool error_reported = false; |
|
for (int i0 = 0; i0 < dims[0]; ++i0) { |
|
for (int i1 = 0; i1 < dims[1]; ++i1) { |
|
for (int i2 = 0; i2 < dims[2]; ++i2) { |
|
Pixel& pixel = a.at<Pixel>(i0, i1, i2); |
|
if (pixel.x != i0 || pixel.y != i1 || pixel.z != i2) { |
|
if (!error_reported) { |
|
ts->printf(cvtest::TS::LOG, "forEach is not correct.\n" |
|
"First error detected at (%d, %d, %d).\n", pixel.x, pixel.y, pixel.z); |
|
error_reported = true; |
|
} |
|
errcount++; |
|
} |
|
total += pixel.x; |
|
total += pixel.y; |
|
total += pixel.z; |
|
} |
|
} |
|
} |
|
uint64 total2 = 0; |
|
for (size_t i = 0; i < sizeof(dims) / sizeof(dims[0]); ++i) { |
|
total2 += ((dims[i] - 1) * dims[i] / 2) * dims[0] * dims[1] * dims[2] / dims[i]; |
|
} |
|
if (total != total2) { |
|
ts->printf(cvtest::TS::LOG, "forEach is not correct because total is invalid.\n"); |
|
errcount++; |
|
} |
|
} |
|
|
|
// test cv::Mat::forEach |
|
// with a matrix that has more dimensions than columns |
|
// See https://github.com/opencv/opencv/issues/8447 |
|
{ |
|
const int dims[5] = { 2, 2, 2, 2, 2 }; |
|
typedef cv::Vec<int, 5> Pixel; |
|
|
|
cv::Mat a = cv::Mat::zeros(5, dims, CV_32SC(5)); |
|
InitializerFunctor5D<Pixel> initializer; |
|
|
|
a.forEach<Pixel>(initializer); |
|
|
|
uint64 total = 0; |
|
bool error_reported = false; |
|
for (int i0 = 0; i0 < dims[0]; ++i0) { |
|
for (int i1 = 0; i1 < dims[1]; ++i1) { |
|
for (int i2 = 0; i2 < dims[2]; ++i2) { |
|
for (int i3 = 0; i3 < dims[3]; ++i3) { |
|
for (int i4 = 0; i4 < dims[4]; ++i4) { |
|
const int i[5] = { i0, i1, i2, i3, i4 }; |
|
Pixel& pixel = a.at<Pixel>(i); |
|
if (pixel[0] != i0 || pixel[1] != i1 || pixel[2] != i2 || pixel[3] != i3 || pixel[4] != i4) { |
|
if (!error_reported) { |
|
ts->printf(cvtest::TS::LOG, "forEach is not correct.\n" |
|
"First error detected at position (%d, %d, %d, %d, %d), got value (%d, %d, %d, %d, %d).\n", |
|
i0, i1, i2, i3, i4, |
|
pixel[0], pixel[1], pixel[2], pixel[3], pixel[4]); |
|
error_reported = true; |
|
} |
|
errcount++; |
|
} |
|
total += pixel[0]; |
|
total += pixel[1]; |
|
total += pixel[2]; |
|
total += pixel[3]; |
|
total += pixel[4]; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
uint64 total2 = 0; |
|
for (size_t i = 0; i < sizeof(dims) / sizeof(dims[0]); ++i) { |
|
total2 += ((dims[i] - 1) * dims[i] / 2) * dims[0] * dims[1] * dims[2] * dims[3] * dims[4] / dims[i]; |
|
} |
|
if (total != total2) { |
|
ts->printf(cvtest::TS::LOG, "forEach is not correct because total is invalid.\n"); |
|
errcount++; |
|
} |
|
} |
|
|
|
// test const cv::Mat::forEach |
|
{ |
|
const Mat a(10, 10, CV_32SC3); |
|
Mat b(10, 10, CV_32SC3); |
|
const Mat & c = b; |
|
a.forEach<Point3i>(EmptyFunctor<Point3i>()); |
|
b.forEach<Point3i>(EmptyFunctor<const Point3i>()); |
|
c.forEach<Point3i>(EmptyFunctor<Point3i>()); |
|
// tests compilation, no runtime check is needed |
|
} |
|
|
|
RNG rng; |
|
const int MAX_DIM = 5, MAX_DIM_SZ = 10; |
|
// sparse matrix operations |
|
for( int si = 0; si < 10; si++ ) |
|
{ |
|
int depth = (unsigned)rng % 2 == 0 ? CV_32F : CV_64F; |
|
int dims = ((unsigned)rng % MAX_DIM) + 1; |
|
int i, k, size[MAX_DIM]={0}, idx[MAX_DIM]={0}; |
|
vector<string> all_idxs; |
|
vector<double> all_vals; |
|
vector<double> all_vals2; |
|
string sidx, min_sidx, max_sidx; |
|
double min_val=0, max_val=0; |
|
|
|
int p = 1; |
|
for( k = 0; k < dims; k++ ) |
|
{ |
|
size[k] = ((unsigned)rng % MAX_DIM_SZ) + 1; |
|
p *= size[k]; |
|
} |
|
SparseMat M( dims, size, depth ); |
|
map<string, double> M0; |
|
|
|
int nz0 = (unsigned)rng % std::max(p/5,10); |
|
nz0 = std::min(std::max(nz0, 1), p); |
|
all_vals.resize(nz0); |
|
all_vals2.resize(nz0); |
|
Mat_<double> _all_vals(all_vals), _all_vals2(all_vals2); |
|
rng.fill(_all_vals, CV_RAND_UNI, Scalar(-1000), Scalar(1000)); |
|
if( depth == CV_32F ) |
|
{ |
|
Mat _all_vals_f; |
|
_all_vals.convertTo(_all_vals_f, CV_32F); |
|
_all_vals_f.convertTo(_all_vals, CV_64F); |
|
} |
|
_all_vals.convertTo(_all_vals2, _all_vals2.type(), 2); |
|
if( depth == CV_32F ) |
|
{ |
|
Mat _all_vals2_f; |
|
_all_vals2.convertTo(_all_vals2_f, CV_32F); |
|
_all_vals2_f.convertTo(_all_vals2, CV_64F); |
|
} |
|
|
|
minMaxLoc(_all_vals, &min_val, &max_val); |
|
double _norm0 = cv/*test*/::norm(_all_vals, CV_C); |
|
double _norm1 = cv/*test*/::norm(_all_vals, CV_L1); |
|
double _norm2 = cv/*test*/::norm(_all_vals, CV_L2); |
|
|
|
for( i = 0; i < nz0; i++ ) |
|
{ |
|
for(;;) |
|
{ |
|
for( k = 0; k < dims; k++ ) |
|
idx[k] = (unsigned)rng % size[k]; |
|
sidx = idx2string(idx, dims); |
|
if( M0.count(sidx) == 0 ) |
|
break; |
|
} |
|
all_idxs.push_back(sidx); |
|
M0[sidx] = all_vals[i]; |
|
if( all_vals[i] == min_val ) |
|
min_sidx = sidx; |
|
if( all_vals[i] == max_val ) |
|
max_sidx = sidx; |
|
setValue(M, idx, all_vals[i], rng); |
|
double v = getValue(M, idx, rng); |
|
if( v != all_vals[i] ) |
|
{ |
|
ts->printf(cvtest::TS::LOG, "%d. immediately after SparseMat[%s]=%.20g the current value is %.20g\n", |
|
i, sidx.c_str(), all_vals[i], v); |
|
errcount++; |
|
break; |
|
} |
|
} |
|
|
|
Ptr<CvSparseMat> M2(cvCreateSparseMat(M)); |
|
MatND Md; |
|
M.copyTo(Md); |
|
SparseMat M3; SparseMat(Md).convertTo(M3, Md.type(), 2); |
|
|
|
int nz1 = (int)M.nzcount(), nz2 = (int)M3.nzcount(); |
|
double norm0 = cv/*test*/::norm(M, CV_C); |
|
double norm1 = cv/*test*/::norm(M, CV_L1); |
|
double norm2 = cv/*test*/::norm(M, CV_L2); |
|
double eps = depth == CV_32F ? FLT_EPSILON*100 : DBL_EPSILON*1000; |
|
|
|
if( nz1 != nz0 || nz2 != nz0) |
|
{ |
|
errcount++; |
|
ts->printf(cvtest::TS::LOG, "%d: The number of non-zero elements before/after converting to/from dense matrix is not correct: %d/%d (while it should be %d)\n", |
|
si, nz1, nz2, nz0 ); |
|
break; |
|
} |
|
|
|
if( fabs(norm0 - _norm0) > fabs(_norm0)*eps || |
|
fabs(norm1 - _norm1) > fabs(_norm1)*eps || |
|
fabs(norm2 - _norm2) > fabs(_norm2)*eps ) |
|
{ |
|
errcount++; |
|
ts->printf(cvtest::TS::LOG, "%d: The norms are different: %.20g/%.20g/%.20g vs %.20g/%.20g/%.20g\n", |
|
si, norm0, norm1, norm2, _norm0, _norm1, _norm2 ); |
|
break; |
|
} |
|
|
|
int n = (unsigned)rng % std::max(p/5,10); |
|
n = std::min(std::max(n, 1), p) + nz0; |
|
|
|
for( i = 0; i < n; i++ ) |
|
{ |
|
double val1, val2, val3, val0; |
|
if(i < nz0) |
|
{ |
|
sidx = all_idxs[i]; |
|
string2idx(sidx, idx, dims); |
|
val0 = all_vals[i]; |
|
} |
|
else |
|
{ |
|
for( k = 0; k < dims; k++ ) |
|
idx[k] = (unsigned)rng % size[k]; |
|
sidx = idx2string(idx, dims); |
|
val0 = M0[sidx]; |
|
} |
|
val1 = getValue(M, idx, rng); |
|
val2 = getValue(M2, idx); |
|
val3 = getValue(M3, idx, rng); |
|
|
|
if( val1 != val0 || val2 != val0 || fabs(val3 - val0*2) > fabs(val0*2)*FLT_EPSILON ) |
|
{ |
|
errcount++; |
|
ts->printf(cvtest::TS::LOG, "SparseMat M[%s] = %g/%g/%g (while it should be %g)\n", sidx.c_str(), val1, val2, val3, val0 ); |
|
break; |
|
} |
|
} |
|
|
|
for( i = 0; i < n; i++ ) |
|
{ |
|
double val1, val2; |
|
if(i < nz0) |
|
{ |
|
sidx = all_idxs[i]; |
|
string2idx(sidx, idx, dims); |
|
} |
|
else |
|
{ |
|
for( k = 0; k < dims; k++ ) |
|
idx[k] = (unsigned)rng % size[k]; |
|
sidx = idx2string(idx, dims); |
|
} |
|
eraseValue(M, idx, rng); |
|
eraseValue(M2, idx); |
|
val1 = getValue(M, idx, rng); |
|
val2 = getValue(M2, idx); |
|
if( val1 != 0 || val2 != 0 ) |
|
{ |
|
errcount++; |
|
ts->printf(cvtest::TS::LOG, "SparseMat: after deleting M[%s], it is =%g/%g (while it should be 0)\n", sidx.c_str(), val1, val2 ); |
|
break; |
|
} |
|
} |
|
|
|
int nz = (int)M.nzcount(); |
|
if( nz != 0 ) |
|
{ |
|
errcount++; |
|
ts->printf(cvtest::TS::LOG, "The number of non-zero elements after removing all the elements = %d (while it should be 0)\n", nz ); |
|
break; |
|
} |
|
|
|
int idx1[MAX_DIM], idx2[MAX_DIM]; |
|
double val1 = 0, val2 = 0; |
|
M3 = SparseMat(Md); |
|
cv::minMaxLoc(M3, &val1, &val2, idx1, idx2); |
|
string s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims); |
|
if( val1 != min_val || val2 != max_val || s1 != min_sidx || s2 != max_sidx ) |
|
{ |
|
errcount++; |
|
ts->printf(cvtest::TS::LOG, "%d. Sparse: The value and positions of minimum/maximum elements are different from the reference values and positions:\n\t" |
|
"(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(), |
|
min_val, max_val, min_sidx.c_str(), max_sidx.c_str()); |
|
break; |
|
} |
|
|
|
cv::minMaxIdx(Md, &val1, &val2, idx1, idx2); |
|
s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims); |
|
if( (min_val < 0 && (val1 != min_val || s1 != min_sidx)) || |
|
(max_val > 0 && (val2 != max_val || s2 != max_sidx)) ) |
|
{ |
|
errcount++; |
|
ts->printf(cvtest::TS::LOG, "%d. Dense: The value and positions of minimum/maximum elements are different from the reference values and positions:\n\t" |
|
"(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(), |
|
min_val, max_val, min_sidx.c_str(), max_sidx.c_str()); |
|
break; |
|
} |
|
} |
|
|
|
ts->set_failed_test_info(errcount == 0 ? cvtest::TS::OK : cvtest::TS::FAIL_INVALID_OUTPUT); |
|
} |
|
|
|
|
|
template <class ElemType> |
|
int calcDiffElemCountImpl(const vector<Mat>& mv, const Mat& m) |
|
{ |
|
int diffElemCount = 0; |
|
const int mChannels = m.channels(); |
|
for(int y = 0; y < m.rows; y++) |
|
{ |
|
for(int x = 0; x < m.cols; x++) |
|
{ |
|
const ElemType* mElem = &m.at<ElemType>(y,x*mChannels); |
|
size_t loc = 0; |
|
for(size_t i = 0; i < mv.size(); i++) |
|
{ |
|
const size_t mvChannel = mv[i].channels(); |
|
const ElemType* mvElem = &mv[i].at<ElemType>(y,x*(int)mvChannel); |
|
for(size_t li = 0; li < mvChannel; li++) |
|
if(mElem[loc + li] != mvElem[li]) |
|
diffElemCount++; |
|
loc += mvChannel; |
|
} |
|
CV_Assert(loc == (size_t)mChannels); |
|
} |
|
} |
|
return diffElemCount; |
|
} |
|
|
|
static |
|
int calcDiffElemCount(const vector<Mat>& mv, const Mat& m) |
|
{ |
|
int depth = m.depth(); |
|
switch (depth) |
|
{ |
|
case CV_8U: |
|
return calcDiffElemCountImpl<uchar>(mv, m); |
|
case CV_8S: |
|
return calcDiffElemCountImpl<char>(mv, m); |
|
case CV_16U: |
|
return calcDiffElemCountImpl<unsigned short>(mv, m); |
|
case CV_16S: |
|
return calcDiffElemCountImpl<short int>(mv, m); |
|
case CV_32S: |
|
return calcDiffElemCountImpl<int>(mv, m); |
|
case CV_32F: |
|
return calcDiffElemCountImpl<float>(mv, m); |
|
case CV_64F: |
|
return calcDiffElemCountImpl<double>(mv, m); |
|
} |
|
|
|
return INT_MAX; |
|
} |
|
|
|
class Core_MergeSplitBaseTest : public cvtest::BaseTest |
|
{ |
|
protected: |
|
virtual int run_case(int depth, size_t channels, const Size& size, RNG& rng) = 0; |
|
|
|
virtual void run(int) |
|
{ |
|
// m is Mat |
|
// mv is vector<Mat> |
|
const int minMSize = 1; |
|
const int maxMSize = 100; |
|
const size_t maxMvSize = 10; |
|
|
|
RNG& rng = theRNG(); |
|
Size mSize(rng.uniform(minMSize, maxMSize), rng.uniform(minMSize, maxMSize)); |
|
size_t mvSize = rng.uniform(1, maxMvSize); |
|
|
|
int res = cvtest::TS::OK; |
|
int curRes = run_case(CV_8U, mvSize, mSize, rng); |
|
res = curRes != cvtest::TS::OK ? curRes : res; |
|
|
|
curRes = run_case(CV_8S, mvSize, mSize, rng); |
|
res = curRes != cvtest::TS::OK ? curRes : res; |
|
|
|
curRes = run_case(CV_16U, mvSize, mSize, rng); |
|
res = curRes != cvtest::TS::OK ? curRes : res; |
|
|
|
curRes = run_case(CV_16S, mvSize, mSize, rng); |
|
res = curRes != cvtest::TS::OK ? curRes : res; |
|
|
|
curRes = run_case(CV_32S, mvSize, mSize, rng); |
|
res = curRes != cvtest::TS::OK ? curRes : res; |
|
|
|
curRes = run_case(CV_32F, mvSize, mSize, rng); |
|
res = curRes != cvtest::TS::OK ? curRes : res; |
|
|
|
curRes = run_case(CV_64F, mvSize, mSize, rng); |
|
res = curRes != cvtest::TS::OK ? curRes : res; |
|
|
|
ts->set_failed_test_info(res); |
|
} |
|
}; |
|
|
|
class Core_MergeTest : public Core_MergeSplitBaseTest |
|
{ |
|
public: |
|
Core_MergeTest() {} |
|
~Core_MergeTest() {} |
|
|
|
protected: |
|
virtual int run_case(int depth, size_t matCount, const Size& size, RNG& rng) |
|
{ |
|
const int maxMatChannels = 10; |
|
|
|
vector<Mat> src(matCount); |
|
int channels = 0; |
|
for(size_t i = 0; i < src.size(); i++) |
|
{ |
|
Mat m(size, CV_MAKETYPE(depth, rng.uniform(1,maxMatChannels))); |
|
rng.fill(m, RNG::UNIFORM, 0, 100, true); |
|
channels += m.channels(); |
|
src[i] = m; |
|
} |
|
|
|
Mat dst; |
|
merge(src, dst); |
|
|
|
// check result |
|
std::stringstream commonLog; |
|
commonLog << "Depth " << depth << " :"; |
|
if(dst.depth() != depth) |
|
{ |
|
ts->printf(cvtest::TS::LOG, "%s incorrect depth of dst (%d instead of %d)\n", |
|
commonLog.str().c_str(), dst.depth(), depth); |
|
return cvtest::TS::FAIL_INVALID_OUTPUT; |
|
} |
|
if(dst.size() != size) |
|
{ |
|
ts->printf(cvtest::TS::LOG, "%s incorrect size of dst (%d x %d instead of %d x %d)\n", |
|
commonLog.str().c_str(), dst.rows, dst.cols, size.height, size.width); |
|
return cvtest::TS::FAIL_INVALID_OUTPUT; |
|
} |
|
if(dst.channels() != channels) |
|
{ |
|
ts->printf(cvtest::TS::LOG, "%s: incorrect channels count of dst (%d instead of %d)\n", |
|
commonLog.str().c_str(), dst.channels(), channels); |
|
return cvtest::TS::FAIL_INVALID_OUTPUT; |
|
} |
|
|
|
int diffElemCount = calcDiffElemCount(src, dst); |
|
if(diffElemCount > 0) |
|
{ |
|
ts->printf(cvtest::TS::LOG, "%s: there are incorrect elements in dst (part of them is %f)\n", |
|
commonLog.str().c_str(), static_cast<float>(diffElemCount)/(channels*size.area())); |
|
return cvtest::TS::FAIL_INVALID_OUTPUT; |
|
} |
|
|
|
return cvtest::TS::OK; |
|
} |
|
}; |
|
|
|
class Core_SplitTest : public Core_MergeSplitBaseTest |
|
{ |
|
public: |
|
Core_SplitTest() {} |
|
~Core_SplitTest() {} |
|
|
|
protected: |
|
virtual int run_case(int depth, size_t channels, const Size& size, RNG& rng) |
|
{ |
|
Mat src(size, CV_MAKETYPE(depth, (int)channels)); |
|
rng.fill(src, RNG::UNIFORM, 0, 100, true); |
|
|
|
vector<Mat> dst; |
|
split(src, dst); |
|
|
|
// check result |
|
std::stringstream commonLog; |
|
commonLog << "Depth " << depth << " :"; |
|
if(dst.size() != channels) |
|
{ |
|
ts->printf(cvtest::TS::LOG, "%s incorrect count of matrices in dst (%d instead of %d)\n", |
|
commonLog.str().c_str(), dst.size(), channels); |
|
return cvtest::TS::FAIL_INVALID_OUTPUT; |
|
} |
|
for(size_t i = 0; i < dst.size(); i++) |
|
{ |
|
if(dst[i].size() != size) |
|
{ |
|
ts->printf(cvtest::TS::LOG, "%s incorrect size of dst[%d] (%d x %d instead of %d x %d)\n", |
|
commonLog.str().c_str(), i, dst[i].rows, dst[i].cols, size.height, size.width); |
|
return cvtest::TS::FAIL_INVALID_OUTPUT; |
|
} |
|
if(dst[i].depth() != depth) |
|
{ |
|
ts->printf(cvtest::TS::LOG, "%s: incorrect depth of dst[%d] (%d instead of %d)\n", |
|
commonLog.str().c_str(), i, dst[i].depth(), depth); |
|
return cvtest::TS::FAIL_INVALID_OUTPUT; |
|
} |
|
if(dst[i].channels() != 1) |
|
{ |
|
ts->printf(cvtest::TS::LOG, "%s: incorrect channels count of dst[%d] (%d instead of %d)\n", |
|
commonLog.str().c_str(), i, dst[i].channels(), 1); |
|
return cvtest::TS::FAIL_INVALID_OUTPUT; |
|
} |
|
} |
|
|
|
int diffElemCount = calcDiffElemCount(dst, src); |
|
if(diffElemCount > 0) |
|
{ |
|
ts->printf(cvtest::TS::LOG, "%s: there are incorrect elements in dst (part of them is %f)\n", |
|
commonLog.str().c_str(), static_cast<float>(diffElemCount)/(channels*size.area())); |
|
return cvtest::TS::FAIL_INVALID_OUTPUT; |
|
} |
|
|
|
return cvtest::TS::OK; |
|
} |
|
}; |
|
|
|
TEST(Core_Reduce, accuracy) { Core_ReduceTest test; test.safe_run(); } |
|
TEST(Core_Array, basic_operations) { Core_ArrayOpTest test; test.safe_run(); } |
|
|
|
TEST(Core_Merge, shape_operations) { Core_MergeTest test; test.safe_run(); } |
|
TEST(Core_Split, shape_operations) { Core_SplitTest test; test.safe_run(); } |
|
|
|
|
|
TEST(Core_IOArray, submat_assignment) |
|
{ |
|
Mat1f A = Mat1f::zeros(2,2); |
|
Mat1f B = Mat1f::ones(1,3); |
|
|
|
EXPECT_THROW( B.colRange(0,3).copyTo(A.row(0)), cv::Exception ); |
|
|
|
EXPECT_NO_THROW( B.colRange(0,2).copyTo(A.row(0)) ); |
|
|
|
EXPECT_EQ( 1.0f, A(0,0) ); |
|
EXPECT_EQ( 1.0f, A(0,1) ); |
|
} |
|
|
|
void OutputArray_create1(OutputArray m) { m.create(1, 2, CV_32S); } |
|
void OutputArray_create2(OutputArray m) { m.create(1, 3, CV_32F); } |
|
|
|
TEST(Core_IOArray, submat_create) |
|
{ |
|
Mat1f A = Mat1f::zeros(2,2); |
|
|
|
EXPECT_THROW( OutputArray_create1(A.row(0)), cv::Exception ); |
|
EXPECT_THROW( OutputArray_create2(A.row(0)), cv::Exception ); |
|
} |
|
|
|
TEST(Core_Mat, issue4457_pass_null_ptr) |
|
{ |
|
ASSERT_ANY_THROW(cv::Mat mask(45, 45, CV_32F, 0)); |
|
} |
|
|
|
TEST(Core_Mat, reshape_1942) |
|
{ |
|
cv::Mat A = (cv::Mat_<float>(2,3) << 3.4884074, 1.4159607, 0.78737736, 2.3456569, -0.88010466, 0.3009364); |
|
int cn = 0; |
|
ASSERT_NO_THROW( |
|
cv::Mat_<float> M = A.reshape(3); |
|
cn = M.channels(); |
|
); |
|
ASSERT_EQ(1, cn); |
|
} |
|
|
|
static void check_ndim_shape(const cv::Mat &mat, int cn, int ndims, const int *sizes) |
|
{ |
|
EXPECT_EQ(mat.channels(), cn); |
|
EXPECT_EQ(mat.dims, ndims); |
|
|
|
if (mat.dims != ndims) |
|
return; |
|
|
|
for (int i = 0; i < ndims; i++) |
|
EXPECT_EQ(mat.size[i], sizes[i]); |
|
} |
|
|
|
TEST(Core_Mat, reshape_ndims_2) |
|
{ |
|
const cv::Mat A(8, 16, CV_8UC3); |
|
cv::Mat B; |
|
|
|
{ |
|
int new_sizes_mask[] = { 0, 3, 4, 4 }; |
|
int new_sizes_real[] = { 8, 3, 4, 4 }; |
|
ASSERT_NO_THROW(B = A.reshape(1, 4, new_sizes_mask)); |
|
check_ndim_shape(B, 1, 4, new_sizes_real); |
|
} |
|
{ |
|
int new_sizes[] = { 16, 8 }; |
|
ASSERT_NO_THROW(B = A.reshape(0, 2, new_sizes)); |
|
check_ndim_shape(B, 3, 2, new_sizes); |
|
EXPECT_EQ(B.rows, new_sizes[0]); |
|
EXPECT_EQ(B.cols, new_sizes[1]); |
|
} |
|
{ |
|
int new_sizes[] = { 2, 5, 1, 3 }; |
|
cv::Mat A_sliced = A(cv::Range::all(), cv::Range(0, 15)); |
|
ASSERT_ANY_THROW(A_sliced.reshape(4, 4, new_sizes)); |
|
} |
|
} |
|
|
|
TEST(Core_Mat, reshape_ndims_4) |
|
{ |
|
const int sizes[] = { 2, 6, 4, 12 }; |
|
const cv::Mat A(4, sizes, CV_8UC3); |
|
cv::Mat B; |
|
|
|
{ |
|
int new_sizes_mask[] = { 0, 864 }; |
|
int new_sizes_real[] = { 2, 864 }; |
|
ASSERT_NO_THROW(B = A.reshape(1, 2, new_sizes_mask)); |
|
check_ndim_shape(B, 1, 2, new_sizes_real); |
|
EXPECT_EQ(B.rows, new_sizes_real[0]); |
|
EXPECT_EQ(B.cols, new_sizes_real[1]); |
|
} |
|
{ |
|
int new_sizes_mask[] = { 4, 0, 0, 2, 3 }; |
|
int new_sizes_real[] = { 4, 6, 4, 2, 3 }; |
|
ASSERT_NO_THROW(B = A.reshape(0, 5, new_sizes_mask)); |
|
check_ndim_shape(B, 3, 5, new_sizes_real); |
|
} |
|
{ |
|
int new_sizes_mask[] = { 1, 1 }; |
|
ASSERT_ANY_THROW(A.reshape(0, 2, new_sizes_mask)); |
|
} |
|
{ |
|
int new_sizes_mask[] = { 4, 6, 3, 3, 0 }; |
|
ASSERT_ANY_THROW(A.reshape(0, 5, new_sizes_mask)); |
|
} |
|
} |
|
|
|
TEST(Core_Mat, push_back) |
|
{ |
|
Mat a = (Mat_<float>(1,2) << 3.4884074f, 1.4159607f); |
|
Mat b = (Mat_<float>(1,2) << 0.78737736f, 2.3456569f); |
|
|
|
a.push_back(b); |
|
|
|
ASSERT_EQ(2, a.cols); |
|
ASSERT_EQ(2, a.rows); |
|
|
|
ASSERT_FLOAT_EQ(3.4884074f, a.at<float>(0, 0)); |
|
ASSERT_FLOAT_EQ(1.4159607f, a.at<float>(0, 1)); |
|
ASSERT_FLOAT_EQ(0.78737736f, a.at<float>(1, 0)); |
|
ASSERT_FLOAT_EQ(2.3456569f, a.at<float>(1, 1)); |
|
|
|
Mat c = (Mat_<float>(2,2) << -0.88010466f, 0.3009364f, 2.22399974f, -5.45933905f); |
|
|
|
ASSERT_EQ(c.rows, a.cols); |
|
|
|
a.push_back(c.t()); |
|
|
|
ASSERT_EQ(2, a.cols); |
|
ASSERT_EQ(4, a.rows); |
|
|
|
ASSERT_FLOAT_EQ(3.4884074f, a.at<float>(0, 0)); |
|
ASSERT_FLOAT_EQ(1.4159607f, a.at<float>(0, 1)); |
|
ASSERT_FLOAT_EQ(0.78737736f, a.at<float>(1, 0)); |
|
ASSERT_FLOAT_EQ(2.3456569f, a.at<float>(1, 1)); |
|
ASSERT_FLOAT_EQ(-0.88010466f, a.at<float>(2, 0)); |
|
ASSERT_FLOAT_EQ(2.22399974f, a.at<float>(2, 1)); |
|
ASSERT_FLOAT_EQ(0.3009364f, a.at<float>(3, 0)); |
|
ASSERT_FLOAT_EQ(-5.45933905f, a.at<float>(3, 1)); |
|
|
|
a.push_back(Mat::ones(2, 2, CV_32FC1)); |
|
|
|
ASSERT_EQ(6, a.rows); |
|
|
|
for(int row=4; row<a.rows; row++) { |
|
|
|
for(int col=0; col<a.cols; col++) { |
|
|
|
ASSERT_FLOAT_EQ(1.f, a.at<float>(row, col)); |
|
} |
|
} |
|
} |
|
|
|
TEST(Core_Mat, copyNx1ToVector) |
|
{ |
|
cv::Mat_<uchar> src(5, 1); |
|
cv::Mat_<uchar> ref_dst8; |
|
cv::Mat_<ushort> ref_dst16; |
|
std::vector<uchar> dst8; |
|
std::vector<ushort> dst16; |
|
|
|
src << 1, 2, 3, 4, 5; |
|
|
|
src.copyTo(ref_dst8); |
|
src.copyTo(dst8); |
|
|
|
ASSERT_PRED_FORMAT2(cvtest::MatComparator(0, 0), ref_dst8, cv::Mat_<uchar>(dst8)); |
|
|
|
src.convertTo(ref_dst16, CV_16U); |
|
src.convertTo(dst16, CV_16U); |
|
|
|
ASSERT_PRED_FORMAT2(cvtest::MatComparator(0, 0), ref_dst16, cv::Mat_<ushort>(dst16)); |
|
} |
|
|
|
TEST(Core_Matx, fromMat_) |
|
{ |
|
Mat_<double> a = (Mat_<double>(2,2) << 10, 11, 12, 13); |
|
Matx22d b(a); |
|
ASSERT_EQ( cvtest::norm(a, b, NORM_INF), 0.); |
|
} |
|
|
|
#ifdef CV_CXX11 |
|
|
|
TEST(Core_Matx, from_initializer_list) |
|
{ |
|
Mat_<double> a = (Mat_<double>(2,2) << 10, 11, 12, 13); |
|
Matx22d b = {10, 11, 12, 13}; |
|
ASSERT_EQ( cvtest::norm(a, b, NORM_INF), 0.); |
|
} |
|
|
|
TEST(Core_Mat, regression_9507) |
|
{ |
|
cv::Mat m = Mat::zeros(5, 5, CV_8UC3); |
|
cv::Mat m2{m}; |
|
EXPECT_EQ(25u, m2.total()); |
|
} |
|
|
|
#endif // CXX11 |
|
|
|
TEST(Core_InputArray, empty) |
|
{ |
|
vector<vector<Point> > data; |
|
ASSERT_TRUE( _InputArray(data).empty() ); |
|
} |
|
|
|
TEST(Core_CopyMask, bug1918) |
|
{ |
|
Mat_<unsigned char> tmpSrc(100,100); |
|
tmpSrc = 124; |
|
Mat_<unsigned char> tmpMask(100,100); |
|
tmpMask = 255; |
|
Mat_<unsigned char> tmpDst(100,100); |
|
tmpDst = 2; |
|
tmpSrc.copyTo(tmpDst,tmpMask); |
|
ASSERT_EQ(sum(tmpDst)[0], 124*100*100); |
|
} |
|
|
|
TEST(Core_SVD, orthogonality) |
|
{ |
|
for( int i = 0; i < 2; i++ ) |
|
{ |
|
int type = i == 0 ? CV_32F : CV_64F; |
|
Mat mat_D(2, 2, type); |
|
mat_D.setTo(88.); |
|
Mat mat_U, mat_W; |
|
SVD::compute(mat_D, mat_W, mat_U, noArray(), SVD::FULL_UV); |
|
mat_U *= mat_U.t(); |
|
ASSERT_LT(cvtest::norm(mat_U, Mat::eye(2, 2, type), NORM_INF), 1e-5); |
|
} |
|
} |
|
|
|
|
|
TEST(Core_SparseMat, footprint) |
|
{ |
|
int n = 1000000; |
|
int sz[] = { n, n }; |
|
SparseMat m(2, sz, CV_64F); |
|
|
|
int nodeSize0 = (int)m.hdr->nodeSize; |
|
double dataSize0 = ((double)m.hdr->pool.size() + (double)m.hdr->hashtab.size()*sizeof(size_t))*1e-6; |
|
printf("before: node size=%d bytes, data size=%.0f Mbytes\n", nodeSize0, dataSize0); |
|
|
|
for (int i = 0; i < n; i++) |
|
{ |
|
m.ref<double>(i, i) = 1; |
|
} |
|
|
|
double dataSize1 = ((double)m.hdr->pool.size() + (double)m.hdr->hashtab.size()*sizeof(size_t))*1e-6; |
|
double threshold = (n*nodeSize0*1.6 + n*2.*sizeof(size_t))*1e-6; |
|
printf("after: data size=%.0f Mbytes, threshold=%.0f MBytes\n", dataSize1, threshold); |
|
|
|
ASSERT_LE((int)m.hdr->nodeSize, 32); |
|
ASSERT_LE(dataSize1, threshold); |
|
} |
|
|
|
|
|
// Can't fix without dirty hacks or broken user code (PR #4159) |
|
TEST(Core_Mat_vector, DISABLED_OutputArray_create_getMat) |
|
{ |
|
cv::Mat_<uchar> src_base(5, 1); |
|
std::vector<uchar> dst8; |
|
|
|
src_base << 1, 2, 3, 4, 5; |
|
|
|
Mat src(src_base); |
|
OutputArray _dst(dst8); |
|
{ |
|
_dst.create(src.rows, src.cols, src.type()); |
|
Mat dst = _dst.getMat(); |
|
EXPECT_EQ(src.dims, dst.dims); |
|
EXPECT_EQ(src.cols, dst.cols); |
|
EXPECT_EQ(src.rows, dst.rows); |
|
} |
|
} |
|
|
|
TEST(Core_Mat_vector, copyTo_roi_column) |
|
{ |
|
cv::Mat_<uchar> src_base(5, 2); |
|
std::vector<uchar> dst1; |
|
|
|
src_base << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; |
|
|
|
Mat src_full(src_base); |
|
Mat src(src_full.col(0)); |
|
#if 0 // Can't fix without dirty hacks or broken user code (PR #4159) |
|
OutputArray _dst(dst1); |
|
{ |
|
_dst.create(src.rows, src.cols, src.type()); |
|
Mat dst = _dst.getMat(); |
|
EXPECT_EQ(src.dims, dst.dims); |
|
EXPECT_EQ(src.cols, dst.cols); |
|
EXPECT_EQ(src.rows, dst.rows); |
|
} |
|
#endif |
|
|
|
std::vector<uchar> dst2; |
|
src.copyTo(dst2); |
|
std::cout << "src = " << src << std::endl; |
|
std::cout << "dst = " << Mat(dst2) << std::endl; |
|
EXPECT_EQ((size_t)5, dst2.size()); |
|
EXPECT_EQ(1, (int)dst2[0]); |
|
EXPECT_EQ(3, (int)dst2[1]); |
|
EXPECT_EQ(5, (int)dst2[2]); |
|
EXPECT_EQ(7, (int)dst2[3]); |
|
EXPECT_EQ(9, (int)dst2[4]); |
|
} |
|
|
|
TEST(Core_Mat_vector, copyTo_roi_row) |
|
{ |
|
cv::Mat_<uchar> src_base(2, 5); |
|
std::vector<uchar> dst1; |
|
|
|
src_base << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; |
|
|
|
Mat src_full(src_base); |
|
Mat src(src_full.row(0)); |
|
OutputArray _dst(dst1); |
|
{ |
|
_dst.create(src.rows, src.cols, src.type()); |
|
Mat dst = _dst.getMat(); |
|
EXPECT_EQ(src.dims, dst.dims); |
|
EXPECT_EQ(src.cols, dst.cols); |
|
EXPECT_EQ(src.rows, dst.rows); |
|
} |
|
|
|
std::vector<uchar> dst2; |
|
src.copyTo(dst2); |
|
std::cout << "src = " << src << std::endl; |
|
std::cout << "dst = " << Mat(dst2) << std::endl; |
|
EXPECT_EQ((size_t)5, dst2.size()); |
|
EXPECT_EQ(1, (int)dst2[0]); |
|
EXPECT_EQ(2, (int)dst2[1]); |
|
EXPECT_EQ(3, (int)dst2[2]); |
|
EXPECT_EQ(4, (int)dst2[3]); |
|
EXPECT_EQ(5, (int)dst2[4]); |
|
} |
|
|
|
TEST(Mat, regression_5991) |
|
{ |
|
int sz[] = {2,3,2}; |
|
Mat mat(3, sz, CV_32F, Scalar(1)); |
|
ASSERT_NO_THROW(mat.convertTo(mat, CV_8U)); |
|
EXPECT_EQ(sz[0], mat.size[0]); |
|
EXPECT_EQ(sz[1], mat.size[1]); |
|
EXPECT_EQ(sz[2], mat.size[2]); |
|
EXPECT_EQ(0, cvtest::norm(mat, Mat(3, sz, CV_8U, Scalar(1)), NORM_INF)); |
|
} |
|
|
|
TEST(Mat, regression_9720) |
|
{ |
|
Mat mat(1, 1, CV_32FC1); |
|
mat.at<float>(0) = 1.f; |
|
const float a = 0.1f; |
|
Mat me1 = (Mat)(mat.mul((a / mat))); |
|
Mat me2 = (Mat)(mat.mul((Mat)(a / mat))); |
|
Mat me3 = (Mat)(mat.mul((a * mat))); |
|
Mat me4 = (Mat)(mat.mul((Mat)(a * mat))); |
|
EXPECT_EQ(me1.at<float>(0), me2.at<float>(0)); |
|
EXPECT_EQ(me3.at<float>(0), me4.at<float>(0)); |
|
} |
|
|
|
#ifdef OPENCV_TEST_BIGDATA |
|
TEST(Mat, regression_6696_BigData_8Gb) |
|
{ |
|
int width = 60000; |
|
int height = 10000; |
|
|
|
Mat destImageBGR = Mat(height, width, CV_8UC3, Scalar(1, 2, 3, 0)); |
|
Mat destImageA = Mat(height, width, CV_8UC1, Scalar::all(4)); |
|
|
|
vector<Mat> planes; |
|
split(destImageBGR, planes); |
|
planes.push_back(destImageA); |
|
merge(planes, destImageBGR); |
|
|
|
EXPECT_EQ(1, destImageBGR.at<Vec4b>(0)[0]); |
|
EXPECT_EQ(2, destImageBGR.at<Vec4b>(0)[1]); |
|
EXPECT_EQ(3, destImageBGR.at<Vec4b>(0)[2]); |
|
EXPECT_EQ(4, destImageBGR.at<Vec4b>(0)[3]); |
|
|
|
EXPECT_EQ(1, destImageBGR.at<Vec4b>(height-1, width-1)[0]); |
|
EXPECT_EQ(2, destImageBGR.at<Vec4b>(height-1, width-1)[1]); |
|
EXPECT_EQ(3, destImageBGR.at<Vec4b>(height-1, width-1)[2]); |
|
EXPECT_EQ(4, destImageBGR.at<Vec4b>(height-1, width-1)[3]); |
|
} |
|
#endif |
|
|
|
TEST(Reduce, regression_should_fail_bug_4594) |
|
{ |
|
cv::Mat src = cv::Mat::eye(4, 4, CV_8U); |
|
std::vector<int> dst; |
|
|
|
EXPECT_THROW(cv::reduce(src, dst, 0, CV_REDUCE_MIN, CV_32S), cv::Exception); |
|
EXPECT_THROW(cv::reduce(src, dst, 0, CV_REDUCE_MAX, CV_32S), cv::Exception); |
|
EXPECT_NO_THROW(cv::reduce(src, dst, 0, CV_REDUCE_SUM, CV_32S)); |
|
EXPECT_NO_THROW(cv::reduce(src, dst, 0, CV_REDUCE_AVG, CV_32S)); |
|
} |
|
|
|
TEST(Mat, push_back_vector) |
|
{ |
|
cv::Mat result(1, 5, CV_32FC1); |
|
|
|
std::vector<float> vec1(result.cols + 1); |
|
std::vector<int> vec2(result.cols); |
|
|
|
EXPECT_THROW(result.push_back(vec1), cv::Exception); |
|
EXPECT_THROW(result.push_back(vec2), cv::Exception); |
|
|
|
vec1.resize(result.cols); |
|
|
|
for (int i = 0; i < 5; ++i) |
|
result.push_back(cv::Mat(vec1).reshape(1, 1)); |
|
|
|
ASSERT_EQ(6, result.rows); |
|
} |
|
|
|
TEST(Mat, regression_5917_clone_empty) |
|
{ |
|
Mat cloned; |
|
Mat_<Point2f> source(5, 0); |
|
|
|
ASSERT_NO_THROW(cloned = source.clone()); |
|
} |
|
|
|
TEST(Mat, regression_7873_mat_vector_initialize) |
|
{ |
|
std::vector<int> dims; |
|
dims.push_back(12); |
|
dims.push_back(3); |
|
dims.push_back(2); |
|
Mat multi_mat(dims, CV_32FC1, cv::Scalar(0)); |
|
|
|
ASSERT_EQ(3, multi_mat.dims); |
|
ASSERT_EQ(12, multi_mat.size[0]); |
|
ASSERT_EQ(3, multi_mat.size[1]); |
|
ASSERT_EQ(2, multi_mat.size[2]); |
|
|
|
std::vector<Range> ranges; |
|
ranges.push_back(Range(1, 2)); |
|
ranges.push_back(Range::all()); |
|
ranges.push_back(Range::all()); |
|
Mat sub_mat = multi_mat(ranges); |
|
|
|
ASSERT_EQ(3, sub_mat.dims); |
|
ASSERT_EQ(1, sub_mat.size[0]); |
|
ASSERT_EQ(3, sub_mat.size[1]); |
|
ASSERT_EQ(2, sub_mat.size[2]); |
|
} |
|
|
|
TEST(Mat, regression_10507_mat_setTo) |
|
{ |
|
Size sz(6, 4); |
|
Mat test_mask(sz, CV_8UC1, cv::Scalar::all(255)); |
|
test_mask.at<uchar>(1,0) = 0; |
|
test_mask.at<uchar>(0,1) = 0; |
|
for (int cn = 1; cn <= 4; cn++) |
|
{ |
|
cv::Mat A(sz, CV_MAKE_TYPE(CV_32F, cn), cv::Scalar::all(5)); |
|
A.setTo(cv::Scalar::all(std::numeric_limits<float>::quiet_NaN()), test_mask); |
|
int nans = 0; |
|
for (int y = 0; y < A.rows; y++) |
|
{ |
|
for (int x = 0; x < A.cols; x++) |
|
{ |
|
for (int c = 0; c < cn; c++) |
|
{ |
|
float v = A.ptr<float>(y, x)[c]; |
|
nans += (v == v) ? 0 : 1; |
|
} |
|
} |
|
} |
|
EXPECT_EQ(nans, cn * (sz.area() - 2)) << "A=" << A << std::endl << "mask=" << test_mask << std::endl; |
|
} |
|
} |
|
|
|
#ifdef CV_CXX_STD_ARRAY |
|
TEST(Core_Mat_array, outputArray_create_getMat) |
|
{ |
|
cv::Mat_<uchar> src_base(5, 1); |
|
std::array<uchar, 5> dst8; |
|
|
|
src_base << 1, 2, 3, 4, 5; |
|
|
|
Mat src(src_base); |
|
OutputArray _dst(dst8); |
|
|
|
{ |
|
_dst.create(src.rows, src.cols, src.type()); |
|
Mat dst = _dst.getMat(); |
|
EXPECT_EQ(src.dims, dst.dims); |
|
EXPECT_EQ(src.cols, dst.cols); |
|
EXPECT_EQ(src.rows, dst.rows); |
|
} |
|
} |
|
|
|
TEST(Core_Mat_array, copyTo_roi_column) |
|
{ |
|
cv::Mat_<uchar> src_base(5, 2); |
|
|
|
src_base << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; |
|
|
|
Mat src_full(src_base); |
|
Mat src(src_full.col(0)); |
|
|
|
std::array<uchar, 5> dst1; |
|
src.copyTo(dst1); |
|
std::cout << "src = " << src << std::endl; |
|
std::cout << "dst = " << Mat(dst1) << std::endl; |
|
EXPECT_EQ((size_t)5, dst1.size()); |
|
EXPECT_EQ(1, (int)dst1[0]); |
|
EXPECT_EQ(3, (int)dst1[1]); |
|
EXPECT_EQ(5, (int)dst1[2]); |
|
EXPECT_EQ(7, (int)dst1[3]); |
|
EXPECT_EQ(9, (int)dst1[4]); |
|
} |
|
|
|
TEST(Core_Mat_array, copyTo_roi_row) |
|
{ |
|
cv::Mat_<uchar> src_base(2, 5); |
|
std::array<uchar, 5> dst1; |
|
|
|
src_base << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; |
|
|
|
Mat src_full(src_base); |
|
Mat src(src_full.row(0)); |
|
OutputArray _dst(dst1); |
|
{ |
|
_dst.create(5, 1, src.type()); |
|
Mat dst = _dst.getMat(); |
|
EXPECT_EQ(src.dims, dst.dims); |
|
EXPECT_EQ(1, dst.cols); |
|
EXPECT_EQ(5, dst.rows); |
|
} |
|
|
|
std::array<uchar, 5> dst2; |
|
src.copyTo(dst2); |
|
std::cout << "src = " << src << std::endl; |
|
std::cout << "dst = " << Mat(dst2) << std::endl; |
|
EXPECT_EQ(1, (int)dst2[0]); |
|
EXPECT_EQ(2, (int)dst2[1]); |
|
EXPECT_EQ(3, (int)dst2[2]); |
|
EXPECT_EQ(4, (int)dst2[3]); |
|
EXPECT_EQ(5, (int)dst2[4]); |
|
} |
|
|
|
TEST(Core_Mat_array, SplitMerge) |
|
{ |
|
std::array<cv::Mat, 3> src; |
|
for (size_t i = 0; i < src.size(); ++i) |
|
{ |
|
src[i] = Mat(10, 10, CV_8U, Scalar((double)(16 * (i + 1)))); |
|
} |
|
|
|
Mat merged; |
|
merge(src, merged); |
|
|
|
std::array<cv::Mat, 3> dst; |
|
split(merged, dst); |
|
|
|
for (size_t i = 0; i < dst.size(); ++i) |
|
{ |
|
EXPECT_EQ(0, cvtest::norm(src[i], dst[i], NORM_INF)); |
|
} |
|
} |
|
#endif |
|
|
|
TEST(Mat, regression_8680) |
|
{ |
|
Mat_<Point2i> mat(3,1); |
|
ASSERT_EQ(mat.channels(), 2); |
|
mat.release(); |
|
ASSERT_EQ(mat.channels(), 2); |
|
} |
|
|
|
#ifdef CV_CXX11 |
|
|
|
TEST(Mat_, range_based_for) |
|
{ |
|
Mat_<uchar> img = Mat_<uchar>::zeros(3, 3); |
|
|
|
for(auto& pixel : img) |
|
{ |
|
pixel = 1; |
|
} |
|
|
|
Mat_<uchar> ref(3, 3); |
|
ref.setTo(Scalar(1)); |
|
ASSERT_DOUBLE_EQ(cvtest::norm(img, ref, NORM_INF), 0.); |
|
} |
|
|
|
TEST(Mat, from_initializer_list) |
|
{ |
|
Mat A({1.f, 2.f, 3.f}); |
|
Mat_<float> B(3, 1); B << 1, 2, 3; |
|
Mat_<float> C({3}, {1,2,3}); |
|
|
|
ASSERT_EQ(A.type(), CV_32F); |
|
ASSERT_DOUBLE_EQ(cvtest::norm(A, B, NORM_INF), 0.); |
|
ASSERT_DOUBLE_EQ(cvtest::norm(A, C, NORM_INF), 0.); |
|
ASSERT_DOUBLE_EQ(cvtest::norm(B, C, NORM_INF), 0.); |
|
|
|
auto D = Mat_<double>({2, 3}, {1, 2, 3, 4, 5, 6}); |
|
EXPECT_EQ(2, D.rows); |
|
EXPECT_EQ(3, D.cols); |
|
} |
|
|
|
TEST(Mat_, from_initializer_list) |
|
{ |
|
Mat_<float> A = {1, 2, 3}; |
|
Mat_<float> B(3, 1); B << 1, 2, 3; |
|
Mat_<float> C({3}, {1,2,3}); |
|
|
|
ASSERT_DOUBLE_EQ(cvtest::norm(A, B, NORM_INF), 0.); |
|
ASSERT_DOUBLE_EQ(cvtest::norm(A, C, NORM_INF), 0.); |
|
ASSERT_DOUBLE_EQ(cvtest::norm(B, C, NORM_INF), 0.); |
|
} |
|
|
|
|
|
TEST(Mat, template_based_ptr) |
|
{ |
|
Mat mat = (Mat_<float>(2, 2) << 11.0f, 22.0f, 33.0f, 44.0f); |
|
int idx[2] = {1, 0}; |
|
ASSERT_FLOAT_EQ(33.0f, *(mat.ptr<float>(idx))); |
|
idx[0] = 1; |
|
idx[1] = 1; |
|
ASSERT_FLOAT_EQ(44.0f, *(mat.ptr<float>(idx))); |
|
} |
|
|
|
TEST(Mat_, template_based_ptr) |
|
{ |
|
int dim[4] = {2, 2, 1, 2}; |
|
Mat_<float> mat = (Mat_<float>(4, dim) << 11.0f, 22.0f, 33.0f, 44.0f, |
|
55.0f, 66.0f, 77.0f, 88.0f); |
|
int idx[4] = {1, 0, 0, 1}; |
|
ASSERT_FLOAT_EQ(66.0f, *(mat.ptr<float>(idx))); |
|
} |
|
|
|
#endif |
|
|
|
|
|
BIGDATA_TEST(Mat, push_back_regression_4158) // memory usage: ~10.6 Gb |
|
{ |
|
Mat result; |
|
|
|
Mat tail(100, 500000, CV_32FC2, Scalar(1, 2)); |
|
|
|
tail.copyTo(result); |
|
for (int i = 1; i < 15; i++) |
|
{ |
|
result.push_back(tail); |
|
std::cout << "i = " << i << " result = " << result.size() << " used = " << (uint64)result.total()*result.elemSize()*(1.0 / (1 << 20)) << " Mb" |
|
<< " allocated=" << (uint64)(result.datalimit - result.datastart)*(1.0 / (1 << 20)) << " Mb" << std::endl; |
|
} |
|
for (int i = 0; i < 15; i++) |
|
{ |
|
Rect roi(0, tail.rows * i, tail.cols, tail.rows); |
|
int nz = countNonZero(result(roi).reshape(1) == 2); |
|
EXPECT_EQ(tail.total(), (size_t)nz) << "i=" << i; |
|
} |
|
} |
|
|
|
|
|
TEST(Core_Merge, hang_12171) |
|
{ |
|
Mat src1(4, 24, CV_8UC1, Scalar::all(1)); |
|
Mat src2(4, 24, CV_8UC1, Scalar::all(2)); |
|
Rect src_roi(0, 0, 23, 4); |
|
Mat src_channels[2] = { src1(src_roi), src2(src_roi) }; |
|
Mat dst(4, 24, CV_8UC2, Scalar::all(5)); |
|
Rect dst_roi(1, 0, 23, 4); |
|
cv::merge(src_channels, 2, dst(dst_roi)); |
|
EXPECT_EQ(5, dst.ptr<uchar>()[0]); |
|
EXPECT_EQ(5, dst.ptr<uchar>()[1]); |
|
EXPECT_EQ(1, dst.ptr<uchar>()[2]); |
|
EXPECT_EQ(2, dst.ptr<uchar>()[3]); |
|
EXPECT_EQ(5, dst.ptr<uchar>(1)[0]); |
|
EXPECT_EQ(5, dst.ptr<uchar>(1)[1]); |
|
EXPECT_EQ(1, dst.ptr<uchar>(1)[2]); |
|
EXPECT_EQ(2, dst.ptr<uchar>(1)[3]); |
|
} |
|
|
|
TEST(Core_Split, hang_12171) |
|
{ |
|
Mat src(4, 24, CV_8UC2, Scalar(1,2,3,4)); |
|
Rect src_roi(0, 0, 23, 4); |
|
Mat dst1(4, 24, CV_8UC1, Scalar::all(5)); |
|
Mat dst2(4, 24, CV_8UC1, Scalar::all(10)); |
|
Rect dst_roi(0, 0, 23, 4); |
|
Mat dst[2] = { dst1(dst_roi), dst2(dst_roi) }; |
|
cv::split(src(src_roi), dst); |
|
EXPECT_EQ(1, dst1.ptr<uchar>()[0]); |
|
EXPECT_EQ(1, dst1.ptr<uchar>()[1]); |
|
EXPECT_EQ(2, dst2.ptr<uchar>()[0]); |
|
EXPECT_EQ(2, dst2.ptr<uchar>()[1]); |
|
EXPECT_EQ(1, dst1.ptr<uchar>(1)[0]); |
|
EXPECT_EQ(1, dst1.ptr<uchar>(1)[1]); |
|
EXPECT_EQ(2, dst2.ptr<uchar>(1)[0]); |
|
EXPECT_EQ(2, dst2.ptr<uchar>(1)[1]); |
|
} |
|
|
|
TEST(Core_Split, crash_12171) |
|
{ |
|
Mat src(4, 40, CV_8UC2, Scalar(1,2,3,4)); |
|
Rect src_roi(0, 0, 39, 4); |
|
Mat dst1(4, 40, CV_8UC1, Scalar::all(5)); |
|
Mat dst2(4, 40, CV_8UC1, Scalar::all(10)); |
|
Rect dst_roi(0, 0, 39, 4); |
|
Mat dst[2] = { dst1(dst_roi), dst2(dst_roi) }; |
|
cv::split(src(src_roi), dst); |
|
EXPECT_EQ(1, dst1.ptr<uchar>()[0]); |
|
EXPECT_EQ(1, dst1.ptr<uchar>()[1]); |
|
EXPECT_EQ(2, dst2.ptr<uchar>()[0]); |
|
EXPECT_EQ(2, dst2.ptr<uchar>()[1]); |
|
EXPECT_EQ(1, dst1.ptr<uchar>(1)[0]); |
|
EXPECT_EQ(1, dst1.ptr<uchar>(1)[1]); |
|
EXPECT_EQ(2, dst2.ptr<uchar>(1)[0]); |
|
EXPECT_EQ(2, dst2.ptr<uchar>(1)[1]); |
|
} |
|
|
|
struct CustomType // like cv::Keypoint |
|
{ |
|
Point2f pt; |
|
float size; |
|
float angle; |
|
float response; |
|
int octave; |
|
int class_id; |
|
}; |
|
|
|
static void test_CustomType(InputArray src_, OutputArray dst_) |
|
{ |
|
Mat src = src_.getMat(); |
|
ASSERT_EQ(sizeof(CustomType), src.elemSize()); |
|
CV_CheckTypeEQ(src.type(), CV_MAKETYPE(CV_8U, sizeof(CustomType)), ""); |
|
|
|
CustomType* kpt = NULL; |
|
{ |
|
Mat dst = dst_.getMat(); |
|
for (size_t i = 0; i < dst.total(); i++) |
|
{ |
|
kpt = dst.ptr<CustomType>(0) + i; |
|
kpt->octave = (int)i; |
|
} |
|
} |
|
const int N = (int)src.total(); |
|
dst_.create(1, N * 2, rawType<CustomType>()); |
|
Mat dst = dst_.getMat(); |
|
for (size_t i = N; i < dst.total(); i++) |
|
{ |
|
kpt = dst.ptr<CustomType>(0) + i; |
|
kpt->octave = -(int)i; |
|
} |
|
#if 0 // Compilation error |
|
CustomType& kpt = dst.at<CustomType>(0, 5); |
|
#endif |
|
} |
|
|
|
TEST(Core_InputArray, support_CustomType) |
|
{ |
|
std::vector<CustomType> kp1(5); |
|
std::vector<CustomType> kp2(3); |
|
test_CustomType(rawIn(kp1), rawOut(kp2)); |
|
ASSERT_EQ((size_t)10, kp2.size()); |
|
for (int i = 0; i < 3; i++) |
|
{ |
|
EXPECT_EQ(i, kp2[i].octave); |
|
} |
|
for (int i = 3; i < 5; i++) |
|
{ |
|
EXPECT_EQ(0, kp2[i].octave); |
|
} |
|
for (int i = 5; i < 10; i++) |
|
{ |
|
EXPECT_EQ(-i, kp2[i].octave); |
|
} |
|
} |
|
|
|
|
|
}} // namespace
|
|
|