Wednesday, June 19, 2013

OpenCV Find Biggest Contour Using C++


                    Using OpencCV C++ interface it is very easy to processing with contour compared to old c interface. In old interface there are object like CvContourScanner  used to scan through each contour and the contours are stored in OpenCV Sequences. Also using all these things the code look like lengthy and complex. So here we are going to do all these thing using c++ interface.  A contour can be considered as a sequence of points that define a specific object in an image. Here in the below image we are going to extract the largest contour.
 




        In the above image each object can be considered as a contour, and the largest object can be find out by comparing area of each object.  So as a first step we have to go through each contour for comparing it's area with the previous one. OpenCV providing various function for doing these and described below.

findContours   :- Find contours in the binary image.
drawContours :- Draw filled contour or outline of contour. 
boundingRect  :- Calculate a bounding rectangle for a contour.
contourArea    :-  Calculate area for a specific contour.


The below code do the following;
  • Load 3 channel image.
  • Convert to single channel gray image.
  • Threshold with a lower value to extract contours.
  • Store all contours as vectors.
  • Find out the biggest contour by comparing area of each contour. 
  • Draw the biggest contour.
  • Show the result.
#include <iostream>
#include "opencv2\highgui\highgui.hpp"
#include "opencv\cv.h"

using namespace cv;
using namespace std;
int main()
{
 int largest_area=0;
 int largest_contour_index=0;
 Rect bounding_rect;

 Mat src = imread("src.jpg"); //Load source image
 Mat thr(src.rows,src.cols,CV_8UC1); 
 Mat dst(src.rows,src.cols,CV_8UC1,Scalar::all(0));
 cvtColor(src,thr,CV_BGR2GRAY); //Convert to gray
 threshold(thr, thr,25, 255,THRESH_BINARY); //Threshold the gray
 
    vector<vector<Point>> contours; // Vector for storing contour
    vector<Vec4i> hierarchy;

    findContours( thr, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); // Find the contours in the image
  
     for( int i = 0; i< contours.size(); i++ ) // iterate through each contour. 
      {
       double a=contourArea( contours[i],false);  //  Find the area of contour
       if(a>largest_area){
       largest_area=a;
       largest_contour_index=i;                //Store the index of largest contour
       bounding_rect=boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
       }
  
      }

 Scalar color( 255,255,255);
 drawContours( dst, contours,largest_contour_index, color, CV_FILLED, 8, hierarchy ); // Draw the largest contour using previously stored index.
 rectangle(src, bounding_rect,  Scalar(0,255,0),1, 8,0);  
 imshow( "src", src );
 imshow( "largest Contour", dst );
 waitKey(0);
}


Result:- 

Source Image










Largest Contour

14 comments:

  1. It draws rectangle on the whole frame. and not on the individual contours? How can I resolve it?

    Regards,

    ReplyDelete
    Replies
    1. Probably your image contain boarder, and findcontour() will take the boarder as the first contour and it will be always the biggest contour that's why you are getting whole the image as biggest contour. To solve this either you have to use imageROI or take second biggest contour as your result. The second method may cause false result if image boarder is not there.

      Delete
  2. Hello, how can I compute width and length of the bounded rectangular?

    ReplyDelete
    Replies
    1. Rect bounding_rect=boundingRect(contours[i]) will give you the bounding rect for contour i

      where ,
      bounding_rect.x ---> x co-ordinate of rectangle
      bounding_rect.y ---> y co-ordinate of rectangle
      bounding_rect.width ---> width of rectangle
      bounding_rect.height ---> height of rectangle

      Delete
  3. Hi.. That worked perfectly. I need your help, how can I get the extract numbers from the Contours ?
    I have successfully implemented Corner Detection, Reduced noise with finding the Contours in the image, which shows all of the contours in the image. But now, I have to extract the numbers from these contours, how can I achieve this, any link ?

    ReplyDelete
    Replies
    1. Probably these links might be helpful,
      http://stackoverflow.com/questions/9413216/simple-digit-recognition-ocr-in-opencv-python/20902310#20902310
      https://github.com/MasteringOpenCV/code/tree/master/Chapter5_NumberPlateRecognition

      Delete
  4. I get memory exception error when trying to extract features of large size objects what is the possible reason for it

    ReplyDelete
    Replies
    1. Large size objects means large image with large contour? Are you using the same code above, if not probably memory leaks in the code can cause the problem.

      Delete
  5. i want to detect any shape of largest area in video so that it could match with shapes of still image by using match shapes ???

    ReplyDelete
  6. can u upload C# implementation of this code???

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. I tried this program with live streaming Video it works fine but after some time it throws error " Unhandled exception at 0x77c83e28 in contourdetails.exe: Microsoft C++ exception: cv::Exception at memory location 0x00aaeb24.."


    Please help with the below program.


    #include
    #include
    #include

    using namespace std;
    using namespace cv;

    int main()
    {
    Mat threshC;
    Mat HSV;
    Mat frame;
    int bmin=0,bmax=0,gmin=0,gmax=0,rmin=0,rmax=0;
    int ContLargestArea=0;
    int ContLargestIndex=0;

    VideoCapture cp(0);

    while(true)
    {

    namedWindow("Trackbar");

    createTrackbar("Blue Min","Trackbar",&bmin,255);
    createTrackbar("Blue Max","Trackbar",&bmax,255);
    createTrackbar("Red Min","Trackbar",&rmin,255);
    createTrackbar("Red Max","Trackbar",&rmax,255);
    createTrackbar("Green Min","Trackbar",&gmin,255);
    createTrackbar("Green Max","Trackbar",&gmax,255);

    cp.read(frame);
    cvtColor(frame,HSV,COLOR_BGR2HSV);
    inRange(HSV,Scalar(bmin,bmax,rmin),Scalar(rmax,gmin,gmax),threshC);
    Mat dst(threshC.rows,threshC.cols,CV_8UC1,Scalar::all(0));


    vector> contours;
    vector hierarchy;
    Rect bounding_rect;

    findContours(threshC,contours,hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

    for(int i=0;iContLargestArea)
    {
    ContLargestArea=a;
    ContLargestIndex=i;
    bounding_rect=boundingRect(contours[i]);
    }
    }
    Scalar color( 255,255,255);
    drawContours(dst,contours,ContLargestIndex,color, CV_FILLED,8, hierarchy );
    rectangle(frame, bounding_rect, Scalar(0,255,0),1, 8,0);

    imshow("Original image",frame);
    imshow(" thresh image ",threshC);

    char key=cvWaitKey(33);
    if(key==27)
    {
    break;
    }

    }


    }

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
  10. http://stackoverflow.com/questions/41603051/python-identify-image-characters

    please can you help ?

    ReplyDelete