A comprehensive guide to template building, registration, and Jacobian analysis using the SlicerANTsPy extension.
- Introduction
- Prerequisites
- Step 1: Obtaining the Data
- Step 2: Loading Data into 3D Slicer
- Step 3: Building a Population Template
- Step 4: Group-wise Registration to Template
- Step 5: Jacobian Analysis
- Troubleshooting
- Advanced Topics
This tutorial demonstrates a complete morphometric analysis workflow using the ANTsPyRegistration module in 3D Slicer. You will:
- Create one canonically oriented sample as a reference
- Build a population-averaged template from mouse microCT scans
- Register individual specimens to the template
- Perform statistical shape analysis using Jacobian determinants
- Compare morphological variation between groups
Dataset: Low-resolution mouse head microCT scans from 29 different inbred and hybrid mouse strains, with 45 craniometric landmarks per specimen. Landmarks are necessary to provide an initial alignment, as most automated registration methods fail if the positional difference between two volumes are too large. Most cases you do not need as many landmark to do an approximate alignment, 4-8 are usually enough.
Biological Context: Mouse strains exhibit cranial shape variation due to genetic differences. This tutorial shows how to quantify and analyze these differences.
- Download and install the latest stable version of 3D Slicer from slicer.org
Install the ANTsPy Extension from the Extension Catalogue
We advise to run this tutorial using MorphoCloudInstances as registration operations are memory and compute intensive. Standard MorphoCloud instances (g3.l) provide 60GB of RAM and 16 cores. If you plan to use your own computer, we advise using a computer with at least 16G of RAM. Similarly we advise using a CPU with many cores as the registration will benefit from increased parallelism.
Open a terminal (Mac/Linux) or Git Bash (Windows) and run:
cd ~/Desktop
git clone https://github.com/muratmaga/ANTsamples.gitThis will create a folder ANTsamples with the following structure:
ANTsamples/
├── LMs/ # 29 landmark files (.mrk.json)
└── volumes/ # 29 volume files (.nii.gz)
Check that you have 29 paired files:
cd ANTsamples
ls volumes/*.nii.gz | wc -l # Should show: 29
ls LMs/*.mrk.json | wc -l # Should show: 29The dataset includes these mouse strains (we'll use all 29 for this tutorial):
- C57BL6_J_ - C57BL/6J (most common laboratory strain)
- BALB_CJ_ - BALB/cJ
- DBA_1J_ - DBA/1J
- DBA_2J_ - DBA/2J
- C3H_HEJ_ - C3H/HeJ
- AKR_J_ - AKR/J
- 129S1_SVLMJ_ - 129S1/SvlmJ
- FVB_NJ_ - FVB/NJ
- ... and 21 more strains
- Open 3D Slicer
- Go to
File → Add Data - Click
Choose File(s) to Add - Navigate to
ANTsamples/volumes/ - Select these files (hold Ctrl/Cmd to select multiple):
C57BL6_J_.nii.gzBALB_CJ_.nii.gzDBA_2J_.nii.gz
- Click
Open, thenOK
- Go to
File → Add Data - Click
Choose File(s) to Add - Navigate to
ANTsamples/LMs/ - Select the corresponding landmark files:
C57BL6_J_.mrk.jsonBALB_CJ_.mrk.jsonDBA_2J_.mrk.json
- Click
Open, thenOK
-
In the Data module, you should see:
- 3 volumes (scalar volumes)
- 3 markups (fiducial nodes with 45 points each)
-
To view a volume:
- Click on
C57BL6_J_in the Data module - It will appear in the slice viewers (Red, Yellow, Green windows)
- Use the mouse wheel to scroll through slices
- Use the 3D view to see the full volume
- Click on
-
To view landmarks:
- In the Markups module, select
C57BL6_J_from the dropdown - Landmarks will appear as small spheres on the skull
- Adjust visibility/size in the Display section if needed
- In the Markups module, select
- None of the samples are oriented canonically; slice planes to not correspond to anatomical planes.
- Landmarks are in millimeters (mm)
- Each specimen has 45 anatomical landmarks on the skull
Before building the template, we need to prepare a reference specimen that will serve as the initial template. This involves reorienting the specimen to align with anatomical planes and creating an average from rigidly aligned samples.
Using a reference specimen (rather than starting from scratch) has advantages and disadvantages:
Advantages:
- Faster convergence during template building
- More anatomically meaningful starting point
- Easier to interpret results in consistent anatomical orientations
Disadvantages:
- Shape bias: The final template may retain some shape characteristics of the reference specimen
- Size bias: Initial size of the reference influences the template
- Asymmetry bias: If the reference has asymmetries, these may persist
- Selection bias: Choosing one strain over others introduces systematic bias
Best Practice: To minimize bias, we'll create an average of rigidly aligned specimens rather than using an actual specimen from our dataset as references. This provides a reasonable starting point while reducing individual specimen bias.
We'll use the NZBWF1_J_ specimen as our initial reference and reorient it so the major axes align with anatomical planes.
- Reset the scene to remove other data.
- If not already loaded:
File → Add Data - Navigate to
ANTsamples/volumes/ - Select
NZBWF1_J_.nii.gz - Click
Open, thenOK
- In the module search bar, type "Crop"
- Select Crop Volume
For detailed instructions, see the CropVolume tutorial.
- Click Apply
- The reoriented volume appears in the scene (it will have the Cropped suffix)
- This will also create a new transformation in the scene that start with Re-orient
- Verify in slice viewers that anatomical planes are aligned with slice views.
- Save the result: Right-click
NZBWF1_J_reoriented→ Export to file- Save as
ANTsamples/NZBWF1_J_reoriented.nii.gz
- Save as
Important: Also reorient the corresponding landmarks:
- Load
NZBWF1_J_.mrk.jsonif not already loaded - Apply the same transform
NZBWF1_J_.mrk.jsonlandmarks and harden the transform to make it permenant. - Save as
NZBWF1_J_reoriented.mrk.jsonin the same folder where you save the volume from previous step.
Now we'll register all specimens to the reoriented reference using rigid registration. This brings them into a common space without changing their shape. We'll use the Group-wise registration tab to process all specimens at once.
- In the module search bar, type "ANTsPy"
- Select ANTsPyRegistration
- Click the "Group-wise" tab
-
Template: Select
NZBWF1_J_reoriented- This is your reoriented reference specimen
- All other specimens will be aligned to this
-
Transform Type: Select
Rigid- Only rotation and translation, no scaling or deformation
- Preserves the original shape and size of each specimen
-
Input directory: Click the folder icon
- Navigate to
ANTsamples/volumes/ - Select the
volumesfolder - This will process all .nii.gz files in this directory
- Navigate to
-
Output Directory: Click the folder icon
- Create a new folder:
ANTsamples/RigidAligned/ - Select it
- All rigidly aligned volumes will be saved here
- Create a new folder:
-
Output transforms as: Select
Composite (single file)orSeparate files- Either option works for rigid transforms since there will be only one output file.
-
Output: Check these boxes:
- ☑ Forward Transform - Saves the rigid transformation
- ☐ Inverse Transform - Not needed for this step, as all linear transformations (rigid, similarity, affine) are invertable.
- ☑ Transformed Volume - REQUIRED - This is what we need for averaging
To ensure accurate rigid alignment:
-
Check ☑ "Compute landmark-based RIGID initial transform"
-
Template Landmarks: Select
NZBWF1_J_reorientedlandmarks- These are the landmarks for your reoriented reference
-
Landmarks directory: Click folder icon
- Navigate to
ANTsamples/LMs/ - Select the
LMsfolder - The module automatically matches landmarks to volumes by basename
- Navigate to
-
☑ Save volume aligned LMs (REQUIRED)
- Must check this to save transformed landmarks
- These are essential for creating averaged landmarks in Step 3C
- Creates files with
-transformed.mrk.jsonsuffix - Without these, you cannot compute the average landmark positions for the averaged image.
-
Click "Register"
-
What happens:
- Each volume in the input directory is rigidly registered to
NZBWF1_J_reoriented - This will result in every transformed volume having the same orientation and image dimensions and resolution as the reference image.
- Landmark-based rigid transform is computed first for initialization
- Final rigid registration refines the alignment
- Outputs are saved to
ANTsamples/RigidAligned/
- Each volume in the input directory is rigidly registered to
-
Progress:
- Button text: "Group registration in progress"
- 29 specimens will be processed sequentially
- Time estimate: 5-15 minutes total (~10-30 seconds per specimen)
- Much faster than deformable registration!
-
Completion:
- Button returns to "Register"
- Check the output directory for results
Navigate to ANTsamples/RigidAligned/ and you should see:
For each specimen:
[specimen]_Composite.h5- Rigid transform file[specimen]-transformed.nii.gz- Rigidly aligned volume (required for averaging)[specimen]-transformed.mrk.json- Transformed landmarks (required for averaging)
Total: 29 rigidly aligned volumes + 29 transformed landmark sets ready for averaging
-
Load the reference:
File → Add Data → NZBWF1_J_reoriented.nii.gz -
Load several rigidly aligned volumes from
ANTsamples/RigidAligned/:C57BL6_J_-transformed.nii.gzBALB_CJ_-transformed.nii.gzDBA_2J_-transformed.nii.gz
-
In the Data module:
- Toggle visibility between reference and aligned volumes
- They should be in the same position and orientation
- Individual shape differences should be clearly visible
- No warping or deformation (only rotation/translation)
Now we'll create an average of all rigidly aligned specimens. This becomes our unbiased initial reference volume to initialize the iterative template building procedure.
- In the ANTsPyRegistration module
- Click the "Average" tab
-
Input directory: Click the folder icon
- Navigate to
ANTsamples/RigidAligned/ - Select the folder containing all rigidly aligned volumes
- The module will automatically find all .nii.gz files in this directory
- Navigate to
-
Output Volume: Click the dropdown
- Select "Create new Volume"
- It will create a node called
Volume - Rename it to
RigidAverage_Template(click on the name to edit)
-
Click "Compute Average"
-
What happens:
- The module loads all .nii.gz files from the input directory
- Computes the voxel-wise mean across all volumes
- Creates the output averaged volume
- Time estimate: 1-2 minutes depending on image size
-
Completion:
- The averaged volume
RigidAverage_Templateappears in the Data module - Verify it loaded correctly by displaying in slice viewers
- The averaged volume
- Right-click
RigidAverage_Templatein the Data module - Select "Export to file..."
- Save as
ANTsamples/RigidAverage_Template.nii.gz
Critical: You must average the landmark positions to match your averaged volume. There is no tool in ANTsPy extension to do that. We will use a simple python script to do this in Slicer.
-
Load all transformed landmark files:
File → Add Data- Navigate to
ANTsamples/RigidAligned/ - Select all 29
*-transformed.mrk.jsonfiles - Click
Open, thenOK
-
Average the landmarks using Python:
- Go to Python Interactor (View → Python Interactor)
- Run this script:
import numpy as np
import slicer
# List all loaded landmark nodes (the transformed ones from RigidAligned folder)
# Adjust these names to match what was loaded (typically specimen_-transformed)
landmarkNames = [
"129S1_SVLMJ_-transformed",
"129X1_SVJ_-transformed",
"AKR_J_-transformed",
"A_J_-transformed",
"B6AF1_J_-transformed",
"B6D2F1_J_-transformed",
"BALB_CBYJ_-transformed",
"BALB_CJ_-transformed",
"BTBR_T_Itpr3tf_j_-transformed",
"C3H_HEJ_-transformed",
"C3H_HEOUJ_-transformed",
"C57BL6_J_-transformed",
"C57BL_10J_-transformed",
"C57BL_6NJ_-transformed",
"C57L_J_-transformed",
"CAF1_J_-transformed",
"CAST_EIJ_-transformed",
"CB6F1_J_-transformed",
"CBA_CAJ_-transformed",
"CBA_J_-transformed",
"DBA_1J_-transformed",
"DBA_2J_-transformed",
"FVB_NJ_-transformed",
"MRL_MPJ_-transformed",
"NOD_SHILTJ_-transformed",
"NU_J_-transformed",
"NZBWF1_J_-transformed",
"NZW_LACJ_-transformed",
"SJL_J_-transformed",
"TALLYHO_JNGJ_-transformed"
]
# Get landmark nodes
markupNodes = [slicer.util.getNode(name) for name in landmarkNames]
# Get point arrays
pointArrays = [slicer.util.arrayFromMarkupsControlPoints(node) for node in markupNodes]
# Verify all have same number of points
numPoints = [arr.shape[0] for arr in pointArrays]
if len(set(numPoints)) != 1:
print(f"ERROR: Not all landmark sets have same number of points: {set(numPoints)}")
else:
print(f"All {len(pointArrays)} landmark sets have {numPoints[0]} points")
# Compute average
avgPoints = np.mean(pointArrays, axis=0)
# Create new markup node
avgMarkups = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLMarkupsFiducialNode', 'RigidAverage_Landmarks')
# Add averaged points
for i in range(avgPoints.shape[0]):
avgMarkups.AddControlPoint(avgPoints[i])
print(f"Average landmarks created: RigidAverage_Landmarks with {avgPoints.shape[0]} points")- Save the averaged landmarks:
- Right-click
RigidAverage_Landmarksin Data module - Export to file →
ANTsamples/RigidAverage_Landmarks.mrk.json
- Right-click
Verify: The averaged landmarks should have 45 points (same as each individual specimen) and be positioned at the mean location of all specimens' landmarks.
Important considerations:
-
Shape bias is reduced but not eliminated:
- The rigid average reduces bias from any single specimen
- However, if your sample is not representative of the full population, bias remains
- Example: If all specimens are adult males, the template won't represent females/juveniles
-
The reference affects final template geometry:
- Template building is iterative, but initial geometry influences convergence
- Very different initial references may lead to slightly different final templates
- For most analyses, this effect is small if you use 2+ iterations
-
Alternative: No initial template:
- Setting "Initial Template" to
Noneit uses the first sample in your pool as the reference. We don't advise doing that except for testing purposes.
- Setting "Initial Template" to
For this tutorial: Using a rigid average provides a good balance between computational efficiency and minimizing bias.
Overview: Template building creates an average shape representing your population using deformable registration. We'll use the original unaligned volumes as the input volumes, and use the landmarks to bring them into alignment with the reference, then run 2 iterations of template refinement. At the end of the first step module will calculate a new template, and start the second iteration using that template as the reference.
**TO DO: Explain why we are not using the output of our rigid registration (-transformed volumes) as input to this procedure. Effects of doing image resampling multiple times etc...
- In the module search bar (top left), type "ANTsPy"
- Select ANTsPyRegistration
- Go to the Template tab
- Initial Template: Select
RigidAverage_Template- This is the averaged volume we created from rigidly aligned specimens
- Using this provides a better starting point than a specific sample.
- Reduces computational time and improves convergence
- Transform Type: Select
SyN(Symmetric Normalization)- This is a deformable registration that can capture shape differences
- Iterations: Set to
2- Each iteration refines the template
- More iterations = better template but longer computation time
- 2-3 iterations are typically sufficient
- Click "Select input images..."
- A file browser opens
- Navigate to
ANTsamples/volumes/ - Select all 29 .nii.gz files:
- Click the first file
- Scroll down, hold Shift, click the last file
- Or use Ctrl+A (Cmd+A on Mac) to select all
- Click Open
View Input Image Paths:
- Click the "View input image paths" collapsible button
- You should see all 29 file paths listed
- Verify the order is correct
- Use "Remove Selected Path" or "Move Path to Top" if you need to adjust
- "Clear input path list" removes all files
This ensures specimens are aligned to the reference before template building begins.
-
Check ☑ "Compute landmark-based RIGID initial transform"
-
Click "Select landmark files..."
-
Navigate to
ANTsamples/LMs/ -
Select all 29 .mrk.json files (same order as volumes)
- The order must match your volume files!
- First volume → first landmark file, etc.
-
Click Open
Verify landmark selection:
- Click "View landmark file paths" to expand
- Check that you have 29 landmark files
- Ensure the basenames match the volume files
- Example:
C57BL6_J_.nii.gz↔C57BL6_J_.mrk.json
- Example:
Important Note: The module will validate this for you. If there's a mismatch in count or basenames, you'll get a clear error message when you try to run.
- Template Landmarks: Select
RigidAverage_Landmarks- These are the average landmark positions we created
- Used if you provide an initial template volume
- Helps with landmark-based initialization
-
Output template:
- Click the dropdown
- Select "Create new Volume"
- It will create a node called
Template - You can rename it if desired (e.g.,
MouseCranium_Template)
-
Output landmarks:
- Click the dropdown
- Select "Create new MarkupsFiducial"
- Creates
Template_Landmarksnode - This will contain the average landmark positions
-
Output Directory:
- Click the folder icon
- Navigate to
ANTsamples/(or create a new folder likeANTsamples/TemplateOutput/) - Select the folder
- This is where all intermediate files and transforms will be saved
-
Click "Run Template Building"
-
What happens:
- Initial alignment: Each specimen is rigidly aligned to the first specimen using landmarks
- Iteration 1: All specimens are registered to the specified template, and then the template is updated
- Iteration 2 (and subsequent iterations): Re-registrat the samples to the updated template
- Calculate the final template.
- Output files are saved to the output directory
-
Progress monitoring:
- Button text changes to "Template building in progress"
- Console output shows registration progress (View → Python Interactor)
- Time estimate: 10-30 minutes depending on your computer
- Per specimen: ~30 seconds to 2 minutes
- 29 specimens × 2 iterations = 58 registrations
-
Completion:
- Button returns to "Run Template Building"
- Template volume appears in the Data module
- Template landmarks appear in the Markups module
- In the Data module, find your template volume (e.g.,
MouseCranium_Template) - Click the eye icon to show it in the viewers
- In the Markups module, select
Template_Landmarks - The template represents the average cranial shape of all 29 mouse strains
- Review for anatomical detail. You can try increasing the number of iterations.
-
Right-click the template volume in the Data module
-
Select "Export to file..."
-
Save as
MouseCranium_Template.nii.gzin your project folder -
Do the same for template landmarks:
- Right-click
Template_Landmarks - Save as
Template_Landmarks.mrk.json
- Right-click
Now we'll register all individual specimens to the template and save the deformation fields (needed for Jacobian analysis). These deformations are going to be used to calculate systematic localized shape difference between groups.
Click the "Group-wise" tab
- Template: Select your template volume from the dropdown
- If you just created it: select
MouseCranium_Template(or whatever you named it) - If you saved and reloaded: use
File → Add Datato load it first
- If you just created it: select
- Transform Type: Select
SyN- Must match what you saved as the output of the template building
- SyN provides deformable registration
- Input directory: Click the folder icon
- Navigate to
ANTsamples/volumes/ - Select the
volumesfolder - This will process all .nii.gz files in this directory
- Output Directory: Click the folder icon
- Create a new folder:
ANTsamples/GroupRegistration/(or similar) - Select it
- All output transforms and volumes will be saved here
- Output transforms as: Select
Separate files- Creates individual forward and inverse transform files
- Required for Jacobian analysis to isolate deformable component
- Composite transforms include affine component of the deformation that can mask subtle shape differences
Why separate files?
- Jacobian analysis should use only the deformable (warp) component
- Composite transforms combine affine + deformable transformations
- The affine component (global scaling/rotation) can dominate and obscure local shape variations
- Separate files allow you to use only the forward warp for statistical analysis
Understanding the output structure:
When you select "Separate files", ANTs creates a multi-step transformation for each specimen:
-
Affine component (
*0GenericAffine.mat):- Global alignment (rotation, translation, scaling, shearing)
- Applied first to roughly align specimen to template
- Small text file (~1-2 KB)
- Example:
C57BL6_J_0GenericAffine.mat
-
Forward deformable warp (
*1Warp.nii.gz):- Local, non-linear deformations
- Captures shape differences after global alignment
- Large image file (same dimensions as input, ~10-50 MB)
- This is what we use for Jacobian analysis
- Example:
C57BL6_J_1Warp.nii.gz
-
Inverse deformable warp (
*1InverseWarp.nii.gz) - Optional:- Reverses the forward warp
- Useful for mapping results back to original specimen space
- Same size as forward warp
- Example:
C57BL6_J_1InverseWarp.nii.gz
Files per specimen:
- If you check only Forward Transform: 2 files (1 affine + 1 forward warp)
- If you check both Forward and Inverse: 3 files (1 affine + 1 forward warp + 1 inverse warp)
For 29 specimens:
- Forward only: 58 files total (29 affine + 29 forward warps)
- Forward + Inverse: 87 files total (29 affine + 29 forward + 29 inverse)
The numbering (0, 1) indicates the order of application:
- Step 0: Apply affine transform first
- Step 1: Apply deformable warp second
Check the boxes for what you want:
- ☑ Forward Transform - REQUIRED for Jacobian analysis (deformable component)
- ☐ Inverse Transform - Optional, but suggested (useful for mapping results back to specimen space)
- ☑ Transformed Volume - Optional, but suggested (useful to verify registration quality)
Important: You MUST save forward transforms for Jacobian analysis!
To improve registration accuracy:
-
Check ☑ "Compute landmark-based RIGID initial transform"
-
Template Landmarks: Select
Template_Landmarksfrom the dropdown- These are the average landmarks you created during template building
-
Landmarks directory: Click folder icon
- Navigate to
ANTsamples/LMs/ - Select the
LMsfolder - The module will automatically match landmarks to volumes by basename
- Navigate to
-
☑ Save volume aligned LMs (Optional)
- Check this to save the transformed landmarks
- Useful for validation and quality control
- Creates files with
-transformed.mrk.jsonsuffix
-
Click "Register"
-
What happens:
- Each volume in the input directory is registered to the template
- Landmark-based rigid transform is computed first
- Then deformable registration (SyN) is applied
- Outputs are saved to the output directory
-
Progress:
- Button text: "Group registration in progress"
- 29 specimens will be processed sequentially
- Time estimate: 15-45 minutes total (~30-90 seconds per specimen)
-
Completion:
- Button returns to "Register"
- Check the output directory for results
Navigate to ANTsamples/GroupRegistration/ and you should see:
For each specimen (example for C57BL6_J_):
C57BL6_J_0GenericAffine.mat- Affine transform componentC57BL6_J_1Warp.nii.gz- Forward deformable warp (used for Jacobian analysis)C57BL6_J_1InverseWarp.nii.gz- Inverse warp (if you enabled inverse transforms)C57BL6_J_-transformed.nii.gz- Registered volume (if you checked that option)C57BL6_J_-transformed.mrk.json- Transformed landmarks (if you checked that option)
Total files:
- 29 affine transforms (.mat files)
- 29 forward warps (.nii.gz files) - These are used for Jacobian analysis
- 29 inverse warps (if selected)
- 29 transformed volumes (if selected)
- 29 transformed landmarks (if selected)
To verify registration quality:
-
Load the template in Slicer:
File → Add Data → MouseCranium_Template.nii.gz -
Load a few transformed volumes:
C57BL6_J_-transformed.nii.gzBALB_CJ_-transformed.nii.gzDBA_2J_-transformed.nii.gz
-
In the Data module:
- Toggle visibility between template and transformed volumes
- They should be well-aligned
- Anatomical features should overlap
-
Use the Markups module to check landmark alignment:
- Load template landmarks and a few transformed landmark sets
- They should be close to each other
Before performing Jacobian analysis, we need to create a mask that defines the anatomical region of interest. This restricts the statistical analysis to biologically relevant structures (skull and mandible) and excludes background, soft tissue, and other elements.
Why create a mask?
- Reduces computational load: We don't analyze every voxel in the image
- Focuses on relevant anatomy: Only skull and mandible for craniometric analysis
- Improves statistical power: Multiple comparison correction is less severe with fewer voxels
- Excludes artifacts: Background noise and reconstruction artifacts are excluded
- Biological relevance: We're interested in bone shape, not soft tissue or air
- If not already loaded:
File → Add Data - Select
MouseCranium_Template.nii.gz - Click
Open, thenOK
- In the module search bar, type "Segment"
- Select Segment Editor
-
Segmentation: Click the dropdown
-
Select "Create new Segmentation"
-
A new segmentation node appears in the scene
-
Source geometry:
- Click the dropdown
- Select
MouseCranium_Template - This ensures the segmentation matches the template geometry
We'll use semi-automatic and manual tools to define the cranium and mandible.
-
Add a new segment:
- Click "Add" button
- Name it "Skull_Mandible"
- Choose a color (e.g., yellow)
-
Use Threshold effect:
- Select "Threshold" from the Effects list
- Adjust the threshold sliders to capture bone:
- Drag the minimum slider until skull/mandible appears
- Drag the maximum slider to exclude very bright artifacts
- Tip: Start with automatic threshold, then refine manually
- Click "Apply"
-
Clean up the segmentation:
-
Islands effect:
- Select "Islands"
- Choose "Keep largest island"
- Click "Apply"
- This removes small disconnected pieces
-
Smoothing effect:
- Select "Smoothing"
- Choose "Median" method
- Kernel size: 3-5 mm
- Click "Apply"
- This reduces noise and stair-stepping
-
-
Remove unwanted structures:
-
If soft tissue, nasal turbinates, or other elements are included:
-
Use "Scissors" effect:
- Select "Scissors"
- Choose "Erase inside" or "Erase outside"
- Draw around regions to remove
- Click "Apply"
-
Use "Paint" effect for manual refinement:
- Select "Paint"
- Adjust sphere brush size
- Hold Shift to erase, regular click to add
- Paint in each slice view to refine boundaries
-
If automatic threshold doesn't work well:
-
Use "Draw" effect:
- Select "Draw" from Effects
- Draw around the skull outline in each slice
- Work through Red, Yellow, and Green slice views
- Time-consuming but very accurate
-
Use "Level Tracing":
- Select "Level Tracing"
- Click points around the boundary
- It traces edges between points
- Faster than manual drawing
-
Combine with "Fill between slices":
- Segment every 5-10 slices manually
- Use "Fill between slices" effect to interpolate
- Review and refine interpolated slices
-
Toggle visibility:
- Click the eye icon next to the segment
- Verify it covers skull and mandible only
- Check in all three slice views
-
Use 3D view:
- The segmentation appears as a 3D surface
- Rotate to check coverage
- Look for holes or included unwanted structures
-
Adjust transparency:
- In Segment Editor, adjust opacity slider
- Overlay on the template volume to verify accuracy
Include:
- ✅ Cranium (all skull bones)
- ✅ Mandible (lower jaw)
- ✅ Zygomatic arches
- ✅ Occipital region
Exclude:
- ❌ Nasal turbinates (thin internal structures)
- ❌ Teeth (if analyzing cranial shape only)
- ❌ Soft tissue
- ❌ Background and air
- ❌ Cervical vertebrae (if visible)
Tip: The goal is to include the bony structures relevant to your morphometric question while excluding everything else.
-
In Segment Editor, click "Segmentations" button (or go to Segmentations module)
-
In the Segmentations module:
- Select your segmentation
- Under "Export/Import" section
- Click "Export to files"
-
Configure export:
- Destination: Choose
ANTsamples/ - File format: Select "NRRD" or "NIfTI"
- Filename:
Template_Mask.nrrd(or.nii.gz) - Click "Export"
- Destination: Choose
Alternative export method:
- Right-click the segmentation in Data module
- Select "Export visible segments to binary labelmap"
- This creates a labelmap node
- Right-click the labelmap → Export to file
- Save as
Template_Mask.nrrd
File → Add Data- Select
Template_Mask.nrrd - The mask appears as a labelmap volume
- Verify it loaded correctly by displaying it
The mask is now ready to use in Jacobian analysis!
Jacobian determinant analysis quantifies local volume changes (expansion/contraction) between each specimen and the template. We'll compare two groups of mouse strains, restricting analysis to the skull and mandible mask we just created.
Since you'll provide a CSV file later, we'll use a random split for now.
-
Create a text file:
ANTsamples/covariates.csv -
Add this content (random group assignment):
specimen,group
129S1_SVLMJ_,A
129X1_SVJ_,B
AKR_J_,A
A_J_,B
B6AF1_J_,A
B6D2F1_J_,B
BALB_CBYJ_,A
BALB_CJ_,B
BTBR_T_Itpr3tf_j_,A
C3H_HEJ_,B
C3H_HEOUJ_,A
C57BL6_J_,B
C57BL_10J_,A
C57BL_6NJ_,B
C57L_J_,A
CAF1_J_,B
CAST_EIJ_,A
CB6F1_J_,B
CBA_CAJ_,A
CBA_J_,B
DBA_1J_,A
DBA_2J_,B
FVB_NJ_,A
MRL_MPJ_,B
NOD_SHILTJ_,A
NU_J_,B
NZBWF1_J_,A
NZW_LACJ_,B
SJL_J_,A
TALLYHO_JNGJ_,B- Save the file
Note: When you provide your real CSV file later, replace this with your actual groupings. The CSV must have:
- Column 1:
specimen(basename without extensions) - Column 2:
group(categorical factor) - Optional: Additional columns for covariates (age, sex, etc.)
- In ANTsPyRegistration module
- Click the "Analysis" tab
- Registration Output Directory: Click folder icon
- Navigate to
ANTsamples/GroupRegistration/ - Select the folder containing your registration outputs
- Filename end pattern: Enter
1Warp.nii.gz- This matches the forward deformable warp files from group registration
- The module will find all files ending with this pattern
- Example: finds
C57BL6_J_1Warp.nii.gz,BALB_CJ_1Warp.nii.gz, etc. - Important: We use only the deformable component (1Warp), NOT the composite or affine transforms
- This isolates local shape changes from global scaling/rotation effects
- Template Volume: Select your template from the dropdown
MouseCranium_Template(or whatever you named it)- If not loaded:
File → Add Datato load it first
- Template Mask: Select
Template_Maskfrom the dropdown- This is the skull/mandible segmentation we created in Step 6
- Restricts analysis to biologically relevant bone structures
- Excludes background, air spaces, and soft tissue
- Critical: Without a mask, analysis includes irrelevant voxels and wastes computation
- If you skipped Step 6, go back and create the mask now
The module needs to know which transform files correspond to which specimens.
-
Click the "View Input Image List" collapsible button
-
The list should auto-populate with files matching your pattern
-
Verify you see 29 files listed
If the list is empty:
- Double-check the directory path
- Verify the filename pattern (
1Warp.nii.gz) - Make sure forward warp files exist in that directory
- Ensure you selected "Separate files" (not "Composite") during group registration
Expand the "Regression" section.
- Expand "Import Covariates table"
- Select path to covariates table: Click the folder icon
- Navigate to
ANTsamples/covariates.csv - Select the file
The module will read your CSV and extract factor variables.
-
Rformula for regression: Enter:
log_jacobian ~ groupExplanation:
log_jacobian- dependent variable (computed by ANTs)~- regressed ongroup- your factor variable from the CSV- This tests if group A and B differ in local volume
Advanced formulas:
log_jacobian ~ group + age- Include age as covariatelog_jacobian ~ group * sex- Test interaction effectslog_jacobian ~ C(group, Treatment('A'))- Set reference group
-
Analysis Cache: Click folder icon
- Select a location to save results:
ANTsamples/JacobianCache.pkl - This saves the analysis so you can reload it later without recomputing
- Useful for trying different visualizations
- Select a location to save results:
-
Click "Run Image Regression"
-
What happens:
- Jacobian determinant maps are computed from each deformation field
- Log transformation is applied (log_jacobian)
- Statistical regression is performed at each voxel
- Results are saved to the cache file
-
Progress:
- This is computationally intensive
- Time estimate: 5-15 minutes depending on image size and CPU
- Watch the Python console for progress messages
-
Completion:
- Button becomes available again
- Results are cached and ready for visualization
Expand the "Image Generation" section.
-
Q Values Image: Select "Create new ScalarVolume"
- This will create a volume showing q-values (FDR-corrected p-values)
- Defaults to name
QValuesImage - Rename if desired (e.g.,
MouseCranium_QValues_GroupComparison)
-
Analysis Cache: Click folder icon
- Select
ANTsamples/JacobianCache.pkl(the file you just created) - This loads the pre-computed analysis
- Select
-
Factor for QValue computation: Select
group- This is the factor you want to visualize
- If you had multiple factors, you'd choose which one to map
-
Click "Generate Output Images"
-
What happens:
- Q-value map is created showing where groups differ significantly
- False Discovery Rate (FDR) correction is applied
- Output volume appears in the Data module
-
Completion:
- Q-value image appears in slice viewers
- Lower q-values (darker) = more significant differences
- Higher q-values (brighter) = less significant
-
In the Volumes module:
- Select your Q-value volume (e.g.,
QValuesImage)
- Select your Q-value volume (e.g.,
-
Adjust the Window/Level to enhance visualization:
- In the slice viewers, click the link icon (top left)
- Drag to adjust brightness/contrast
- Or use the Volume Rendering module for 3D visualization
-
Interpretation:
- Dark regions (low q-values, e.g., < 0.05): Significant group differences
- Bright regions (high q-values, e.g., > 0.05): No significant difference
- Q-values are FDR-corrected for multiple comparisons
To see only significant regions:
- Go to Segment Editor module
- Create a new segmentation
- Use Threshold effect:
- Set range: 0.0 to 0.05 (for q < 0.05)
- Click "Apply"
- This creates a binary mask of significant regions
- In Data module:
- Load both template and Q-value image
- In Volumes module:
- Set template as background
- Set Q-value as foreground
- Adjust foreground opacity slider
- Go to Volume Rendering module
- Select your Q-value volume
- Click the eye icon to enable rendering
- Adjust Shift slider to set threshold
- Change colormap to highlight significant regions
Save your analysis results:
-
Q-value volume:
- Right-click in Data module → Export to file
- Save as
MouseCranium_QValues_GroupAvsB.nii.gz
-
Analysis cache:
- Already saved as
JacobianCache.pkl - Can reload for future analyses
- Already saved as
-
Screenshots:
- Use Slicer's screenshot feature: Ctrl+Shift+G (Cmd+Shift+G on Mac)
- Or module menu → Screen Capture
Jacobian Determinant Values:
- J > 1: Local expansion relative to template
- J = 1: No volume change
- J < 1: Local contraction relative to template
Log-Jacobian (used in regression):
- log(J) > 0: Expansion
- log(J) = 0: No change
- log(J) < 0: Contraction
Q-values:
- < 0.05: Statistically significant difference (5% FDR)
- < 0.01: Highly significant (1% FDR)
- > 0.05: Not significant after multiple comparison correction
Example Biological Interpretation: If group A shows significant expansion (positive log-Jacobian, low q-value) in the frontal region compared to group B, this suggests group A has relatively larger frontal bones.
Cause: Mismatch between selected image files and landmark files.
Solution:
- Check the "View input image paths" and "View landmark file paths" lists
- Ensure you have the same number of files in each list (e.g., 29 and 29)
- Verify the order matches - first image corresponds to first landmark file
- Check basenames match (e.g.,
C57BL6_J_.nii.gz↔C57BL6_J_.mrk.json)
Cause: Basename mismatch between volumes and landmarks.
Solution:
- Check the error message - it tells you which file is missing a match
- Verify landmark file exists with matching basename
- Check for typos in filenames
- Ensure consistent naming (underscores, capitalization, etc.)
Possible causes:
- Initial alignment failed (try checking landmark-based initialization)
- Transform type too restrictive (try SyN instead of Rigid)
- Too few iterations (increase to 3-4)
- Image quality issues
Solution:
- Verify landmarks are correctly placed on all specimens
- Check that initial rigid alignment worked (use Python console output)
- Try increasing iterations
- Visualize intermediate templates in the output directory
Causes:
- Large image dimensions
- High-resolution scans
- Limited CPU resources
Solutions:
- Reduce image resolution: Use Crop Volume or Resample Scalar Volume modules
- Close other applications to free up RAM
- Process fewer specimens initially to test settings
- Consider using a faster transform type (e.g., Affine before SyN)
Causes:
- Incorrect transform file format
- Missing files
- Wrong filename pattern
Solutions:
- Verify all
*1Warp.nii.gzfiles exist in the directory - Check the filename pattern matches your files exactly (
1Warp.nii.gz) - Ensure you used "Separate files" output (not "Composite") during registration
- Ensure covariates CSV has correct specimen names (match basenames)
- Load cache file if previously completed successfully
Causes:
- No significant differences found
- Threshold too restrictive
- Analysis hasn't run successfully
Solutions:
- Check if analysis completed (look for cache file)
- Adjust Window/Level in Volumes module
- Try different statistical threshold (e.g., q < 0.1 instead of 0.05)
- Verify group assignments in CSV are correct
- Check sample size is adequate (need at least 3-5 per group)
Cause: Incompatible transform file format or corrupted file.
Solution:
- Check that registration completed successfully
- Verify warp files (
*1Warp.nii.gz) are not corrupted (check file sizes > 0) - Ensure you selected "Separate files" not "Composite" during group registration
- Re-run group registration if needed
- Ensure you're using the correct ANTsPy version
You can create additional masks for region-specific analysis:
Example: Neurocranium only (exclude facial bones)
- Load the template in Slicer
- Go to Segment Editor module
- Load your existing skull mask
- Use Scissors effect to remove facial region
- Export as
Template_Mask_Neurocranium.nrrd - Use this mask in Jacobian analysis to focus on braincase only
Example: Left vs Right side analysis
- Create two masks by splitting the existing mask at midline
- Use Scissors with "Erase outside" to keep only one side
- Export as
Template_Mask_Left.nrrdandTemplate_Mask_Right.nrrd - Run separate analyses to compare asymmetry between groups
Example: Regional masks
Create masks for specific bones:
- Frontal bone only
- Parietal bones only
- Zygomatic region only
- Mandible only (exclude cranium)
This allows region-specific hypothesis testing.
For more complex experimental designs:
specimen,group,sex,age
C57BL6_J_,A,M,8
BALB_CJ_,A,F,10
DBA_2J_,B,M,9
...Regression formula examples:
log_jacobian ~ group + sex + age
log_jacobian ~ group * sex
log_jacobian ~ C(group) + age + sex
For processing large datasets, consider Python scripting.
Below is a script to rigidly align all specimens to the reference. You will need to manipulate some of the parameters (such as volumesDir) to match paths on your system. The easist way to edit and use these scripts, is installing the ScriptEditor extension to Slicer and copy and pasting the code into it. Then you can change things directly in the Slicer and directly execute the code with a simple keystrokes (CMD/CTRL+Enter). See the tutorial for ScriptEditor for more details
import os
import slicer
# Configuration
volumesDir = "/path/to/ANTsamples/volumes"
landmarksDir = "/path/to/ANTsamples/LMs"
outputDir = "/path/to/ANTsamples/RigidAligned"
referenceVolume = "NZBWF1_J_reoriented"
referenceLandmarks = "NZBWF1_J_reoriented_landmarks"
# Get list of volume files
volumeFiles = [f for f in os.listdir(volumesDir) if f.endswith('.nii.gz')]
# Get module logic
logic = slicer.modules.antspyregistration.widgetRepresentation().self().logic
# Get reference nodes
fixedVolume = slicer.util.getNode(referenceVolume)
fixedLandmarks = slicer.util.getNode(referenceLandmarks)
for volFile in volumeFiles:
basename = os.path.splitext(os.path.splitext(volFile)[0])[0]
# Skip reference
if basename == "NZBWF1_J_reoriented":
continue
print(f"Processing {basename}...")
# Load moving volume
movingVolPath = os.path.join(volumesDir, volFile)
movingVolume = slicer.util.loadVolume(movingVolPath)
# Load moving landmarks
landmarkFile = basename + ".mrk.json"
landmarkPath = os.path.join(landmarksDir, landmarkFile)
movingLandmarks = slicer.util.loadMarkups(landmarkPath)
# Create output nodes
outputTransform = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLTransformNode',
f'{basename}_rigidTransform')
outputVolume = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLScalarVolumeNode',
f'{basename}_rigidlyAligned')
# Set up registration parameters
# (This is pseudo-code - actual API may differ)
params = {
'fixedVolume': fixedVolume.GetID(),
'movingVolume': movingVolume.GetID(),
'outputTransform': outputTransform.GetID(),
'outputVolume': outputVolume.GetID(),
'transformType': 'Rigid',
'useInitialTransform': True,
'initialTransformType': 'landmarks',
'fixedLandmarks': fixedLandmarks.GetID(),
'movingLandmarks': movingLandmarks.GetID()
}
# Run registration
# logic.runRegistration(params) # Actual method depends on module implementation
# Save outputs
outputVolPath = os.path.join(outputDir, f'{basename}_rigidlyAligned.nii.gz')
slicer.util.saveNode(outputVolume, outputVolPath)
# Clean up
slicer.mrmlScene.RemoveNode(movingVolume)
slicer.mrmlScene.RemoveNode(movingLandmarks)
print(f" Saved: {outputVolPath}")
print("Batch processing complete!")Note: The exact API for programmatic ANTs registration may vary. Check the module documentation or examine the module's Python code for the correct method signatures.
You can export Jacobian maps for analysis in R, Python, or FSL:
- Save Q-value and Jacobian volumes as NIfTI (.nii.gz)
- Extract voxel values using Quantification modules
- Export to CSV for statistical software
- Use template mask to extract ROI values
Create publication-quality 3D visualizations:
- Volume Rendering module
- Select Q-value volume
- Adjust preset: "CT-AAA" or create custom
- Modify color/opacity transfer functions
- Use ROI to crop display
- Adjust view angle and lighting
- Screen Capture for figures
Use landmarks to compute registration error:
import numpy as np
# Get fixed and moving landmarks (after registration)
fixedPoints = slicer.util.arrayFromMarkupsControlPoints(fixedMarkups)
movingPoints = slicer.util.arrayFromMarkupsControlPoints(movingMarkups)
# Compute Euclidean distances
errors = np.sqrt(np.sum((fixedPoints - movingPoints)**2, axis=1))
print(f"Mean error: {np.mean(errors):.2f} mm")
print(f"Max error: {np.max(errors):.2f} mm")For different biological questions:
- Rigid only: For specimens with same shape, different orientation
- Affine: For size normalization without shape changes
- SyNRA: Rigid + Affine + SyN (comprehensive)
- SyNCC: SyN with cross-correlation metric (for similar intensities)
Landmark-based registration only:
- Use Fiducial Registration Wizard module for TPS or affine
- Faster but less detailed than image-based
You've completed a full morphometric analysis pipeline:
- ✅ Obtained data from GitHub repository (29 mouse specimens)
- ✅ Prepared reference specimen by reorienting to anatomical axes
- ✅ Created rigid average from all specimens to minimize bias
- ✅ Built a population template using landmark-initialized, iterative registration
- ✅ Registered all specimens to the template with deformable transforms
- ✅ Created anatomical mask to focus analysis on skull and mandible
- ✅ Performed Jacobian analysis to identify regions of significant group differences
- ✅ Visualized results as statistical maps and 3D renderings
NZBWF1_J_reoriented.nii.gz- Reference specimen aligned to anatomical axesRigidAverage_Template.nii.gz- Average of rigidly aligned specimensRigidAverage_Landmarks.mrk.json- Average landmark positionsMouseCranium_Template.nii.gz- Final population-averaged templateTemplate_Mask.nrrd- Skull and mandible mask for statistical analysisGroupRegistration/*0GenericAffine.mat- Affine transform componentsGroupRegistration/*1Warp.nii.gz- Deformable warp fields (used for Jacobian analysis)GroupRegistration/*-transformed.nii.gz- Registered volumesJacobianCache.pkl- Cached statistical analysisQValuesImage.nii.gz- Statistical significance map
- Replace random groupings with your real experimental design CSV
- Create anatomical masks for region-specific analysis
- Test different covariates and interactions
- Export data for external statistical analysis
- Generate publication-quality figures
- SlicerANTsPy Documentation: GitHub
- ANTs Documentation: ANTs Wiki
- 3D Slicer Training: Slicer Documentation
- SlicerMorph: slicermorph.github.io
If you use this workflow in your research, please cite:
- 3D Slicer: Fedorov A., et al. (2012). 3D Slicer as an image computing platform for the Quantitative Imaging Network. Magnetic Resonance Imaging, 30(9), 1323-1341.
- ANTs: Avants B.B., et al. (2011). A reproducible evaluation of ANTs similarity metric performance in brain image registration. NeuroImage, 54(3), 2033-2044.
- SlicerMorph: Rolfe S., et al. (2021). SlicerMorph: An open and extensible platform to retrieve, visualize and analyse 3D morphology. Methods in Ecology and Evolution, 12(10), 1816-1825.
Tutorial Version: 1.0
Last Updated: November 21, 2025
Questions? Open an issue on the SlicerANTsPy GitHub repository