From c80a168d9d339d1b418bccbdf0db07513d3832d2 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Wed, 11 Apr 2018 18:08:29 +0300 Subject: [PATCH] Updated warpAffine test to ensure bit-exactness for CV_8U (#10921) * Updated warpAffine test to ensure bit-exactness for CV_8U * Updated invertAffineTransform to bit-exact evaluation --- modules/imgproc/src/imgwarp.cpp | 47 +++++++++--------- modules/imgproc/test/test_imgwarp_strict.cpp | 51 ++++++++++++-------- 2 files changed, 56 insertions(+), 42 deletions(-) diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp index d793616cfc..24af8e2b66 100644 --- a/modules/imgproc/src/imgwarp.cpp +++ b/modules/imgproc/src/imgwarp.cpp @@ -52,6 +52,7 @@ #include "hal_replacement.hpp" #include "opencv2/core/openvx/ovx_defs.hpp" +#include "opencv2/core/softfloat.hpp" #include "imgwarp.hpp" using namespace cv; @@ -172,7 +173,7 @@ static inline void interpolateLanczos4( float x, float* coeffs ) } float sum = 0; - double y0=-(x+3)*CV_PI*0.25, s0 = sin(y0), c0=cos(y0); + double y0=-(x+3)*CV_PI*0.25, s0 = std::sin(y0), c0= std::cos(y0); for(int i = 0; i < 8; i++ ) { double y = -(x+3-i)*CV_PI*0.25; @@ -3079,8 +3080,8 @@ cv::Mat cv::getRotationMatrix2D( Point2f center, double angle, double scale ) CV_INSTRUMENT_REGION() angle *= CV_PI/180; - double alpha = cos(angle)*scale; - double beta = sin(angle)*scale; + double alpha = std::cos(angle)*scale; + double beta = std::sin(angle)*scale; Mat M(2, 3, CV_64F); double* m = M.ptr(); @@ -3199,30 +3200,30 @@ void cv::invertAffineTransform(InputArray _matM, OutputArray __iM) if( matM.type() == CV_32F ) { - const float* M = matM.ptr(); - float* iM = _iM.ptr(); + const softfloat* M = matM.ptr(); + softfloat* iM = _iM.ptr(); int step = (int)(matM.step/sizeof(M[0])), istep = (int)(_iM.step/sizeof(iM[0])); - double D = M[0]*M[step+1] - M[1]*M[step]; - D = D != 0 ? 1./D : 0; - double A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D; - double b1 = -A11*M[2] - A12*M[step+2]; - double b2 = -A21*M[2] - A22*M[step+2]; + softdouble D = M[0]*M[step+1] - M[1]*M[step]; + D = D != 0. ? softdouble(1.)/D : softdouble(0.); + softdouble A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D; + softdouble b1 = -A11*M[2] - A12*M[step+2]; + softdouble b2 = -A21*M[2] - A22*M[step+2]; - iM[0] = (float)A11; iM[1] = (float)A12; iM[2] = (float)b1; - iM[istep] = (float)A21; iM[istep+1] = (float)A22; iM[istep+2] = (float)b2; + iM[0] = A11; iM[1] = A12; iM[2] = b1; + iM[istep] = A21; iM[istep+1] = A22; iM[istep+2] = b2; } else if( matM.type() == CV_64F ) { - const double* M = matM.ptr(); - double* iM = _iM.ptr(); + const softdouble* M = matM.ptr(); + softdouble* iM = _iM.ptr(); int step = (int)(matM.step/sizeof(M[0])), istep = (int)(_iM.step/sizeof(iM[0])); - double D = M[0]*M[step+1] - M[1]*M[step]; - D = D != 0 ? 1./D : 0; - double A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D; - double b1 = -A11*M[2] - A12*M[step+2]; - double b2 = -A21*M[2] - A22*M[step+2]; + softdouble D = M[0]*M[step+1] - M[1]*M[step]; + D = D != 0. ? softdouble(1.)/D : softdouble(0.); + softdouble A11 = M[step+1]*D, A22 = M[0]*D, A12 = -M[1]*D, A21 = -M[step]*D; + softdouble b1 = -A11*M[2] - A12*M[step+2]; + softdouble b2 = -A21*M[2] - A22*M[step+2]; iM[0] = A11; iM[1] = A12; iM[2] = b1; iM[istep] = A21; iM[istep+1] = A22; iM[istep+2] = b2; @@ -3497,8 +3498,8 @@ void cv::logPolar( InputArray _src, OutputArray _dst, for (phi = 0; phi < dsize.height; phi++) { - double cp = cos(phi * 2 * CV_PI / dsize.height); - double sp = sin(phi * 2 * CV_PI / dsize.height); + double cp = std::cos(phi * 2 * CV_PI / dsize.height); + double sp = std::sin(phi * 2 * CV_PI / dsize.height); float* mx = (float*)(mapx.data + phi*mapx.step); float* my = (float*)(mapy.data + phi*mapy.step); @@ -3699,8 +3700,8 @@ void cv::linearPolar( InputArray _src, OutputArray _dst, for (phi = 0; phi < dsize.height; phi++) { - double cp = cos(phi * 2 * CV_PI / dsize.height); - double sp = sin(phi * 2 * CV_PI / dsize.height); + double cp = std::cos(phi * 2 * CV_PI / dsize.height); + double sp = std::sin(phi * 2 * CV_PI / dsize.height); float* mx = (float*)(mapx.data + phi*mapx.step); float* my = (float*)(mapy.data + phi*mapy.step); diff --git a/modules/imgproc/test/test_imgwarp_strict.cpp b/modules/imgproc/test/test_imgwarp_strict.cpp index cb3fee5c11..31869f1d75 100644 --- a/modules/imgproc/test/test_imgwarp_strict.cpp +++ b/modules/imgproc/test/test_imgwarp_strict.cpp @@ -77,6 +77,7 @@ protected: virtual void run_func() = 0; virtual void run_reference_func() = 0; + virtual float get_success_error_level(int _interpolation, int _depth) const; virtual void validate_results() const; virtual void prepare_test_data_for_reference_func(); @@ -229,6 +230,20 @@ void CV_ImageWarpBaseTest::run(int) ts->set_gtest_status(); } +float CV_ImageWarpBaseTest::get_success_error_level(int _interpolation, int) const +{ + if (_interpolation == INTER_CUBIC) + return 1.0f; + else if (_interpolation == INTER_LANCZOS4) + return 1.0f; + else if (_interpolation == INTER_NEAREST) + return 1.0f; + else if (_interpolation == INTER_AREA) + return 2.0f; + else + return 1.0f; +} + void CV_ImageWarpBaseTest::validate_results() const { Mat _dst; @@ -237,15 +252,7 @@ void CV_ImageWarpBaseTest::validate_results() const Size dsize = dst.size(), ssize = src.size(); int cn = _dst.channels(); dsize.width *= cn; - float t = 1.0f; - if (interpolation == INTER_CUBIC) - t = 1.0f; - else if (interpolation == INTER_LANCZOS4) - t = 1.0f; - else if (interpolation == INTER_NEAREST) - t = 1.0f; - else if (interpolation == INTER_AREA) - t = 2.0f; + float t = get_success_error_level(interpolation & INTER_MAX, dst.depth()); for (int dy = 0; dy < dsize.height; ++dy) { @@ -1034,7 +1041,7 @@ public: protected: virtual void generate_test_data(); - virtual void prepare_test_data_for_reference_func(); + virtual float get_success_error_level(int _interpolation, int _depth) const; virtual void run_func(); virtual void run_reference_func(); @@ -1083,16 +1090,16 @@ void CV_WarpAffine_Test::run_func() cv::warpAffine(src, dst, M, dst.size(), interpolation, borderType, borderValue); } -void CV_WarpAffine_Test::prepare_test_data_for_reference_func() +float CV_WarpAffine_Test::get_success_error_level(int _interpolation, int _depth) const { - CV_ImageWarpBaseTest::prepare_test_data_for_reference_func(); + return _depth == CV_8U ? 0 : CV_ImageWarpBaseTest::get_success_error_level(_interpolation, _depth); } void CV_WarpAffine_Test::run_reference_func() { - prepare_test_data_for_reference_func(); - - warpAffine(src, reference_dst); + Mat tmp = Mat::zeros(dst.size(), dst.type()); + warpAffine(src, tmp); + tmp.convertTo(reference_dst, reference_dst.depth()); } void CV_WarpAffine_Test::warpAffine(const Mat& _src, Mat& _dst) @@ -1123,7 +1130,7 @@ void CV_WarpAffine_Test::warpAffine(const Mat& _src, Mat& _dst) const int AB_SCALE = 1 << AB_BITS; int round_delta = (inter == INTER_NEAREST) ? AB_SCALE / 2 : (AB_SCALE / INTER_TAB_SIZE / 2); - const double* data_tM = tM.ptr(0); + const softdouble* data_tM = tM.ptr(0); for (int dy = 0; dy < dsize.height; ++dy) { short* yM = mapx.ptr(dy); @@ -1162,6 +1169,7 @@ public: protected: virtual void generate_test_data(); + virtual float get_success_error_level(int _interpolation, int _depth) const; virtual void run_func(); virtual void run_reference_func(); @@ -1204,11 +1212,16 @@ void CV_WarpPerspective_Test::run_func() cv::warpPerspective(src, dst, M, dst.size(), interpolation, borderType, borderValue); } -void CV_WarpPerspective_Test::run_reference_func() +float CV_WarpPerspective_Test::get_success_error_level(int _interpolation, int _depth) const { - prepare_test_data_for_reference_func(); + return CV_ImageWarpBaseTest::get_success_error_level(_interpolation, _depth); +} - warpPerspective(src, reference_dst); +void CV_WarpPerspective_Test::run_reference_func() +{ + Mat tmp = Mat::zeros(dst.size(), dst.type()); + warpPerspective(src, tmp); + tmp.convertTo(reference_dst, reference_dst.depth()); } void CV_WarpPerspective_Test::warpPerspective(const Mat& _src, Mat& _dst)