Closed SubMishMar closed 6 years ago
Can you share input_M3500_g2o.txt too? I will have a look.
Edit: Can I use this one? https://www.dropbox.com/s/gmdzo74b3tzvbrw/input_M3500_g2o.g2o?dl=0
Infomation matrix should not have zero diagonal element. Otherwise, it will produce zero residual. Replacing
info = np.zeros(shape)
this with
info = np.identity(shape)
will minimize graph energy. I got this
[GlobalOptimizationLM] Optimizing PoseGraph having 3500 nodes and 5453 edges.
Line process weight : 0.082639
[Initial ] residual : 7.036830e+04, lambda : 1.448914e+01
[Iteration 00] residual : 3.065880e+03, valid edges : 1826, time : 979.903 sec.
[Iteration 01] residual : 2.532268e+03, valid edges : 2834, time : 981.329 sec.
:
A few notes:
@syncle , yes thats the right link to the dataset I am using.
Yes, I now understand that having zeros on the diagonal of the info matrix makes no sense. I had tried replacing this by an identity matrix like you have and as you have mentioned, it took forever, so I never waited long enough to see the first iteration and just pressed ctrl+c .
As an answer to your note:
x = float(line.split(' ')[2])
y = float(line.split(' ')[3])
theta = float(line.split(' ')[4])
c = np.cos(theta)
s = np.sin(theta)
wTi = np.array([[ c, -s, 0, x], [ s, c, 0, y], [ 0, 0, 1, 0], [ 0, 0, 0, 1]])
And the information matrix as
shape = (6)
info = np.identity(shape)
info[0][0] = float(line.split(' ')[6])
info[1][1] = float(line.split(' ')[9])
info[5][5] = float(line.split(' ')[11])
Now, I only fill info[0][0] , info[1][1] and info[5][5] because I think that they represent the variance terms for X, Y and Yaw(theta) respectively. Correct me if I am wrong.
If you look at the data set, there are two types of rows, VERTICES and EDGES and their description can be found here: (https://github.com/RainerKuemmerle/g2o/wiki/File-Format-SLAM-2D)
As I can see that you were patient enough to wait for the execution to complete, did you compare the input poses and the optimized output poses?
Could you tell me how I can fill the info matrix for 2D pose graph optimization? Also, Can I just comment that block out and re-make open3d? Will not calculating the determinant affect my results?
@syncle Which part do you think is the major bottle neck? is it
double det = A.determinant();
or
Eigen::MatrixXd x = A.ldlt().solve(b);
@syncle Moreover, I dont think that that particular function you have mentioned is being called when I am doing pose graph optimization, I have put a cout flag there and I dont see any output. I searched for the files where this function has been called and they are located at https://github.com/IntelVCL/Open3D/blob/35be432d45bf47bbcdf920c62d7d9d446ac6d36d/src/Core/Registration/ColoredICP.cpp and https://github.com/IntelVCL/Open3D/blob/b30ee02042a7a490e13f8db68dd98dc25113f467/src/Core/Registration/FastGlobalRegistration.cpp And I don't thnk these files have much to do with pose graph optimization (or do they?)
You're right. It does not use this function. The only bottleneck is Eigen::VectorXd delta = H.ldlt().solve(b);
I am looking your description about information matrix.
I think nodes are fine, but filling information matrix need to be carefully considered to use g2o compatible dataset in open3d.
Open3D's Pose graph optimization follows the definition of information matrix described in here: http://redwood-data.org/indoor/registration.html (please see Eq 8) The key idea is to embed point to point distance into an information matrix.
I will check it out, thanks.
So, you say that there is some difference between the way information matrices are defined for g2o and open3d?
Correct. This case I haven't tried so far, and it require some study. Let's share our thoughts in this thread.
In my opinion, one of the major differences between the formats of information matrices in open3d and g2o is that, in open3d the first three diagonal elements of the information matrix are related to rotation components and the last three to translational components,
But, in g2o it must be the other way, i.e., the first three diagonal elements belong to translational variables and the last three to rotational. As shown in the following links,
I found this t2v representation in a graph slam course by Dr. Cyrill Stachniss and I think this is the one implemented in g2o .
The link to the course slide is http://ais.informatik.uni-freiburg.de/teaching/ws13/mapping/pdf/slam15-ls-slam.pdf . Please check slide 27.
That's awesome. I also found some related bug and submitted fix in #368. Another difference is that g2o uses quaternion for representing rotational components, whereas open3d uses linear coefficients for skew symmetric matrix, which is not exact rotation matrix.
Another thing is open3d builds information matrix \sum_q [-q_x | I ]^T * [-q_x | I ]
where q is not quatanion. It is from a correspondence. (please see http://redwood-data.org/indoor/registration.html).
"whereas open3d uses linear coefficients for skew symmetric matrix, which is not exact rotation matrix"
What do you mean by this?
Does the following code refer to the "linearized" rotational components?
@syncle, I was wondering if we can provide any arbitrary information matrix (ofcourse it must be a valid information matrix, satisfying all basic properties) to the pose graph optimization algorithm in open3d or it should necessarily be generated from one of the various open3d functions which return the information matrix for eg get_information_matrix_from_point_clouds()
or compute_rgbd_odometry()
Yes, I believe you can use any valid information matrix.
While executing the reconstruction tutorial given in the open3d website on the 016 dataset I realized that the result of the final integration doesnt change if I use or dont use pose graph optimization. @syncle @qianyizh , can you please explain this? Is it because of the fact that the number of poses being optimized is pretty small?
We just merged a patch related to the information matrix. It will be needed to make a pose graph again. Or, It maybe just because the pose graph is much accurate than before. With the patched version, I observe the tutorial script takes just 3~5 times of LM iteration, while energy is reduced 20x smaller than the initial one.
Interesting. The optimization works for sure, but the changes on the final integration is not prominently visible. Probably because the initial alignment algorithms work very well.
Besides, I replaced the ldlt thing by using sparse cholesky decomposition. Something like this:
Eigen::MatrixXd H_LM = H + current_lambda * H_I;
Eigen::SparseMatrix<double> H_LM_sparse = H_LM.sparseView();
Eigen::SimplicialCholesky<Eigen::SparseMatrix<double>> chol(H_LM_sparse);
Eigen::VectorXd delta = chol.solve(b);
So, now the manhattan dataset is processed pretty fast and it takes about 2 seconds per iteration:
[Initial ] residual : 7.185224e+04, lambda : 1.291831e-01
[Iteration 00] residual : 1.481994e+03, valid edges : 14, time : 6.333 sec.
[Iteration 01] residual : 5.288676e+02, valid edges : 58, time : 2.327 sec.
[Iteration 02] residual : 2.837691e+02, valid edges : 113, time : 2.221 sec.
[Iteration 03] residual : 1.859188e+02, valid edges : 215, time : 2.229 sec.
[Iteration 04] residual : 1.387585e+02, valid edges : 378, time : 2.231 sec.
[Iteration 05] residual : 1.039180e+02, valid edges : 588, time : 2.239 sec.
[Iteration 06] residual : 6.296705e+01, valid edges : 785, time : 2.293 sec.
[Iteration 07] residual : 3.927089e+01, valid edges : 1022, time : 2.264 sec.
[Iteration 08] residual : 2.727294e+01, valid edges : 1211, time : 2.249 sec.
.....
(earlier it used to take 500 seconds), but I still dont understand how to input the information data available in manhattan dataset into open3d.
WOW, this is really awesome. Thanks Subodh! You can submit your changes for the better Open3D :)
Okay, I will submit a PR later today. Thanks :)
This issue needs to be closed as the "Result of the pose graph optimization was same as the input" only because there were not enough loop closure edges added to the graph. Adding enough loop closure edges will give a different result (which may not always be the best).
But, the other issues mentioned in the above thread still needs to be solved.
Is it possible for us to view the pose graph optimization process (such as iterations of cost reduction), so we can understand the error really decreasing?
@szx0112 could you please open a new issue with your question.
I am trying to use the open3d implementation of posegraph optimization for optimizing the poses of the Manhattan g2o format dataset. But due to some strange reason, the output of the optimization process is identically same to the input pose graph. Can anyone tell me why is it so?
Here is the code:
`