我有对象让我们说模型图像 . 我想计算模型图像上的对象和目标图像上的对象之间的变换(位移,缩放,旋转) . 我想假设对象可以被视为2D,因此只应计算2D变换 .
首先,我想用手动辅助的方式 . 用户在模型图像上选择基点,然后在目标图像上选择目标点 . 点数应由用户定义(但不低于最低2-3点) . 当点给出不同的信息时,应该对变换进行平均,并且例如由此可以计算匹配的质量 .
所以问题是关于计算两组点的转换,但正如我想在图像上做的那样,我添加了图像处理标签 .
特别欢迎使用一些代码或伪代码的参考和建议 .
有两点是非常容易的问题,只应采用线的旋转,比例和位移,但如何用更多的点来做,并对其进行平均并计算一些质量因素 .
Current solution is:
void transformFnc(std::vector<PointF> basePoints, std::vector<PointF> targetPoints,
PointF& offset, double rotation, double scale)
{
std::vector<Line> basePointsLines;
std::vector<Line> targetPointsLines;
assert(basePoints.size() == targetPoints.size());
int pointsNumber = basePoints.size();
for(int i = 0; i < pointsNumber; i++)
{
for(int j = i + 1; j < pointsNumber; j++)
{
basePointsLines.push_back(Line(basePoints[i], basePoints[j]));
targetPointsLines.push_back(Line(targetPoints[i], targetPoints[j]));
}
}
std::vector<double> scalesVector;
std::vector<double> rotationsVector;
double baseCenterX = 0, baseCenterY = 0, targetCenterX = 0, targetCenterY = 0;
for(std::vector<Line>::iterator it = basePointsLines.begin(), i = targetPointsLines.begin();
it != basePointsLines.end(), i != targetPointsLines.end(); it++, i++)
{
scalesVector.push_back((*i).length()/(*it).length());
baseCenterX += (*it).pointAt(0.5).x();
baseCenterY += (*it).pointAt(0.5).y();
targetCenterX += (*i).pointAt(0.5).x();
targetCenterY += (*i).pointAt(0.5).y();
double rotation;
rotation = (*i).angleTo((*it));
rotationsVector.push_back(rotation);
}
baseCenterX = baseCenterX / pointsNumber;
baseCenterY = baseCenterY / pointsNumber;
targetCenterX = targetCenterX / pointsNumber;
targetCenterY = targetCenterY / pointsNumber;
offset = PointF(targetCenterX - baseCenterX, targetCenterY - baseCenterY);
scale = sum(scalesVector) / scalesVector.size();
rotation = sum(rotationsVector) / rotationsVector.size();
}
我在这段代码中只能找到的优化是从比例和旋转中消除那些与其他值差别太大的值 .
I'm looking for codes or pseudocodes of solution propositions. It can also be references to some codes.
到目前为止,我知道答案:
-
可以使用RANSAC算法
-
我需要在最小二乘意义上寻找一些仿射变换计算算法
5 回答
首先用3x3仿射变换矩阵在一个简单的仿射变换中推广该问题:即
既然我们已经知道第三行总是[0 0 1],我们可以简单地忽略它 .
现在我们可以将问题描述为以下矩阵方程
其中xp和yp是投影坐标,x和y是原始坐标 .
我们称之为
然后我们可以计算出适合转换的最小二乘法
其中pinv是伪逆 .
这给了我们一个仿射变换,它最符合最小二乘意义上给出的点 .
现在显然这也会给出剪切,坐标翻转以及你不想要的非均匀缩放,所以我们需要以某种方式限制仿射变换以避免剪切 . 事实证明这很简单,我们可以使用单个向量来描述旋转(向量的方向)和缩放(向量的大小),另一个向量将简单地与它正交 . 这将自由度降低了两倍 .
所以减少到
在我们求解上述矩阵方程后,从M12和M11计算M21和M22 .
我会试试Iterative closest point算法 .
Here您找到了具有缩放功能的实现 . (SICP)
另一个有用的link
为简单起见,假设您的输入
x1,...,xn
和输出y1,...,yn
是复数 .您可以通过计算
avg(y) - avg(x)
来计算平均位移,一旦完成,您可以减去x
和y
的平均值,使它们以0为中心 .您现在想要找到旋转和比例 . 您可以将两者都表示为单个复数
z
,以便x*z
应尽可能接近y
. 但x*z
是 R 的_实体坐标(zx,zy)
的 R -线性函数:因此您可以使用经典线性代数求解z
,使得x*z
在最小二乘意义上尽可能接近y
.总而言之,这为您提供了最小二乘意义上的最佳转换 .
您的转换是仿射变换,可以用3 * 3矩阵编写 . 因此,您的问题基本上是计算从一组点到其他点的最小均方误差仿射变换 .
在常见的计算几何文献中很容易解决这个问题 . 这是一本很好的经典书:http://www.robots.ox.ac.uk/~vgg/hzbook/hzbook1.html(没有广告,它只是大多数人的参考书) . 您将找到有关2D和3D几何的所有信息 . 像"affine transformation LMSE"这样的快速谷歌也会为您提供信息和代码 .
此外,您还可以使用其他类型的算法,如RANSAC等强大的算法 . 根据您的应用,向这个方向前进可能会很有趣 .
更多simple and clear code in Matlab可以让你变换 .
并且more complex C++ code(using VXL lib)包含python和matlab包装 .
或者您可以使用一些对噪声具有鲁棒性的修改后的ICP(迭代最近点)算法 .