OpenCV的fitEllipse()有时返回完全错误的省略号 [英] OpenCV's fitEllipse() sometimes returns completely wrong ellipses
问题描述
我的目标是识别图像中存在的所有形状。
这个想法是:
- 提取轮廓
- / li>
- 正确的形状应该是最接近
轮廓区域的区域。
示例图片:
我使用 fitEllipse()
找到最适合轮廓的椭圆,但结果有点凌乱:
可能正确的椭圆填充蓝色,边界椭圆为黄色。
可能不正确的轮廓以绿色填充,(错误的)边界椭圆是青色。
如您所见,第一行看起来不错,最适合。第三行中三角形的边界椭圆似乎不是最佳拟合,但仍然可以作为拒绝错误椭圆的标准。
但我可以不知道为什么剩余的三角形有边界椭圆完全在其轮廓之外。
最坏的情况是最后一行中的第三个三角形:椭圆是完全错误的,但它恰好具有接近轮廓的区域的面积,因此三角形被错误地识别为椭圆。
我错过了什么吗?我的代码:
#include< iostream>
#include< opencv / cv.h>
#include< opencv / highgui.h>
using namespace std;
using namespace cv;
void getEllipses(vector< vector< Point>& contours,vector< RotatedRect>& ellipses){
ellipses.clear
Mat img(Size(800,500),CV_8UC3);
for(unsigned i = 0; i if(contours [i] .size()> = 5){
RotatedRect temp = fitEllipse (Mat(contour [i]));
if(area(temp)<= 1.1 * contourArea(contoururs [i])){
// cout<面积(temp) < 1.1 *<<轮廓区域(轮廓[i])< endl;
ellipses.push_back(temp);
drawContours(img,contoururs,i,Scalar(255,0,0),-1,8);
ellipse(img,temp,Scalar(0,255,255),2,8);
imshow(ellipses,img);
waitKey();
} else {
// cout<< 拒绝椭圆< i<< endl;
drawContours(img,contoururs,i,Scalar(0,255,0),-1,8);
ellipse(img,temp,Scalar(255,255,0),2,8);
imshow(Ellipses,img);
waitKey();
}
}
}
}
int main(){
Mat img = imread(image.png,CV_8UC1) ;
threshold(img,img,127,255,CV_THRESH_BINARY);
vector< vector< Point> >轮廓;
vector< Vec4i>层次;
findContours(img,contour,hierarchy,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);
vector< RotatedRect>椭圆
getEllipses(contour,ellipses);
return 0;
}
请记住, code> fitEllipse 不是一个boundingEllipse的计算,而是一个假定点位于一个椭圆上的最小二乘优化。
我不能告诉你为什么它在最后一行的三个三角形失败,但在上面的三角形工作,但我看到的一个事情是,最后一行中的所有3个三角形拟合具有 angle 0
的rotateRect。可能最小二乘法拟合刚刚失败了。
但我不知道openCV实现中是否有错误,或者算法无法处理这些情况。使用此算法: http://www.bmva.org/bmvc/1995/bmvc-95 -050.pdf
我的建议是,只有使用 fitEllipse
点真正属于一个椭圆。如果你有随机数据点,你不会假设从 fitLine
得到合理的结果。您可能需要查看的其他函数有: minAreaRect
和 minEnclosingCircle
$ b如果使用
RotatedRect temp = minAreaRect(Mat(contours [i])); 而不是 fitEllipse
您会得到如下图像:
也许你甚至可以使用这两种方法,并拒绝在两个版本中失败的所有省略号,并接受两个版本都接受的所有省略号,不同?!?
My goal is to recognize all the shapes present in an image.
The idea is:
- Extract contours
- Fit each contour with different shapes
- The correct shape should be the one with area closest to the
contour's area.
Example image:
I use fitEllipse()
to find the best fit ellipse to the contours, but the result is a bit messy:
The likely-correct ellipses are filled with blue, and the bounding ellipses are yellow.
The likely-incorrect contours are filled with green, and the (wrong) bounding ellipses are cyan.
As you can see, the ellipse bounding the triangle in the first row looks pretty good for the best fit. The bounding ellipse of the triangle in the third row doesn't seem to be the best fit, but still acceptable as a criteria for rejecting an incorrect ellipse.
But I can't understand why the remaining triangles have bounding ellipse completely outside their contour.
And the worst case is the third triangle in the last row: The ellipse is completely wrong but it happens to have the area close to the contour's area, so the triangle is wrongly recognized as an ellipse.
Do I miss anything? My code:
#include <iostream>
#include <opencv/cv.h>
#include <opencv/highgui.h>
using namespace std;
using namespace cv;
void getEllipses(vector<vector<Point> >& contours, vector<RotatedRect>& ellipses) {
ellipses.clear();
Mat img(Size(800,500), CV_8UC3);
for (unsigned i = 0; i<contours.size(); i++) {
if (contours[i].size() >= 5) {
RotatedRect temp = fitEllipse(Mat(contours[i]));
if (area(temp) <= 1.1 * contourArea(contours[i])) {
//cout << area(temp) << " < 1.1* " << contourArea(contours[i]) << endl;
ellipses.push_back(temp);
drawContours(img, contours, i, Scalar(255,0,0), -1, 8);
ellipse(img, temp, Scalar(0,255,255), 2, 8);
imshow("Ellipses", img);
waitKey();
} else {
//cout << "Reject ellipse " << i << endl;
drawContours(img, contours, i, Scalar(0,255,0), -1, 8);
ellipse(img, temp, Scalar(255,255,0), 2, 8);
imshow("Ellipses", img);
waitKey();
}
}
}
}
int main() {
Mat img = imread("image.png", CV_8UC1);
threshold(img, img, 127,255,CV_THRESH_BINARY);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(img, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
vector<RotatedRect> ellipses;
getEllipses(contours, ellipses);
return 0;
}
解决方案 Keep in mind, that fitEllipse
is not the computation of a boundingEllipse but a least square optimization that assumes the points to lie on an ellipse.
I can't tell you why it fails on the 3 triangles in the last row so badly but "works" on the triangle one line above, but one thing I've seen is, that all 3 triangles in the last row were fitted to a rotatedRect with angle 0
. Probably the least square fitting just failed there.
But I don't know whether there is a bug in the openCV implementation, or wether the algorithm can't handle those cases. This algorithm is used: http://www.bmva.org/bmvc/1995/bmvc-95-050.pdf
My advice is, to only use fitEllipse
if you are quite sure that the points really belong to an ellipse. You wont either assume to get reasonable results from fitLine
if you have random data points. Other functions you might want to look at are: minAreaRect
and minEnclosingCircle
if you use RotatedRect temp = minAreaRect(Mat(contours[i]));
instead of fitEllipse
you will get an image like this:
maybe you can even use both methods and refuse all ellipses that fail in both versions and accept all that are accepted in both versions, but investigate further in the ones that differ?!?
这篇关于OpenCV的fitEllipse()有时返回完全错误的省略号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!