diff --git a/modules/imgproc/perf/perf_houghLines.cpp b/modules/imgproc/perf/perf_houghLines.cpp index 2b3c36cb22..c866d01509 100644 --- a/modules/imgproc/perf/perf_houghLines.cpp +++ b/modules/imgproc/perf/perf_houghLines.cpp @@ -8,6 +8,11 @@ using namespace perf; using std::tr1::make_tuple; using std::tr1::get; +bool polarComp(Vec2f a, Vec2f b) +{ + return a[1] > b[1] || (a[1] == b[1] && a[0] < b[0]); +} + typedef std::tr1::tuple Image_RhoStep_ThetaStep_Threshold_t; typedef perf::TestBaseWithParam Image_RhoStep_ThetaStep_Threshold; @@ -36,6 +41,6 @@ PERF_TEST_P(Image_RhoStep_ThetaStep_Threshold, HoughLines, TEST_CYCLE() HoughLines(image, lines, rhoStep, thetaStep, threshold); - transpose(lines, lines); - SANITY_CHECK(lines); + EXPECT_FALSE(lines.empty()); + SANITY_CHECK_NOTHING(); } diff --git a/modules/imgproc/src/hough.cpp b/modules/imgproc/src/hough.cpp index b7a3c38daa..a5cfc89fb7 100644 --- a/modules/imgproc/src/hough.cpp +++ b/modules/imgproc/src/hough.cpp @@ -12,6 +12,7 @@ // // Copyright (C) 2000, Intel Corporation, all rights reserved. // Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2014, Itseez, Inc, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, @@ -97,7 +98,7 @@ HoughLinesStandard( const Mat& img, float rho, float theta, int numangle = cvRound((max_theta - min_theta) / theta); int numrho = cvRound(((width + height) * 2 + 1) / rho); -#if (defined(HAVE_IPP) && IPP_VERSION_MAJOR >= 8) +#if (defined(HAVE_IPP) && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 801) IppiSize srcSize = { width, height }; IppPointPolar delta = { rho, theta }; IppPointPolar dstRoi[2] = {{(Ipp32f) -(width + height), (Ipp32f) min_theta},{(Ipp32f) (width + height), (Ipp32f) max_theta}}; diff --git a/modules/imgproc/test/test_houghLines.cpp b/modules/imgproc/test/test_houghLines.cpp index 660b3dd583..4ddb7652ad 100644 --- a/modules/imgproc/test/test_houghLines.cpp +++ b/modules/imgproc/test/test_houghLines.cpp @@ -12,6 +12,7 @@ // // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2014, Itseez, Inc, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, @@ -45,107 +46,173 @@ using namespace cv; using namespace std; -class CV_HoughLinesTest : public cvtest::BaseTest +template +struct SimilarWith { -public: - enum {STANDART = 0, PROBABILISTIC}; - CV_HoughLinesTest() {} - ~CV_HoughLinesTest() {} -protected: - void run_test(int type); + T value; + double eps; + double rho_eps; + SimilarWith(T val, double e, double r_e): value(val), eps(e), rho_eps(r_e) { }; + bool operator()(T other); }; -class CV_StandartHoughLinesTest : public CV_HoughLinesTest +template<> +bool SimilarWith::operator()(Vec2f other) { -public: - CV_StandartHoughLinesTest() {} - ~CV_StandartHoughLinesTest() {} - virtual void run(int); -}; + return abs(other[0] - value[0]) < rho_eps && abs(other[1] - value[1]) < eps; +} -class CV_ProbabilisticHoughLinesTest : public CV_HoughLinesTest +template<> +bool SimilarWith::operator()(Vec4i other) { -public: - CV_ProbabilisticHoughLinesTest() {} - ~CV_ProbabilisticHoughLinesTest() {} - virtual void run(int); -}; + return abs(other[0] - value[0]) < eps && abs(other[1] - value[1]) < eps && abs(other[2] - value[2]) < eps && abs(other[2] - value[2]) < eps; +} -void CV_StandartHoughLinesTest::run(int) +template +int countMatIntersection(Mat expect, Mat actual, double eps, double rho_eps) { - run_test(STANDART); + int count = 0; + if (!expect.empty() && !actual.empty()) + { + for (MatIterator_ it=expect.begin(); it!=expect.end(); it++) + { + MatIterator_ f = std::find_if(actual.begin(), actual.end(), SimilarWith(*it, eps, rho_eps)); + if (f != actual.end()) + count++; + } + } + return count; } -void CV_ProbabilisticHoughLinesTest::run(int) +String getTestCaseName(String filename) { - run_test(PROBABILISTIC); + string temp(filename); + size_t pos = temp.find_first_of("\\/."); + while ( pos != string::npos ) { + temp.replace( pos, 1, "_" ); + pos = temp.find_first_of("\\/."); + } + return String(temp); } -void CV_HoughLinesTest::run_test(int type) +class BaseHoughLineTest { - Mat src = imread(string(ts->get_data_path()) + "shared/pic1.png"); - if (src.empty()) +public: + enum {STANDART = 0, PROBABILISTIC}; +protected: + void run_test(int type); + + string picture_name; + double rhoStep; + double thetaStep; + int threshold; + int minLineLength; + int maxGap; +}; + +typedef std::tr1::tuple Image_RhoStep_ThetaStep_Threshold_t; +class StandartHoughLinesTest : public BaseHoughLineTest, public testing::TestWithParam +{ +public: + StandartHoughLinesTest() { - ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); - return; + picture_name = get<0>(GetParam()); + rhoStep = get<1>(GetParam()); + thetaStep = get<2>(GetParam()); + threshold = get<3>(GetParam()); + minLineLength = 0; + maxGap = 0; } +}; + +typedef std::tr1::tuple Image_RhoStep_ThetaStep_Threshold_MinLine_MaxGap_t; +class ProbabilisticHoughLinesTest : public BaseHoughLineTest, public testing::TestWithParam +{ +public: + ProbabilisticHoughLinesTest() + { + picture_name = get<0>(GetParam()); + rhoStep = get<1>(GetParam()); + thetaStep = get<2>(GetParam()); + threshold = get<3>(GetParam()); + minLineLength = get<4>(GetParam()); + maxGap = get<5>(GetParam()); + } +}; + +void BaseHoughLineTest::run_test(int type) +{ + string filename = cvtest::TS::ptr()->get_data_path() + picture_name; + Mat src = imread(filename, IMREAD_GRAYSCALE); + EXPECT_FALSE(src.empty()) << "Invalid test image: " << filename; string xml; if (type == STANDART) - xml = string(ts->get_data_path()) + "imgproc/HoughLines.xml"; + xml = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/HoughLines.xml"; else if (type == PROBABILISTIC) - xml = string(ts->get_data_path()) + "imgproc/HoughLinesP.xml"; - else - { - ts->printf(cvtest::TS::LOG, "Error: unknown HoughLines algorithm type.\n"); - ts->set_failed_test_info(cvtest::TS::FAIL_GENERIC); - return; - } + xml = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/HoughLinesP.xml"; Mat dst; Canny(src, dst, 50, 200, 3); + EXPECT_FALSE(dst.empty()) << "Failed Canny edge detector"; Mat lines; if (type == STANDART) - HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0); + HoughLines(dst, lines, rhoStep, thetaStep, threshold, 0, 0); else if (type == PROBABILISTIC) - HoughLinesP(dst, lines, 1, CV_PI/180, 100, 0, 0); + HoughLinesP(dst, lines, rhoStep, thetaStep, threshold, minLineLength, maxGap); + + String test_case_name = format("lines_%s_%.0f_%.2f_%d_%d_%d", picture_name.c_str(), rhoStep, thetaStep, + threshold, minLineLength, maxGap); + test_case_name = getTestCaseName(test_case_name); FileStorage fs(xml, FileStorage::READ); - if (!fs.isOpened()) + FileNode node = fs[test_case_name]; + if (node.empty()) { - fs.open(xml, FileStorage::WRITE); - if (!fs.isOpened()) - { - ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); - return; - } - fs << "exp_lines" << lines; + fs.release(); + fs.open(xml, FileStorage::APPEND); + EXPECT_TRUE(fs.isOpened()) << "Cannot open sanity data file: " << xml; + fs << test_case_name << lines; fs.release(); fs.open(xml, FileStorage::READ); - if (!fs.isOpened()) - { - ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); - return; - } + EXPECT_TRUE(fs.isOpened()) << "Cannot open sanity data file: " << xml; } Mat exp_lines; - read( fs["exp_lines"], exp_lines, Mat() ); + read( fs[test_case_name], exp_lines, Mat() ); fs.release(); - if( exp_lines.size != lines.size ) - transpose(lines, lines); + float eps = 1e-2f; + int count = -1; + if (type == STANDART) + count = countMatIntersection(exp_lines, lines, thetaStep + FLT_EPSILON, rhoStep + FLT_EPSILON); + else if (type == PROBABILISTIC) + count = countMatIntersection(exp_lines, lines, thetaStep, 0.0); - if ( exp_lines.size != lines.size || cvtest::norm(exp_lines, lines, NORM_INF) > 1e-4 ) - { - ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); - return; - } + EXPECT_GE( count, (int) (exp_lines.total() * 0.8) ); +} - ts->set_failed_test_info(cvtest::TS::OK); +TEST_P(StandartHoughLinesTest, regression) +{ + run_test(STANDART); } -TEST(Imgproc_HoughLines, regression) { CV_StandartHoughLinesTest test; test.safe_run(); } +TEST_P(ProbabilisticHoughLinesTest, regression) +{ + run_test(PROBABILISTIC); +} -TEST(Imgproc_HoughLinesP, regression) { CV_ProbabilisticHoughLinesTest test; test.safe_run(); } +INSTANTIATE_TEST_CASE_P( ImgProc, StandartHoughLinesTest, testing::Combine(testing::Values( "shared/pic5.png", "../stitching/a1.png" ), + testing::Values( 1, 10 ), + testing::Values( 0.01, 0.1 ), + testing::Values( 100, 200 ) + )); + +INSTANTIATE_TEST_CASE_P( ImgProc, ProbabilisticHoughLinesTest, testing::Combine(testing::Values( "shared/pic5.png", "shared/pic1.png" ), + testing::Values( 5, 10 ), + testing::Values( 0.01, 0.1 ), + testing::Values( 75, 150 ), + testing::Values( 0, 10 ), + testing::Values( 0, 4 ) + ));