Ask Your Question

OpenCV Draw draw contours of 2 largest objects

asked 2013-02-21 14:59:28 -0500

Tomazi gravatar image

updated 2013-02-21 17:18:59 -0500

I am doing a OpenCV software that detects boxing gloves therefore i want to detect and draw only 2 largest contours (one for each boxing glove).

My software draws contours for everything and some things are noise only which ofcourse i dont want

My code for drawing contours:

   vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours(mBlur, contours, hierarchy, CV_RETR_EXTERNAL,  CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

    vector<vector<Point> > contours_poly(contours.size());
    vector<Rect> boundRect (contours.size());
    vector<Point2f> boundingBoxArea(boundRect.size());


    for( int i = 0; i < contours.size(); i++ )
       approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
       boundRect[i] = boundingRect( Mat(contours_poly[i]) );


    /// Draw polygonal contour + bonding rects
   Mat drawing = Mat::zeros( range_out.size(), CV_8UC3 );

    for( int i = 0; i< contours.size(); i++ )

           Scalar color = Scalar(0,0,255);
           drawContours( drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
           fillPoly(drawing, contours, Scalar(255,0,0));


Example Image image description My program already segments the gloves by color, The problelem is that at times small contours are drawn in random locations due to noise. Now of course the gloves contours are by far dominant and this is why i want to keep only the contours of these. Hope this makes my question clearer

Could someone suggest a solution please I am coding in C++ environment regards

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted

answered 2013-02-22 05:52:08 -0500

AndreasM gravatar image

updated 2013-02-22 07:40:56 -0500

A simple approach could be to judge the size by the number of points in the contour and simply remove all contours which are not one of the two biggest. Something like this (right after findContours):

// Before all this you must #include <algorithm> to have access to min_element() and max_element()

int contourIds[] = {0, 1}; // Holds the indexes of the two largest contours.
int contourSizes[] = {contours[0].size(), contours[1].size()}; // Holds the values of the two largest contours.
for(int i = 2; i < (int)contours.size(); i++) { // Find the largest contours, start scanning at contour 2, since 0 and 1 are out initial assumptions for the largest.
    int smallest = *std::min_element(contourSizes, contourSizes+2);
    if(contours[i].size() <= smallest) {
        continue; // This contour is smaller than the two stored contours, so we ignore it.
    // Replace the smallest:
    int smallestId = contourSizes[0] != smallest; // Find if the smallest is contained in spot 0 or 1 in contourIds and contourSizes (using that false == 0 and true == 1)
    contourIds[smallestId] = i;
    contourSizes[smallestId] = contours[i].size();
// Erase the 3 intervals of smaller contours:
contours.erase(contours.begin(), contours.begin()+*std::min_element(contourIds, contourIds+2));
contours.erase(contours.begin()+*std::min_element(contourIds, contourIds+2)+1, contours.begin()+*std::max_element(contourIds, contourIds+2));
contours.erase(contours.begin()+*std::max_element(contourIds, contourIds+2)+1, contours.end());

I have not tested the above code, but I think it should more or less work.

If you want to use the actual areas you can calculate the area of the contours with contourArea and store the actual area instead of the vector size in contourSizes. The code above should still work in that case.

edit flag offensive delete link more

Question Tools


Asked: 2013-02-21 14:59:28 -0500

Seen: 3,620 times

Last updated: Feb 22 '13