我想计算两组3D点之间的刚性3D转换。我搜寻了自己,没有找到合适的实现,并在基于此guide的Apache Commons Math库的帮助下自己实现了该实现。该实现可以在下面看到:
public static RigidTransformation3dAnswer computeRigidTransformation3D(RealMatrix src,
RealMatrix dst) {
if (src.getRowDimension() == dst.getRowDimension() && src.getColumnDimension() == dst
.getColumnDimension()) {
int n = src.getRowDimension();
RealMatrix centroidSrc = computeCentroid(src);
RealMatrix centroidDst = computeCentroid(dst);
RealMatrix aa = src.subtract(tile(centroidSrc, n));
RealMatrix bb = dst.subtract(tile(centroidDst, n));
RealMatrix h = aa.transpose().multiply(bb);
SingularValueDecomposition singularValueDecomposition = new SingularValueDecomposition(h);
RealMatrix u = singularValueDecomposition.getU();
RealMatrix vt = singularValueDecomposition.getVT();
RealMatrix rotationMatrix = vt.transpose().multiply(u.transpose());
if (new LUDecomposition(rotationMatrix).getDeterminant() < 0) {
vt.setColumn(2, vt.getColumnVector(2).mapMultiplyToSelf(-1).toArray());
rotationMatrix = vt.transpose().multiply(u.transpose());
}
RealMatrix transpose = (rotationMatrix.scalarMultiply(-1).multiply(centroidSrc.transpose()))
.add(centroidDst.transpose());
RigidTransformation3dAnswer answer = new RigidTransformation3dAnswer();
answer.setRotationMatrix(rotationMatrix);
answer.setTranslationMatrix(transpose);
return answer;
}
return null;
}
private static RealMatrix tile(RealMatrix a, int n) {
RealMatrix realMatrix = new Array2DRowRealMatrix(n, a.getColumnDimension());
for (int i = 0; i < n; i++) {
realMatrix.setEntry(i, 0, a.getEntry(0, 0));
realMatrix.setEntry(i, 1, a.getEntry(0, 1));
realMatrix.setEntry(i, 2, a.getEntry(0, 2));
}
return realMatrix;
}
private static RealMatrix computeCentroid(RealMatrix mat) {
double sumX = 0;
double sumY = 0;
double sumZ = 0;
double[][] returnArray = new double[1][3];
for (int i = 0; i < mat.getRowDimension(); i++) {
double a = mat.getEntry(i, 0);
sumX = sumX + a;
a = mat.getEntry(i, 1);
sumY = sumY + a;
a = mat.getEntry(i, 2);
sumZ = sumZ + a;
}
double centroidX = sumX / (double) mat.getRowDimension();
double centroidY = sumY / (double) mat.getRowDimension();
double centroidZ = sumZ / (double) mat.getRowDimension();
returnArray[0][0] = centroidX;
returnArray[0][1] = centroidY;
returnArray[0][2] = centroidZ;
return new Array2DRowRealMatrix(returnArray);
}
尽管此实现效果很好,但效率不是很高,并且在桌面上大约需要50毫秒,因此不合适,因为我想在Android应用程序中使用它。 所以这是三个问题:
a)有没有更有效的库或框架方法可用于计算刚性3D转换?
b)如果没有,例如,如果我排除平移并且只想绕Z(垂直)轴旋转,那么是否有启发式方法,因此更有效地实现了这种变换?
c)如果这两点都没有答案,是否有办法提高我的代码效率?