diff --git a/modules/calib3d/test/test_chesscorners.cpp b/modules/calib3d/test/test_chesscorners.cpp index f4208a574c..781eec2ffb 100644 --- a/modules/calib3d/test/test_chesscorners.cpp +++ b/modules/calib3d/test/test_chesscorners.cpp @@ -373,8 +373,6 @@ bool CV_ChessboardDetectorTest::checkByGenerator() { bool res = true; -// for some reason, this test sometimes fails on Ubuntu -#if (defined __APPLE__ && defined __x86_64__) || defined _MSC_VER //theRNG() = 0x58e6e895b9913160; //cv::DefaultRngAuto dra; //theRNG() = *ts->get_rng(); @@ -473,7 +471,6 @@ bool CV_ChessboardDetectorTest::checkByGenerator() cv::drawChessboardCorners(cb, cbg.cornersSize(), Mat(corners_found), found); } -#endif return res; } diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 9e25825412..7d51c34dcb 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -3732,21 +3732,17 @@ CV_EXPORTS_W int connectedComponentsWithStats(InputArray image, OutputArray labe /** @brief Finds contours in a binary image. The function retrieves contours from the binary image using the algorithm @cite Suzuki85 . The contours -are a useful tool for shape analysis and object detection and recognition. See squares.c in the +are a useful tool for shape analysis and object detection and recognition. See squares.cpp in the OpenCV sample directory. -@note Source image is modified by this function. Also, the function does not take into account -1-pixel border of the image (it's filled with 0's and used for neighbor analysis in the algorithm), -therefore the contours touching the image border will be clipped. - @param image Source, an 8-bit single-channel image. Non-zero pixels are treated as 1's. Zero -pixels remain 0's, so the image is treated as binary . You can use compare , inRange , threshold , -adaptiveThreshold , Canny , and others to create a binary image out of a grayscale or color one. -The function modifies the image while extracting the contours. If mode equals to RETR_CCOMP -or RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1). -@param contours Detected contours. Each contour is stored as a vector of points. -@param hierarchy Optional output vector, containing information about the image topology. It has -as many elements as the number of contours. For each i-th contour contours[i] , the elements +pixels remain 0's, so the image is treated as binary . You can use cv::compare, cv::inRange, cv::threshold , +cv::adaptiveThreshold, cv::Canny, and others to create a binary image out of a grayscale or color one. +If mode equals to cv::RETR_CCOMP or cv::RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1). +@param contours Detected contours. Each contour is stored as a vector of points (e.g. +std::vector >). +@param hierarchy Optional output vector (e.g. std::vector), containing information about the image topology. It has +as many elements as the number of contours. For each i-th contour contours[i], the elements hierarchy[i][0] , hiearchy[i][1] , hiearchy[i][2] , and hiearchy[i][3] are set to 0-based indices in contours of the next and previous contours at the same hierarchical level, the first child contour and the parent contour, respectively. If for the contour i there are no next, previous, diff --git a/modules/imgproc/src/contours.cpp b/modules/imgproc/src/contours.cpp index d59c5a17df..4c78621408 100644 --- a/modules/imgproc/src/contours.cpp +++ b/modules/imgproc/src/contours.cpp @@ -199,10 +199,10 @@ _CvContourScanner; Initializes scanner structure. Prepare image for scanning ( clear borders and convert all pixels to 0-1. */ -CV_IMPL CvContourScanner -cvStartFindContours( void* _img, CvMemStorage* storage, +static CvContourScanner +cvStartFindContours_Impl( void* _img, CvMemStorage* storage, int header_size, int mode, - int method, CvPoint offset ) + int method, CvPoint offset, int needFillBorder ) { if( !storage ) CV_Error( CV_StsNullPtr, "" ); @@ -310,15 +310,18 @@ cvStartFindContours( void* _img, CvMemStorage* storage, CV_Assert(size.height >= 1); /* make zero borders */ - int esz = CV_ELEM_SIZE(mat->type); - memset( img, 0, size.width*esz ); - memset( img + static_cast(step) * (size.height - 1), 0, size.width*esz ); - - img += step; - for( int y = 1; y < size.height - 1; y++, img += step ) + if(needFillBorder) { - for( int k = 0; k < esz; k++ ) - img[k] = img[(size.width - 1)*esz + k] = (schar)0; + int esz = CV_ELEM_SIZE(mat->type); + memset( img, 0, size.width*esz ); + memset( img + static_cast(step) * (size.height - 1), 0, size.width*esz ); + + img += step; + for( int y = 1; y < size.height - 1; y++, img += step ) + { + for( int k = 0; k < esz; k++ ) + img[k] = img[(size.width - 1)*esz + k] = (schar)0; + } } /* converts all pixels to 0 or 1 */ @@ -328,6 +331,14 @@ cvStartFindContours( void* _img, CvMemStorage* storage, return scanner; } +CV_IMPL CvContourScanner +cvStartFindContours( void* _img, CvMemStorage* storage, + int header_size, int mode, + int method, CvPoint offset ) +{ + return cvStartFindContours_Impl(_img, storage, header_size, mode, method, offset, 1); +} + /* Final stage of contour processing. Three variants possible: @@ -1796,7 +1807,55 @@ icvFindContoursInInterval( const CvArr* src, return count; } +static int +cvFindContours_Impl( void* img, CvMemStorage* storage, + CvSeq** firstContour, int cntHeaderSize, + int mode, + int method, CvPoint offset, int needFillBorder ) +{ + CvContourScanner scanner = 0; + CvSeq *contour = 0; + int count = -1; + if( !firstContour ) + CV_Error( CV_StsNullPtr, "NULL double CvSeq pointer" ); + + *firstContour = 0; + + if( method == CV_LINK_RUNS ) + { + if( offset.x != 0 || offset.y != 0 ) + CV_Error( CV_StsOutOfRange, + "Nonzero offset is not supported in CV_LINK_RUNS yet" ); + + count = icvFindContoursInInterval( img, storage, firstContour, cntHeaderSize ); + } + else + { + try + { + scanner = cvStartFindContours_Impl( img, storage, cntHeaderSize, mode, method, offset, + needFillBorder); + + do + { + count++; + contour = cvFindNextContour( scanner ); + } + while( contour != 0 ); + } + catch(...) + { + if( scanner ) + cvEndFindContours(&scanner); + throw; + } + + *firstContour = cvEndFindContours( &scanner ); + } + + return count; +} /*F/////////////////////////////////////////////////////////////////////////////////////// // Name: cvFindContours @@ -1824,47 +1883,7 @@ cvFindContours( void* img, CvMemStorage* storage, int mode, int method, CvPoint offset ) { - CvContourScanner scanner = 0; - CvSeq *contour = 0; - int count = -1; - - if( !firstContour ) - CV_Error( CV_StsNullPtr, "NULL double CvSeq pointer" ); - - *firstContour = 0; - - if( method == CV_LINK_RUNS ) - { - if( offset.x != 0 || offset.y != 0 ) - CV_Error( CV_StsOutOfRange, - "Nonzero offset is not supported in CV_LINK_RUNS yet" ); - - count = icvFindContoursInInterval( img, storage, firstContour, cntHeaderSize ); - } - else - { - try - { - scanner = cvStartFindContours( img, storage, cntHeaderSize, mode, method, offset ); - - do - { - count++; - contour = cvFindNextContour( scanner ); - } - while( contour != 0 ); - } - catch(...) - { - if( scanner ) - cvEndFindContours(&scanner); - throw; - } - - *firstContour = cvEndFindContours( &scanner ); - } - - return count; + return cvFindContours_Impl(img, storage, firstContour, cntHeaderSize, mode, method, offset, 1); } void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours, @@ -1878,13 +1897,14 @@ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours, CV_Assert(_contours.empty() || (_contours.channels() == 2 && _contours.depth() == CV_32S)); - Mat image = _image.getMat(); + Mat image; + copyMakeBorder(_image, image, 1, 1, 1, 1, BORDER_CONSTANT, Scalar(0)); MemStorage storage(cvCreateMemStorage()); CvMat _cimage = image; CvSeq* _ccontours = 0; if( _hierarchy.needed() ) _hierarchy.clear(); - cvFindContours(&_cimage, storage, &_ccontours, sizeof(CvContour), mode, method, offset); + cvFindContours_Impl(&_cimage, storage, &_ccontours, sizeof(CvContour), mode, method, offset + Point(-1, -1), 0); if( !_ccontours ) { _contours.clear(); diff --git a/modules/imgproc/test/test_contours.cpp b/modules/imgproc/test/test_contours.cpp index d8d51f2fe1..851ec2c340 100644 --- a/modules/imgproc/test/test_contours.cpp +++ b/modules/imgproc/test/test_contours.cpp @@ -483,10 +483,26 @@ TEST(Imgproc_FindContours, hilbert) img.setTo(Scalar::all(0)); drawContours(img, contours, 0, Scalar::all(255), 1); - //imshow("hilbert", img); - //waitKey(); + ASSERT_EQ(1, (int)contours.size()); ASSERT_EQ(9832, (int)contours[0].size()); } +TEST(Imgproc_FindContours, border) +{ + Mat img; + copyMakeBorder(Mat::zeros(8, 10, CV_8U), img, 1, 1, 1, 1, BORDER_CONSTANT, Scalar(1)); + + std::vector > contours; + findContours(img, contours, RETR_LIST, CHAIN_APPROX_NONE); + + Mat img_draw_contours = Mat::zeros(img.size(), CV_8U); + for (size_t cpt = 0; cpt < contours.size(); cpt++) + { + drawContours(img_draw_contours, contours, static_cast(cpt), cv::Scalar(255)); + } + + ASSERT_TRUE(norm(img - img_draw_contours, NORM_INF) == 0.0); +} + /* End of file. */