Merge pull request #7516 from sovrasov:find_contours_fix

pull/7586/head
Alexander Alekhin 8 years ago
commit 4c66772783
  1. 3
      modules/calib3d/test/test_chesscorners.cpp
  2. 20
      modules/imgproc/include/opencv2/imgproc.hpp
  3. 82
      modules/imgproc/src/contours.cpp
  4. 20
      modules/imgproc/test/test_contours.cpp

@ -373,8 +373,6 @@ bool CV_ChessboardDetectorTest::checkByGenerator()
{ {
bool res = true; bool res = true;
// for some reason, this test sometimes fails on Ubuntu
#if (defined __APPLE__ && defined __x86_64__) || defined _MSC_VER
//theRNG() = 0x58e6e895b9913160; //theRNG() = 0x58e6e895b9913160;
//cv::DefaultRngAuto dra; //cv::DefaultRngAuto dra;
//theRNG() = *ts->get_rng(); //theRNG() = *ts->get_rng();
@ -473,7 +471,6 @@ bool CV_ChessboardDetectorTest::checkByGenerator()
cv::drawChessboardCorners(cb, cbg.cornersSize(), Mat(corners_found), found); cv::drawChessboardCorners(cb, cbg.cornersSize(), Mat(corners_found), found);
} }
#endif
return res; return res;
} }

@ -3732,21 +3732,17 @@ CV_EXPORTS_W int connectedComponentsWithStats(InputArray image, OutputArray labe
/** @brief Finds contours in a binary image. /** @brief Finds contours in a binary image.
The function retrieves contours from the binary image using the algorithm @cite Suzuki85 . The contours 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. 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 @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 , pixels remain 0's, so the image is treated as binary . You can use cv::compare, cv::inRange, cv::threshold ,
adaptiveThreshold , Canny , and others to create a binary image out of a grayscale or color one. cv::adaptiveThreshold, cv::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 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).
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 (e.g.
@param contours Detected contours. Each contour is stored as a vector of points. std::vector<std::vector<cv::Point> >).
@param hierarchy Optional output vector, containing information about the image topology. It has @param hierarchy Optional output vector (e.g. std::vector<cv::Vec4i>), 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 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 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 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, contour and the parent contour, respectively. If for the contour i there are no next, previous,

@ -199,10 +199,10 @@ _CvContourScanner;
Initializes scanner structure. Initializes scanner structure.
Prepare image for scanning ( clear borders and convert all pixels to 0-1. Prepare image for scanning ( clear borders and convert all pixels to 0-1.
*/ */
CV_IMPL CvContourScanner static CvContourScanner
cvStartFindContours( void* _img, CvMemStorage* storage, cvStartFindContours_Impl( void* _img, CvMemStorage* storage,
int header_size, int mode, int header_size, int mode,
int method, CvPoint offset ) int method, CvPoint offset, int needFillBorder )
{ {
if( !storage ) if( !storage )
CV_Error( CV_StsNullPtr, "" ); CV_Error( CV_StsNullPtr, "" );
@ -310,6 +310,8 @@ cvStartFindContours( void* _img, CvMemStorage* storage,
CV_Assert(size.height >= 1); CV_Assert(size.height >= 1);
/* make zero borders */ /* make zero borders */
if(needFillBorder)
{
int esz = CV_ELEM_SIZE(mat->type); int esz = CV_ELEM_SIZE(mat->type);
memset( img, 0, size.width*esz ); memset( img, 0, size.width*esz );
memset( img + static_cast<size_t>(step) * (size.height - 1), 0, size.width*esz ); memset( img + static_cast<size_t>(step) * (size.height - 1), 0, size.width*esz );
@ -320,6 +322,7 @@ cvStartFindContours( void* _img, CvMemStorage* storage,
for( int k = 0; k < esz; k++ ) for( int k = 0; k < esz; k++ )
img[k] = img[(size.width - 1)*esz + k] = (schar)0; img[k] = img[(size.width - 1)*esz + k] = (schar)0;
} }
}
/* converts all pixels to 0 or 1 */ /* converts all pixels to 0 or 1 */
if( CV_MAT_TYPE(mat->type) != CV_32S ) if( CV_MAT_TYPE(mat->type) != CV_32S )
@ -328,6 +331,14 @@ cvStartFindContours( void* _img, CvMemStorage* storage,
return scanner; 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. Final stage of contour processing.
Three variants possible: Three variants possible:
@ -1796,33 +1807,11 @@ icvFindContoursInInterval( const CvArr* src,
return count; return count;
} }
static int
cvFindContours_Impl( void* img, CvMemStorage* storage,
/*F///////////////////////////////////////////////////////////////////////////////////////
// Name: cvFindContours
// Purpose:
// Finds all the contours on the bi-level image.
// Context:
// Parameters:
// img - source image.
// Non-zero pixels are considered as 1-pixels
// and zero pixels as 0-pixels.
// step - full width of source image in bytes.
// size - width and height of the image in pixels
// storage - pointer to storage where will the output contours be placed.
// header_size - header size of resulting contours
// mode - mode of contour retrieval.
// method - method of approximation that is applied to contours
// first_contour - pointer to first contour pointer
// Returns:
// CV_OK or error code
// Notes:
//F*/
CV_IMPL int
cvFindContours( void* img, CvMemStorage* storage,
CvSeq** firstContour, int cntHeaderSize, CvSeq** firstContour, int cntHeaderSize,
int mode, int mode,
int method, CvPoint offset ) int method, CvPoint offset, int needFillBorder )
{ {
CvContourScanner scanner = 0; CvContourScanner scanner = 0;
CvSeq *contour = 0; CvSeq *contour = 0;
@ -1845,7 +1834,8 @@ cvFindContours( void* img, CvMemStorage* storage,
{ {
try try
{ {
scanner = cvStartFindContours( img, storage, cntHeaderSize, mode, method, offset ); scanner = cvStartFindContours_Impl( img, storage, cntHeaderSize, mode, method, offset,
needFillBorder);
do do
{ {
@ -1867,6 +1857,35 @@ cvFindContours( void* img, CvMemStorage* storage,
return count; return count;
} }
/*F///////////////////////////////////////////////////////////////////////////////////////
// Name: cvFindContours
// Purpose:
// Finds all the contours on the bi-level image.
// Context:
// Parameters:
// img - source image.
// Non-zero pixels are considered as 1-pixels
// and zero pixels as 0-pixels.
// step - full width of source image in bytes.
// size - width and height of the image in pixels
// storage - pointer to storage where will the output contours be placed.
// header_size - header size of resulting contours
// mode - mode of contour retrieval.
// method - method of approximation that is applied to contours
// first_contour - pointer to first contour pointer
// Returns:
// CV_OK or error code
// Notes:
//F*/
CV_IMPL int
cvFindContours( void* img, CvMemStorage* storage,
CvSeq** firstContour, int cntHeaderSize,
int mode,
int method, CvPoint offset )
{
return cvFindContours_Impl(img, storage, firstContour, cntHeaderSize, mode, method, offset, 1);
}
void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours, void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
OutputArray _hierarchy, int mode, int method, Point offset ) OutputArray _hierarchy, int mode, int method, Point offset )
{ {
@ -1878,13 +1897,14 @@ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
CV_Assert(_contours.empty() || (_contours.channels() == 2 && _contours.depth() == CV_32S)); 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()); MemStorage storage(cvCreateMemStorage());
CvMat _cimage = image; CvMat _cimage = image;
CvSeq* _ccontours = 0; CvSeq* _ccontours = 0;
if( _hierarchy.needed() ) if( _hierarchy.needed() )
_hierarchy.clear(); _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 ) if( !_ccontours )
{ {
_contours.clear(); _contours.clear();

@ -483,10 +483,26 @@ TEST(Imgproc_FindContours, hilbert)
img.setTo(Scalar::all(0)); img.setTo(Scalar::all(0));
drawContours(img, contours, 0, Scalar::all(255), 1); drawContours(img, contours, 0, Scalar::all(255), 1);
//imshow("hilbert", img);
//waitKey();
ASSERT_EQ(1, (int)contours.size()); ASSERT_EQ(1, (int)contours.size());
ASSERT_EQ(9832, (int)contours[0].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<std::vector<cv::Point> > 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<int>(cpt), cv::Scalar(255));
}
ASSERT_TRUE(norm(img - img_draw_contours, NORM_INF) == 0.0);
}
/* End of file. */ /* End of file. */

Loading…
Cancel
Save