-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wishlist: "shape-based" transform #3
Comments
Definitely sounds like something which exists! In the worst case it's a 6-parameter optimisation problem, right (rotation around each axis, plus translation in each axis)? Downsample/ prune both neurons ahead of time, or pick the root and major branch points or something, then use something like squared distance to nearest neighbour as a cost function; you'd only need to construct one KDtree (because the target is static). Orientation might be a problem for some data. Normalise the translation and rotation parameters to between -1 and 1 (multiply by pi for the rotations, and by the length of the bounding box for the translation) and most optimisers would work, although the cost function would be pretty slow. I'm practically certain there's some linear algebra which can do it properly, although I don't know what it is, I'm afraid. |
The thinplate-spline transform in I'll see if that would be suited but as you say: something like that MUST already exist. This is probably one of those things where you just need to to know the correct term and Google will help. Maybe @aschampion knows? |
I'm confused -- are the points between each each set paired with each other? If so, this is just a least squares problem and can be solved directly with the eigenvector (from SVD). If not, it requires some way of doing point matching and is more open-ended, but the most common point cloud matching approaches are to do an expectation-maximization-like process where you generate candidate matches (kNN or similar) based on the previous xform, fit a new xform, and repeat. |
For the former problem see the fitting in CATMAID for rigid xform. |
Ah, sorry: here the points would not be paired. |
This looks interesting: https://github.com/siavashk/pycpd |
I use/forked pycpd for mesh registration -- would recommend. |
Here's another one: https://github.com/neka-nat/probreg |
I just had a closer look at |
The clouds I was using were ~ 10-50K vertices. Generating registrations is 10s minutes-1 hour, but transforming points was fine, and I typically was rendering a warp field once that I would use for most subsequent projections anyway. |
Thanks! I'm about to open an issue on the pycpd repo asking for advice on the parameters - I'll tag you in case you have a suggestion. |
Actually nvm: I now have some decent results - my I did run into another issue though: |
You can transform arbitrary point sets from the source space with the pycpd registrations using the Generating a warp field makes sense if you need to amortize computation for xform of many points or image volumes and your input space is bounded and discretized (e.g., locations are reasonably approximated as voxel coordinates in some relatively low-resolution grid). However it's not something you'd want to generate for something like EM-scale skeleton transformation. Here's some pseudo-ish code for generating a field, but details such as which direction (+/- original coordinates) and whether the warp vectors are in physical units, source coordinates, or target coordinates, is up to your particular use: def registration_to_warp_field(regst, shape, downsample=(1, 1, 1)):
ranges = np.asarray([slice(None, r, d) for (r, d) in zip(shape, downsample)])
coords = np.mgrid[ranges].reshape(len(shape), -1).T
x_coords = np.copy(coords)
CHUNK_SIZE = 1000
for i in range(0, len(coords), CHUNK_SIZE):
end = min(i + CHUNK_SIZE, len(coords))
x_coords[i:end] = r.transform_point_cloud(x_coords[i:end])
x_coords = x_coords - coords
dshape = np.ceil(np.asarray(shape) / downsample).astype(np.int64)
return x_coords.reshape(*dshape, len(shape)) |
You probably know this already, but to note for |
Thanks for the snippet!
Yes, I used a RigidTransform but that seemed to also do a decent enough job for initial alignment. FYI, I'm trying to align the CNS of Seymour (red) and Igor (green = after rigid; red = rigid + warp) for the guys in Bonn: I'm still a bit confused re the return Y + np.dot(self.G, self.W) Here >>> reg.transform_point_cloud(np.array([[0,0,0], [1,1,1]]))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-217-c28b12d2586a> in <module>
----> 1 deform.transform_point_cloud(np.array([[0,0,0], [1,1,1,]]))
~/Google Drive/Cloudbox/Github/pycpd/pycpd/deformable_registration.py in transform_point_cloud(self, Y)
66 return
67 else:
---> 68 return Y + np.dot(self.G, self.W)
69
70 def update_variance(self):
ValueError: operands could not be broadcast together with shapes (2,3) (11784,3) What am I missing? |
This rang a bell. Looking at my notes I had a workaround padding or batching the input point sets to be the same size as the source set, but removed that when rebasing sometime last year, because of the merging of this PR. I think that's not on pypi. |
Ah yes: there are changes to this method in the |
Never mind - I looked at the wrong line. Will check it out, thanks! |
Quick question for @aschampion: do you know if it possible to invert a |
Have to do it manually, e.g.: def invert_affine_reg(affine: pycpd.AffineRegistration):
(B, t) = affine.get_registration_parameters()
B_inv = np.linalg.inv(B)
t_inv = - np.dot(t, B_inv)
t_inv = np.expand_dims(t_inv, 0)
return pycpd.AffineRegistration(B=B_inv, t=t_inv, X=affine.Y, Y=affine.X) |
Basically, what I want is a Transform that accepts two sets of points (e.g. from two neurons) and then finds an affine (i.e. non-warping) transform that minimises the distance between those points. This affine transform could be restricted to e.g. only use translation and rotation but not scaling.
One use case would be to align two neurons of the same cell type but from different segments.
I'm sure I've read about/seen something like this but I can't think of the proper term. @clbarnes: any idea of what I'm talking about?
The text was updated successfully, but these errors were encountered: