我正在尝试适应从一组坐标到另一组坐标的转换。
x' = R + Px + Qy
y' = S - Qx + Py
Where P,Q,R,S are constants, P = scale*cos(rotation). Q=scale*sin(rotation)
有一种众所周知的“手动”公式,用于将P,Q,R,S拟合到一组对应点。 但是我需要对拟合进行误差估计 - 所以我需要一个最小二乘解决方案。
阅读'数字食谱',但我无法弄清楚如何为包含x和y的数据集执行此操作。
有人能指出如何做到这一点的示例/教程/代码示例吗?
对语言不太感兴趣。
但是 - 只使用Matlab / Lapack / numpy / R的内置功能可能没有帮助!
编辑: 我有一大套旧的(x,y)新(x,y)适合。问题是超定的(比未知数更多的数据点)如此简单的矩阵求逆是不够的 - 正如我所说,我真的需要适合的误差。
答案 0 :(得分:4)
要查找P,Q,R和S,您可以使用最小二乘法。我认为令人困惑的是,通常的最小二乘描述使用x和y,但它们与你问题中的x和y不匹配。您只需要将问题小心地转换为最小二乘框架。在你的情况下,自变量是未转换的坐标x和y,因变量是变换后的坐标x'和y',可调参数是P,Q,R和S.(如果这个不够清楚,让我知道,我会发布更多细节。)
一旦你找到了P,Q,R和S,那么scale = sqrt(P ^ 2 + Q ^ 2)然后你可以从sin旋转中找到旋转= Q / scale和cos rotation = P /规模。
答案 1 :(得分:3)
以下代码应该可以解决问题。我使用以下公式表示残差:
residual[i] = (computed_x[i] - actual_x[i])^2
+ (computed_y[i] - actual_y[i])^2
然后根据Wolfram的MathWorld中描述的general procedure推导出最小二乘公式。
我在Excel中测试了这个算法并且它按预期执行。我使用了十个随机点的集合,然后通过随机生成的变换矩阵进行旋转,平移和缩放。
没有随机噪声应用于输出数据,此程序产生四个参数(P
,Q
,R
和S
),它们与输入相同参数,rSquared
值为零。
随着越来越多的随机噪声应用于输出点,常数开始偏离正确的值,rSquared
值也相应增加。
以下是代码:
// test data
const int N = 1000;
float oldPoints_x[N] = { ... };
float oldPoints_y[N] = { ... };
float newPoints_x[N] = { ... };
float newPoints_y[N] = { ... };
// compute various sums and sums of products
// across the entire set of test data
float Ex = Sum(oldPoints_x, N);
float Ey = Sum(oldPoints_y, N);
float Exn = Sum(newPoints_x, N);
float Eyn = Sum(newPoints_y, N);
float Ex2 = SumProduct(oldPoints_x, oldPoints_x, N);
float Ey2 = SumProduct(oldPoints_y, oldPoints_y, N);
float Exxn = SumProduct(oldPoints_x, newPoints_x, N);
float Exyn = SumProduct(oldPoints_x, newPoints_y, N);
float Eyxn = SumProduct(oldPoints_y, newPoints_x, N);
float Eyyn = SumProduct(oldPoints_y, newPoints_y, N);
// compute the transformation constants
// using least-squares regression
float divisor = Ex*Ex + Ey*Ey - N*(Ex2 + Ey2);
float P = (Exn*Ex + Eyn*Ey - N*(Exxn + Eyyn))/divisor;
float Q = (Exn*Ey + Eyn*Ex + N*(Exyn - Eyxn))/divisor;
float R = (Exn - P*Ex - Q*Ey)/N;
float S = (Eyn - P*Ey + Q*Ex)/N;
// compute the rSquared error value
// low values represent a good fit
float rSquared = 0;
float x;
float y;
for (int i = 0; i < N; i++)
{
x = R + P*oldPoints_x[i] + Q*oldPoints_y[i];
y = S - Q*oldPoints_x[i] + P*oldPoints_y[i];
rSquared += (x - newPoints_x[i])^2;
rSquared += (y - newPoints_y[i])^2;
}
答案 2 :(得分:1)
定义3x3矩阵T(P,Q,R,S),使(x',y',1) = T (x,y,1)
。然后计算
A = \sum_i |(T (x_i,y_i,1)) - (x'_i,y'_i,1)|^2
并最小化A对(P,Q,R,S)。
自己编码是一个中型到大型项目,除非你能保证数据条件良好,特别是当你想要从程序中获得良好的错误估计时。你可能最好使用支持误差估计的现有最小化器。
粒子物理类型将直接从minuit使用CERNLIB(编码最容易在fortran77中完成),或者来自ROOT(使用c ++编码,或者应该是通过python绑定可访问)。但如果您还没有这些工具,那么这是一个很大的安装。
我确信其他人可以推荐其他最小化器。
答案 3 :(得分:1)
您可以使用levmar程序来计算。它经过测试并集成到包括我的多种产品中。它是根据GPL许可的,但如果这是一个非开源项目,他将为您更改许可证(收费)
答案 4 :(得分:1)
感谢eJames,这几乎是我所拥有的。我用一本旧的军队测量手册编写了这本书,该手册是基于早先的“测量员指南”说明,必须是100岁! (它使用北和东的N和E而不是x / y)
拟合优度参数将非常有用 - 如果它们使得适合性变差,我可以交互式地抛弃选定的点。
FindTransformation(vector<Point2D> known,vector<Point2D> unknown) {
{
// sums
for (unsigned int ii=0;ii<known.size();ii++) {
sum_e += unknown[ii].x;
sum_n += unknown[ii].y;
sum_E += known[ii].x;
sum_N += known[ii].y;
++n;
}
// mean position
me = sum_e/(double)n;
mn = sum_n/(double)n;
mE = sum_E/(double)n;
mN = sum_N/(double)n;
// differences
for (unsigned int ii=0;ii<known.size();ii++) {
de = unknown[ii].x - me;
dn = unknown[ii].y - mn;
// for P
sum_deE += (de*known[ii].x);
sum_dnN += (dn*known[ii].y);
sum_dee += (de*unknown[ii].x);
sum_dnn += (dn*unknown[ii].y);
// for Q
sum_dnE += (dn*known[ii].x);
sum_deN += (de*known[ii].y);
}
double P = (sum_deE + sum_dnN) / (sum_dee + sum_dnn);
double Q = (sum_dnE - sum_deN) / (sum_dee + sum_dnn);
double R = mE - (P*me) - (Q*mn);
double S = mN + (Q*me) - (P*mn);
}
答案 5 :(得分:0)
一个问题是像这样的数字通常很棘手。即使算法很简单,实际计算中也会出现问题。
出于这个原因,如果有一个系统可以很容易地获得具有内置功能的系统,那么最好使用它。