siavashk / pycpd

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

rigid transformation #34

Closed mingweiY closed 2 years ago

mingweiY commented 4 years ago

Thanks for the code.
Now I have two sets of points, one is a template, and the other is the same as the template but has some noisy points and is rotated 90 degrees. When I used the rigid method to register these two sets, I found that the effect was not ideal. The rigid transformation include translation, rotation, and scaling. What is the reason for this? Looking forward to your reply, thanks again. 16535_fusept.txt FormTax_00013_fusept.txt

siavashk commented 4 years ago

What do you mean by "the effect was not ideal"?

siavashk commented 4 years ago

Closed due to inactivity.

KingDeng005 commented 4 years ago

Hi siavashk, for the regid transformation, why scaling was computed? For my case, I computed rigid transform for two point clouds in 2D, and s_reg returns a non 1 value. It then made it non-rigid am I missing something?

ckolluru commented 2 years ago

Hi, thanks for your work. Is there a way to get a rigid transformation result without any scaling?

There is no scaling effect between the two point clouds in my application. Thanks.

gattia commented 2 years ago

Hey, @ckolluru I've reopened this issue because you & @KingDeng005 make good point - we should have the option to do rigid registration without scaling.

I don't have the time to do this right now, but that should be easy to do and is described in the original paper (quote at the end). Essentially, I think you just need to add an option for the rigid registration method that is a boolean of whether or not scaling should be optimized here. I'd call it scale since that isn't used yet (I don't think?) - we use s in the code base, and set the default to be True. You'll need to make the class inherit scale (self.scale) roughly here. Then, later in the update transform step here add something like:

if self.scale is True:
    self.s = np.trace(np.dot(np.transpose(self.A),
                                 np.transpose(self.R))) / self.YPY
else:
    pass                 

As is, this should also allow the user to pre-specify a non-unitary scaling, which would be useful.

Thanks for the interest! Let me know if you have any additional thoughts.

https://arxiv.org/pdf/0905.2635.pdf :

The most challenging here is that we biased the outliers to the different sides of fish point sets. We were able to register such point sets only by fixing the scaling to be constant (estimating rotation and translation only). CPD demonstrates accurate and robust registration performance

gattia commented 2 years ago

@ckolluru did this help your usecase?

ckolluru commented 2 years ago

I think this works.

Just one more question - with scaling disabled, is it reasonable to expect that the diagonal elements in the final transformation be very close to 1? 0.99 or higher?

gattia commented 2 years ago

did you try this? If so, please feel free to make the changes on a development branch of your own fork of the repository and contribute back - others would really benefit from the addition.

That's a great question, not necessarily. They will only be close to 1.0 if the registration didn't rotate the object very much. This describes how a 3D rotation matrix should look.... you can see that all of the diagonal elements are describes as cos(theta)... therefore, if theta (the change in angle) is close to zero, then the element will be close to one. If you make the angle bigger, these elements will change accordingly.

Also.. pycpd does the scaling separate from the rotation matrix: here, so this shouldn't affect the rotation matrix at all.

ckolluru commented 2 years ago

Submitted a PR, please take a look when you can and let me know if I can do anything else.

gattia commented 2 years ago

Ability to select whether scaling is included in rigid registration has been added & merged to dev: https://github.com/siavashk/pycpd/pull/67