siavashk / pycpd

Pure Numpy Implementation of the Coherent Point Drift Algorithm
MIT License
510 stars 115 forks source link

Example fish_affine_2D diverges instead of converges #40

Closed ghost closed 4 years ago

ghost commented 4 years ago

Hi,

Thank you for making this implementation of CPD.

I am looking to align two point clouds by affine transformation and later add/draw additional points related to the source points with the achieved transformation matrices (B, t) after succesful registration .

Starting out with the provided example -- and using the fish data -- fish_affine_2D.py, I get a divergence terminating in error (Q) = -550 after 100 iterations. I did not make any modifications to the code. What would be your best guess for what is going on? Installed with pip install pycpd (2.0.0)

Thanks!

gattia commented 4 years ago

Hey!

I noticed you had a question and then closed it (sorry, didn't get to it while open still).

Did you find an answer? Was there an issue with the code? Or maybe did you have an environment issue?

If you did solve it, mind sharing so that others might find this if they happen upon the same issue?

Thanks!

ghost commented 4 years ago

The mistakes were mine: I had made some changes to the different registration classes that I thought I had undone, but I hadn’t. Reinstalled pycpd and everything worked beautifully.

I am though very curious about your latest pull request for pycpd: allowing for points that are not part of the deformable registration, but should be moved with the same transformation. This is exactly what I need. With the low-rank option, I would be able to do the transformation (only) on m points and have n points follow in array[m,n] with num_eig=len(m) and low_rank=True, right?

gattia commented 4 years ago

Excellent. I understand the pains! Just wanted to make sure a learning opportunity for others wasn't missed.

https://github.com/siavashk/pycpd/pull/37 The above pull request implements the lowrank. Low rank just lets you compress the point cloud (using eigenvectors of the points). The point of this is to speed up CPD, which it does HUGELY. It also has the added benefit of regularizing the deformable transformation, so it helps with making sure that the deformation arent too abnormal in shape.

https://github.com/siavashk/pycpd/pull/38 This pull request is the one that implements the ability to apply the transformation to any arbitrary point cloud size. I did these edits after doing the lowrank and that's the only reason you see lowrank in this pull request at all, in theory this can be done without lowrank.

If you want this ability right away... I have created a version of pycpd that uses cython at this repo:

https://github.com/gattia/cycpd

Though, I will note that @siavashk has made some changes (particularly to the deformable stopping criteria) that are more recent than my cycpd implementation and so they aren't incorporated. I also used the old syntax/style of pycpd (version 1.xx) However, the results should be very similar.

If you just want to pull the version of pycpd in my pull request, I believe you can actually do that. I haven't done so myself, but the details to do so are here:

https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/checking-out-pull-requests-locally

ghost commented 4 years ago

Thank you for your thorough reply!

I pulled the version with #38 . Could you maybe provide an example of how you would do the registration on selected points and then apply the transformation to additional points?

gattia commented 4 years ago

No problem.

I've added an example and pushed it to the same pull request https://github.com/siavashk/pycpd/pull/38. So you should be able to pull it again and see the example/code. Or just look at the code in the pull request if you rather.

Below summarizes the gist of it:

Ysubset = Y[1::2,:]

reg = DeformableRegistration(**{'X': X, 'Y': Ysubset})
reg.register()
YT = reg.transform_point_cloud(Y=Y)

If we take some subset of the data (in this case Ysubset) and do the registration with it. We can then apply that transformation to the full dataset (Y) to get the transformed dataset (YT) using the last line.

ghost commented 4 years ago

Almost forgot: Thank you very much! This was spot on what I needed!