Java中更有效的刚性3D转换

时间:2018-11-22 13:33:27

标签: java math optimization geometry

我想计算两组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)有没有更有效的库或框架方法可用于计算刚性3​​D转换?

b)如果没有,例如,如果我排除平移并且只想绕Z(垂直)轴旋转,那么是否有启发式方法,因此更有效地实现了这种变换?

c)如果这两点都没有答案,是否有办法提高我的代码效率?

0 个答案:

没有答案