/*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 "test_precomp.hpp" using namespace cv; using namespace std; class CV_ImgWarpBaseTest : public cvtest::ArrayTest { public: CV_ImgWarpBaseTest( bool warp_matrix ); protected: int read_params( CvFileStorage* fs ); int prepare_test_case( int test_case_idx ); void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); void fill_array( int test_case_idx, int i, int j, Mat& arr ); int interpolation; int max_interpolation; double spatial_scale_zoom, spatial_scale_decimate; }; CV_ImgWarpBaseTest::CV_ImgWarpBaseTest( bool warp_matrix ) { test_array[INPUT].push_back(NULL); if( warp_matrix ) test_array[INPUT].push_back(NULL); test_array[INPUT_OUTPUT].push_back(NULL); test_array[REF_INPUT_OUTPUT].push_back(NULL); max_interpolation = 5; interpolation = 0; element_wise_relative_error = false; spatial_scale_zoom = 0.01; spatial_scale_decimate = 0.005; } int CV_ImgWarpBaseTest::read_params( CvFileStorage* fs ) { int code = cvtest::ArrayTest::read_params( fs ); return code; } void CV_ImgWarpBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ) { cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high ); if( CV_MAT_DEPTH(type) == CV_32F ) { low = Scalar::all(-10.); high = Scalar::all(10); } } void CV_ImgWarpBaseTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) { RNG& rng = ts->get_rng(); int depth = cvtest::randInt(rng) % 3; int cn = cvtest::randInt(rng) % 3 + 1; cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F; cn += cn == 2; types[INPUT][0] = types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn); if( test_array[INPUT].size() > 1 ) types[INPUT][1] = cvtest::randInt(rng) & 1 ? CV_32FC1 : CV_64FC1; interpolation = cvtest::randInt(rng) % max_interpolation; } void CV_ImgWarpBaseTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) { if( i != INPUT || j != 0 ) cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr ); } int CV_ImgWarpBaseTest::prepare_test_case( int test_case_idx ) { int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); Mat& img = test_mat[INPUT][0]; int i, j, cols = img.cols; int type = img.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); double scale = depth == CV_16U ? 1000. : 255.*0.5; double space_scale = spatial_scale_decimate; vector buffer(img.cols*cn); if( code <= 0 ) return code; if( test_mat[INPUT_OUTPUT][0].cols >= img.cols && test_mat[INPUT_OUTPUT][0].rows >= img.rows ) space_scale = spatial_scale_zoom; for( i = 0; i < img.rows; i++ ) { uchar* ptr = img.ptr(i); switch( cn ) { case 1: for( j = 0; j < cols; j++ ) buffer[j] = (float)((sin((i+1)*space_scale)*sin((j+1)*space_scale)+1.)*scale); break; case 2: for( j = 0; j < cols; j++ ) { buffer[j*2] = (float)((sin((i+1)*space_scale)+1.)*scale); buffer[j*2+1] = (float)((sin((i+j)*space_scale)+1.)*scale); } break; case 3: for( j = 0; j < cols; j++ ) { buffer[j*3] = (float)((sin((i+1)*space_scale)+1.)*scale); buffer[j*3+1] = (float)((sin(j*space_scale)+1.)*scale); buffer[j*3+2] = (float)((sin((i+j)*space_scale)+1.)*scale); } break; case 4: for( j = 0; j < cols; j++ ) { buffer[j*4] = (float)((sin((i+1)*space_scale)+1.)*scale); buffer[j*4+1] = (float)((sin(j*space_scale)+1.)*scale); buffer[j*4+2] = (float)((sin((i+j)*space_scale)+1.)*scale); buffer[j*4+3] = (float)((sin((i-j)*space_scale)+1.)*scale); } break; default: assert(0); } /*switch( depth ) { case CV_8U: for( j = 0; j < cols*cn; j++ ) ptr[j] = (uchar)cvRound(buffer[j]); break; case CV_16U: for( j = 0; j < cols*cn; j++ ) ((ushort*)ptr)[j] = (ushort)cvRound(buffer[j]); break; case CV_32F: for( j = 0; j < cols*cn; j++ ) ((float*)ptr)[j] = (float)buffer[j]; break; default: assert(0); }*/ cv::Mat src(1, cols*cn, CV_32F, &buffer[0]); cv::Mat dst(1, cols*cn, depth, ptr); src.convertTo(dst, dst.type()); } return code; } ///////////////////////// class CV_ResizeTest : public CV_ImgWarpBaseTest { public: CV_ResizeTest(); protected: void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); void run_func(); void prepare_to_validation( int /*test_case_idx*/ ); double get_success_error_level( int test_case_idx, int i, int j ); }; CV_ResizeTest::CV_ResizeTest() : CV_ImgWarpBaseTest( false ) { } void CV_ResizeTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) { RNG& rng = ts->get_rng(); CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); CvSize sz; sz.width = (cvtest::randInt(rng) % sizes[INPUT][0].width) + 1; sz.height = (cvtest::randInt(rng) % sizes[INPUT][0].height) + 1; if( cvtest::randInt(rng) & 1 ) { int xfactor = cvtest::randInt(rng) % 10 + 1; int yfactor = cvtest::randInt(rng) % 10 + 1; if( cvtest::randInt(rng) & 1 ) yfactor = xfactor; sz.width = sizes[INPUT][0].width / xfactor; sz.width = MAX(sz.width,1); sz.height = sizes[INPUT][0].height / yfactor; sz.height = MAX(sz.height,1); sizes[INPUT][0].width = sz.width * xfactor; sizes[INPUT][0].height = sz.height * yfactor; } if( cvtest::randInt(rng) & 1 ) sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = sz; else { sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = sizes[INPUT][0]; sizes[INPUT][0] = sz; } if( interpolation == 4 && (MIN(sizes[INPUT][0].width,sizes[INPUT_OUTPUT][0].width) < 4 || MIN(sizes[INPUT][0].height,sizes[INPUT_OUTPUT][0].height) < 4)) interpolation = 2; } void CV_ResizeTest::run_func() { cvResize( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], interpolation ); } double CV_ResizeTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) { int depth = test_mat[INPUT][0].depth(); return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 1e-1; } void CV_ResizeTest::prepare_to_validation( int /*test_case_idx*/ ) { CvMat _src = test_mat[INPUT][0], _dst = test_mat[REF_INPUT_OUTPUT][0]; CvMat *src = &_src, *dst = &_dst; int i, j, k; CvMat* x_idx = cvCreateMat( 1, dst->cols, CV_32SC1 ); CvMat* y_idx = cvCreateMat( 1, dst->rows, CV_32SC1 ); int* x_tab = x_idx->data.i; int elem_size = CV_ELEM_SIZE(src->type); int drows = dst->rows, dcols = dst->cols; if( interpolation == CV_INTER_NN ) { for( j = 0; j < dcols; j++ ) { int t = (j*src->cols*2 + MIN(src->cols,dcols) - 1)/(dcols*2); t -= t >= src->cols; x_idx->data.i[j] = t*elem_size; } for( j = 0; j < drows; j++ ) { int t = (j*src->rows*2 + MIN(src->rows,drows) - 1)/(drows*2); t -= t >= src->rows; y_idx->data.i[j] = t; } } else { double scale_x = (double)src->cols/dcols; double scale_y = (double)src->rows/drows; for( j = 0; j < dcols; j++ ) { double f = ((j+0.5)*scale_x - 0.5); i = cvRound(f); x_idx->data.i[j] = (i < 0 ? 0 : i >= src->cols ? src->cols - 1 : i)*elem_size; } for( j = 0; j < drows; j++ ) { double f = ((j+0.5)*scale_y - 0.5); i = cvRound(f); y_idx->data.i[j] = i < 0 ? 0 : i >= src->rows ? src->rows - 1 : i; } } for( i = 0; i < drows; i++ ) { uchar* dptr = dst->data.ptr + dst->step*i; const uchar* sptr0 = src->data.ptr + src->step*y_idx->data.i[i]; for( j = 0; j < dcols; j++, dptr += elem_size ) { const uchar* sptr = sptr0 + x_tab[j]; for( k = 0; k < elem_size; k++ ) dptr[k] = sptr[k]; } } cvReleaseMat( &x_idx ); cvReleaseMat( &y_idx ); } ///////////////////////// static void test_remap( const Mat& src, Mat& dst, const Mat& mapx, const Mat& mapy, Mat* mask=0, int interpolation=CV_INTER_LINEAR ) { int x, y, k; int drows = dst.rows, dcols = dst.cols; int srows = src.rows, scols = src.cols; uchar* sptr0 = src.data; int depth = src.depth(), cn = src.channels(); int elem_size = (int)src.elemSize(); int step = (int)(src.step / CV_ELEM_SIZE(depth)); int delta; if( interpolation != CV_INTER_CUBIC ) { delta = 0; scols -= 1; srows -= 1; } else { delta = 1; scols = MAX(scols - 3, 0); srows = MAX(srows - 3, 0); } int scols1 = MAX(scols - 2, 0); int srows1 = MAX(srows - 2, 0); if( mask ) *mask = Scalar::all(0); for( y = 0; y < drows; y++ ) { uchar* dptr = dst.ptr(y); const float* mx = mapx.ptr(y); const float* my = mapy.ptr(y); uchar* m = mask ? mask->ptr(y) : 0; for( x = 0; x < dcols; x++, dptr += elem_size ) { float xs = mx[x]; float ys = my[x]; int ixs = cvFloor(xs); int iys = cvFloor(ys); if( (unsigned)(ixs - delta - 1) >= (unsigned)scols1 || (unsigned)(iys - delta - 1) >= (unsigned)srows1 ) { if( m ) m[x] = 1; if( (unsigned)(ixs - delta) >= (unsigned)scols || (unsigned)(iys - delta) >= (unsigned)srows ) continue; } xs -= ixs; ys -= iys; switch( depth ) { case CV_8U: { const uchar* sptr = sptr0 + iys*step + ixs*cn; for( k = 0; k < cn; k++ ) { float v00 = sptr[k]; float v01 = sptr[cn + k]; float v10 = sptr[step + k]; float v11 = sptr[step + cn + k]; v00 = v00 + xs*(v01 - v00); v10 = v10 + xs*(v11 - v10); v00 = v00 + ys*(v10 - v00); dptr[k] = (uchar)cvRound(v00); } } break; case CV_16U: { const ushort* sptr = (const ushort*)sptr0 + iys*step + ixs*cn; for( k = 0; k < cn; k++ ) { float v00 = sptr[k]; float v01 = sptr[cn + k]; float v10 = sptr[step + k]; float v11 = sptr[step + cn + k]; v00 = v00 + xs*(v01 - v00); v10 = v10 + xs*(v11 - v10); v00 = v00 + ys*(v10 - v00); ((ushort*)dptr)[k] = (ushort)cvRound(v00); } } break; case CV_32F: { const float* sptr = (const float*)sptr0 + iys*step + ixs*cn; for( k = 0; k < cn; k++ ) { float v00 = sptr[k]; float v01 = sptr[cn + k]; float v10 = sptr[step + k]; float v11 = sptr[step + cn + k]; v00 = v00 + xs*(v01 - v00); v10 = v10 + xs*(v11 - v10); v00 = v00 + ys*(v10 - v00); ((float*)dptr)[k] = (float)v00; } } break; default: assert(0); } } } } ///////////////////////// class CV_WarpAffineTest : public CV_ImgWarpBaseTest { public: CV_WarpAffineTest(); protected: void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); void run_func(); int prepare_test_case( int test_case_idx ); void prepare_to_validation( int /*test_case_idx*/ ); double get_success_error_level( int test_case_idx, int i, int j ); }; CV_WarpAffineTest::CV_WarpAffineTest() : CV_ImgWarpBaseTest( true ) { //spatial_scale_zoom = spatial_scale_decimate; spatial_scale_decimate = spatial_scale_zoom; } void CV_WarpAffineTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) { CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); CvSize sz = sizes[INPUT][0]; // run for the second time to get output of a different size CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); sizes[INPUT][0] = sz; sizes[INPUT][1] = cvSize( 3, 2 ); } void CV_WarpAffineTest::run_func() { CvMat mtx = test_mat[INPUT][1]; cvWarpAffine( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx, interpolation ); } double CV_WarpAffineTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) { int depth = test_mat[INPUT][0].depth(); return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2; } int CV_WarpAffineTest::prepare_test_case( int test_case_idx ) { RNG& rng = ts->get_rng(); int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); const Mat& src = test_mat[INPUT][0]; const Mat& dst = test_mat[INPUT_OUTPUT][0]; Mat& mat = test_mat[INPUT][1]; CvPoint2D32f center; double scale, angle; if( code <= 0 ) return code; double buf[6]; Mat tmp( 2, 3, mat.type(), buf ); center.x = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.cols); center.y = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.rows); angle = cvtest::randReal(rng)*360; scale = ((double)dst.rows/src.rows + (double)dst.cols/src.cols)*0.5; getRotationMatrix2D(center, angle, scale).convertTo(mat, mat.depth()); rng.fill( tmp, CV_RAND_NORMAL, Scalar::all(1.), Scalar::all(0.01) ); cv::max(tmp, 0.9, tmp); cv::min(tmp, 1.1, tmp); cv::multiply(tmp, mat, mat, 1.); return code; } void CV_WarpAffineTest::prepare_to_validation( int /*test_case_idx*/ ) { const Mat& src = test_mat[INPUT][0]; Mat& dst = test_mat[REF_INPUT_OUTPUT][0]; Mat& dst0 = test_mat[INPUT_OUTPUT][0]; Mat mapx(dst.size(), CV_32F), mapy(dst.size(), CV_32F); double m[6]; Mat srcAb, dstAb( 2, 3, CV_64FC1, m ); //cvInvert( &tM, &M, CV_LU ); // [R|t] -> [R^-1 | -(R^-1)*t] test_mat[INPUT][1].convertTo( srcAb, CV_64F ); Mat A = srcAb.colRange(0, 2); Mat b = srcAb.col(2); Mat invA = dstAb.colRange(0, 2); Mat invAb = dstAb.col(2); cv::invert(A, invA, CV_SVD); cv::gemm(invA, b, -1, Mat(), 0, invAb); for( int y = 0; y < dst.rows; y++ ) for( int x = 0; x < dst.cols; x++ ) { mapx.at(y, x) = (float)(x*m[0] + y*m[1] + m[2]); mapy.at(y, x) = (float)(x*m[3] + y*m[4] + m[5]); } Mat mask( dst.size(), CV_8U ); test_remap( src, dst, mapx, mapy, &mask ); dst.setTo(Scalar::all(0), mask); dst0.setTo(Scalar::all(0), mask); } ///////////////////////// class CV_WarpPerspectiveTest : public CV_ImgWarpBaseTest { public: CV_WarpPerspectiveTest(); protected: void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); void run_func(); int prepare_test_case( int test_case_idx ); void prepare_to_validation( int /*test_case_idx*/ ); double get_success_error_level( int test_case_idx, int i, int j ); }; CV_WarpPerspectiveTest::CV_WarpPerspectiveTest() : CV_ImgWarpBaseTest( true ) { //spatial_scale_zoom = spatial_scale_decimate; spatial_scale_decimate = spatial_scale_zoom; } void CV_WarpPerspectiveTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) { CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); CvSize sz = sizes[INPUT][0]; // run for the second time to get output of a different size CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); sizes[INPUT][0] = sz; sizes[INPUT][1] = cvSize( 3, 3 ); } void CV_WarpPerspectiveTest::run_func() { CvMat mtx = test_mat[INPUT][1]; cvWarpPerspective( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx, interpolation ); } double CV_WarpPerspectiveTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) { int depth = test_mat[INPUT][0].depth(); return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2; } int CV_WarpPerspectiveTest::prepare_test_case( int test_case_idx ) { RNG& rng = ts->get_rng(); int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); const CvMat& src = test_mat[INPUT][0]; const CvMat& dst = test_mat[INPUT_OUTPUT][0]; Mat& mat = test_mat[INPUT][1]; Point2f s[4], d[4]; int i; if( code <= 0 ) return code; s[0] = Point2f(0,0); d[0] = Point2f(0,0); s[1] = Point2f(src.cols-1.f,0); d[1] = Point2f(dst.cols-1.f,0); s[2] = Point2f(src.cols-1.f,src.rows-1.f); d[2] = Point2f(dst.cols-1.f,dst.rows-1.f); s[3] = Point2f(0,src.rows-1.f); d[3] = Point2f(0,dst.rows-1.f); float buf[16]; Mat tmp( 1, 16, CV_32FC1, buf ); rng.fill( tmp, CV_RAND_NORMAL, Scalar::all(0.), Scalar::all(0.1) ); for( i = 0; i < 4; i++ ) { s[i].x += buf[i*4]*src.cols/2; s[i].y += buf[i*4+1]*src.rows/2; d[i].x += buf[i*4+2]*dst.cols/2; d[i].y += buf[i*4+3]*dst.rows/2; } cv::getPerspectiveTransform( s, d ).convertTo( mat, mat.depth() ); return code; } void CV_WarpPerspectiveTest::prepare_to_validation( int /*test_case_idx*/ ) { Mat& src = test_mat[INPUT][0]; Mat& dst = test_mat[REF_INPUT_OUTPUT][0]; Mat& dst0 = test_mat[INPUT_OUTPUT][0]; Mat mapx(dst.size(), CV_32F), mapy(dst.size(), CV_32F); double m[9]; Mat srcM, dstM(3, 3, CV_64F, m); //cvInvert( &tM, &M, CV_LU ); // [R|t] -> [R^-1 | -(R^-1)*t] test_mat[INPUT][1].convertTo( srcM, CV_64F ); cv::invert(srcM, dstM, CV_SVD); for( int y = 0; y < dst.rows; y++ ) { for( int x = 0; x < dst.cols; x++ ) { double xs = x*m[0] + y*m[1] + m[2]; double ys = x*m[3] + y*m[4] + m[5]; double ds = x*m[6] + y*m[7] + m[8]; ds = ds ? 1./ds : 0; xs *= ds; ys *= ds; mapx.at(y, x) = (float)xs; mapy.at(y, x) = (float)ys; } } Mat mask( dst.size(), CV_8U ); test_remap( src, dst, mapx, mapy, &mask ); dst.setTo(Scalar::all(0), mask); dst0.setTo(Scalar::all(0), mask); } ///////////////////////// class CV_RemapTest : public CV_ImgWarpBaseTest { public: CV_RemapTest(); protected: void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); void run_func(); int prepare_test_case( int test_case_idx ); void prepare_to_validation( int /*test_case_idx*/ ); double get_success_error_level( int test_case_idx, int i, int j ); void fill_array( int test_case_idx, int i, int j, Mat& arr ); }; CV_RemapTest::CV_RemapTest() : CV_ImgWarpBaseTest( false ) { //spatial_scale_zoom = spatial_scale_decimate; test_array[INPUT].push_back(NULL); test_array[INPUT].push_back(NULL); spatial_scale_decimate = spatial_scale_zoom; } void CV_RemapTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) { CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); types[INPUT][1] = types[INPUT][2] = CV_32FC1; interpolation = CV_INTER_LINEAR; } void CV_RemapTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) { if( i != INPUT ) CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr ); } void CV_RemapTest::run_func() { cvRemap( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], test_array[INPUT][1], test_array[INPUT][2], interpolation ); } double CV_RemapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) { int depth = test_mat[INPUT][0].depth(); return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2; } int CV_RemapTest::prepare_test_case( int test_case_idx ) { RNG& rng = ts->get_rng(); int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); const Mat& src = test_mat[INPUT][0]; double a[9] = {0,0,0,0,0,0,0,0,1}, k[4]; Mat _a( 3, 3, CV_64F, a ); Mat _k( 4, 1, CV_64F, k ); double sz = MAX(src.rows, src.cols); if( code <= 0 ) return code; double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7; a[2] = (src.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5; a[5] = (src.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5; a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6); a[4] = aspect_ratio*a[0]; k[0] = cvtest::randReal(rng)*0.06 - 0.03; k[1] = cvtest::randReal(rng)*0.06 - 0.03; if( k[0]*k[1] > 0 ) k[1] = -k[1]; k[2] = cvtest::randReal(rng)*0.004 - 0.002; k[3] = cvtest::randReal(rng)*0.004 - 0.002; cvtest::initUndistortMap( _a, _k, test_mat[INPUT][1].size(), test_mat[INPUT][1], test_mat[INPUT][2] ); return code; } void CV_RemapTest::prepare_to_validation( int /*test_case_idx*/ ) { Mat& dst = test_mat[REF_INPUT_OUTPUT][0]; Mat& dst0 = test_mat[INPUT_OUTPUT][0]; Mat mask( dst.size(), CV_8U ); test_remap(test_mat[INPUT][0], dst, test_mat[INPUT][1], test_mat[INPUT][2], &mask, interpolation ); dst.setTo(Scalar::all(0), mask); dst0.setTo(Scalar::all(0), mask); } ////////////////////////////// undistort ///////////////////////////////// class CV_UndistortTest : public CV_ImgWarpBaseTest { public: CV_UndistortTest(); protected: void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); void run_func(); int prepare_test_case( int test_case_idx ); void prepare_to_validation( int /*test_case_idx*/ ); double get_success_error_level( int test_case_idx, int i, int j ); void fill_array( int test_case_idx, int i, int j, Mat& arr ); private: bool useCPlus; cv::Mat input0; cv::Mat input1; cv::Mat input2; cv::Mat input_new_cam; cv::Mat input_output; bool zero_new_cam; bool zero_distortion; }; CV_UndistortTest::CV_UndistortTest() : CV_ImgWarpBaseTest( false ) { //spatial_scale_zoom = spatial_scale_decimate; test_array[INPUT].push_back(NULL); test_array[INPUT].push_back(NULL); test_array[INPUT].push_back(NULL); spatial_scale_decimate = spatial_scale_zoom; } void CV_UndistortTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) { RNG& rng = ts->get_rng(); CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); int type = types[INPUT][0]; type = CV_MAKETYPE( CV_8U, CV_MAT_CN(type) ); types[INPUT][0] = types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = type; types[INPUT][1] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F; types[INPUT][2] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F; sizes[INPUT][1] = cvSize(3,3); sizes[INPUT][2] = cvtest::randInt(rng)%2 ? cvSize(4,1) : cvSize(1,4); types[INPUT][3] = types[INPUT][1]; sizes[INPUT][3] = sizes[INPUT][1]; interpolation = CV_INTER_LINEAR; } void CV_UndistortTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) { if( i != INPUT ) CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr ); } void CV_UndistortTest::run_func() { if (!useCPlus) { CvMat a = test_mat[INPUT][1], k = test_mat[INPUT][2]; cvUndistort2( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &a, &k); } else { if (zero_distortion) { cv::undistort(input0,input_output,input1,cv::Mat()); } else { cv::undistort(input0,input_output,input1,input2); } } } double CV_UndistortTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) { int depth = test_mat[INPUT][0].depth(); return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2; } int CV_UndistortTest::prepare_test_case( int test_case_idx ) { RNG& rng = ts->get_rng(); int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); const Mat& src = test_mat[INPUT][0]; double k[4], a[9] = {0,0,0,0,0,0,0,0,1}; double new_cam[9] = {0,0,0,0,0,0,0,0,1}; double sz = MAX(src.rows, src.cols); Mat& _new_cam0 = test_mat[INPUT][3]; Mat _new_cam(test_mat[INPUT][3].rows,test_mat[INPUT][3].cols,CV_64F,new_cam); Mat& _a0 = test_mat[INPUT][1]; Mat _a(3,3,CV_64F,a); Mat& _k0 = test_mat[INPUT][2]; Mat _k(_k0.rows,_k0.cols, CV_MAKETYPE(CV_64F,_k0.channels()),k); if( code <= 0 ) return code; double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7; a[2] = (src.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5; a[5] = (src.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5; a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6); a[4] = aspect_ratio*a[0]; k[0] = cvtest::randReal(rng)*0.06 - 0.03; k[1] = cvtest::randReal(rng)*0.06 - 0.03; if( k[0]*k[1] > 0 ) k[1] = -k[1]; if( cvtest::randInt(rng)%4 != 0 ) { k[2] = cvtest::randReal(rng)*0.004 - 0.002; k[3] = cvtest::randReal(rng)*0.004 - 0.002; } else k[2] = k[3] = 0; new_cam[0] = a[0] + (cvtest::randReal(rng) - (double)0.5)*0.2*a[0]; //10% new_cam[4] = a[4] + (cvtest::randReal(rng) - (double)0.5)*0.2*a[4]; //10% new_cam[2] = a[2] + (cvtest::randReal(rng) - (double)0.5)*0.3*test_mat[INPUT][0].rows; //15% new_cam[5] = a[5] + (cvtest::randReal(rng) - (double)0.5)*0.3*test_mat[INPUT][0].cols; //15% _a.convertTo(_a0, _a0.depth()); zero_distortion = (cvtest::randInt(rng)%2) == 0 ? false : true; _k.convertTo(_k0, _k0.depth()); zero_new_cam = (cvtest::randInt(rng)%2) == 0 ? false : true; _new_cam.convertTo(_new_cam0, _new_cam0.depth()); //Testing C++ code useCPlus = ((cvtest::randInt(rng) % 2)!=0); if (useCPlus) { input0 = test_mat[INPUT][0]; input1 = test_mat[INPUT][1]; input2 = test_mat[INPUT][2]; input_new_cam = test_mat[INPUT][3]; } return code; } void CV_UndistortTest::prepare_to_validation( int /*test_case_idx*/ ) { if (useCPlus) { Mat& output = test_mat[INPUT_OUTPUT][0]; input_output.convertTo(output, output.type()); } Mat& src = test_mat[INPUT][0]; Mat& dst = test_mat[REF_INPUT_OUTPUT][0]; Mat& dst0 = test_mat[INPUT_OUTPUT][0]; Mat mapx, mapy; cvtest::initUndistortMap( test_mat[INPUT][1], test_mat[INPUT][2], dst.size(), mapx, mapy ); Mat mask( dst.size(), CV_8U ); test_remap( src, dst, mapx, mapy, &mask, interpolation ); dst.setTo(Scalar::all(0), mask); dst0.setTo(Scalar::all(0), mask); } class CV_UndistortMapTest : public cvtest::ArrayTest { public: CV_UndistortMapTest(); protected: void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); void run_func(); int prepare_test_case( int test_case_idx ); void prepare_to_validation( int /*test_case_idx*/ ); double get_success_error_level( int test_case_idx, int i, int j ); void fill_array( int test_case_idx, int i, int j, Mat& arr ); private: bool dualChannel; }; CV_UndistortMapTest::CV_UndistortMapTest() { test_array[INPUT].push_back(NULL); test_array[INPUT].push_back(NULL); test_array[OUTPUT].push_back(NULL); test_array[OUTPUT].push_back(NULL); test_array[REF_OUTPUT].push_back(NULL); test_array[REF_OUTPUT].push_back(NULL); element_wise_relative_error = false; } void CV_UndistortMapTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) { RNG& rng = ts->get_rng(); cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); int depth = cvtest::randInt(rng)%2 ? CV_64F : CV_32F; CvSize sz = sizes[OUTPUT][0]; types[INPUT][0] = types[INPUT][1] = depth; dualChannel = cvtest::randInt(rng)%2 == 0; types[OUTPUT][0] = types[OUTPUT][1] = types[REF_OUTPUT][0] = types[REF_OUTPUT][1] = dualChannel ? CV_32FC2 : CV_32F; sizes[INPUT][0] = cvSize(3,3); sizes[INPUT][1] = cvtest::randInt(rng)%2 ? cvSize(4,1) : cvSize(1,4); sz.width = MAX(sz.width,16); sz.height = MAX(sz.height,16); sizes[OUTPUT][0] = sizes[OUTPUT][1] = sizes[REF_OUTPUT][0] = sizes[REF_OUTPUT][1] = sz; } void CV_UndistortMapTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) { if( i != INPUT ) cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr ); } void CV_UndistortMapTest::run_func() { CvMat a = test_mat[INPUT][0], k = test_mat[INPUT][1]; if (!dualChannel ) cvInitUndistortMap( &a, &k, test_array[OUTPUT][0], test_array[OUTPUT][1] ); else cvInitUndistortMap( &a, &k, test_array[OUTPUT][0], 0 ); } double CV_UndistortMapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) { return 1e-3; } int CV_UndistortMapTest::prepare_test_case( int test_case_idx ) { RNG& rng = ts->get_rng(); int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); const Mat& mapx = test_mat[OUTPUT][0]; double k[4], a[9] = {0,0,0,0,0,0,0,0,1}; double sz = MAX(mapx.rows, mapx.cols); Mat& _a0 = test_mat[INPUT][0], &_k0 = test_mat[INPUT][1]; Mat _a(3,3,CV_64F,a); Mat _k(_k0.rows,_k0.cols, CV_MAKETYPE(CV_64F,_k0.channels()),k); if( code <= 0 ) return code; double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7; a[2] = (mapx.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5; a[5] = (mapx.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5; a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6); a[4] = aspect_ratio*a[0]; k[0] = cvtest::randReal(rng)*0.06 - 0.03; k[1] = cvtest::randReal(rng)*0.06 - 0.03; if( k[0]*k[1] > 0 ) k[1] = -k[1]; k[2] = cvtest::randReal(rng)*0.004 - 0.002; k[3] = cvtest::randReal(rng)*0.004 - 0.002; _a.convertTo(_a0, _a0.depth()); _k.convertTo(_k0, _k0.depth()); if (dualChannel) { test_mat[REF_OUTPUT][1] = Scalar::all(0); test_mat[OUTPUT][1] = Scalar::all(0); } return code; } void CV_UndistortMapTest::prepare_to_validation( int ) { Mat mapx, mapy; cvtest::initUndistortMap( test_mat[INPUT][0], test_mat[INPUT][1], test_mat[REF_OUTPUT][0].size(), mapx, mapy ); if( !dualChannel ) { mapx.copyTo(test_mat[REF_OUTPUT][0]); mapy.copyTo(test_mat[REF_OUTPUT][1]); } else { Mat p[2] = {mapx, mapy}; cv::merge(p, 2, test_mat[REF_OUTPUT][0]); } } ////////////////////////////// GetRectSubPix ///////////////////////////////// static void test_getQuadrangeSubPix( const Mat& src, Mat& dst, double* a ) { int sstep = (int)(src.step / sizeof(float)); int scols = src.cols, srows = src.rows; CV_Assert( src.depth() == CV_32F && src.type() == dst.type() ); int cn = dst.channels(); for( int y = 0; y < dst.rows; y++ ) for( int x = 0; x < dst.cols; x++ ) { float* d = dst.ptr(y) + x*cn; float sx = (float)(a[0]*x + a[1]*y + a[2]); float sy = (float)(a[3]*x + a[4]*y + a[5]); int ix = cvFloor(sx), iy = cvFloor(sy); int dx = cn, dy = sstep; const float* s; sx -= ix; sy -= iy; if( (unsigned)ix >= (unsigned)(scols-1) ) ix = ix < 0 ? 0 : scols - 1, sx = 0, dx = 0; if( (unsigned)iy >= (unsigned)(srows-1) ) iy = iy < 0 ? 0 : srows - 1, sy = 0, dy = 0; s = src.ptr(iy) + ix*cn; for( int k = 0; k < cn; k++, s++ ) { float t0 = s[0] + sx*(s[dx] - s[0]); float t1 = s[dy] + sx*(s[dy + dx] - s[dy]); d[k] = t0 + sy*(t1 - t0); } } } class CV_GetRectSubPixTest : public CV_ImgWarpBaseTest { public: CV_GetRectSubPixTest(); protected: void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); void run_func(); int prepare_test_case( int test_case_idx ); void prepare_to_validation( int /*test_case_idx*/ ); double get_success_error_level( int test_case_idx, int i, int j ); void fill_array( int test_case_idx, int i, int j, Mat& arr ); CvPoint2D32f center; bool test_cpp; }; CV_GetRectSubPixTest::CV_GetRectSubPixTest() : CV_ImgWarpBaseTest( false ) { //spatial_scale_zoom = spatial_scale_decimate; spatial_scale_decimate = spatial_scale_zoom; test_cpp = false; } void CV_GetRectSubPixTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) { RNG& rng = ts->get_rng(); CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); int src_depth = cvtest::randInt(rng) % 2, dst_depth; int cn = cvtest::randInt(rng) % 2 ? 3 : 1; CvSize src_size, dst_size; dst_depth = src_depth = src_depth == 0 ? CV_8U : CV_32F; if( src_depth < CV_32F && cvtest::randInt(rng) % 2 ) dst_depth = CV_32F; types[INPUT][0] = CV_MAKETYPE(src_depth,cn); types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(dst_depth,cn); src_size = sizes[INPUT][0]; dst_size.width = cvRound(sqrt(cvtest::randReal(rng)*src_size.width) + 1); dst_size.height = cvRound(sqrt(cvtest::randReal(rng)*src_size.height) + 1); dst_size.width = MIN(dst_size.width,src_size.width); dst_size.height = MIN(dst_size.width,src_size.height); sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = dst_size; center.x = (float)(cvtest::randReal(rng)*src_size.width); center.y = (float)(cvtest::randReal(rng)*src_size.height); interpolation = CV_INTER_LINEAR; test_cpp = (cvtest::randInt(rng) & 256) == 0; } void CV_GetRectSubPixTest::fill_array( int test_case_idx, int i, int j, Mat& arr ) { if( i != INPUT ) CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr ); } void CV_GetRectSubPixTest::run_func() { if(!test_cpp) cvGetRectSubPix( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], center ); else { cv::Mat _out = cv::cvarrToMat(test_array[INPUT_OUTPUT][0]); cv::getRectSubPix( cv::cvarrToMat(test_array[INPUT][0]), _out.size(), center, _out, _out.type()); } } double CV_GetRectSubPixTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) { int in_depth = test_mat[INPUT][0].depth(); int out_depth = test_mat[INPUT_OUTPUT][0].depth(); return in_depth >= CV_32F ? 1e-3 : out_depth >= CV_32F ? 1e-2 : 1; } int CV_GetRectSubPixTest::prepare_test_case( int test_case_idx ) { return CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); } void CV_GetRectSubPixTest::prepare_to_validation( int /*test_case_idx*/ ) { Mat& src0 = test_mat[INPUT][0]; Mat& dst0 = test_mat[REF_INPUT_OUTPUT][0]; Mat src = src0, dst = dst0; int ftype = CV_MAKETYPE(CV_32F,src0.channels()); double a[] = { 1, 0, center.x - dst.cols*0.5 + 0.5, 0, 1, center.y - dst.rows*0.5 + 0.5 }; if( src.depth() != CV_32F ) src0.convertTo(src, CV_32F); if( dst.depth() != CV_32F ) dst.create(dst0.size(), ftype); test_getQuadrangeSubPix( src, dst, a ); if( dst.data != dst0.data ) dst.convertTo(dst0, dst0.depth()); } class CV_GetQuadSubPixTest : public CV_ImgWarpBaseTest { public: CV_GetQuadSubPixTest(); protected: void get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ); void run_func(); int prepare_test_case( int test_case_idx ); void prepare_to_validation( int /*test_case_idx*/ ); double get_success_error_level( int test_case_idx, int i, int j ); }; CV_GetQuadSubPixTest::CV_GetQuadSubPixTest() : CV_ImgWarpBaseTest( true ) { //spatial_scale_zoom = spatial_scale_decimate; spatial_scale_decimate = spatial_scale_zoom; } void CV_GetQuadSubPixTest::get_test_array_types_and_sizes( int test_case_idx, vector >& sizes, vector >& types ) { int min_size = 4; CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); CvSize sz = sizes[INPUT][0], dsz; RNG& rng = ts->get_rng(); int msz, src_depth = cvtest::randInt(rng) % 2, dst_depth; int cn = cvtest::randInt(rng) % 2 ? 3 : 1; dst_depth = src_depth = src_depth == 0 ? CV_8U : CV_32F; if( src_depth < CV_32F && cvtest::randInt(rng) % 2 ) dst_depth = CV_32F; types[INPUT][0] = CV_MAKETYPE(src_depth,cn); types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(dst_depth,cn); sz.width = MAX(sz.width,min_size); sz.height = MAX(sz.height,min_size); sizes[INPUT][0] = sz; msz = MIN( sz.width, sz.height ); dsz.width = cvRound(sqrt(cvtest::randReal(rng)*msz) + 1); dsz.height = cvRound(sqrt(cvtest::randReal(rng)*msz) + 1); dsz.width = MIN(dsz.width,msz); dsz.height = MIN(dsz.width,msz); dsz.width = MAX(dsz.width,min_size); dsz.height = MAX(dsz.height,min_size); sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = dsz; sizes[INPUT][1] = cvSize( 3, 2 ); } void CV_GetQuadSubPixTest::run_func() { CvMat mtx = test_mat[INPUT][1]; cvGetQuadrangleSubPix( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx ); } double CV_GetQuadSubPixTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) { int in_depth = test_mat[INPUT][0].depth(); //int out_depth = test_mat[INPUT_OUTPUT][0].depth(); return in_depth >= CV_32F ? 1e-2 : 4; } int CV_GetQuadSubPixTest::prepare_test_case( int test_case_idx ) { RNG& rng = ts->get_rng(); int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx ); const Mat& src = test_mat[INPUT][0]; Mat& mat = test_mat[INPUT][1]; CvPoint2D32f center; double scale, angle; if( code <= 0 ) return code; double a[6]; Mat A( 2, 3, CV_64FC1, a ); center.x = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.cols); center.y = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.rows); angle = cvtest::randReal(rng)*360; scale = cvtest::randReal(rng)*0.2 + 0.9; // y = Ax + b -> x = A^-1(y - b) = A^-1*y - A^-1*b scale = 1./scale; angle = angle*(CV_PI/180.); a[0] = a[4] = cos(angle)*scale; a[1] = sin(angle)*scale; a[3] = -a[1]; a[2] = center.x - a[0]*center.x - a[1]*center.y; a[5] = center.y - a[3]*center.x - a[4]*center.y; A.convertTo( mat, mat.depth() ); return code; } void CV_GetQuadSubPixTest::prepare_to_validation( int /*test_case_idx*/ ) { Mat& src0 = test_mat[INPUT][0]; Mat& dst0 = test_mat[REF_INPUT_OUTPUT][0]; Mat src = src0, dst = dst0; int ftype = CV_MAKETYPE(CV_32F,src0.channels()); double a[6], dx = (dst0.cols - 1)*0.5, dy = (dst0.rows - 1)*0.5; Mat A( 2, 3, CV_64F, a ); if( src.depth() != CV_32F ) src0.convertTo(src, CV_32F); if( dst.depth() != CV_32F ) dst.create(dst0.size(), ftype); test_mat[INPUT][1].convertTo( A, CV_64F ); a[2] -= a[0]*dx + a[1]*dy; a[5] -= a[3]*dx + a[4]*dy; test_getQuadrangeSubPix( src, dst, a ); if( dst.data != dst0.data ) dst.convertTo(dst0, dst0.depth()); } ////////////////////////////////////////////////////////////////////////// TEST(Imgproc_Resize, accuracy) { CV_ResizeTest test; test.safe_run(); } TEST(Imgproc_WarpAffine, accuracy) { CV_WarpAffineTest test; test.safe_run(); } TEST(Imgproc_WarpPerspective, accuracy) { CV_WarpPerspectiveTest test; test.safe_run(); } TEST(Imgproc_Remap, accuracy) { CV_RemapTest test; test.safe_run(); } TEST(Imgproc_Undistort, accuracy) { CV_UndistortTest test; test.safe_run(); } TEST(Imgproc_InitUndistortMap, accuracy) { CV_UndistortMapTest test; test.safe_run(); } TEST(Imgproc_GetRectSubPix, accuracy) { CV_GetRectSubPixTest test; test.safe_run(); } TEST(Imgproc_GetQuadSubPix, accuracy) { CV_GetQuadSubPixTest test; test.safe_run(); } /* End of file. */