diff --git a/modules/calib3d/test/test_cameracalibration.cpp b/modules/calib3d/test/test_cameracalibration.cpp index 523594224d..55618c27e4 100644 --- a/modules/calib3d/test/test_cameracalibration.cpp +++ b/modules/calib3d/test/test_cameracalibration.cpp @@ -1701,9 +1701,10 @@ void CV_StereoCalibrationTest::run( int ) const float minCoord = -300.0f; const float maxCoord = 300.0f; const float minDisparity = 0.1f; - const float maxDisparity = 600.0f; + const float maxDisparity = 60.0f; const int pointsCount = 500; const float requiredAccuracy = 1e-3f; + const float allowToFail = 0.2f; // 20% RNG& rng = ts->get_rng(); Mat projectedPoints_1(2, pointsCount, CV_32FC1); @@ -1732,9 +1733,29 @@ void CV_StereoCalibrationTest::run( int ) Mat reprojectedPoints; perspectiveTransform(sparsePoints, reprojectedPoints, Q); - if (cvtest::norm(triangulatedPoints, reprojectedPoints, NORM_L2) / sqrt((double)pointsCount) > requiredAccuracy) + Mat diff; + absdiff(triangulatedPoints, reprojectedPoints, diff); + Mat mask = diff > requiredAccuracy; + mask = mask.reshape(1); + mask = mask.col(0) | mask.col(1) | mask.col(2); + int numFailed = countNonZero(mask); +#if 0 + std::cout << "numFailed=" << numFailed << std::endl; + for (int i = 0; i < triangulatedPoints.rows; i++) { - ts->printf( cvtest::TS::LOG, "Points reprojected with a matrix Q and points reconstructed by triangulation are different, testcase %d\n", testcase); + if (mask.at(i)) + { + // failed points usually have 'w'~0 (points4d[3]) + std::cout << "i=" << i << " triangulatePoints=" << triangulatedPoints.row(i) << " reprojectedPoints=" << reprojectedPoints.row(i) << std::endl << + " points4d=" << points4d.col(i).t() << " projectedPoints_1=" << projectedPoints_1.col(i).t() << " disparities=" << disparities.col(i).t() << std::endl; + } + } +#endif + + if (numFailed >= allowToFail * pointsCount) + { + ts->printf( cvtest::TS::LOG, "Points reprojected with a matrix Q and points reconstructed by triangulation are different (tolerance=%g, failed=%d), testcase %d\n", + requiredAccuracy, numFailed, testcase); ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT ); } diff --git a/modules/calib3d/test/test_solvepnp_ransac.cpp b/modules/calib3d/test/test_solvepnp_ransac.cpp index 4efdc79902..e6e9b6b22f 100644 --- a/modules/calib3d/test/test_solvepnp_ransac.cpp +++ b/modules/calib3d/test/test_solvepnp_ransac.cpp @@ -322,10 +322,12 @@ TEST(Calib3d_SolvePnPRansac, input_type) std::vector points3d; std::vector points2d; - for (int i = 0; i < numPoints; i++) + for (int i = 0; i < numPoints; i+=2) { - points3d.push_back(cv::Point3i(i, 0, 0)); - points2d.push_back(cv::Point2i(i, 0)); + points3d.push_back(cv::Point3i(5+i, 3, 2)); + points3d.push_back(cv::Point3i(5+i, 3+i, 2+i)); + points2d.push_back(cv::Point2i(0, i)); + points2d.push_back(cv::Point2i(-i, i)); } Mat R1, t1, R2, t2, R3, t3, R4, t4; @@ -359,12 +361,16 @@ TEST(Calib3d_SolvePnP, double_support) std::vector points2d; std::vector points3dF; std::vector points2dF; - for (int i = 0; i < 10 ; i++) + for (int i = 0; i < 10 ; i+=2) { - points3d.push_back(cv::Point3d(i,0,0)); - points3dF.push_back(cv::Point3d(i,0,0)); - points2d.push_back(cv::Point2d(i,0)); - points2dF.push_back(cv::Point2d(i,0)); + points3d.push_back(cv::Point3d(5+i, 3, 2)); + points3dF.push_back(cv::Point3d(5+i, 3, 2)); + points3d.push_back(cv::Point3d(5+i, 3+i, 2+i)); + points3dF.push_back(cv::Point3d(5+i, 3+i, 2+i)); + points2d.push_back(cv::Point2d(0, i)); + points2dF.push_back(cv::Point2d(0, i)); + points2d.push_back(cv::Point2d(-i, i)); + points2dF.push_back(cv::Point2d(-i, i)); } Mat R,t, RF, tF; vector inliers; diff --git a/modules/core/perf/opencl/perf_arithm.cpp b/modules/core/perf/opencl/perf_arithm.cpp index 9cb5ac9821..3efccb07a8 100644 --- a/modules/core/perf/opencl/perf_arithm.cpp +++ b/modules/core/perf/opencl/perf_arithm.cpp @@ -91,7 +91,10 @@ OCL_PERF_TEST_P(ExpFixture, Exp, ::testing::Combine( OCL_TEST_CYCLE() cv::exp(src, dst); - SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); + if (CV_MAT_DEPTH(type) >= CV_32F) + SANITY_CHECK(dst, 1e-5, ERROR_RELATIVE); + else + SANITY_CHECK(dst, 1); } ///////////// Log //////////////////////// @@ -113,7 +116,10 @@ OCL_PERF_TEST_P(LogFixture, Log, ::testing::Combine( OCL_TEST_CYCLE() cv::log(src, dst); - SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); + if (CV_MAT_DEPTH(type) >= CV_32F) + SANITY_CHECK(dst, 1e-5, ERROR_RELATIVE); + else + SANITY_CHECK(dst, 1); } ///////////// Add //////////////////////// @@ -193,9 +199,21 @@ OCL_PERF_TEST_P(DivFixture, Divide, UMat src1(srcSize, type), src2(srcSize, type), dst(srcSize, type); declare.in(src1, src2, WARMUP_RNG).out(dst); + // remove zeros from src2 + { + Mat m2 = src2.getMat(ACCESS_RW); + Mat zero_mask = m2 == 0; + Mat fix; + zero_mask.convertTo(fix, type); // 0 or 255 + cv::add(m2, fix, m2); + } + OCL_TEST_CYCLE() cv::divide(src1, src2, dst); - SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); + if (CV_MAT_DEPTH(type) >= CV_32F) + SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); + else + SANITY_CHECK(dst, 1); } ///////////// Absdiff //////////////////////// @@ -660,7 +678,10 @@ OCL_PERF_TEST_P(SqrtFixture, Sqrt, ::testing::Combine( OCL_TEST_CYCLE() cv::sqrt(src, dst); - SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); + if (CV_MAT_DEPTH(type) >= CV_32F) + SANITY_CHECK(dst, 1e-5, ERROR_RELATIVE); + else + SANITY_CHECK(dst, 1); } ///////////// SetIdentity //////////////////////// @@ -983,7 +1004,7 @@ OCL_PERF_TEST_P(ConvertScaleAbsFixture, ConvertScaleAbs, OCL_TEST_CYCLE() cv::convertScaleAbs(src, dst, 0.5, 2); - SANITY_CHECK(dst); + SANITY_CHECK(dst, 1); // CV_8U } ///////////// PatchNaNs //////////////////////// diff --git a/modules/core/perf/perf_convertTo.cpp b/modules/core/perf/perf_convertTo.cpp index 8007361228..3738e32f76 100644 --- a/modules/core/perf/perf_convertTo.cpp +++ b/modules/core/perf/perf_convertTo.cpp @@ -26,12 +26,16 @@ PERF_TEST_P( Size_DepthSrc_DepthDst_Channels_alpha, convertTo, int channels = get<3>(GetParam()); double alpha = get<4>(GetParam()); + int maxValue = 255; + Mat src(sz, CV_MAKETYPE(depthSrc, channels)); - randu(src, 0, 255); + randu(src, 0, maxValue); Mat dst(sz, CV_MAKETYPE(depthDst, channels)); int runs = (sz.width <= 640) ? 8 : 1; TEST_CYCLE_MULTIRUN(runs) src.convertTo(dst, depthDst, alpha); - SANITY_CHECK(dst, alpha == 1.0 ? 1e-12 : 1e-7); + double eps = depthSrc <= CV_32S ? 1e-12 : (FLT_EPSILON * maxValue); + eps = eps * std::max(1.0, fabs(alpha)); + SANITY_CHECK(dst, eps); } diff --git a/modules/core/perf/perf_merge.cpp b/modules/core/perf/perf_merge.cpp index e7e8d2fe3f..6af7feeb41 100644 --- a/modules/core/perf/perf_merge.cpp +++ b/modules/core/perf/perf_merge.cpp @@ -22,16 +22,19 @@ PERF_TEST_P( Size_SrcDepth_DstChannels, merge, int srcDepth = get<1>(GetParam()); int dstChannels = get<2>(GetParam()); + int maxValue = 255; + vector mv; for( int i = 0; i < dstChannels; ++i ) { mv.push_back( Mat(sz, CV_MAKETYPE(srcDepth, 1)) ); - randu(mv[i], 0, 255); + randu(mv[i], 0, maxValue); } Mat dst; int runs = (sz.width <= 640) ? 8 : 1; TEST_CYCLE_MULTIRUN(runs) merge( (vector &)mv, dst ); - SANITY_CHECK(dst, 1e-12); + double eps = srcDepth <= CV_32S ? 1e-12 : (FLT_EPSILON * maxValue); + SANITY_CHECK(dst, eps); } diff --git a/modules/imgproc/perf/perf_houghLines.cpp b/modules/imgproc/perf/perf_houghLines.cpp index a6ab50e644..96575eca53 100644 --- a/modules/imgproc/perf/perf_houghLines.cpp +++ b/modules/imgproc/perf/perf_houghLines.cpp @@ -8,7 +8,7 @@ using namespace perf; using std::tr1::make_tuple; using std::tr1::get; -typedef std::tr1::tuple Image_RhoStep_ThetaStep_Threshold_t; +typedef std::tr1::tuple Image_RhoStep_ThetaStep_Threshold_t; typedef perf::TestBaseWithParam Image_RhoStep_ThetaStep_Threshold; PERF_TEST_P(Image_RhoStep_ThetaStep_Threshold, HoughLines, @@ -16,30 +16,58 @@ PERF_TEST_P(Image_RhoStep_ThetaStep_Threshold, HoughLines, testing::Values( "cv/shared/pic5.png", "stitching/a1.png" ), testing::Values( 1, 10 ), testing::Values( 0.01, 0.1 ), - testing::Values( 300, 500 ) + testing::Values( 0.5, 1.1 ) ) ) { string filename = getDataPath(get<0>(GetParam())); double rhoStep = get<1>(GetParam()); double thetaStep = get<2>(GetParam()); - int threshold = get<3>(GetParam()); + double threshold_ratio = get<3>(GetParam()); Mat image = imread(filename, IMREAD_GRAYSCALE); if (image.empty()) FAIL() << "Unable to load source image" << filename; - Canny(image, image, 0, 0); + Canny(image, image, 32, 128); - Mat lines; + // add some syntetic lines: + line(image, Point(0, 0), Point(image.cols, image.rows), Scalar::all(255), 3); + line(image, Point(image.cols, 0), Point(image.cols/2, image.rows), Scalar::all(255), 3); + + vector lines; declare.time(60); + int threshold = (int)(std::min(image.cols, image.rows) * threshold_ratio); + TEST_CYCLE() HoughLines(image, lines, rhoStep, thetaStep, threshold); - transpose(lines, lines); -#if (0 && defined(HAVE_IPP) && IPP_VERSION_X100 >= 810) - SANITY_CHECK_NOTHING(); -#else - SANITY_CHECK(lines); + printf("%dx%d: %d lines\n", image.cols, image.rows, (int)lines.size()); + + if (threshold_ratio < 1.0) + { + EXPECT_GE(lines.size(), 2u); + } + + EXPECT_LT(lines.size(), 3000u); + +#if 0 + cv::cvtColor(image,image,cv::COLOR_GRAY2BGR); + for( size_t i = 0; i < lines.size(); i++ ) + { + float rho = lines[i][0], theta = lines[i][1]; + Point pt1, pt2; + double a = cos(theta), b = sin(theta); + double x0 = a*rho, y0 = b*rho; + pt1.x = cvRound(x0 + 1000*(-b)); + pt1.y = cvRound(y0 + 1000*(a)); + pt2.x = cvRound(x0 - 1000*(-b)); + pt2.y = cvRound(y0 - 1000*(a)); + line(image, pt1, pt2, Scalar(0,0,255), 1, cv::LINE_AA); + } + cv::imshow("result", image); + cv::waitKey(); #endif + + SANITY_CHECK_NOTHING(); } diff --git a/modules/photo/test/test_decolor.cpp b/modules/photo/test/test_decolor.cpp index 259f7afd10..d7b620cff5 100644 --- a/modules/photo/test/test_decolor.cpp +++ b/modules/photo/test/test_decolor.cpp @@ -47,8 +47,6 @@ using namespace cv; using namespace std; -static const double numerical_precision = 10.; - TEST(Photo_Decolor, regression) { string folder = string(cvtest::TS::ptr()->get_data_path()) + "decolor/"; @@ -57,16 +55,16 @@ TEST(Photo_Decolor, regression) Mat original = imread(original_path, IMREAD_COLOR); ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path; - ASSERT_FALSE(original.channels()!=3) << "Load color input image " << original_path; + ASSERT_EQ(3, original.channels()) << "Load color input image " << original_path; Mat grayscale, color_boost; decolor(original, grayscale, color_boost); Mat reference_grayscale = imread(folder + "grayscale_reference.png", 0 /* == grayscale image*/); - double error_grayscale = cvtest::norm(reference_grayscale, grayscale, NORM_L1); - EXPECT_LE(error_grayscale, numerical_precision); + double gray_psnr = cvtest::PSNR(reference_grayscale, grayscale); + EXPECT_GT(gray_psnr, 60.0); Mat reference_boost = imread(folder + "boost_reference.png"); - double error_boost = cvtest::norm(reference_boost, color_boost, NORM_L1); - EXPECT_LE(error_boost, numerical_precision); + double boost_psnr = cvtest::PSNR(reference_boost, color_boost); + EXPECT_GT(boost_psnr, 60.0); } diff --git a/modules/ts/misc/run_suite.py b/modules/ts/misc/run_suite.py index 280c21caa6..bd80874475 100644 --- a/modules/ts/misc/run_suite.py +++ b/modules/ts/misc/run_suite.py @@ -85,8 +85,8 @@ class TestSuite(object): return set(res) def isTest(self, fullpath): - if fullpath == "java": - return True + if fullpath in ['java', 'python2', 'python3']: + return self.options.mode == 'test' if not os.path.isfile(fullpath): return False if self.cache.getOS() == "nt" and not fullpath.endswith(".exe"): @@ -102,6 +102,14 @@ class TestSuite(object): return res + cmd return cmd + def tryCommand(self, cmd): + try: + if 0 == execute(cmd, cwd = workingDir): + return True + except: + pass + return False + def runTest(self, path, logfile, workingDir, args = []): args = args[:] exe = os.path.abspath(path) @@ -109,6 +117,22 @@ class TestSuite(object): cmd = [self.cache.ant_executable, "-Dopencv.build.type=%s" % self.cache.build_type, "buildAndTest"] ret = execute(cmd, cwd = self.cache.java_test_binary_dir + "/.build") return None, ret + elif path in ['python2', 'python3']: + executable = os.getenv('OPENCV_PYTHON_BINARY', None) + if executable is None: + executable = path + if not self.tryCommand([executable, '--version']): + executable = 'python' + cmd = [executable, self.cache.opencv_home + '/modules/python/test/test.py', '--repo', self.cache.opencv_home, '-v'] + args + module_suffix = '' if not 'Visual Studio' in self.cache.cmake_generator else '/' + self.cache.build_type + env = {} + env['PYTHONPATH'] = self.cache.opencv_build + '/lib' + module_suffix + os.pathsep + os.getenv('PYTHONPATH', '') + if self.cache.getOS() == 'nt': + env['PATH'] = self.cache.opencv_build + '/bin' + module_suffix + os.pathsep + os.getenv('PATH', '') + else: + env['LD_LIBRARY_PATH'] = self.cache.opencv_build + '/bin' + os.pathsep + os.getenv('LD_LIBRARY_PATH', '') + ret = execute(cmd, cwd = workingDir, env = env) + return None, ret else: if isColorEnabled(args): args.append("--gtest_color=yes") @@ -140,12 +164,15 @@ class TestSuite(object): more_args = [] exe = self.getTest(test) - userlog = [a for a in args if a.startswith("--gtest_output=")] - if len(userlog) == 0: - logname = self.getLogName(exe, date) - more_args.append("--gtest_output=xml:" + logname) + if exe in ["java", "python2", "python3"]: + logname = None else: - logname = userlog[0][userlog[0].find(":")+1:] + userlog = [a for a in args if a.startswith("--gtest_output=")] + if len(userlog) == 0: + logname = self.getLogName(exe, date) + more_args.append("--gtest_output=xml:" + logname) + else: + logname = userlog[0][userlog[0].find(":")+1:] log.debug("Running the test: %s (%s) ==> %s in %s", exe, args + more_args, logname, workingDir) if self.options.dry_run: diff --git a/modules/ts/misc/run_utils.py b/modules/ts/misc/run_utils.py index 5841631a7c..8740aa7855 100644 --- a/modules/ts/misc/run_utils.py +++ b/modules/ts/misc/run_utils.py @@ -22,13 +22,17 @@ class Err(Exception): def __init__(self, msg, *args): self.msg = msg % args -def execute(cmd, silent = False, cwd = "."): +def execute(cmd, silent = False, cwd = ".", env = None): try: log.debug("Run: %s", cmd) + if env: + for k in env: + log.debug(" Environ: %s=%s", k, env[k]) + env = os.environ.update(env) if silent: - return check_output(cmd, stderr = STDOUT, cwd = cwd).decode("latin-1") + return check_output(cmd, stderr = STDOUT, cwd = cwd, env = env).decode("latin-1") else: - return check_call(cmd, cwd = cwd) + return check_call(cmd, cwd = cwd, env = env) except CalledProcessError as e: if silent: log.debug("Process returned: %d", e.returncode) @@ -171,6 +175,8 @@ parse_patterns = ( {'name': "cuda_library", 'default': None, 'pattern': re.compile(r"^CUDA_CUDA_LIBRARY:FILEPATH=(.+)$")}, {'name': "cuda_version", 'default': None, 'pattern': re.compile(r"^CUDA_VERSION:STRING=(.+)$")}, {'name': "core_dependencies", 'default': None, 'pattern': re.compile(r"^opencv_core_LIB_DEPENDS:STATIC=(.+)$")}, + {'name': "python2", 'default': None, 'pattern': re.compile(r"^BUILD_opencv_python2:BOOL=(.*)$")}, + {'name': "python3", 'default': None, 'pattern': re.compile(r"^BUILD_opencv_python3:BOOL=(.*)$")}, ) class CMakeCache: @@ -247,11 +253,15 @@ class CMakeCache: files = glob.glob(os.path.join(d, mask)) if not self.getOS() == "android" and self.withJava(): files.append("java") + if self.withPython2(): + files.append("python2") + if self.withPython3(): + files.append("python3") return [f for f in files if isGood(f)] return [] def isMainModule(self, name): - return name in self.main_modules + return name in self.main_modules + ['python2', 'python3'] def withCuda(self): return self.cuda_version and self.with_cuda == "ON" and self.cuda_library and not self.cuda_library.endswith("-NOTFOUND") @@ -259,6 +269,12 @@ class CMakeCache: def withJava(self): return self.ant_executable and self.java_test_binary_dir + def withPython2(self): + return self.python2 == 'ON' + + def withPython3(self): + return self.python3 == 'ON' + def getGitVersion(self): if self.cmake_home_vcver: if self.cmake_home_vcver == self.opencv_home_vcver: