gvtulder / elasticdeform

Differentiable elastic deformations for N-dimensional images (Python, SciPy, NumPy, TensorFlow, PyTorch).
Other
186 stars 25 forks source link

Help with setting up displacement vector #5

Closed regproj closed 4 years ago

regproj commented 5 years ago

Hello, I'm trying to register two different nifti volumes (size = 512,512,256), and I have a set of 11 control points (size = 11,3) for each volume. How do I go about setting up the displacement array that feeds into the function deform_grid?

gvtulder commented 5 years ago

The displacement matrix has a shape [image dimension, grid points in dim 1, grid points in dim 2, ...]. For each grid point, you need to specify the displacement in each dimension. E.g., if you want to move output grid point (1, 2) with y = +3 and x = -2, you would set

# displacement in first image dimension
displacement[0, 1, 2] = 3
# displacement in second image dimension
displacement[1, 1, 2] = -2

In your case, your displacement matrix would have shape [3, 11, 3].

It might be easier to understand if you play with a simple example. Here's a small demo notebook: https://gist.github.com/gvtulder/33bce7e87082d5eb1fbeb8bcd1e2b1fa

regproj commented 5 years ago

Thanks for the quick reply! I'm still a bit confused. In the 3d case, say I have the grid point (1,2,3) with displacements y=+3, x = -2, and z =+1,

would the displacement then be the following: displacement[0,1,2,3] = 3 displacement[1,1,2,3] = -2 displacement[2,1,2,3] = +1

(Also why is the y displacement at [0,1,2,3] instead of [1,1,2,3]? And do you set all the other elements of this array to 0?)

gvtulder commented 5 years ago

Sorry for the confusion about the x, y dimensions. You’re correct. The first dimension of the displacement matrix corresponds with the dimensions of your image. If your 3D image has dimensions x, y, z, then you should indeed set your y displacement in [1, ...]. For my example, y=1 and x=0 because the pyplot imshow command draws the image as (rows, cols). It depends on your data.

The displacement matrix defines the offset of the grid points in the output image (in pixels). If you set the values to 0, they will be placed in their default positions: the first grid point on the first pixel, the last grid point on the last pixel, the rest spaced evenly in between. If you would set [0, ...] = 2 you would shift the image by two pixels in the first dimension.

regproj commented 5 years ago

No worries. Would it be okay to just post the problem I'm having?

I have these original coordinates (unrounded): [[250.43150685 302.43835616 177.0890411 ] [250.39680024 316.50785081 79.58403091] [245.36945825 339.81282322 122.76914194] [268.7184466 330.76699029 179.21682848] [228.27838828 328.01465201 178.86446886] [305.74431146 298.98362488 130.54504801] [191.92361759 296.2922809 130.70827891] [250.50482731 303.17895889 104.90793272] [251.24213254 266.61080258 71.35698712] [278.87152914 320.60363707 102.27649589] [219.57076205 320.73294823 98.46300822]]

And these displacements (also unrounded): [[ 9.9552856 -2.44150082 26.51630482] [ 9.35554389 8.75201708 48.22992108] [14.49956975 17.54208917 41.94959402] [14.26769659 -2.21733671 26.22658953] [ 6.82608933 1.16694003 27.01115303] [11.88820743 4.01848482 38.17166282] [10.0043615 0.35475132 38.0590227 ] [ 9.473421 8.84596892 46.81189404] [ 8.16002024 -7.11721053 53.21746028] [14.5515138 8.9936416 46.05165396] [ 6.89129806 4.68017493 48.22100937]]

Both of these arrays are of shape (11,3), but you mentioned that I should get them into shape (3,11,3). I'm not sure how to go about doing this. Also the toy example you mentioned makes me think that the shape should be (3,512,512,256), but I don't think that's right either?

gvtulder commented 5 years ago

The elastic deformation method expects you to define a regular grid on your input image. If you have a 2D input image, you could for example define a 5 x 3 grid: you would then have 5 grid columns in the first dimension (spaced evenly between the first and last pixel in that direction) and 3 grid columns in the second. For each of these 15 grid points you have to define the displacement in each dimension, so the shape of the displacement matrix should be (2, 5, 3). The displacement for the pixels in between grid points is interpolated to give you a smooth output image.

If you give your displacement vector the shape (3,512,512,256), that would specify a different displacement for every input voxel. That only makes sense if you pre-interpolate the displacements to get a smooth deformation field, otherwise you would get a very weird-looking result.

If you don't have a regular displacement grid, this library doesn't do what you want. From your new description it looks like you have a registration problem (from your initial question I had the impression that you had solved the registration and only wanted to transform an image). If all you have is a set of 11 arbitrary corresponding points, you will need to use a point-based registration method first.