Need Help with correct approach for getting just the leaf area as image from a white background Image
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:
- Get image, convert from RGB to BGR.
- Convert to Grayscale
- Apply threshold, Binary Inverse
- Get Contours, find maximum area Contour
- Get minimum area Rectangle from the maximum contour.
- Find Rotation Matrix
- Apply warpAffine
- Get Submat.
With all these steps, the output comes to be like below:
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: