基于代数距离的椭圆拟合

问题

给定离散点集Xi=(xi,yi),i=1,2,...NX_i=(x_i,y_i) ,i=1,2,...NXi=(xi,yi),i=1,2,...N,我们希望找到误差最小的椭圆去拟合这些离散点。

方法

由于椭圆的形式可以给定, 自然我们将使用最小二乘法来求解椭圆。主要依据论文《Direct least squares fitting of ellipsees, Fitzgibbon, Pilu and Fischer in Fitzgibbon, A.W., Pilu, M., and Fischer R.B.,Proc. of the 13th Internation Conference on Pattern Recognition, pp 253–257, Vienna, 1996》。

椭圆拟合的难点

通常我们使用最小二乘法求解如下的最优化问题:

Min∑i=1Nf(xi,E)Min \sum_{i=1}^N f(x_i,E)Mini=1Nf(xi,E)
这里f(xi,E)f(x_i,E)f(xi,E)表示点xix_ixi到E(指待拟合的椭圆)的最小距离。一般称为几何距离。但是我们很难直接给定几何距离的解析表达,因此很难求出。因此我们退而求其次,我们采用:为椭圆写下隐式方程,然后将点的坐标带入此隐式方程就得到了点到椭圆的距离。这种方法对于直线拟合、圆拟合,返回的就是到其的真实距离。而对于椭圆拟合,它返回的值是与距离有类似的属性,但不是一个真正的距离值。因此这个距离被称为代数距离
椭圆可以用下面的隐式方程表达:

a1x2+a2xy+a3y2+a4x+a5y+a6=0a_1x^2+a_2xy+a_3y^2+a_4x+a_5y+a_6=0a1x2+a2xy+a3y2+a4x+a5y+a6=0

与直线类似(直线表达为:a1x+a2y+a3=0a_1x+a_2y+a_3=0a1x+a2y+a3=0),上式的一组参数也是齐次量,即只能定义到一个比例因子。而且表达式也能表达双曲线和抛物线。而椭圆
通常要求:a22−4a1a4&lt;0a_2^2-4a_1a_4&lt;0a224a1a4<0。最好通过令a22−4a1a4=−1a_2^2-4a_1a_4=-1a224a1a4=1,即可同时解决这两个问题。

请参考维基百科椭圆定义和wolfram MathWorld 椭圆定义

一般的求解过程

对上面的椭圆方程改写为:

f(a,(x,y))=D⋅a=0f(a,(x,y))=D\cdot a=0f(a,(x,y))=Da=0

这里D=(x2,xy,y2,x,y,1)D=(x^2, xy, y^2, x, y, 1)D=(x2,xy,y2,x,y,1),a=(a1,a2,a3,a4,a5,a6)a=(a_1, a_2, a_3, a_4, a_5, a_6)a=(a1,a2,a3,a4,a5,a6).
于是给定N个离散点Xi=(xi,yi),i=1...NX_i=(x_i,y_i),i=1...NXi=(xi,yi),i=1...N,通过最小化代数距离:

MinΔ(a,X)=∑i=1N(f(a,Xi))2Min \Delta(a,X)=\sum_{i=1}^{N}(f(a,X_i))^2MinΔ(a,X)=i=1N(f(a,Xi))2

重写上式,即有:

MinΔ(a,X)=∑i=1NaTDiTDia=aTSaMin \Delta(a,X)=\sum_{i=1}^{N}a^TD_i^TD_ia=a^TSaMinΔ(a,X)=i=1NaTDiTDia=aTSa

这里S=∑DiTDiS=\sum D_i^T D_iS=DiTDi为6x6矩阵。
另外,我们可以把各个DiD_iDi合并起来,则有
D^=(D1D2⋮DN)\hat{D}=\begin{pmatrix} D_1\\ D_2\\ \vdots \\ D_N \end{pmatrix}D^=D1D2DN
因此:
S=D^TD^S=\hat{D}^T\hat{D}S=D^TD^

此外,我们还有约束条件:
a22−4a1a4&lt;0a_2^2-4a_1a_4&lt;0a224a1a4<0,可以改写为:

aTCa=−1a^TCa=-1aTCa=1

其中C∈R6×6C\in R^{6\times 6}CR6×6,且大部分为0,只有C1,3=C3,1=−2,C2,2=1C_{1,3}=C_{3,1}=-2,C_{2,2}=1C1,3=C3,1=2,C2,2=1
因此综合上来即为,求解如下的最优化问题:

MinaTSaMin~~~ a^TSa Min   aTSa
s.t.aTCa=−1s.t. ~~~a^TCa=-1s.t.   aTCa=1

公式和拉格朗日乘子法

通过使用拉格朗日乘子法 ,我们可以得到

L(a)=aTSa−λ(aTCa+1)L(a)=a^TSa-\lambda (a^TCa+1)L(a)=aTSaλ(aTCa+1)

然后求解∂aL(a)=0\partial_aL(a)=0aL(a)=0可以求解得到:
Sa=λCaSa=\lambda CaSa=λCa

上式是经典的广义特征值问题。我们可以直接求解,其中λ\lambdaλ为广义特征值,而a为广义特征向量
论文 中指出有且仅有一个负的特征值,且其对应的特征向量即为我们需要的椭圆方程的系数,即这里的a.

一般的圆锥方程到标准椭圆方程的转化。

当我们求解得到了圆锥曲线的系数,即a,我们一般需要获得椭圆的标准方程,也就是获得椭圆的如下参数:
中心(cx,cy)(c_x,c_y)(cx,cy)、长短半轴r1,r2r_1,r_2r1,r2,旋转角度θ\thetaθ.

这里我们可以给出结果,也可以自己结合椭圆的标准形式与圆锥曲线的方程去推导.

参考文献:http://mathworld.wolfram.com/Ellipse.html.
##编程实现
下面描述matlab与c++实现。

matlab

% fitellip gives the 6 parameter vector of the algebraic circle fit
% to a(1)x^2 + a(2)xy + a(3)y^2 + a(4)x + a(5)y + a(6) = 0
% X & Y are lists of point coordinates and must be column vectors.(或者行向量)
function a = fitellip(X,Y)% normalize datamx = mean(X);my = mean(Y);sx = (max(X)-min(X))/2;sy = (max(Y)-min(Y))/2;x = (X-mx)/sx;y = (Y-my)/sy;% Force to column vectorsx = x(:);y = y(:);% Build design matrixD = [ x.*x  x.*y  y.*y  x  y  ones(size(x)) ];% Build scatter matrixS = D'*D;% Build 6x6 constraint matrixC(6,6) = 0; C(1,3) = -2; C(2,2) = 1; C(3,1) = -2;% Solve eigensystem[gevec, geval] = eig(S,C);% Find the negative eigenvalue[NegR, NegC] = find(geval < 0 & ~isinf(geval));% Extract eigenvector corresponding to positive eigenvalueA = gevec(:,NegC);% unnormalizea = [A(1)*sy*sy,   ...A(2)*sx*sy,   ...A(3)*sx*sx,   ...-2*A(1)*sy*sy*mx - A(2)*sx*sy*my + A(4)*sx*sy*sy,   ...-A(2)*sx*sy*mx - 2*A(3)*sx*sx*my + A(5)*sx*sx*sy,   ...A(1)*sy*sy*mx*mx + A(2)*sx*sy*mx*my + A(3)*sx*sx*my*my   ...- A(4)*sx*sy*sy*mx - A(5)*sx*sx*sy*my   ...+ A(6)*sx*sx*sy*sy   ...]';

c++

我们参考了网上的版本,并修复了他的问题,最终也做出了和matlab一样的效果。其中最关键的是广义特征值的求解。我们使用了Eigenclapack库。其中Eigen易于表达矩阵,和matlab用法类似,是个强大的C++线性代数库。而CLAPACK是线性代数包Lapack面向C/c++的接口。里面包含了很丰富的线性代数算法,包括广义特征值求解接口,而且速度很快。我们希望将二者结合起来使用。

Eigen的安装

Eigen直接以源代码的方式提供给用户,因此我们从官网上下载下后,直接在工程中包含其头文件路径即可。具体可参考:http://blog.csdn.net/abcjennifer/article/details/7781936

clapack的安装

请查看官网,里面包含了详细的使用与安装步骤。

也可以使用我们已经编译了的vc2010和vc2013的库,可以点击下载。

尽管clapack面向c语言,因此需要我们在包含头文件的时候,记得加上extern “C”.但是最新的版本(比如CLAPACK 3.2.1)已经为我们在头文件中加上了这些限制符,因此最新的版本可以兼容c和c++,所以直接在项目包含头文件即可。

比如像下面一样:

//Eigen
#include <Eigen/Dense>
#include <Eigen/Core>
#include <iostream>//clapack,必须放在Eigen后面#include <f2c.h>
#include <clapack.h>

而且应该注意Eigen与CLAPACK混合使用的时候,CLAPACK的头文件要加在Eigen的后面。否则会出错

代码

请查看Github主页:https://github.com/xiamenwcy/EllipseFitting

实验结果

在这里插入图片描述

参考文献

Eigen、LAPACK

  1. Interfacing Eigen with LAPACK
  2. Using BLAS/LAPACK from Eigen
  3. CLAPACK for Windows
  4. 如何在VC中调用CLAPACK
  5. 使用Lapack库的一些重要规则
  6. 在VS中用CLAPACK解决广义特征值问题
  7. LAPACK 3.7.0
  8. C++编程:C++中同时使用Eigen和CLAPACK
  9. CLAPACK在vc++6.0中成功调用
  10. CLAPACK动态调用
  11. Leading dimension
  12. leading dimension 2

椭圆拟合

  • Fitting an Ellipse to a Set of Data Points(python实现)
  • 二次曲线Quadratic Curve
  • fitellipse.cpp(opencv)
  • Creating Bounding rotated boxes and ellipses for contours
  • OpenCV’s fitEllipse() sometimes returns completely wrong ellipses
  • Fitting an Ellipse to a Set of Data Points
  • Direct Least Square Fitting of Ellipses (论文)
  • best-fitting-line-circle-and-ellipse
  • opencv中的椭圆拟合
  • Python and C implementations of an ellipse fitting algorithm in double and fixed point precision.
  • C++ code for circle fitting algorithms
  • OriginDelight/EllipseFit (c++源码)

论文作者,著名学者主页:

  • Bob Fisher: http://homepages.inf.ed.ac.uk/rbf/
  • Fitzgibbon, Pilu, Fisher: Direct Least Squares Fitting of Ellipses:http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/FITZGIBBON/ELLIPSE/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/258791.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java与C语言比较(Java参考书中摘录)

C语言为面向过程的编程语言&#xff0c;Java为面向对象的编程语言。 在面向过程的编程语言(如C语言)中&#xff0c;编程一般面向操作&#xff0c;编程单位是函数(在Java中函数称为方法)。 在Java中&#xff0c;编程单位是类。最终实例化(即创建)这些类而得到对象&#xff0c;属…

Android调试技巧之Eclipse行号和Logcat

很多初入Android的开发者可能会发现经常遇到Force Close或ANR这样的问题&#xff0c;一般我们通过Android系统的错误日志打印工具Logcat可以看到出错的内容&#xff0c;今天一起来说下如何通过 Eclipse行号和Logcat捕捉出错点&#xff0c;我们遇到错误可以首先在Eclipse的DDMS中…

第六章 产权市场

《市场经济概论》&#xff08;6&#xff09;产权市场一 第六章 产权市场 产权是指人们对于某种资产所拥有的所有权、占有权、支配权、使用权。产权市场是指人们对于某种资产所拥有的所有权、占有权、支配权、使用权进行有偿转让的场所领域及其有关各方面相互关系的总和。在过去…

js打开本地文件夹_vue + ArcGIS 地图应用系列一:arcgis api本地部署(开发环境)

1. 下载 ArcGIS API for JavaScript 官网地址&#xff1a; https://developers.arcgis.com/javascript/3/ 下载地址&#xff1a;http://links.esri.com/javascript-api/latest-download需要稳定的网络环境注册账号后才可以下载下载完成后解压文件&#xff0c;文件比较大可能需要…

基于几何距离的椭圆拟合

问题 给定离散点集Xi(xi,yi)X_i(x_i,y_i)Xi​(xi​,yi​)&#xff0c;我们希望找到最好的椭圆去拟合这些离散点。 方法 通常我们使用最小二乘法求解如下的最优化问题&#xff1a; Min∑i1Nf(xi,E)2Min \sum_{i1}^N f(x_i,E)^2 Mini1∑N​f(xi​,E)2 这里f(xi,E)f(x_i,E)f(xi…

Generate Parentheses

题目 Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. For example, given n 3, a solution set is: "((()))", "(()())", "(())()", "()(())", "()()()" 方法…

ReportViewer 2010 打印预览,用鼠标快速切换显示比例时报错:存储空间不足,不能处理此命令...

CreateCompatibleDIB 存储空间不足 无法处理此命令 安装 ReportViewer 2010 sp1 即可。转载于:https://www.cnblogs.com/runliuv/p/3640856.html

贪心/二分查找 BestCoder Round #43 1002 pog loves szh II

题目传送门 1 /*2 贪心/二分查找&#xff1a;首先对ai%p&#xff0c;然后sort&#xff0c;这样的话就有序能使用二分查找。贪心的思想是每次找到一个aj使得和为p-1(如果有的话)3 当然有可能两个数和超过p&#xff0c;那么an的值最优&#xff0c;每次还要和…

nohup命令输出日志_逼格高又实用的Linux高级命令,开发运维都要懂

在运维的坑里摸爬滚打好几年了&#xff0c;我还记得我刚开始的时候&#xff0c;我只会使用一些简单的命令&#xff0c;写脚本的时候&#xff0c;也是要多简单有多简单&#xff0c;所以有时候写出来的脚本又长又臭&#xff0c;像一些高级点的命令&#xff0c;比如说Xargs 命令、…

JavaScript中OOP——面向对象中的继承/闭包

前 言 OOP JavaScript中OOP——>>>面向对象中的继承/闭包 1.1面向对象的概念 使用一个子类继承另一个父类&#xff0c;子类可以自动拥有父类的属性和方法。>>> 继承的两方&#xff0c;发生在两个类之间。1.2JS模拟实现继承的三种方式&#xff1a; 首先&am…

js常用字符串函数

这些东西是以前整理的&#xff0c;放到这里&#xff0c;有需要的可以看看~挺全的~ /** * anchor()方法 * 在对象中的指定文本两端放置一个有Name属性的HTML锚点 * strVariable.anchor(anchorString) anchorString为锚点名称 * 它本身不会检查其他的ahchor锚点是否有name指…

c++11中的智能指针

在C11中有四种智能指针&#xff0c;auto_ptr&#xff0c;shared-ptr&#xff0c;unique_ptr和weak-ptr&#xff0c;其中auto_ptr有许多不足之处&#xff0c;在C11中已经建议废弃使用。 1. shared_ptr std::shared_ptr智能指针可以通过共享指向对象的所有权&#xff0c;从而实现…

ubuntu14.04设置静态IP

啊&#xff0c;最近懒惰了&#xff0c;好久没有写博客了。 一般机器启动的时候会自动从DHCP服务器上面获取动态IP地址&#xff0c;这是一件很方便的事情&#xff0c;可以不用手动设置网络相关的蚕参数&#xff0c;但是有时候还是需要机器固定IP地址的。 第一步&#xff0c;编辑…

高中学历python培训靠谱吗_高中学历学完Python就能干人工智能?

最近Python大热&#xff0c;主要是人工智能的热度&#xff0c;昨天后院活动部介绍了一位女网友为男朋友选择Java还是Python&#xff0c;大量的程序员热议&#xff0c;也有人询问如何学习Python&#xff0c;比如这位网友询问高中学历学习Python是不是就能干人工智能。兄弟&#…

curl+个人证书(又叫客户端证书)访问https站点

目前&#xff0c;大公司的OA管理系统&#xff08;俗称内网&#xff09;&#xff0c;安全性要求较高&#xff0c;通常采用https的双向 认证模式。 首先&#xff0c;什么是https&#xff0c;简单的说就是在SSL协议之上实现的http协议&#xff08;get、post等操作&#xff09;。更…

boot.oat FC问题分析报告

【NE现场】 pid: 5252, tid: 5252, name: ndroid.contacts >>> com.android.contacts <<< signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x1458x0 0000000000000000 x1 0000000090d9892c x2 0000000000000001 x3 000000000000012cx4 …

c++ 虚函数的实现机制

转载自&#xff1a;http://blog.csdn.net/jiangnanyouzi/article/details/3720807 1、c实现多态的方法 其实很多人都知道&#xff0c;虚函数在c中的实现机制就是用虚表和虚指针&#xff0c;但是具体是怎样的呢&#xff1f;从more effecive c其中一篇文章里面可以知道&#xff…

powerdesigner 技巧

1.修改建表脚本生成规则。如果每个表格都有相同的字段&#xff0c;可以如下修改&#xff1a; Database -> Edit Current DBMS 展开 Script -> Object -> Table -> Create 见右下的Value值&#xff0c;可以直接修改如下&#xff1a;/* tablename: %TNAME% */ create…

勒索病毒攻击应急防范

北京时间5月12日&#xff0c;互联网上出现针对Windows操作系统的勒索软件&#xff08;Wannacry&#xff09;攻击案例。勒索软件利用此前披露的Windows SMB服务漏洞&#xff08;对应微软漏洞公告&#xff1a;MS17-010&#xff09;攻击手段&#xff0c;向终端用户进行渗透传播&am…

C++中虚析构函数的作用

C中的虚析构函数到底什么时候有用的&#xff0c;什么作用呢。 总的来说虚析构函数是为了避免内存泄露&#xff0c;而且是当子类中会有指针成员变量时才会使用得到的。也就说虚析构函数使得在删除指向子类对象的基类指针时可以调用子类的析构函数达到释放子类中堆内存的目的&…