mirror of
https://github.com/opencv/opencv.git
synced 2024-11-28 05:06:29 +08:00
Merge pull request #7516 from sovrasov:find_contours_fix
This commit is contained in:
commit
4c66772783
@ -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;
|
||||
}
|
||||
|
@ -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<std::vector<cv::Point> >).
|
||||
@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
|
||||
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,
|
||||
|
@ -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<size_t>(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<size_t>(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();
|
||||
|
@ -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<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. */
|
||||
|
Loading…
Reference in New Issue
Block a user