椭圆拟合方法

news/2024/11/8 9:30:29/

最近工作中遇到了有关椭圆拟合的问题,把在这一过程中踩坑和最后使用的方法进行了总结。
参考链接:https://github.com/seisgo/EllipseFit
https://github.com/xiamenwcy/EllipseFitting

opencv3.2的方法

首先使用的是opencv的方法,该方法有时候会失效。

//待拟合的点
vector<Point> vpfinalfit = dangerzone;//把点的数量限制到20个
int interval = floor(vpfinalfit.size() / 20.0);
if (interval > 1)
{vector<Point> vpsample;for (int i = 0; i < vpfinalfit.size(); i += interval){vpsample.push_back(vpfinalfit[i]);}vpfinalfit = vpsample;
}//把坐标输出的文件中,在matlab中拟合
ofstream fout3;
fout3.open("data3.txt");
for (unsigned long i = 0; i < vpfinalfit.size(); i++)
{fout3 << vpfinalfit[i].x << " " << vpfinalfit[i].y << endl;
}
fout3.close();//使用椭圆拟合的方法
RotatedRect rr;
if (vpfinalfit.size() > 5)
{rr = fitEllipse(vpfinalfit);ellipse(src, rr, Scalar(0, 0, 0), 4);
}

拟合较好的结果
在这里插入图片描述
拟合不对的结果
在这里插入图片描述

matlab的方法(BFisher方法)

参考链接 http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/FITZGIBBON/ELLIPSE/
参考文献:Andrew W. Fitzgibbon, Maurizio Pilu, and Robert B. Fisher Direct least-squares fitting of ellipses, IEEE Transactions on Pattern Analysis and Machine Intelligence, 21(5), 476–480, May 1999

同样的点,在matlab中进行拟合,则可以实现较好的效果。

x = load('data3.mat');
p0=[0.005 0.005 0.005 0.005 0.005 0.005];
warning off
F=@(p,x)p(1)*x(:,1).^2+p(2)*x(:,1).*x(:,2)+p(3)*x(:,2).^2+p(4)*x(:,1)+p(5)*x(:,2)+p(6);
% ???????????
p=nlinfit(x,zeros(size(x,1),1),F,p0);A=p(1)/p(6);
B=p(2)/p(6);
C=p(3)/p(6);
D=p(4)/p(6);
E=p(5)/p(6);X_center = (B*E-2*C*D)/(4*A*C - B^2);
Y_center = (B*D-2*A*E)/(4*A*C - B^2);
fprintf(' X_center=%g, Y_center=%g\n',X_center,Y_center);a= 2*sqrt((2*A*(X_center^2)+2*C*(Y_center^2)+2*B*X_center*Y_center-2)/(A+C+sqrt(((A-C)^2+B^2))));
b= 2*sqrt((2*A*(X_center^2)+2*C*(Y_center^2)+2*B*X_center*Y_center-2)/(A+C-sqrt(((A-C)^2+B^2))));q=0.5 * atan(B/(A-C));
fprintf(' q=%g\n',q);fprintf(' a=%g, b=%g\n',a,b);
plot(x(:,1),x(:,2),'ro');hold on;
xmin=min(x(:,1));
xmax=max(x(:,1));
ymin=min(x(:,2));
ymax=max(x(:,2));
% 作图ezplot(@(x,y)F(p,[x,y]),[xmin,xmax,ymin,ymax]);
title('曲线拟合');
legend('采样点','拟合结果')

在这里插入图片描述

c++版本(BFisher方法)

该方法也有c++的版本,但是lapack的配置比较复杂。
DirectEllipseFit拟合的类定义,具体的代码可以去CSDN下载,稍后会上传,命名分别为myEllipse.h和myEllipse.cpp

template <typename T>
class DirectEllipseFit
{
public:DirectEllipseFit(const vector<T>& xData, const vector<T>& yData);Ellipse doEllipseFit();private:T getMeanValue(const vector<T>& data);T getMaxValue(const vector<T>& data);T getMinValue(const vector<T>& data);T getScaleValue(const vector<T>& data);vector<T> symmetricNormalize(const vector<T>& data);//Make sure xData and yData are of same sizevector<T> dotMultiply(const vector<T>& xData, const vector<T>& yData);//Get n*6 design matrix D, make sure xData and yData are of same sizevector<vector<T> > getDesignMatrix(const vector<T>& xData,const vector<T>& yData);//Get 6*6 constraint matrix Cvector<vector<T> > getConstraintMatrix();//Get 6*6 scatter matrix S from design matrixvector<vector<T> > getScatterMatrix(const vector<vector<T> >& dMtrx);//Transpose matrixvector<vector<T> > transposeMatrix(const vector<vector<T> >& mtrx);//Do matrix multiplication, mtrx1: j*l; mtrx2: l*i; return: j*ivector<vector<T> > doMtrxMul(const vector<vector<T> >& mtrx1,const vector<vector<T> >& mtrx2);/*** @brief solveGeneralEigens:   Solve generalized eigensystem* @note        For real eiginsystem solving.* @param sMtrx:    6*6 square matrix in this application* @param cMtrx:    6*6 square matrix in this application* @param eigVV:    eigenvalues and eigenvectors, 6*7 matrix* @return  success or failure status*/bool solveGeneralEigens(const vector<vector<T> >& sMtrx,const vector<vector<T> >& cMtrx,vector<vector<T> >& eigVV);//Convert matrix expression from nested QVector to 1-order arraydouble* mtrx2array(const vector<vector<T> >& mtrx);/*** @brief calcEllipsePara:  calculate ellipse parameter form eigen information* @param eigVV:    eigenvalues and eigenvectors* @return ellipse parameter*/Ellipse calcEllipsePara(const vector<vector<T> >& eigVV);private:vector<T> m_xData, m_yData;
};

更简单的方法

如果你喜欢用最新版的软件,在opencv4.0以上的版本中,椭圆拟合函数增加了新的方法,其中有一个就是使用的上述方法,所有可以直接调用opencv4.0以上版本的库。

RotatedRect rr;
if (vpfinalfit.size() > 5)
{rr = fitEllipseAMS(vpfinalfit);//rr = fitEllipse(vpfinalfit);ellipse(src, rr, Scalar(0, 255, 255), 1);  //画椭圆
}

但是不能盲目升级,就是因为这个原因,笔者把原来开发的Android程序jni使用的opencv版本从3.2升级到了4.0,导致队友原来开发的视觉算法编译通不过来,不过没有什么,从opencv3到opencv4大部分是是简单的变量命名替换,改起来还是比较轻松。


http://www.ppmy.cn/news/233142.html

相关文章

椭圆的绘制算法

问题描述 已知椭圆的长半轴a和短半轴b&#xff0c;以及椭圆的中心(xc,yc)&#xff0c;绘制椭圆像素图。 中点椭圆算法 中点椭圆算法与圆的绘制算法类似&#xff0c;也是在某一区域范围内&#xff0c;单位间隔取样&#xff0c;确定离指定椭圆最近的像素位置&#xff0c;然后通…

椭圆拟合

1.最小二乘拟合 最小二乘拟合是一种数学上的近似和优化&#xff0c;利用已知的数据得出一条直线或者曲线&#xff0c;使之在坐标系上与已知数据之间的距离的平方和最小。 2.RANSAC算法 参见王荣先老师的博文 http://www.cnblogs.com/xrwang/archive/2011/03/09/ransac-1.html 3…

椭圆中心到椭圆切线的距离

本文将要讨论的是椭圆中心到椭圆切线的距离公式&#xff0c;在求这个距离之前&#xff0c;我们首先要知道两个定理。 定理1&#xff1a;椭圆 上的点到椭圆左&#xff0c;右焦点的距离分别是和&#xff0c;其中是椭圆的离心率。 定理2&#xff1a;椭圆&#xff08;1&#xff09;…

椭圆积分

转载自&#xff1a;http://blog.sina.com.cn/s/blog_3feefc7c0102xv37.html

四轴飞行器的运动原理

四旋翼飞行器通过调节四个电机转速来改变旋翼转速&#xff0c;实现升力的变化&#xff0c;从而控制飞行器的姿态和位置。四旋翼飞行器是一种六自由度的垂直升降机&#xff0c;但只有四个输入力&#xff0c;同时却有六个状态输出&#xff0c;所以它又是一种欠驱动系统。 以四轴&…

椭圆 / 椭圆的画法

原文链接&#xff1a; https://www.lfhacks.com/t/draw-ellipse 在现实生活中如何画 椭圆 &#xff1f;椭圆并不是由圆压扁而来&#xff0c;而是要符合一定的规则才能称为椭圆。现实生活中如果有画椭圆的需求&#xff0c;应该按照固定的方法作图。本文介绍一些绘制椭圆的方法。…

误差椭圆

原文链接&#xff1a;https://blog.csdn.net/u010182633/article/details/45924061 介绍 在这篇文章中&#xff0c;我将展示如何绘制二维正态分布数据的误差椭圆&#xff0c;又名置信椭圆。误差椭圆代表高斯分布的等值轮廓线&#xff0c;并允许可视化一个2D置信区间。下图显示了…

Ellipse(椭圆)

原滋原味的英文介绍&#xff0c;挺有意思&#xff01; http://mathworld.wolfram.com/Ellipse.html An ellipse is a curve that is the locus of all points in the plane the sum of whose distances and from two fixed points and (the foci) separated by a distance…