OpenCV的fitEllipse()有时返回完全错误的省略号 [英] OpenCV's fitEllipse() sometimes returns completely wrong ellipses

查看:1501
本文介绍了OpenCV的fitEllipse()有时返回完全错误的省略号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标是识别图像中存在的所有形状。
这个想法是:


  1. 提取轮廓

  2. / li>
  3. 正确的形状应该是最接近
    轮廓区域的区域。

示例图片:



我使用 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:

  1. Extract contours
  2. Fit each contour with different shapes
  3. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆