OpenCV - 拟合叶子在fitEllipse()的轮廓内

时间:2016-04-20 16:49:49

标签: opencv image-processing computer-vision shape image-recognition

在这个项目中,我必须在椭圆内部装入许​​多不同的叶子图像(一次一个)以获得以下信息:

1)宽高比;

2)平均直径,测量每2度的直径;

3)半径比;

4)圆度;

5)卑鄙的恐惧。

问题是:当我试图将对象装入椭圆内部时,椭圆实际上是在其内部绘制的,因此,对象的高度和宽度是错误的。 我无法理解我做错了什么,因为我使用findNonZero()只获得实际上有像素的图像部分。

结果如下:enter image description here

这是我的代码:

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

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

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


/*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);
waitKey(0);

//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);
waitKey(0);

//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);
waitKey(0);
destroyAllWindows;

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

编辑1:

在回答用户提出的问题时,我决定编辑主帖而不是简单回复而没有新图像来说明情况。

findCountours()之后的掩码如下所示: enter image description here

没有它: enter image description here

我们没有轮廓,最终结果总是一样。

编辑2:

根据用户 sietschie 提供的解决方案,我尝试实现他的代码here,但事实证明我总是在第105行收到错误。命令行显示的消息是:

OpenCV错误:cvFitEllipse2中输入数组的大小不正确(点数应该> = 5),文件C:\ builds \ 2_4_PackSlave-win64-vc12-shared \ opencv \ modules \ imgproc \ src.cpp,第799行

我仍然无法弄清楚我做错了什么,因为他在写作和工作时也是如此,因为他展示了结果。 为了试着理解发生了什么,我得到了轮廓的图像(第104行),它实际上看起来很奇怪:

enter image description here

1 个答案:

答案 0 :(得分:0)

问题是,您尝试使用蒙版的所有白色像素来拟合椭圆。这导致椭圆试图最小化到所有白色像素的距离。你想要的是一个椭圆,它最大限度地减少了到面具轮廓的距离。像这样:

std::vector< std::vector<cv::Point> > contours;
cv::Mat tmp = mask.clone();
cv::findContours(tmp, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
cv::RotatedRect elipse = cv::fitEllipse(contours[0]);

除了茎所在的区域外,这会产生更好的近似值。

enter image description here