Ask Your Question

FindContours hirerarcy issue

asked 2015-09-06 07:52:51 -0500

gdarmon gravatar image

updated 2015-09-06 08:41:37 -0500

I'm trying to convert the following Matlab code into openCV. My code works really great for most of the examples I have(~700), except this one.

Original Image
image description

Here is the matlab output:

image description

Here is the openCV output: image description

Here is what happens when I remove CV_Fill: image description

% Convert to BW image
 bwImg = im2bw(imageData, grayThresh);

% If we end up with totally black or white image return false status.
if all(bwImg(:)) || all(~bwImg(:))
    status = false;
    cornerXY = [];
    centroidXY = [];
    centroidMedianDistance = [];

  % Calculate each separated object area
cDist=regionprops(bwImg, 'Area');

% Label each object
[bwImgLabeled, ~]=bwlabel(bwImg);

% Calculate min and max object size based on assumptions on the color
% checker size
maxLabelSize = prod(size(imageData)./[4 6]);
minLabelSize = prod(size(imageData)./[4 6]./10);

% Find label indices for objects that are too large or too small
remInd = find(cDist > maxLabelSize);
remInd = [remInd find(cDist < minLabelSize)];

% Remove over/undersized objects
for n=1:length(remInd)
    ri = bwImgLabeled == remInd(n);
    bwImgLabeled(ri) = 0;

% Fill any holes in the objects
bwImgLabeled = imfill(bwImgLabeled,'holes');

% Re-label the result image objects
bwImgLabeled(bwImgLabeled>0) = 1;
[bwImgLabeled, nObjs] = bwlabel(bwImgLabeled);

Here is my C++/OpenCV code

cv::Mat bwImg = Utilities::im2bw(imageData, grayThresh);    

double sum = cv::sum(bwImg)[0];
if(sum == bwImg.rows * bwImg.cols||sum == 0 )
    return AutomaticMacbethDetectionResults(false);

cv::vector<cv::vector<cv::Point> > contours_1;
cv::vector<cv::Vec4i> hierarchy_1;
cv::findContours(bwImg,contours_1,hierarchy_1,CV_RETR_TREE,   CV_CHAIN_APPROX_SIMPLE,cv::Point(0,0));*/

cv::vector<cv::vector<cv::Point> > contours_1;
cv::vector<cv::Vec4i> hierarchy;

double maxLabelSize = (bwImg.rows/4.0) * (bwImg.cols/6.0);
double minLabelSize = ((bwImg.rows/40.0) * (bwImg.cols/60.0));

//OPENCV hierarchy *[Next, Previous, First_Child, Parent]**

cv::vector<cv::vector<cv::Point> > goodContours;
    for (int i = 0; i < contours_1.size(); i++)
    double size = cv::contourArea(contours_1[i]);
    if (size < maxLabelSize && size > minLabelSize) //I added my check for hierarachy[i][2] ==-1 here! 

cv::Mat filterContours = cv::Mat::zeros(bwImg.size(),CV_8UC3);  
for (int i = 0; i < goodContours.size(); i++)
    cv::RNG rng(12345);
    cv::Scalar color = cv::Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );

imageData = filterContours;
/*% Re-label the result image objects
bwImgLabeled(bwImgLabeled > 0) = 1;*/
cv::threshold(imageData, imageData, 0 ,254,CV_THRESH_BINARY);

so as far as I understand I can use the Hierarchy feature in order to understand if there is a contour which holds other contours. Hierarchy

and I added a switch to check for hierarchy[i][2] == -1 (meaning it has no children)

however this ruins my results for other images. Can you please explain the difference between regionprops and findcontours? and maybe suggests a way to solve my issue?

edit retag flag offensive close merge delete


when you use cv::drawContours(filterContours,goodContours,i,color,CV_FILLED); contour interior is filled so opencv result is logic.

Without seeing original image I have got some difficulties to understand but may be you shouls add your hierachy test before filled (may be with a parity test too)

LBerger gravatar imageLBerger ( 2015-09-06 08:36:00 -0500 )edit

@LBerger I added the original image, I don't know what you mean by parity test.. Can you explain please?

gdarmon gravatar imagegdarmon ( 2015-09-06 08:42:51 -0500 )edit

If you find a contour it means that color changed dark to light and if you v've got another contour inside I think that it is light to dark and so on. In your problem you don't need to fill all shape or may be changed color

LBerger gravatar imageLBerger ( 2015-09-06 08:52:17 -0500 )edit

@gdarmon: if you include that hierachy[i][2]==-1 check everything is fine so, what is your problem with the rest of your images in that case (can you provide an example)? Anyway, you may want to switch to OpenCV 3.0 (if not using it already) and try the connectedComponents function - findContours is not really the equivalent of regionProps because it does not look for connected components

LorenaGdL gravatar imageLorenaGdL ( 2015-09-06 09:59:32 -0500 )edit

1 answer

Sort by ยป oldest newest most voted

answered 2015-09-06 10:57:31 -0500

LBerger gravatar image

updated 2015-09-06 11:02:29 -0500

with this program color are blue or green as funtion level in hierarchy (and not if contour have got a son or not) vector<vector<point> > contours; vector<vec4i> hierarchy; vector<char> fillCtr; Mat c;

void DrawTree( int idx, int level)
    int i=idx;
    if (level%2==0)
        drawContours(c, contours, i, Scalar(255  , 0,0),CV_FILLED);
        drawContours(c, contours, i, Scalar(0, 255 ,0),CV_FILLED);
    while (hierarchy[i][0]!=-1)
        int j=hierarchy[i][0];
        if (fillCtr[j] == 0)
            if (level%2==0)
                drawContours(c, contours, j, Scalar(255  , 0,0),CV_FILLED);
                drawContours(c, contours, j, Scalar(0, 255 ,0),CV_FILLED);

    if (hierarchy[idx][2]!=-1)

int main (int argc,char **argv)

 Mat x = imread("14415468805620458.jpg",CV_LOAD_IMAGE_GRAYSCALE);
Mat y;
Mat yc;
findContours(y,contours,hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
c =Mat::zeros(x.size(),CV_8UC3);
vector<Mat> plan = {x,x,x};
cout << c.channels() << "\n";
for( int i=0;i <contours.size();i++)
   if (hierarchy[i][3] == -1 && fillCtr[i]==0)

edit flag offensive delete link more
Login/Signup to Answer

Question Tools

1 follower


Asked: 2015-09-06 07:47:28 -0500

Seen: 924 times

Last updated: Sep 06 '15