OpenCV - 查找轮廓图像的高度和宽度

时间:2016-04-17 19:14:03

标签: c++ opencv image-processing shape image-recognition

我试图找到高度和宽度的值,使用下面的代码但没有成功的图像轮廓恢复对象的Aspect Ration,因为代码在整个区域创建了许多矩形图像,当我打算在对象周围创建一个矩形时。 我试图创建这个矩形,因为我不知道是否有另一种方法来获得除此之外的高度和宽度(甚至是宽高比)。

*** RNG rng(12345); //全局变量用于绘制图像轮廓的矩形和圆形。

/*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;

原始图片在这里:

enter image description here

最终结果的例子在这里:

enter image description here

我尝试了以下链接(OpenCV Bounding Box)中描述的示例,但我也无法使其正常工作。

编辑2:

因为我必须找到一些我用矩形找不到的叶子的特征(如长宽比,平均直径,半径比,圆度和平均值)我不得不改变从矩形中找到叶子的方法到一个椭圆。事实上,椭圆正被绘制在轮廓内的叶子内部。

这是我的代码:

/*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;

结果如下所示:

enter image description here

我无法理解我做错了什么,因为我只是更改了用户 Miki 给出的代码,而且实际上效果非常好。

1 个答案:

答案 0 :(得分:1)

由于您的图像非常简单(背景平坦),因此可以简化查找叶子的任务。但是,在这里我仍然使用基于阈值HSV值的方法,这通常可能更加稳健。

要查找叶子的宽度和高度,您基本上需要找到它的边界框。您不需要查找颜色蒙版的所有轮廓,也不需要合并所有边界框。但你可以:

1)计算黄色,绿色和棕色的遮罩(我将范围修改为更有意义的值)

黄色:

enter image description here

绿色:

enter image description here

布朗:

enter image description here

2)或这些面具是否

enter image description here

3)找到所有非零像素 4)计算边界框

enter image description here

代码:

#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;
}