Ask Your Question
0

Need Help with correct approach for getting just the leaf area as image from a white background Image

asked 2019-11-09 14:12:13 -0600

karDilip gravatar image

updated 2019-11-10 05:44:08 -0600

Hello Everyone!

Have been struggling for some time now to get the correct approach to grap a leaf (Rice/Wheat/Grass) object over a white background. Have tried multiple approach for same and will share what I've tried so far.

Kindly note: - Leaf is not completely inside the image. - Leaf can be rotated at any angle. - Leaf may not be uniform in size as well, i.e. getting thinner at ends.

So far, have tried below approach to get the final image to include only leaf:

  1. Get image, convert from RGB to BGR.
  2. Convert to Grayscale
  3. Apply threshold, Binary Inverse
  4. Get Contours, find maximum area Contour
  5. Get minimum area Rectangle from the maximum contour.
  6. Find Rotation Matrix
  7. Apply warpAffine
  8. Get Submat.

With all these steps, the output comes to be like below:

image description

Issue is for output Image, just the Leaf Area is needed - No White Region or Black Patches. I've tried drawing contours, but don't know how to pick exactly the contour area and save as a image.(The object not completely inside is a issues) Have also tried making the background transparent after getting the required area after applying mask, but the writing the png file with transparent background is taking too much time.

Kindly suggest if there can be simpler approach to just get the leaf area as a separate image ? I'm new to OpenCV and trying to learn more.

Code Reference Java OpenCV 3.4:

    Size kernelsize = new Size(11, 11);
       //Convert Original Image to GrayScale
        Imgproc.cvtColor(cameraInputImg, cameraInputImg, COLOR_RGB2BGR);
        Imgproc.cvtColor(cameraInputImg, grayscale, Imgproc.COLOR_BGR2GRAY);
        //Threshold the Gray Scaled Image, Change the Threshold as per required color applicable under the image.
        Imgproc.threshold(grayscale, threshed, 90, 255, Imgproc.THRESH_BINARY_INV);
        //Set Kernel for the Image
        kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, kernelsize);
        Imgproc.morphologyEx(threshed, morphed, Imgproc.MORPH_CLOSE, kernel);
        Mat hierarchy = new Mat();
        List<MatOfPoint> contours = new ArrayList<>();
        Imgproc.findContours(morphed, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
            //Check for Countours Before proceeding to find structures.
            double maxArea = 0;
            MatOfPoint max_contour = new MatOfPoint();
        if (!contours.isEmpty()) {
            //Find Max Area Contour
            Iterator<MatOfPoint> iterator = contours.iterator();
            while (iterator.hasNext()) {
                MatOfPoint contour = iterator.next();
                double area = Imgproc.contourArea(contour);
                if (area > maxArea) {
                    maxArea = area;
                    max_contour = contour;
                }
            }
        }

RotatedRect boundedLeaf = Imgproc.minAreaRect(new MatOfPoint2f(max_contour.toArray()));
        Mat rotated = new Mat();
        Mat cropped = new Mat();
        double angle = boundedLeaf.angle;
        Size rect_size = boundedLeaf.size;
        double temp;
            // thanks to http://felix.abecassis.me/2011/10/opencv-rotation-deskewing/
            if (angle < -45.) {
                angle += 90.0;
                temp = rect_size.width;
                rect_size.width = rect_size.height;
                rect_size.height = temp;
                }
            // get the rotation matrix
             M = Imgproc.getRotationMatrix2D(boundedLeaf.center, angle, 1);
            // perform the affine transformation
            Imgproc.warpAffine(cameraInputImg, rotated, M, cameraInputImg.size(), INTER_CUBIC, BORDER_CONSTANT, white);   //Refine if needed.
            Imgproc.getRectSubPix(rotated, rect_size, boundedLeaf.center, cropped);

Sample Input Image: image description

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
0

answered 2019-11-10 02:33:48 -0600

mvuori gravatar image

Merging the contour contents with transparent. background is the only way, see https://answers.opencv.org/question/3... ... but if saving the result takes too much time, you are out of luck...

edit flag offensive delete link more

Comments

Thank you for kind response. Have tried the same, but need only green sections under the image not even the transparent background. The image will be fed to next process to pick points and process on same and should include only green data.

Having a best fit rectangle inside the contour will be exactly what I'll need and that would be huge help! Was looking at 1. https://stackoverflow.com/questions/3... 2. https://stackoverflow.com/questions/3...

With these also, will get Rotated Rectangle and getting it to Rectangle gets messy. Do we have a similar process for getting best fit rectangle inside a Contour for Java?

karDilip gravatar imagekarDilip ( 2019-11-10 05:36:05 -0600 )edit

Also, as you can see from the Output Image, there are color variation, may be close up to the image is modifying the intensity of color. I'm converting the original image from RGB to BGR before processing the same in OpenCV. Can there be any other reason for change in Color for the output... I'm afraid color variations after processing with OpenCV may lead to issues in next set of processing. Any comments ?

karDilip gravatar imagekarDilip ( 2019-11-10 05:43:23 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2019-11-09 14:12:13 -0600

Seen: 391 times

Last updated: Nov 10 '19