包含之前几篇文章提到的算法的C#实现。
界面很简单,点按钮选择数据文件,一行一个点的xyz坐标。选择类型,然后计算。
可执行文件同目录下有两个测试用数据文件。
二进制包下载LSQ_Feature_binary
源码及二进制包下载(VS2012 Express)
包含之前几篇文章提到的算法的C#实现。
界面很简单,点按钮选择数据文件,一行一个点的xyz坐标。选择类型,然后计算。
可执行文件同目录下有两个测试用数据文件。
二进制包下载LSQ_Feature_binary
源码及二进制包下载(VS2012 Express)
同前一篇文章相同,算法主要根据这篇文章,修改了其中一些笔误并微调以适合C#代码。
首先是将圆柱参数化并简化该模型。
圆柱的轴线为一空间直线,由一点\(P\)和一空间向量\(V\)定义。
如果经过坐标变换,新坐标系零点为\(P\)且坐标z轴为\(V\),那么该轴线的未知量就由\(x_0,y_0,z_0,a,b,c\)减少为4个。
圆柱的轴线表示为经过点\(P\left(x_0,y_0,z_0\right)\)向量为\(V\left(a,b,c\right)\)的直线,半径为R
我个人觉得这种求法偏繁琐,不过的确相当接近最后拟合值,迭代次数相当少。
对于圆柱面上任一点\(P_i\left(x_i,y_i,z_i\right)\)有\[A^2+B^2+C^2=R^2\]其中\[A=c\left(y_i-y_0\right)-b\left(z_i-z_0\right)\]\[B=a\left(z_i-z_0\right)-c\left(x_i-x_0\right)\]\[C=b\left(x_i-x_0\right)-a\left(y_i-y_0\right)\]
将上面的等式代入展开\[\left[c\left(y_i-y_0\right)-b\left(z_i-z_0\right)\right]^2+\left[a\left(z_i-z_0\right)-c\left(x_i-x_0\right)\right]^2+\left[b\left(x_i-x_0\right)-a\left(y_i-y_0\right)\right]^2=R^2\]这个等式很简单(不得不吐槽,当时看到这里我都疯了,现在手打这些公式更疯了),它等价于\[Ax_i^2+By_i^2+Cz_i^2+Dx_iy_i+Ex_iz_i+Fy_iz_i+Gx_i+Hy_i+Iz_i+J=0\]其中\begin{array}{lclp{12}}
A&=&\left(b^2+c^2\right)\\
B&=&\left(a^2+c^2\right)\\
C&=&\left(a^2+b^2\right)\\
D&=&-2ab\\
E&=&-2ac\\
F&=&-2bc\\
G&=&-2\left(b^2+c^2\right)x_0+2aby_0+2acz_0\\
H&=&2abx_0-2\left(a^2+c^2\right)y_0+2bcz_0\\
I&=&2acx_0+2bcy_0-2\left(a^2+b^2\right)z_0\\
J&=&\left(b^2+c^2\right)x_0^2+\left(a^2+c^2\right)y_0^2+\left(a^2+b^2\right)z_0^2-2bcy_0z_0-2acz_0x_0-2abx_0y_0-R^2
\end{array}
两边同除以\(A\)并将\(x\)二次项移到等式右边得
\[\frac{B}{A}y_i^2+\frac{C}{A}z_i^2+\frac{D}{A}x_iy_i+\frac{E}{A}x_iz_i+\frac{F}{A}y_iz_i+\frac{G}{A}x_i+\frac{G}{A}y_i+\frac{I}{A}z_i+\frac{J}{A}=-x^2\]
这是一个线性方程组
\[\begin{bmatrix}y_1^2 &z_1^2 & x_1y_1 & x_1z_1 & y_1z_1 & x_1 & y_1 & z_1 & 1 \\y_2^2 & z_2^2 & x_2y_2 & x_2z_2 & y_2z_2 & x_2 & y_2 & z_2 & 1 \\\vdots &\vdots &\vdots &\vdots &\vdots &\vdots &\vdots &\vdots &\vdots \\y_n^2 &z_n^2 & x_ny_n & x_nz_n & y_nz_n & x_n & y_n & z_n & 1 \end{bmatrix}\begin{bmatrix}B/A\\C/A\\D/A\\E/A\\F/A\\G/A\\H/A\\I/A\\J/A\end{bmatrix}=\begin{bmatrix}-x_1^2\\-x_2^2\\\vdots\\-x_n^2\end{bmatrix}\]
求解:
令\(B’=B/A,C’=C/A,D’=D/A,E’=E/A,F’=F/A,G’=G/A,H’=H/A,I’=I/A,J’=J/A\)
如果\(|D’|\),\(|E’|\)和\(|F’|\)近似等于0(意味着abc中有两个近似于0,向量与某坐标轴平行),如果\(B’\)近似于1向量为\(\left(0,0,1\right)\),如果\(C’\)近似于1向量为\(\left(0,1,0\right)\)
否则,令\[k=\frac{2}{1+B’+C’}\]则\[A=k,B=kB’,C=kC’,D=kD’,E=kE’,F=kF’,G=kG’,H=kH’,I=kI’,J=kJ’\]如果\(A,B\)近似于1,则\begin{array}{lcl}c’&=&\left(1-C\right)^{1/2}\\a’&=&E/-2c’\\b’&=&F/-2c’\end{array}
如果A近似1,B不近似1则\begin{array}{lcl}b’&=&\left(1-B\right)^{1/2}\\a’&=&D/-2b’\\c’&=&F/-2b’\end{array}
如果A不近似于1\begin{array}{lcl}a’&=&\left(1-A\right)^{1/2}\\b’&=&D/-2a’\\c’&=&E/-2a’\end{array}
将向量\(\left(a’,b’,c’\right)\)正规化得到单位向量\[\left(a,b,c\right)\]
注:近似于这个概念很模糊,由于我使用在机械测量中,通常设备采集原始点的精度为0.001左右,而点云本身的标准差在0.001~1,所以我在程序中将近似于定义为\(\Delta<0.001\)
上文两次提到近似于,第一次是\(DEF\),用来判断向量是否平行于某一轴。第二次是\(A,B\),实际上此时已经排除了向量平行于轴线的可能性,这里是用来判断向量更接近于哪个轴,从而避免近似0 的小数开平方造成的精度误差,所以在算法中我将这部分改为了比大小。
另外就是\(ABC\)三个值有可能略微大于1,用原文算法有可能出现负数开方造成无解。
根据\(x_0,y_0,z_0\)与\(G,H,I\)的关系,以及等式\(ax_0+by_0+cz_0=0\)(注:原文中使用原点到轴线的垂足作为起始点,因为个人需要,我将之替换为数据第一点投影到轴线的垂足\(ax_0+by_0+cz_0=ax_1+by_1+cz_1\)得到线性方程组
\[\begin{bmatrix}-2\left(b^2+c^2\right)&2ab&2ac\\2ab&-2\left(a^2+c^2\right)&2bc\\2ac&2bc&-2\left(a^2+b^2\right)\\a&b&c\end{bmatrix}\begin{bmatrix}x_0\\y_0\\z_0\end{bmatrix}=\begin{bmatrix}G\\H\\I\\ax_1+by_1+cz_1\end{bmatrix}\]
注:在实际使用中,这个初始值算法有一些问题,当圆柱的轴线非常接近于\((0,0,1)\)时(很常见,通常为了仪器测量方便都会先找正),该方程组变为了\[\begin{bmatrix}-2&0&0\\0&-2&0\\0&0&0\\0&0&1\end{bmatrix}\begin{bmatrix}x_0\\y_0\\z_0\end{bmatrix}=\begin{bmatrix}G\\H\\I\\z_1\end{bmatrix}\]这个一看就知道\(x_0=-\frac{G}{2},y_0=-\frac{H}{2},z_0=z_1\),但是由于第三行都是0的存在,使得矩阵的任何操作都有问题。
原文使用了前面\(J\)的等式。\[R^2=(b^2+c^2)x_0^2+(a^2+c^2)y_0^2+(a^2+b^2)z_0^2-2bcy_0z_0-2acx_0z_0-2abx_0y_0-J\]
注:依然是在我的实际使用中,发现J的解在特定情况下会是极大的正数(可能是由于圆柱的轴线长度小于直径的原因),于是又出现了负数开方无解的情况,例如这组数据,于是我用了所有测量点半径平均值来代替。
在\((x_0,y_0,z_0)\)处以\((a,b,c)\)为Z轴建立一个坐标系U并将所有实测点的一个副本变换到该坐标系下。
\[\begin{bmatrix}x_i\\y_i\\z_i\end{bmatrix}=\left(\begin{bmatrix}x_i\\y_i\\z_i\end{bmatrix}-\begin{bmatrix}x_0\\y_0\\z_0\end{bmatrix}\right)U\]
其中\[U=\begin{bmatrix}1&0&0\\0&c_1&s_1\\0&-s1&c1\end{bmatrix}\begin{bmatrix}c_2&0&s2\\0&1&0\\-s2&0&c2\end{bmatrix}\]
当\((a,b,c)\)为\((1,0,0)\)时\(s_1=0,c_1=1,s_2=-1,c_2=0\)否则\[\begin{array}{lcl}c_1&=&\frac{c}{\sqrt{b^2+c^2}}\\s_1&=&\frac{-b}{\sqrt{b^2+c^2}}\\c_2&=&\frac{cc_1-b_s1}{\sqrt{a^2+(cc_1-bs_1)^2}}\\s_2&=&\frac{-a}{\sqrt{a^2+(cc_1-bs_1)^2}}\end{array}\]
参考直线距离公式,并且将\(a=b=0,c=1,z=0\)代入得到\[\begin{bmatrix}-x_1/r_1&-y_1/r_1&-x_1z_1/r_1&-y_1z_1/r_1&-1\\-x_2/r_2&-y_2/r_2&-x_2z_2/r_2&-y_2z_2/r_2&-1\\\vdots&\vdots&\vdots&\vdots&\vdots\\-x_m/r_m&-y_m/r_m&-x_mz_m/r_m&-y_mz_m/r_m&-1\end{bmatrix}\begin{bmatrix}P_{x0}\\P_{y0}\\P_a\\P_b\\P_r\end{bmatrix}=-1\begin{bmatrix}r_1-r\\r_2-r\\\vdots\\r_m-r\end{bmatrix}\]
\[\begin{bmatrix}x_0\\y_0\\z_0\end{bmatrix}=\begin{bmatrix}x_0\\y_0\\z_0\end{bmatrix}+\begin{bmatrix}P_{x_0}\\P_{y_0}\\-P_{x_0}P_a-P_{y_0}P_b\end{bmatrix}U^T\]
\[\begin{bmatrix}a\\b\\c\end{bmatrix}=\begin{bmatrix}P_a\\P_b\\1\end{bmatrix}U^T\]
\[r=r+P_r\]
重复1~3,直到满足终止条件。
终止条件3选1:
本文讨论并实现的算法主要(99%)基于这篇文章,更多参考请阅读这里。
大部分能搜索到的关于直线最小二乘拟合的资料是基于2维空间的\[y=ax+ b\]
而从三维空间的角度上来看,这只是一种特例。本文主要讨论三维空间上的直线拟合。
三维直线的表示如下。\[\left(x,y,z\right)=\left(x_0,y_0,z_0\right) + t\left(a,b,c\right)\]
其中\(\left(x_0,y_0,z_0\right)\)为直线上任一已知点,\(\left(a,b,c\right)\)为向量,所以所有直线都可以使用一个点坐标及一个向量来表示。
对于测量点\(P_i\left(x_i,y_i,z_i\right)\)与直线的距离为\[d_i=\sqrt{{u_i}^2+{v_i}^2+{w_i}^2}\]
其中:\[u_i=c\left(y_i-y_0\right)-b\left(z_i-z_0\right)\]\[v_i=a\left(z_i-z_0\right)-c\left(x_i-x_0\right)\]\[w_i=b\left(x_i-x_0\right)-a\left(y_i-y_0\right)\]
根据原文:拟合的直线过所有点的平均值,没有证明……
所以未知量其实是3个,构建一个矩阵\[A=\begin{bmatrix}x_1-x_0&y_1-y_0&z_1-z_0\\x_2-x_0&y_2-y_0&z_2-z_0\\\vdots & \vdots & \vdots \\x_i-x_0&y_i-y_0&z_i-z_0\end{bmatrix}\]
将矩阵A做奇异值分解(SVD),令:\[A=U_1SV^T\]
矩阵\(V\)的第一列(Column)即是直线向量\(\left(a,b,c\right)\)。
代码实现:
public override void Estimate(List<Point3D> datas)
{
double sum_x = 0;
double sum_y = 0;
double sum_z = 0;
foreach (Point3D temp in datas)
{
sum_x += temp.x;
sum_y += temp.y;
sum_z += temp.z;
}
sum_x /= datas.Count;
sum_y /= datas.Count;
sum_z /= datas.Count;
DenseMatrix jacobian = new DenseMatrix(datas.Count, 3);
foreach (Point3D temp in datas)
{
Vector<double> gradient = new DenseVector(3);
gradient[0] = temp.x - sum_x;
gradient[1] = temp.y - sum_y;
gradient[2] = temp.z - sum_z;
jacobian.SetRow(datas.IndexOf(temp), gradient);
}
Svd svd = jacobian.Svd(true);
// get matrix of left singular vectors with first n columns of U
Matrix<double> U1 = svd.U().SubMatrix(0, datas.Count, 0, 3);
// get matrix of singular values
Matrix<double> S = new DiagonalMatrix(3, 3, svd.S().ToArray());
// get matrix of right singular vectors
Matrix<double> V = svd.VT().Transpose();
Vector<double> parameters = new DenseVector(3);
parameters = V.Column(0);
x = sum_x;
y = sum_y;
z = sum_z;
i = parameters[0];
j = parameters[1];
k = parameters[2];
}
放在一起的原因是这两种元素的算法是完全一样的,直线拟合最后一步得到的矩阵V第一列是直线的向量,而第三列就是平面的向量。
平面同样可以用一个点\(\left(x_0,y_0,z_0\right)\)和一个向量\(\left(a,b,c\right)\)来表示,只是垂直与该向量。
平面的公式为\[a\left(x-x_0\right)+b\left(y-y_0\right)+c\left(z-z_0\right)=0\)
对于测量点\(P_i\left(x_i,y_i,z_i\right)\)直接的距离为\[d_i=a\left(x-x_0\right)+b\left(y-y_0\right)+c\left(z-z_0\right)\]
与直线的算法完全相同。
本系列的主要目的是将拟合算法用C#实现,相关的操作用到了Math.NET数值运算库,所以将一些基本概念,算法和对应的C#代码放到前面。
对于线性模型,例如直线和平面,算法大约分三步:
对于非线性模型,例如圆柱,Gauss-Newton算法类似:
线性模型的解法是基础,详细的分析请看这篇文章,这里只解释代码部分。在Math.Net中
对于矩阵\(A=\begin{bmatrix}A_{11} & A_{12}\\A_{21} & A_{22}\end{bmatrix}\)
A.Transpose() 代表A的转置矩阵\(A^T=\begin{bmatrix}A_{11} & A_{21}\\A_{12} & A_{22}\end{bmatrix}\)
这在坐标运算中是非常重要的,因为坐标运算中坐标系都表示为正交矩阵(抱歉,没找到证明),当计算一个点(用二维举例)\(P=\left(x,y\right)\)在新坐标系A中的坐标\(P^{‘}=\left(x^{‘},y^{‘}\right)\)时。\[P^{‘}=PA\]
而已知坐标系A中的坐标点\(P^{‘}\)求原坐标值可用\[P=P^{‘}A^T\]
一些类似的代码为:
A.Inverse()代表A的逆矩阵\(A^{-1}\)
A.Multiply(B)代表矩阵乘法\(A*B\)或者矩阵乘以向量\(A*b\)
对于常用的算法:
已知Jacobian矩阵\(J\)及等式右值(偏差值向量)\(y\),另\[Ax=y\]求解向量x
x = A.Transpose().Multiply(A).Inverse().Multiply(A.Transpose().Multiply(y));
更快和更稳定的方法将是对左侧的矩阵进行乔姆斯基分解(Cholesky decomposition),实现代码
x = A.Transpose().Multiply(A).Cholesky().Solve(A.Transpose().Multiply(y));
这两个在一些限定条件下是等价的,而这些限定条件在点数远大于参数的情况下是满足的。
x=A.QR().Solve(y);
x = A.Svd(true).Solve(y);
A不是方阵的情况下代码为
// compute the SVD
Svd svd = A.Svd(true);
// get matrix of left singular vectors with first n columns of U
Matrix U1 = svd.U().SubMatrix(0, m,0, n);
// get matrix of singular values
Matrix S = new DiagonalMatrix(n, n, svd.S().ToArray());
// get matrix of right singular vectors
Matrix V = svd.VT().Transpose();
x = V.Multiply(S.Inverse()).Multiply(U1.Transpose().Multiply(y));
这部分对于代码并没有什么区别,只是需要迭代(循环)及判断终止条件。
在网上看了太多又臭又长的类似文章,从方方面面夸或者黑某种语言,我选择C#的理由很简单,所以如果有和我类似情况的,我也推荐你选择C#作为开发语言。
我的情况:
1.公司提供的工作环境和客户的工作站全部是Windows环境。
2.开发程序的规模要求比较小:
比如:不会有大规模的客户端连接,也不需要数据量,负载等等,像我自己目前开发的小程序都是订制型的,客户的数量都是个位数的。
3.对C或C系列语言有些基础,比如(C,C++,JAVA等等)。
C#的优点:
1.免费,因为我写的程序虽然小,但是的确是以公司的名义提供给客户的,当然是收费的,所以选择免费的开发工具是很有必要的。而目前VS Express已经做到了完全免费,除了开发大型软件需要的功能,所有桌面级别的功能全部是免费的。
2.配置简单,千篇一律可能是专业开发人员的槽点,我上大学时也以自己搭建开发环境为兴趣,但是当我只想花一天写一个坐标转换的小程序时,VS Express这种高度集成的开发工具帮助极大,Express不支持绝大部分的插件和订制(专业版可以),但是好处是当你遇到一引起问题,你看到的问题解答中的界面和你永远是一样的,对于初学者这其实是很友好的。
3.语言的自解释,这本来是一种开发者写代码时需要注意的事项,但是我觉得.NET系列语言做得非常好,.NET库是不需要头文件的!刚开始我四处找头文件,后来发现当你引用一个库时,所有的函数及参数列表都是可见,而且所有.NET程序都可以非常简单的反编译,推荐ILSPY,这意味着你不用任何参考就可以直接使用函数,如果愿意还可以看到源码实现。(这叫强制开源吧。。。)
4.部署方便,Win7默认包含.NET 3.5,这意味着你开发的任何一个程序都可以在所有的Win7上运行,不用考虑环境设置,库的引用,而且程序非常小(我之前使用QT开发,最让人郁闷的一点就是任意带GUI的程序都要10M以上)。
缺点:
1.跨平台,很难在其他平台上使用,虽然有MONO,但是不免费。
2.库相对少,并不意味着没有,只不过当你 的需求非常专业,那么C++的历史在那摆着,库肯定多且专业,参考资料也多。
实际上C#的库比较多,但是因为自解释的原因吧,专业人员用起来肯本不需要文档,初学者就会很郁闷了。
12年没有写,补个13年吧。
首先是12年底把证领了,也算是裸婚,虽然我觉得这个词没什么意义。12年绝对是工作后最累的一年,时间管理相当差的我还为了工作牺牲了好多私人利益,教训是深刻的。结婚则是因为已经决定13年来德国,领了证才有可能申请签证。
13年1月老房东卖房想毁约,经历一些斗争,和平解决,新房东同意我们4月份才搬走。
然后就是开始折腾签证,雷声大雨点小的外派终于进入操作阶段,德国的中介开始操作所有事情,我也尽可能地在配合,预计开始的日期是4月1日,但是1月份才开始准备有点太紧了。
说是派两个人,老板也在春节公司一起吃饭时宣布了,然后另外一个一直不怎么积极的同事宣布不去了,然后闪电离职,虽然没有什么实际利益,但是对我还是好事情,至少不用给同事做饭了,我带老婆来德国还得帮同事做饭也不太爽啊。
后面的乏善可陈,德国的人事拖拖拉拉地一直不给合同,于是一直卡在这个坎上,最后4月终于把合同拿到手,我一是担心使馆耽误时间,二也是不想太赶,于是把日期改到了7月1日,没想到德国中介太NB,已经在德国拿到了移民局的批准,一周不到签证就下来了,不过还是照着我填的7月1号开始。
于是奸计得逞,虽然还是苦逼干活,但是走之前申请了两周婚假,虽然还是各种折腾行李,但是难得地休了长假。
国内的工作大撒把,话说的再好谁也不清楚一年后的事情。
7月来到德国,至现在半年了,一直在做工程师的工作,毕竟干工程师算是轻车熟路,所以还是很自在,压力也有,都是自己加的,避免自己太过放松。
德国同事比想像得热情,带我在开车能到的地方转了很多,其实也有机会自己玩,不过主要目的还是来工作,所以YY的欧洲游没有实现,德国都没出过。
德语是最大的问题,语言不能导致交流的不顺畅,工作的同事还好,大家都在国际化的环境中工作过,都能在适度的理解和宽容下工作,而且客观来说我表现得也不错。但是其他方面就没办法了,德国是单一民族的国家,Aalen还算国际化,要是去其他城市我估计我就直接挂了。
总的来说13年是调整的一年,来德国这一年休假的同时也充实了自己不少,虽然是技术上的,由于国内目前依然结构调整中,所以我的未来依然不明朗,不过14年是增长放缓甚至衰退的一年,挑战往往也是机会。
写这些(为了避免单个过长)文章的目的有两个,一是记录下最近工作的过程和参考的档案,避免以后忘记。二是万一有人和我有一样的问题,也许能搜到这篇文章,避免像我一样走这么多的歪路。
最近半因为工作,半因为兴趣,想实现一些笛卡尔三维坐标内的点云拟合基本元素(直线、平面、圆柱等),虽然很多软件都有非常强的功能,但是基本上都是重量级的收费工业软件,我买不起,而像我们公司的虽然我不用付费,API又几乎没有,所以也借这个机会来学习一下。
先要吐一下槽,中文的资料几乎找不到,不是一些算法课的作业和解答,就是论文数据库中付费才能看,而且不知道质量好坏的论文。不过也是这些论文拯救了我,虽然论文不免费,但是参考文档直接列在那,看参考文档往往比看这些翻译+“优化”的论文要好。
另外一个比较有用的工具是google 学术搜索,可以看到一个论文被引用的次数,后面附的一篇论文被引用了150多次,基本上是这个话题里最早的几篇论文,也是讲的最基础的论文。
另外还要感谢维基百科,一些基本已经忘记的数学概念都是通过这个想起来的,还可以当专业词典用,一篇文章切换中英文,可以极大的帮助理解。
以下是参考资料,会不断更新。
C#类:
math.net库是一个C#实现的数值计算库,在算法实现中大量实用了这个库提供的线代矩阵操作。如果使用C++,一个更有名的库是boost
msdn有任何问题和错误来msdn肯定能查到,比csdn要靠谱太多了。
stackoverflow无数次把我从绝望深渊拯救上来的人,什么问题都可以问,什么问题都有人问,几乎都会得到正确的解释和参考信息。
算法及原理类:
使用Math.NET进行线性与非线性最小二乘拟合,我最早找到的文章之一,我几乎以为单凭这篇文章就可以帮助我搞定问题。
这篇文章的优点是罗列了从基本到常用的几种线性与非线性算法,提供了比较详细的推导过程(不包括线代的定理),和所有的C#代码实现。(下载二进制,源代码)
不过这篇文章里只有单变量二维空间上的拟合。
使用这篇文章及代码可以了解如何使用Math.NET进行矩阵操作,帮助极大,因为其他的文章偏向于论文,往往推导出解法后连计算步骤都不给,使用这里提供的算法可以得到最后一步的结果。
我在代码中找到了一个小BUG,于是给作者写了信,作者很热心的回复并且告诉我有个中国朋友进行了翻译,这是赵毅力同学的翻译。更推荐先阅读这个版本,因为所有的基本概念都做了介绍,不用自己去查教材或者维基百科了。
无名文章,这是我正在使用而且帮助排名第二的文章,看格式像论文或者会议上的技术报告,但是没找到标题,这篇文章提供了笛卡尔空间上的线,圆柱,圆锥,球等的拟合算法,由于没找到引用信息,无法判断这篇文章的正确或者权威性,我目前看到空间直线部分,和我们公司的软件的计算结果取得一致,未来两天会继续验证。(1月23日添加,已验证直线平面和圆柱,算法正确)
缺点是这篇文章里只有基本数据的计算方法,和算法思路,稍微具体点的推导都没有。例如——矩阵A是每个点减平均算出来的,然后使用SVD对A进行计算就可以得到空间向量的解。
如果没有线代基础或者相关的算法概念会觉得莫名其妙,结合第一篇文章看就好很多了。
更原理性的一篇,这篇文章有两个版本,这篇稍老,新的没仔细看,和这个几乎一样Faithful版本,要赞一下这个Prof.论文都放到了个人网站上,省得去各个黑心网站上付费,我觉得论文这种东西写出来就是为了让大家看的,卖几十刀实在是太黑了啊。
不过对应用层面帮助不大,不过如果想对算法实现改进(例如从最小二乘至最小元素法),应该会有帮助的,等我有需求时再看吧。
另外还有几篇是针对圆柱的,因为我个人工作的需求主要针对圆柱的拟合,所以也列在这里了。
5点计算圆柱的算法,给出了详细的推导和分析,产生多种结果的原因,以及Mathematica下的代码实现。
最小误差(条件)及最小二乘拟合圆柱的实现应该是一个图形库的文档,应该是基于C++和OpenGL的库,也提供了代码实现。而且库中直接实现了基本元素的最小二乘拟合实现,圆柱C++实现。
去年重新把域名换成cn后就一直没用过,各种事情折腾,不过好在数据库还留着,所以弄了一个来小时总算是大概可以用了。
来德国半年里做了相当多的技术工作,虽然不是多么复杂或高科技,但是相比于在国内时的重复性对外培训和paper work,感觉一个可以记录内容的blog还是必须的,可以适时的总结与记录工作与状态。
域名还有两年,空间也续租了,未来一年里,争取多写一些吧,也是督促自己多学一些或者多做一些工作。