Wednesday, November 28, 2012

OpenCV Find Biggest Contour

          Here is an example to find largest contour from the input image. A contour can be considered as a sequence of points that define a specific object in an image. Here I took contours as the brightest object in the image. Contours can be easily extracted  by thresholding the gray scale image.

   After creating the contour images the function to find biggest contour is called where contour scanner used to scan through each contour and find biggest contour.

If you want C++ code, see my new post , OpenCV Find Biggest Contour Using C++

Here is the C code


 
#include <iostream>  
 #include "opencv2/highgui/highgui.hpp"  
 #include "opencv/cv.h"  
 using namespace cv;  
 using namespace std;  
 cv::Mat FC_FindBiggestContours(cv::Mat src);  
 CvRect R;  
 int main()  
 {  
   cv::Mat src;  
   cv::Mat src_binary;  
   src=cv::imread("src.jpeg");  
   if(src.empty()){  
     cout<<"Cannot load the image !"<<endl;  
     return 0;  
     }  
    cvtColor(src, src_binary, CV_BGR2GRAY); // Convert BGR to gray  
    cv::threshold(src_binary, src_binary, 200, 255, 0); // Threshold the image to convert binary image  
    imshow("src_binary",src_binary);  
    src_binary=FC_FindBiggestContours(src_binary);  
    rectangle(src, Point(R.x,R.y), Point(R.x+R.width,R.y+R.height), Scalar(0,255,0),2,8, 0);  
    imshow("Largest Contour", src_binary);  
    imshow("Source",src);  
    cvWaitKey(0); // Wait for key press  
    return 0;  
 }  
 cv::Mat FC_FindBiggestContours(cv::Mat mat_src)  
  {  
    IplImage temp=mat_src;  
    IplImage *src_img=cvCreateImage(cvSize(temp.width,temp.height),IPL_DEPTH_32S,1);  
    IplImage *dest=cvCreateImage(cvSize(temp.width,temp.height),IPL_DEPTH_8U,1);  
    CvArr* _mask=&temp;  
    int poly1Hull0=1;  
    CvPoint offset;  
    offset.x=0;  
    offset.y=0;  
   CvMat mstub, *mask = cvGetMat( _mask, &mstub );  
   CvMemStorage* tempStorage = cvCreateMemStorage();  
   CvSeq *contours, *c;  
   int nContours = 0;  
   double largest_length = 0,len = 0;  
   CvContourScanner scanner;  
   // clean up raw mask  
   cvMorphologyEx( mask, mask, 0, 0, CV_MOP_OPEN, 1 );  
   cvMorphologyEx( mask, mask, 0, 0, CV_MOP_CLOSE, 1 );  
   // find contours around only bigger regions  
   scanner = cvStartFindContours( mask, tempStorage,  
                   sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, offset );  
   while( (c = cvFindNextContour( scanner )) != 0 )  
   {  
     len = cvContourPerimeter( c );  
     if(len > largest_length)  
     {  
       largest_length = len;  
     }  
   }  
   contours=cvEndFindContours( &scanner );  
   scanner = cvStartFindContours( mask, tempStorage,  
                   sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, offset );  
   while( (c = cvFindNextContour( scanner )) != 0 )  
   {  
     len = cvContourPerimeter( c );  
     double q = largest_length ;  
     if( len < q ) //Get rid of blob if it's perimeter is too small  
       cvSubstituteContour( scanner, 0 );  
     else  //Smooth it's edges if it's large enough  
     {  
       CvSeq* newC;  
       if( poly1Hull0 ) //Polygonal approximation of the segmentation  
         newC = cvApproxPoly( c, sizeof(CvContour), tempStorage, CV_POLY_APPROX_DP, 2, 0 );  
       else //Convex Hull of the segmentation  
         newC = cvConvexHull2( c, tempStorage, CV_CLOCKWISE, 1 );  
       cvSubstituteContour( scanner, newC );  
       nContours++;  
       R=cvBoundingRect(c,0);  
     }  
   }  
   contours = cvEndFindContours( &scanner );  
   // paint the found regions back into the image  
   cvZero( src_img );  
   cvZero( _mask );  
   for( c=contours; c != 0; c = c->h_next )  
   {  
     cvDrawContours( src_img, c, cvScalarAll(1), cvScalarAll(1), -1, -1, 8,  
             cvPoint(-offset.x,-offset.y));  
   }  
     cvReleaseMemStorage( &tempStorage );  
 // convert to 8 bit IplImage  
  for( int i = 0; i < src_img->height; i++ )  
    for( int j = 0; j < src_img->width; j++ )  
    {  
     int idx = CV_IMAGE_ELEM( src_img, int, i, j );  //get reference to pixel at (col,row),  
     uchar* dst = &CV_IMAGE_ELEM( dest, uchar, i, j );                          //for multi-channel images (col) should be multiplied by number of channels */  
     if( idx == -1 || idx == 1 )  
      *dst = (uchar)255;  
     else if( idx <= 0 || idx > 1 )  
      *dst = (uchar)0; // should not get here  
     else {  
      *dst = (uchar)0;  
        }  
      }  
  cvReleaseImage(&src_img);  
  Mat ret=cvarrToMat(dest);  
  return ret;  
 } 
 The source image:
src.jpeg
 
Result:
Hope these help.
  

4 comments:

  1. Hi, thanks for the post...
    I want to ask, what about moving object, how to find the biggest contour?

    Regards & Thanks

    ReplyDelete
    Replies
    1. Hi you can do these for each frame and compare the contour for maximum area.

      Delete