You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
adds missing text (normal and spoiler sandpaper style) for the cropping and registration sections, including figs, regs and other minor cosmetic changes #4
Copy file name to clipboardExpand all lines: episodes/itksnap.Rmd
+85-8Lines changed: 85 additions & 8 deletions
Original file line number
Diff line number
Diff line change
@@ -369,13 +369,11 @@ nii3ct.shape
369
369
```
370
370
371
371
3. Affine transform, mapping from voxel space to world space
372
-
```callout
373
372
There are two common ways of specifying the affine transformation mapping from voxel coordinates
374
373
to world coordinates in the nifti header, called the `sform` and the `qform'.
375
374
Another transformation is that neither the sform or qform is used the mapping is performed based just on the voxel dimensions.
376
375
The **sform** directly stores the affine transformation in the header
377
376
whereas the **qform** stores the affine transformation using [quaternions](https://en.wikipedia.org/wiki/Quaternion).
378
-
```
379
377
380
378
:::::::::::::::::::::::::::::::::::::: spoiler
381
379
@@ -483,12 +481,17 @@ print(nii3ct.get_qform())
483
481
# [ 0. 0. 0. 1. ]]
484
482
```
485
483
486
-
```callout
487
-
However, the nifti format does not require that the sform and qform specify the same
488
-
matrix, and it is not well defined what should be done when they are both provided and are
489
-
different from each other.
484
+
485
+
486
+
:::::::::::::::::::::::::::::::::::::: spoiler
487
+
488
+
### Advincing on using `sform`
489
+
However, the nifti format does not require that the sform and qform specify the same matrix.
490
+
It is also not well defined what should be done when they are both provided and are different from each other.
490
491
Often the `qform` is simply ignored and the `sform` is used, so the general advice is to only use the `sform` and set the `qform` to unknown to avoid any confusion.
491
-
```
492
+
493
+
::::::::::::::::::::::::::::::::::::::
494
+
492
495
493
496
### Coordinate system
494
497
#### LPS
@@ -703,6 +706,16 @@ print(nii3ct_float32.header)
703
706
704
707
### Cropping data
705
708
Cropping data might often contain background voxels which can be useful in some instances but might take up valuable RAM memory, especially for large images.
709
+
We are going to crop the image from slice 103 to slice 381 in the x dimension (Sagittal slices) and from slice 160 to 340 in the y dimension (Coronal slices).
710
+
Use ITK-SNAP to confirm that cropping the image to these slices will only remove slices that do not contain the patient.
711
+
712
+
:::::::::::::::::::::::::::::::::::::: spoiler
713
+
714
+
### Notes on `Nifti1Image` object
715
+
It is not possible to change the image data in a Nifti1Image object, e.g. to use a smaller array corresponding to a cropped image.
716
+
Therefore, if you want to modify the image data you need to create a new array with the modified data, then create a new Nifti1Image object using this new array which is used to save the modified image to disk.
717
+
718
+
::::::::::::::::::::::::::::::::::::::
706
719
707
720
* Read the image data from disk using `get_fdata` and then create a new array containing a copy of the desired slices:
It is important to create a copy of the data (using the copy function, as show above).
748
+
Otherwise the new image will reference the data in the original image, and if you make any changes to the values in the new image they will also be changed in the original image.
749
+
750
+
::::::::::::::::::::::::::::::::::::::
751
+
752
+
753
+
754
+
When creating a new Nifti1Image object you can provide an affine transform and/or a Nifti1Header object (e.g. nii_1.header).
755
+
When you just provide an affine, a default header is created with the sform set according to the provided affine transform and the qform set to unknown.
756
+
When you provide a header, the values in it will be copied into the header for the new image, except that the dim values will be updated based on the image data provided.
757
+
If you provide an affine as well as a header, and the affine is different to the sform or qform in the header they will be set to the provided affine and unknown respectively.
758
+
If the affine is not provided, it is not set from the header but left empty.
759
+
So, if any of your downstream processing will make use of the affine, make sure you manually set it from the header either when creating the Nifti1Image object or by calling the set_sform or set_qform functions for the object (which update the affine as well as setting the sform/qform).
760
+
Here we will provide a Nifti1Header object as we want the header for the new image to based on the uncropped image and will use the sform from the header as the affine for the new Nifti1Image.
* Setting world coordinates of voxel (103, 160, 0) in the uncropped image.
823
+
Now load the cropped image into ITK-SNAP.
824
+
You will see that the image has been cropped in the x and y dimensions as expected, but it is shifted relative to the uncropped image:
825
+
826
+

827
+
828
+
This is because we did not update the origin/offset in the nifti header to account for the slices we removed.
829
+
The origin gives the world coordinates of the voxel (0, 0, 0).
830
+
So, if we want the images to remain aligned, we need to set the origin for the cropped image to be the same as the world coordinates of voxel (103, 160, 0) in the uncropped image.
831
+
This can be calculated using the affine from the uncropped image, and used to create a new affine matrix with this as the origin (the origin is the top 3 values in the 4th column of the matrix).
832
+
The new affine matrix can then be used to set the sform (which also sets the affine) for the cropped image, which can then be saved.
Note, NiBabel provides handy functionality for slicing nifti images and updating the affine transforms and header accordingly using the slicer attribute:
But you wouldn’t have learnt so much if we’d simply done that to start with :)
885
+
886
+
If you load the cropped and aligned image into ITK-SNAP using overlay semi-transparent feature, you will see that it is now aligned with the original image but has fewer slices in the x and y dimensions.
887
+
888
+

889
+
890
+
891
+
If we try to perform a registration between these images as they are, it will likely have difficulties as the images are so far out of alignment to start with.
892
+
One way to roughly align the images prior to performing a registration is to align the centres of the images by modifying the origin for the 2nd subject such that the image centres for both images have the same world coordinates.
893
+
894
+
This can be done by following these steps:
895
+
* Load `ct_for_pet_cropped.nii.gz`
896
+
* Calculate the centre of this image in voxel coordinates
897
+
* Calculate the centre of this image in world coordinates
898
+
* Calculate the centre of the cropped image from subject 1 in voxel coordinates
899
+
* Calculate the centre of the cropped image from subject 1 in world coordinates
900
+
* Calculate the translation (in world coordinates) required to align the images: Centre image 1 = centre image 2 + translation
901
+
902
+
Add this translation to the origin for image 2
903
+
Save the image for image 2 using the header with the updated origin
904
+
Try and write code to implement these steps yourself, based on what you have learnt so far.
905
+
If you get stuck ask me or one of the PGTAs for help.
906
+
907
+
If you have implemented this correctly when you load the aligned image from image 2 into ITK-SNAP is should appear roughly aligned with the images from image 1.
908
+
You can use `Color Map` feature tab and the scroll bar to see the differences between two images.
909
+
910
+

911
+
839
912
### Cropped and aligned image
840
913
Automated image registrations can be prone to be failure if there are very large initial differences between the images. A manual alignment is subjective, but can provide a good enough starting guess that keeps the objective, automated registration more reliable.
841
914
* Manually aligning images
@@ -855,4 +928,8 @@ You can use [niftyreg](https://nipype.readthedocs.io/en/latest/api/generated/nip
855
928
* [Tutorial: Getting Started with ITK-SnAP](http://www.itksnap.org/docs/viewtutorial.php)
856
929
* [ITK-SNAP 3.x Training Class Final Program](http://itksnap.org/files/handout_201409.pdf)
0 commit comments