Path: blob/master/modules/imgproc/test/test_houghcircles.cpp
16339 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.13// Copyright (C) 2009, Willow Garage Inc., all rights reserved.14// Copyright (C) 2014, Itseez, Inc, all rights reserved.15// Third party copyrights are property of their respective owners.16//17// Redistribution and use in source and binary forms, with or without modification,18// are permitted provided that the following conditions are met:19//20// * Redistribution's of source code must retain the above copyright notice,21// this list of conditions and the following disclaimer.22//23// * Redistribution's in binary form must reproduce the above copyright notice,24// this list of conditions and the following disclaimer in the documentation25// and/or other materials provided with the distribution.26//27// * The name of the copyright holders may not be used to endorse or promote products28// derived from this software without specific prior written permission.29//30// This software is provided by the copyright holders and contributors "as is" and31// any express or implied warranties, including, but not limited to, the implied32// warranties of merchantability and fitness for a particular purpose are disclaimed.33// In no event shall the Intel Corporation or contributors be liable for any direct,34// indirect, incidental, special, exemplary, or consequential damages35// (including, but not limited to, procurement of substitute goods or services;36// loss of use, data, or profits; or business interruption) however caused37// and on any theory of liability, whether in contract, strict liability,38// or tort (including negligence or otherwise) arising in any way out of39// the use of this software, even if advised of the possibility of such damage.40//41//M*/4243#include "test_precomp.hpp"4445namespace opencv_test { namespace {4647#ifndef DEBUG_IMAGES48#define DEBUG_IMAGES 049#endif5051//#define GENERATE_DATA // generate data in debug mode via CPU code path (without IPP / OpenCL and other accelerators)5253using namespace cv;54using namespace std;5556static string getTestCaseName(const string& picture_name, double minDist, double edgeThreshold, double accumThreshold, int minRadius, int maxRadius)57{58string results_name = format("circles_%s_%.0f_%.0f_%.0f_%d_%d",59picture_name.c_str(), minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);60string temp(results_name);61size_t pos = temp.find_first_of("\\/.");62while (pos != string::npos) {63temp.replace(pos, 1, "_");64pos = temp.find_first_of("\\/.");65}66return temp;67}6869#if DEBUG_IMAGES70static void highlightCircles(const string& imagePath, const vector<Vec3f>& circles, const string& outputImagePath)71{72Mat imgDebug = imread(imagePath, IMREAD_COLOR);73const Scalar yellow(0, 255, 255);7475for (vector<Vec3f>::const_iterator iter = circles.begin(); iter != circles.end(); ++iter)76{77const Vec3f& circle = *iter;78float x = circle[0];79float y = circle[1];80float r = max(circle[2], 2.0f);81cv::circle(imgDebug, Point(int(x), int(y)), int(r), yellow);82}83imwrite(outputImagePath, imgDebug);84}85#endif8687typedef tuple<string, double, double, double, int, int> Image_MinDist_EdgeThreshold_AccumThreshold_MinRadius_MaxRadius_t;88class HoughCirclesTestFixture : public testing::TestWithParam<Image_MinDist_EdgeThreshold_AccumThreshold_MinRadius_MaxRadius_t>89{90string picture_name;91double minDist;92double edgeThreshold;93double accumThreshold;94int minRadius;95int maxRadius;9697public:98HoughCirclesTestFixture()99{100picture_name = get<0>(GetParam());101minDist = get<1>(GetParam());102edgeThreshold = get<2>(GetParam());103accumThreshold = get<3>(GetParam());104minRadius = get<4>(GetParam());105maxRadius = get<5>(GetParam());106}107108HoughCirclesTestFixture(const string& picture, double minD, double edge, double accum, int minR, int maxR) :109picture_name(picture), minDist(minD), edgeThreshold(edge), accumThreshold(accum), minRadius(minR), maxRadius(maxR)110{111}112113template <typename CircleType>114void run_test(const char* xml_name)115{116string test_case_name = getTestCaseName(picture_name, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);117string filename = cvtest::TS::ptr()->get_data_path() + picture_name;118Mat src = imread(filename, IMREAD_GRAYSCALE);119EXPECT_FALSE(src.empty()) << "Invalid test image: " << filename;120121GaussianBlur(src, src, Size(9, 9), 2, 2);122123vector<CircleType> circles;124const double dp = 1.0;125HoughCircles(src, circles, CV_HOUGH_GRADIENT, dp, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);126127string imgProc = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/";128#if DEBUG_IMAGES129highlightCircles(filename, circles, imgProc + test_case_name + ".png");130#endif131132string xml = imgProc + xml_name;133#ifdef GENERATE_DATA134{135FileStorage fs(xml, FileStorage::READ);136ASSERT_TRUE(!fs.isOpened() || fs[test_case_name].empty());137}138{139FileStorage fs(xml, FileStorage::APPEND);140EXPECT_TRUE(fs.isOpened()) << "Cannot open sanity data file: " << xml;141fs << test_case_name << circles;142}143#else144FileStorage fs(xml, FileStorage::READ);145FileNode node = fs[test_case_name];146ASSERT_FALSE(node.empty()) << "Missing test data: " << test_case_name << std::endl << "XML: " << xml;147vector<CircleType> exp_circles;148read(fs[test_case_name], exp_circles, vector<CircleType>());149fs.release();150EXPECT_EQ(exp_circles.size(), circles.size());151#endif152}153};154155TEST_P(HoughCirclesTestFixture, regression)156{157run_test<Vec3f>("HoughCircles.xml");158}159160TEST_P(HoughCirclesTestFixture, regression4f)161{162run_test<Vec4f>("HoughCircles4f.xml");163}164165INSTANTIATE_TEST_CASE_P(ImgProc, HoughCirclesTestFixture, testing::Combine(166// picture_name:167testing::Values("imgproc/stuff.jpg"),168// minDist:169testing::Values(20),170// edgeThreshold:171testing::Values(20),172// accumThreshold:173testing::Values(30),174// minRadius:175testing::Values(20),176// maxRadius:177testing::Values(200)178));179180TEST(HoughCirclesTest, DefaultMaxRadius)181{182string picture_name = "imgproc/stuff.jpg";183const double dp = 1.0;184double minDist = 20;185double edgeThreshold = 20;186double accumThreshold = 30;187int minRadius = 20;188int maxRadius = 0;189190string filename = cvtest::TS::ptr()->get_data_path() + picture_name;191Mat src = imread(filename, IMREAD_GRAYSCALE);192EXPECT_FALSE(src.empty()) << "Invalid test image: " << filename;193194GaussianBlur(src, src, Size(9, 9), 2, 2);195196vector<Vec3f> circles;197vector<Vec4f> circles4f;198HoughCircles(src, circles, CV_HOUGH_GRADIENT, dp, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);199HoughCircles(src, circles4f, CV_HOUGH_GRADIENT, dp, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);200201#if DEBUG_IMAGES202string imgProc = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/";203highlightCircles(filename, circles, imgProc + "HoughCirclesTest_DefaultMaxRadius.png");204#endif205206int maxDimension = std::max(src.rows, src.cols);207208EXPECT_GT(circles.size(), size_t(0)) << "Should find at least some circles";209for (size_t i = 0; i < circles.size(); ++i)210{211EXPECT_GE(circles[i][2], minRadius) << "Radius should be >= minRadius";212EXPECT_LE(circles[i][2], maxDimension) << "Radius should be <= max image dimension";213}214}215216TEST(HoughCirclesTest, CentersOnly)217{218string picture_name = "imgproc/stuff.jpg";219const double dp = 1.0;220double minDist = 20;221double edgeThreshold = 20;222double accumThreshold = 30;223int minRadius = 20;224int maxRadius = -1;225226string filename = cvtest::TS::ptr()->get_data_path() + picture_name;227Mat src = imread(filename, IMREAD_GRAYSCALE);228EXPECT_FALSE(src.empty()) << "Invalid test image: " << filename;229230GaussianBlur(src, src, Size(9, 9), 2, 2);231232vector<Vec3f> circles;233vector<Vec4f> circles4f;234HoughCircles(src, circles, CV_HOUGH_GRADIENT, dp, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);235HoughCircles(src, circles4f, CV_HOUGH_GRADIENT, dp, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);236237#if DEBUG_IMAGES238string imgProc = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/";239highlightCircles(filename, circles, imgProc + "HoughCirclesTest_CentersOnly.png");240#endif241242EXPECT_GT(circles.size(), size_t(0)) << "Should find at least some circles";243for (size_t i = 0; i < circles.size(); ++i)244{245EXPECT_EQ(circles[i][2], 0.0f) << "Did not ask for radius";246EXPECT_EQ(circles[i][0], circles4f[i][0]);247EXPECT_EQ(circles[i][1], circles4f[i][1]);248EXPECT_EQ(circles[i][2], circles4f[i][2]);249}250}251252TEST(HoughCirclesTest, ManySmallCircles)253{254string picture_name = "imgproc/beads.jpg";255const double dp = 1.0;256double minDist = 10;257double edgeThreshold = 90;258double accumThreshold = 11;259int minRadius = 7;260int maxRadius = 18;261262string filename = cvtest::TS::ptr()->get_data_path() + picture_name;263Mat src = imread(filename, IMREAD_GRAYSCALE);264EXPECT_FALSE(src.empty()) << "Invalid test image: " << filename;265266vector<Vec3f> circles;267vector<Vec4f> circles4f;268HoughCircles(src, circles, CV_HOUGH_GRADIENT, dp, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);269HoughCircles(src, circles4f, CV_HOUGH_GRADIENT, dp, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);270271#if DEBUG_IMAGES272string imgProc = string(cvtest::TS::ptr()->get_data_path()) + "imgproc/";273string test_case_name = getTestCaseName(picture_name, minDist, edgeThreshold, accumThreshold, minRadius, maxRadius);274highlightCircles(filename, circles, imgProc + test_case_name + ".png");275#endif276277EXPECT_GT(circles.size(), size_t(3000)) << "Should find a lot of circles";278EXPECT_EQ(circles.size(), circles4f.size());279}280281}} // namespace282283284