Updated warpAffine test to ensure bit-exactness for CV_8U (#10921)
authorVitaly Tuzov <terfendail@users.noreply.github.com>
Wed, 11 Apr 2018 15:08:29 +0000 (18:08 +0300)
committerVadim Pisarevsky <vadim.pisarevsky@gmail.com>
Wed, 11 Apr 2018 15:08:29 +0000 (18:08 +0300)
* Updated warpAffine test to ensure bit-exactness for CV_8U

* Updated invertAffineTransform to bit-exact evaluation

modules/imgproc/src/imgwarp.cpp
modules/imgproc/test/test_imgwarp_strict.cpp

index d793616..24af8e2 100644 (file)
@@ -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<double>();
@@ -3199,30 +3200,30 @@ void cv::invertAffineTransform(InputArray _matM, OutputArray __iM)
 
     if( matM.type() == CV_32F )
     {
-        const float* M = matM.ptr<float>();
-        float* iM = _iM.ptr<float>();
+        const softfloat* M = matM.ptr<softfloat>();
+        softfloat* iM = _iM.ptr<softfloat>();
         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>();
-        double* iM = _iM.ptr<double>();
+        const softdouble* M = matM.ptr<softdouble>();
+        softdouble* iM = _iM.ptr<softdouble>();
         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);
 
index cb3fee5..31869f1 100644 (file)
@@ -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<double>(0);
+    const softdouble* data_tM = tM.ptr<softdouble>(0);
     for (int dy = 0; dy < dsize.height; ++dy)
     {
         short* yM = mapx.ptr<short>(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)