Extract one object from bunch of objects and detect edges

Grant picture Grant · Jun 26, 2014 · Viewed 8.4k times · Source

For my college project I need to identify a species of a plant from plant leaf shape by detecting edges of a leaf. (I use OpenCV 2.4.9 and C++), but the source image has taken in the real environment of the plant and has more than one leaf. See the below example image. So here I need to extract the edge pattern of just one leaf to process further.

enter image description here

Using Canny Edge Detector I can identify edges of the whole image.

enter image description here

But I don't know how to proceed from here to extract edge pattern of just one leaf, may be more clear and complete leaf. I don't know even if this is possible also. Can anyone please tell me if this is possible how to extract edges of one leaf I just want to know the image peocessing steps that I need to apply to the image. I don't want any code samples. I'm new to image processing and OpenCV and learning by doing experiments.

Thanks in advance.

Edit

As Luis said said I have done Morphological close to the image after doing edge detection using Canny edge detection, but it seems still it is difficult me to find the largest contour from the image. Here are the steps I have taken to process the image

  1. Apply Bilateral Filter to reduce noise

    bilateralFilter(img_src, img_blur, 31, 31 * 2, 31 / 2);
    
  2. Adjust contrast by histogram equaliztion

    cvtColor(img_blur,img_equalized,CV_BGR2GRAY);
    
  3. Apply Canny edge detector

    Canny(img_equalized, img_edge_detected, 20, 60, 3);
    
  4. Threshold binary image to remove some background data

    threshold(img_edge_detected, img_threshold, 1, 255,THRESH_BINARY_INV);
    
  5. Morphological close of the image

    morphologyEx(img_threshold, img_closed, MORPH_CLOSE, getStructuringElement(MORPH_ELLIPSE, Size(2, 2)));
    

Following are the resulting images I'm getting.

This result I'm getting for the above original image

enter image description here

Source image and result for second image

Source :

enter image description here

Result :

enter image description here

Is there any way to detect the largest contour and extract it from the image ?

Note that my final target is to create a plant identification system using real environmental image, but here I cannot use template matching or masking kind of things because the user has to take an image and upload it so the system doesn't have any prior idea about the leaf.

Here is the full code

#include <opencv\cv.h>
#include <opencv\highgui.h>
using namespace cv;

int main()
{
Mat img_src,     img_blur,img_gray,img_equalized,img_edge_detected,img_threshold,img_closed;
//Load original image
img_src = imread("E:\\IMAG0196.jpg");

//Apply Bilateral Filter to reduce noise
bilateralFilter(img_src, img_blur, 31, 31 * 2, 31 / 2);

//Adjust contrast by histogram equaliztion
cvtColor(img_blur,img_equalized,CV_BGR2GRAY);

//Apply Canny edge detector
Canny(img_equalized, img_edge_detected, 20, 60, 3);

//Threshold binary image to remove some background data
threshold(img_edge_detected, img_threshold, 15, 255,THRESH_BINARY_INV);

//Morphological close of the image
morphologyEx(img_threshold, img_closed, MORPH_CLOSE, getStructuringElement(MORPH_ELLIPSE, Size(2, 2)));

imshow("Result", img_closed);
waitKey(0);
return 0;
}

Thank you.

Answer

Luis Enrique picture Luis Enrique · Jun 26, 2014

Well there is a similar question that was asked here:

It seems that edge information is not a good descriptor for the image, still if you want to try it I'll do the following steps:

  1. Load image and convert it to grayscale
  2. Detect edges - Canny, Sobel try them and find what it suits you best
  3. Set threshold to a given value that eliminates most background - Binarize image
  4. Close the image - Morphological close dont close the window!
  5. Count and identify objects in the image (Blobs, Watershed)
  6. Check each object for a shape (assuming you have described shapes of the leaf you could find before or a standard shape like an ellipse) features like:
  7. If a given object has a given shape that you described as a leaf then you detected the leaf!.

I believe that given images are taken in the real world these algorithm will perform poorly but it's a start. Well hope it helps :).

-- POST EDIT 06/07

Well since you have no prior information about the leaf, I think the best we could do is the following:

  • Load image
  • Bilateral filter
  • Canny
  • Extract contours
  • Assume: that the contour with the largest perimeter is the leaf
  • Convex hull the 3 or 2 largest contours (the blue line is the convex hull done)
  • Use this convex hull to do a graph cut on the image and segmentate it

If you do those steps, you'll end up with images like these:

Leaf 1 segmentation

Leaf 2 segmentation

I won't post the code here, but you can check it out in my messy github. I hope you don't mind it was made in python.

Leaf - Github

Still, I have a couple of things to finish that could improve the result.. Roadmap would be:

  • Define the mask in the graphcut (like its described in the doc)
  • Apply region grow may give a better convex hull
  • Remove all edges that touch the border of the image can help to identify larger edges

Well, again, I hope it helps