Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

You can segment the number easily using watershed() for this you need to create markers to distinguish foreground and background.

1. Create Mask: As first step we will create make image, you need to do adaptiveThreshold(), contour finding(largest), convexHull() etc..

image description image description

Below is the code how to do it

Mat src=imread("src.jpg",1);
Mat thr,gray;
cvtColor(src,gray,CV_BGR2GRAY);
adaptiveThreshold(gray,thr,255,ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY,51,5);

vector< vector <Point> > contours; // Vector for storing contour
vector< Vec4i > hierarchy;
int largest_contour_index=0;
int largest_area=0;
Mat mask(src.rows,src.cols,CV_8UC1,Scalar::all(0)); //create destination image
findContours( thr.clone(), contours, hierarchy,CV_RETR_EXTERNAL, 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
  }
 }
 vector<vector<Point> >hull(1);
 convexHull(contours[largest_contour_index],  hull[0],false,true );
 drawContours( mask, hull, 0, Scalar(125), -1, 8, vector<Vec4i>(), 0, Point() );

2. Create Foreground: For this you need to do again adaptiveThreshold() but with THRESH_BINARY_INV option, and erode() result to reduce noise, finally find biggest contour which represent your foreground object, here you need to consider the mask while copying to foreground image. The result look like the object to be segmented, but for better result we will move to next steps like background creation, watershed etc..

image description

 Mat fg;
 adaptiveThreshold(gray,thr,255,ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV,151,5);
 erode(thr,thr,Mat(),Point(-1,-1),1);
 contours.clear();
 hierarchy.clear();
 largest_contour_index=0;
 largest_area=0;
 thr.copyTo(fg,mask),
 findContours( fg, contours, hierarchy,CV_RETR_EXTERNAL, 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
    }
   }

 fg.setTo(0);
 drawContours( fg,contours, largest_contour_index, Scalar(255),CV_FILLED, 8, hierarchy );

3. Create Background: Creating background marker is easy as you have mask and foreground just subtract foreground from mask, then apply erode() to make little separation between fg and bg while merging.

image description

 Mat bg=mask-fg;
 erode(bg,bg,Mat(),Point(-1,-1),7);

4. Create Marker for Watershed: Just add up fg and bg and convert CV_32S for passing watershed() image description

5. Perform watershed Operation: Here you need to pass this marker image along with your source image.

image description

 markers.convertTo(markers, CV_32S);
 watershed(src, markers);
 markers.convertTo(markers,CV_8U);
 imshow("Segmented",markers);