1

I'm trying to find the values for Height and Width to recover the Aspect Ration of the object using the contour of an image with the code below but not having success, since the code is creating many rectangles all over the image, when my intention is to create a single rectangle around the object. I'm trying to create this rectangle because i don't know if there is another way to get the Height and Width (or even the Aspect Ratio) other than this one.

***RNG rng(12345); //Global Variable used for drawing rectangles and circles for the contours of images.

/*Load the image*/
Mat img_bgr = imread("img.jpg", 1);
if (img_bgr.empty()){
    cout << "No image..." << endl;
    return -1;
}

/*Display the image*/
namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", img_bgr);

/*Conversion to HSV*/
Mat img_hsv;
cvtColor(img_bgr, img_hsv, CV_BGR2HSV);

/*Extracting colors - HSV*/
Mat green, yellow, brown;

//Yellow
inRange(img_hsv, Scalar(25, 0, 0), Scalar(36, 255, 255), yellow);   //until 33 - consider "yellow" - from there up to 36 - consider for chlorosis
imwrite("c:\\test\\results\\yellow.jpg", yellow);

//Green
inRange(img_hsv, Scalar(37, 0, 0), Scalar(70, 255, 255), green);    //Consider lower as 37
imwrite("c:\\test\\results\\green.jpg", green);

//Brown
inRange(img_hsv, Scalar(10, 0, 0), Scalar(20, 255, 255), brown);
imwrite("c:\\test\\results\\brown.jpg", brown);

namedWindow("Yellow", WINDOW_NORMAL);
imshow("Yellow", yellow);

namedWindow("Green", WINDOW_NORMAL);
imshow("Green", green);

namedWindow("Brown", WINDOW_NORMAL);
imshow("Brown", brown);

/*Finding Contours of the Thresholded images*/
vector<std::vector<Point>>green_cnt;
vector<std::vector<Point>>yellow_cnt;
vector<std::vector<Point>>brown_cnt;

//Green Contour
findContours(green, green_cnt, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);

//Draw the Contours - Green
Mat green_cnt_draw(green.size(), CV_8UC3, Scalar(0, 0, 0));
Scalar green_cnt_colors[3];
green_cnt_colors[0] = Scalar(0, 255, 0);
green_cnt_colors[1] = Scalar(0, 255, 0);
green_cnt_colors[2] = Scalar(0, 255, 0);

for (size_t idx_green = 0; idx_green < green_cnt.size(); idx_green++){
    drawContours(green_cnt_draw, green_cnt, idx_green, green_cnt_colors[idx_green % 3]);
}

namedWindow("Green - Contours", CV_WINDOW_NORMAL);
imshow("Green - Contours", green_cnt_draw);

//Yellow Contour
findContours(yellow, yellow_cnt, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);

//Draw the Contours - Yellow
Mat yellow_cnt_draw(yellow.size(), CV_8UC3, Scalar(0, 0, 0));
Scalar yellow_cnt_colors[3];
yellow_cnt_colors[0] = Scalar(0, 255, 255);
yellow_cnt_colors[1] = Scalar(0, 255, 255);
yellow_cnt_colors[2] = Scalar(0, 255, 255);

for (size_t idx_yellow = 0; idx_yellow < yellow_cnt.size(); idx_yellow++){
    drawContours(yellow_cnt_draw, yellow_cnt, idx_yellow, yellow_cnt_colors[idx_yellow % 3]);
}

namedWindow("Yellow - Contours", CV_WINDOW_NORMAL);
imshow("Yellow - Contours", yellow_cnt_draw);

//Brown Contour
findContours(brown, brown_cnt, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);

//Draw the Contours - Brown
Mat brown_cnt_draw(brown.size(), CV_8UC3, Scalar(0, 0, 0));
Scalar brown_cnt_colors[3];
brown_cnt_colors[0] = Scalar(42, 42, 165);
brown_cnt_colors[1] = Scalar(42, 42, 165);
brown_cnt_colors[1] = Scalar(42, 42, 165);

for (size_t idx_brown = 0; idx_brown < brown_cnt.size(); idx_brown++){
    drawContours(brown_cnt_draw, brown_cnt, idx_brown, brown_cnt_colors[idx_brown % 3]);
}

namedWindow("Brown - Contours", CV_WINDOW_NORMAL);
imshow("Brown - Contours", brown_cnt_draw);


/*Creating rectangles around the contours*/
//Green
vector<vector<Point>>green_contours_poly(green_cnt.size());
vector<Rect>green_boundRect(green_cnt.size());
vector<Point2f>green_center(green_cnt.size());
vector<float>green_radius(green_cnt.size());

for (int i = 0; i < green_cnt.size(); i++){
    approxPolyDP(Mat(green_cnt[i]), green_contours_poly[i], 3, true);
    green_boundRect[i] = boundingRect(Mat(green_cnt[i]));
    minEnclosingCircle((Mat)green_contours_poly[i], green_center[i], green_radius[i]);
}

//Green - Draw polygonal contour AND bounding rects + circles
Mat green_drawRecAndCirc = Mat::zeros(green.size(), CV_8UC3);
for (int i = 0; i < green_cnt.size(); i++){
    Scalar green_drawRecAndCircColor = Scalar(rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255));
    rectangle(green_drawRecAndCirc, green_boundRect[i].tl(), green_boundRect[i].br(), green_drawRecAndCircColor, 2, 8, 0);
    //circle(green_drawRecAndCirc, green_center[i], (int)green_radius[i], green_drawRecAndCircColor, 2, 8, 0);
}
imwrite("c:\\testeimagem\\theeye\\resultados\\green_rectangle_and_circle.jpg", green_drawRecAndCirc);

namedWindow("Green - Rectangle and Circle", CV_WINDOW_NORMAL);
imshow("Green - Rectangle and Circle", green_drawRecAndCirc);

/*Creating rectangles around the contours*/
//Yellow
vector<vector<Point>>yellow_contours_poly(yellow_cnt.size());
vector<Rect>yellow_boundRect(yellow_cnt.size());
vector<Point2f>yellow_center(yellow_cnt.size());
vector<float>yellow_radius(yellow_cnt.size());

for (int i = 0; i < yellow_cnt.size(); i++){
    approxPolyDP(Mat(yellow_cnt[i]), yellow_contours_poly[i], 3, true);
    yellow_boundRect[i] = boundingRect(Mat(yellow_cnt[i]));
    minEnclosingCircle((Mat)yellow_contours_poly[i], yellow_center[i], yellow_radius[i]);
}

//Yellow - Draw polygonal contour AND bounding rects + circles
Mat yellow_drawRecAndCirc = Mat::zeros(yellow.size(), CV_8UC3);
for (int i = 0; i < yellow_cnt.size(); i++){
    Scalar yellow_drawRecAndCircColor = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    rectangle(yellow_drawRecAndCirc, yellow_boundRect[i].tl(), yellow_boundRect[i].br(), yellow_drawRecAndCircColor, 2, 8, 0);
    //circle(green_drawRecAndCirc, green_center[i], (int)green_radius[i], green_drawRecAndCircColor, 2, 8, 0);
}
waitKey(0);
destroyAllWindows;

return 0;

The original image is here:

enter image description here

And the example of the final result is here:

enter image description here

I tried the examples described in the following link (OpenCV Bounding Box) but I couldn't make it work either.


Edit 2:

Since i have to find some characteristics of the leaf that i cannot find with a rectangle (like, aspect ratio, mean diameter, radius ratio, roundness and mean feret) i had to change the approach of finding the leaf from a rectangle to an ellipse. The thing is, the ellipse is being drawn inside the leaf insteaf of contouring it.

Here is my code:

/*Load the image*/
Mat img_bgr = imread("image path", 1);
if (img_bgr.empty()){
    cout << "No image found..." << endl;
    return -1;
}

/*Conversion to HSV*/
Mat img_hsv;
cvtColor(img_bgr, img_hsv, CV_BGR2HSV);

/*Extracting colors - HSV*/
Mat yellow, green, brown;

//Yellow
inRange(img_hsv, Scalar(25, 80, 80), Scalar(36, 255, 255), yellow);

//Green
inRange(img_hsv, Scalar(37, 80, 80), Scalar(70, 255, 255), green);

//Brown
inRange(img_hsv, Scalar(10, 80, 80), Scalar(30, 200, 200), brown);

// logical OR mask
Mat1b mask = yellow | green | brown;

// Find non zero pixels
vector<Point> pts;

findNonZero(mask, pts);

// Compute ellipse
RotatedRect elipse = fitEllipse(pts);

//ELLIPSE - Heigth, Width and Center of Mass
cout << "ELLIPSE:" << endl;
cout << "\nHeight and Width: " << elipse.size;  //Height and Width
cout << "\nCenter of Mass: " << elipse.center << endl;  //Center of mass (probably given in X and Y coordinates)

// Show Ellipse
ellipse(img_bgr, elipse, Scalar(0, 0, 255), 3);
namedWindow("Ellipse", CV_WINDOW_NORMAL);
imshow("Ellipse", img_bgr); 

waitKey(0);
destroyAllWindows;

return 0;

The result is shown below:

enter image description here

I can't understand what I'm doing wrong since i just changed the code the user Miki gave and that actually works perfectly.

2
  • 1
    You need "one big box to rule them all"... Commented Apr 17, 2016 at 20:12
  • Hi Karl. I see you are the author of a solution mentioned on the link i posted. Please, feel free to share your experience and knowledge with us.
    – Nicholas
    Commented Apr 17, 2016 at 21:45

1 Answer 1

1

Since your image is quite simple (you have a flat background) you can simplify a lot the task of finding the leaf. However, here I still use your approach based on thresholding the HSV values, which is likely to be more robust in general.


To find width and height of the leaf, you basically need to find it's bounding box. You don't need to find all contours of your color masks, nor to merge all bounding boxes. But you can:

1) compute the mask for the yellow, green and brown colors (I sligthly modified the ranges to more meaningful values)

Yellow:

enter image description here

Green:

enter image description here

Brown:

enter image description here

2) OR these mask toghether

enter image description here

3) find all non zero pixels 4) compute the bounding box

enter image description here

Code:

#include <opencv2/opencv.hpp>
#include <vector>
#include <string>

using namespace std;
using namespace cv;

int main()
{
    // Load the image
    Mat3b img_bgr = imread("path_to_image");
    if (img_bgr.empty()){
        cout << "No image..." << endl;
        return -1;
    }

    // Convert to hsv
    Mat3b img_hsv;
    cvtColor(img_bgr, img_hsv, COLOR_BGR2HSV);

    Mat1b yellow, green, brown;

    //Yellow
    inRange(img_hsv, Scalar(25, 80, 80), Scalar(36, 255, 255), yellow);
    //Green
    inRange(img_hsv, Scalar(37, 80, 80), Scalar(70, 255, 255), green);
    //Brown
    inRange(img_hsv, Scalar(10, 80, 80), Scalar(30, 200, 200), brown);

    // logical OR mask
    Mat1b mask = yellow | green | brown;

    // Find non zero pixels
    vector<Point> pts;
    findNonZero(mask, pts);

    // Compute bounding box
    Rect box = boundingRect(pts);

    cout << "Width: " << box.width;
    cout << "Height: " << box.height << endl;

    // Show box
    rectangle(img_bgr, box, Scalar(0,0,255), 3);
    imshow("Box", img_bgr);

    return 0;
}
3
  • can you please tell me how to get the width and height of the leaf?
    – user3600801
    Commented Jun 22, 2017 at 17:47
  • it prints some multi digit number
    – user3600801
    Commented Jun 22, 2017 at 17:47
  • It's in the end of the code, as Miki demonstrated: // Compute bounding box Rect box = boundingRect(pts); cout << "Width: " << box.width; cout << "Height: " << box.height << endl; // Show box rectangle(img_bgr, box, Scalar(0,0,255), 3); imshow("Box", img_bgr);
    – Nicholas
    Commented Jul 5, 2017 at 17:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.