diff --git a/modules/imgproc/perf/perf_houghLines.cpp b/modules/imgproc/perf/perf_houghLines.cpp index 2b3c36cb22..a6e7e73408 100644 --- a/modules/imgproc/perf/perf_houghLines.cpp +++ b/modules/imgproc/perf/perf_houghLines.cpp @@ -37,5 +37,9 @@ PERF_TEST_P(Image_RhoStep_ThetaStep_Threshold, HoughLines, TEST_CYCLE() HoughLines(image, lines, rhoStep, thetaStep, threshold); transpose(lines, lines); +#if (0 && defined(HAVE_IPP) && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 801) + SANITY_CHECK_NOTHING(); +#else SANITY_CHECK(lines); +#endif } diff --git a/modules/imgproc/src/hough.cpp b/modules/imgproc/src/hough.cpp index 061835cc09..dc98426b27 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,6 +98,28 @@ 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 (0 && 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}}; + int bufferSize; + int nz = countNonZero(img); + int ipp_linesMax = std::min(linesMax, nz*numangle/threshold); + int linesCount = 0; + lines.resize(ipp_linesMax); + IppStatus ok = ippiHoughLineGetSize_8u_C1R(srcSize, delta, ipp_linesMax, &bufferSize); + Ipp8u* buffer = ippsMalloc_8u(bufferSize); + if (ok >= 0) ok = ippiHoughLine_Region_8u32f_C1R(image, step, srcSize, (IppPointPolar*) &lines[0], dstRoi, ipp_linesMax, &linesCount, delta, threshold, buffer); + ippsFree(buffer); + if (ok >= 0) + { + lines.resize(linesCount); + return; + } + lines.clear(); + setIppErrorStatus(); +#endif + AutoBuffer _accum((numangle+2) * (numrho+2)); std::vector _sort_buf; AutoBuffer _tabSin(numangle); @@ -404,6 +427,31 @@ HoughLinesProbabilistic( Mat& image, int numangle = cvRound(CV_PI / theta); int numrho = cvRound(((width + height) * 2 + 1) / rho); +#if (0 && defined(HAVE_IPP) && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 801) + IppiSize srcSize = { width, height }; + IppPointPolar delta = { rho, theta }; + IppiHoughProbSpec* pSpec; + int bufferSize, specSize; + int ipp_linesMax = std::min(linesMax, numangle*numrho); + int linesCount = 0; + lines.resize(ipp_linesMax); + IppStatus ok = ippiHoughProbLineGetSize_8u_C1R(srcSize, delta, &specSize, &bufferSize); + Ipp8u* buffer = ippsMalloc_8u(bufferSize); + pSpec = (IppiHoughProbSpec*) malloc(specSize); + if (ok >= 0) ok = ippiHoughProbLineInit_8u32f_C1R(srcSize, delta, ippAlgHintNone, pSpec); + if (ok >= 0) ok = ippiHoughProbLine_8u32f_C1R(image.data, image.step, srcSize, threshold, lineLength, lineGap, (IppiPoint*) &lines[0], ipp_linesMax, &linesCount, buffer, pSpec); + + free(pSpec); + ippsFree(buffer); + if (ok >= 0) + { + lines.resize(linesCount); + return; + } + lines.clear(); + setIppErrorStatus(); +#endif + Mat accum = Mat::zeros( numangle, numrho, CV_32SC1 ); Mat mask( height, width, CV_8UC1 ); std::vector trigtab(numangle*2); diff --git a/modules/imgproc/test/test_houghLines.cpp b/modules/imgproc/test/test_houghLines.cpp index 660b3dd583..fd9783b317 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,176 @@ using namespace cv; using namespace std; -class CV_HoughLinesTest : public cvtest::BaseTest +template +struct SimilarWith +{ + T value; + float theta_eps; + float rho_eps; + SimilarWith(T val, float e, float r_e): value(val), theta_eps(e), rho_eps(r_e) { }; + bool operator()(T other); +}; + +template<> +bool SimilarWith::operator()(Vec2f other) +{ + return abs(other[0] - value[0]) < rho_eps && abs(other[1] - value[1]) < theta_eps; +} + +template<> +bool SimilarWith::operator()(Vec4i other) +{ + return norm(value, other) < theta_eps; +} + +template +int countMatIntersection(Mat expect, Mat actual, float eps, float rho_eps) +{ + 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; +} + +String getTestCaseName(String filename) +{ + 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); +} + +class BaseHoughLineTest { public: enum {STANDART = 0, PROBABILISTIC}; - CV_HoughLinesTest() {} - ~CV_HoughLinesTest() {} protected: void run_test(int type); + + string picture_name; + double rhoStep; + double thetaStep; + int threshold; + int minLineLength; + int maxGap; }; -class CV_StandartHoughLinesTest : public CV_HoughLinesTest +typedef std::tr1::tuple Image_RhoStep_ThetaStep_Threshold_t; +class StandartHoughLinesTest : public BaseHoughLineTest, public testing::TestWithParam { public: - CV_StandartHoughLinesTest() {} - ~CV_StandartHoughLinesTest() {} - virtual void run(int); + StandartHoughLinesTest() + { + picture_name = std::tr1::get<0>(GetParam()); + rhoStep = std::tr1::get<1>(GetParam()); + thetaStep = std::tr1::get<2>(GetParam()); + threshold = std::tr1::get<3>(GetParam()); + minLineLength = 0; + maxGap = 0; + } }; -class CV_ProbabilisticHoughLinesTest : public CV_HoughLinesTest +typedef std::tr1::tuple Image_RhoStep_ThetaStep_Threshold_MinLine_MaxGap_t; +class ProbabilisticHoughLinesTest : public BaseHoughLineTest, public testing::TestWithParam { public: - CV_ProbabilisticHoughLinesTest() {} - ~CV_ProbabilisticHoughLinesTest() {} - virtual void run(int); + ProbabilisticHoughLinesTest() + { + picture_name = std::tr1::get<0>(GetParam()); + rhoStep = std::tr1::get<1>(GetParam()); + thetaStep = std::tr1::get<2>(GetParam()); + threshold = std::tr1::get<3>(GetParam()); + minLineLength = std::tr1::get<4>(GetParam()); + maxGap = std::tr1::get<5>(GetParam()); + } }; -void CV_StandartHoughLinesTest::run(int) +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(cvtest::TS::ptr()->get_data_path()) + "imgproc/HoughLines.xml"; + else if (type == PROBABILISTIC) + xml = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/HoughLinesP.xml"; + + Mat dst; + Canny(src, dst, 100, 150, 3); + EXPECT_FALSE(dst.empty()) << "Failed Canny edge detector"; + + Mat lines; + if (type == STANDART) + HoughLines(dst, lines, rhoStep, thetaStep, threshold, 0, 0); + else if (type == PROBABILISTIC) + 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); + FileNode node = fs[test_case_name]; + if (node.empty()) + { + 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); + EXPECT_TRUE(fs.isOpened()) << "Cannot open sanity data file: " << xml; + } + + Mat exp_lines; + read( fs[test_case_name], exp_lines, Mat() ); + fs.release(); + + int count = -1; + if (type == STANDART) + count = countMatIntersection(exp_lines, lines, (float) thetaStep + FLT_EPSILON, (float) rhoStep + FLT_EPSILON); + else if (type == PROBABILISTIC) + count = countMatIntersection(exp_lines, lines, 1e-4f, 0.f); + +#if (0 && defined(HAVE_IPP) && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 801) + EXPECT_GE( count, (int) (exp_lines.total() * 0.8) ); +#else + EXPECT_EQ( count, (int) exp_lines.total()); +#endif +} + +TEST_P(StandartHoughLinesTest, regression) { run_test(STANDART); } -void CV_ProbabilisticHoughLinesTest::run(int) +TEST_P(ProbabilisticHoughLinesTest, regression) { run_test(PROBABILISTIC); } -void CV_HoughLinesTest::run_test(int type) -{ - Mat src = imread(string(ts->get_data_path()) + "shared/pic1.png"); - if (src.empty()) - { - ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); - return; - } +INSTANTIATE_TEST_CASE_P( ImgProc, StandartHoughLinesTest, testing::Combine(testing::Values( "shared/pic5.png", "../stitching/a1.png" ), + testing::Values( 1, 10 ), + testing::Values( 0.05, 0.1 ), + testing::Values( 80, 150 ) + )); - string xml; - if (type == STANDART) - xml = string(ts->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; - } - - Mat dst; - Canny(src, dst, 50, 200, 3); - - Mat lines; - if (type == STANDART) - HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0); - else if (type == PROBABILISTIC) - HoughLinesP(dst, lines, 1, CV_PI/180, 100, 0, 0); - - FileStorage fs(xml, FileStorage::READ); - if (!fs.isOpened()) - { - 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::READ); - if (!fs.isOpened()) - { - ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA); - return; - } - } - - Mat exp_lines; - read( fs["exp_lines"], exp_lines, Mat() ); - fs.release(); - - if( exp_lines.size != lines.size ) - transpose(lines, lines); - - 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; - } - - ts->set_failed_test_info(cvtest::TS::OK); -} - -TEST(Imgproc_HoughLines, regression) { CV_StandartHoughLinesTest test; test.safe_run(); } - -TEST(Imgproc_HoughLinesP, regression) { CV_ProbabilisticHoughLinesTest test; test.safe_run(); } +INSTANTIATE_TEST_CASE_P( ImgProc, ProbabilisticHoughLinesTest, testing::Combine(testing::Values( "shared/pic5.png", "shared/pic1.png" ), + testing::Values( 5, 10 ), + testing::Values( 0.05, 0.1 ), + testing::Values( 75, 150 ), + testing::Values( 0, 10 ), + testing::Values( 0, 4 ) + ));