### Minimal Evaluation Script Setup Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/levenberg-marquardt.md Boilerplate imports and setup for a script evaluating registration performance with the LM optimizer. ```python """ evaluate_levenberg.py --------------------- Registers fixed/moving image pairs with the Levenberg-Marquardt optimizer and saves per-label Dice scores. Usage: python evaluate_levenberg.py \ --pairs pairs.tsv \ --n_labels 35 \ --output_dir ./results pairs.tsv format (tab-separated, no header): fixed.nii.gz moving.nii.gz fixed_seg.nii.gz moving_seg.nii.gz """ import argparse import gc import os import numpy as np import torch from tqdm import tqdm from fireants.io.image import BatchedImages, Image from fireants.registration.greedy import GreedyRegistration ``` -------------------------------- ### Install FireANTs from Source Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/install.md Clones the repository and performs an editable installation. ```bash git clone https://github.com/rohitrango/fireants cd fireants pip install -e . ``` -------------------------------- ### Perform Affine Registration and Optimize Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/keypoint-fidelity.md Initialize and run an AffineRegistration process. This example uses MSE loss and disables the progress bar. ```python from fireants.registration.affine import AffineRegistration from fireants.registration.greedy import GreedyRegistration from fireants.io.image import BatchedImages from fireants.io.keypoints import BatchedKeypoints, compute_keypoint_distance fixed_batch = BatchedImages([img_fixed]) moving_batch = BatchedImages([img_moving]) fixed_kp_batch = BatchedKeypoints([kp_fixed_torch]) moving_kp_batch = BatchedKeypoints([kp_moving_torch]) # Example: affine registration reg = AffineRegistration( scales=[2, 1], iterations=[200, 100], fixed_images=fixed_batch, moving_images=moving_batch, loss_type="mse", progress_bar=False, ) reg.optimize() ``` -------------------------------- ### Command-line execution examples Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/levenberg-marquardt.md Demonstrates how to run the evaluation script with default and custom parameters, including overriding damping parameters and limiting the number of samples. ```bash # Register all pairs with default LM parameters python evaluate_levenberg.py \ --pairs pairs.tsv \ --n_labels 35 \ --output_dir ./results ``` ```bash # Override damping parameters python evaluate_levenberg.py \ --pairs pairs.tsv \ --n_labels 35 \ --output_dir ./results \ --lambda_init 0.1 \ --lambda_increase 5.0 \ --lambda_decrease 0.7 ``` ```bash # Quick smoke-test on 3 pairs python evaluate_levenberg.py \ --pairs pairs.tsv \ --n_labels 35 \ --output_dir ./results \ --num_samples 3 ``` -------------------------------- ### Configure Scale-Aware Loss Usage Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/advanced/scale-aware-losses.md Example of initializing a registration object with a list of kernel sizes to enable scale-aware behavior. ```python from fireants.registration.greedy import GreedyRegistration from fireants.losses.fusedcc import FusedLocalNormalizedCrossCorrelationLoss # Define kernel sizes for each scale # scales = [8, 4, 2, 1] -> kernel_sizes = [3, 5, 7, 9] kernel_sizes = [3, 5, 7, 9] # Create registration with scale-aware kernel sizes reg = GreedyRegistration( scales=[8, 4, 2, 1], iterations=[200, 100, 50, 25], fixed_images=fixed_images, moving_images=moving_images, loss_type='fusedcc', cc_kernel_size=kernel_sizes, # Pass list instead of single int # ... other parameters ) # The loss function will automatically adjust kernel size at each scale reg.optimize() ``` -------------------------------- ### Install FireANTs from PyPI Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/install.md Installs the package directly from the Python Package Index. ```bash pip install fireants ``` -------------------------------- ### Basic fireantsRegistration Usage Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/cli.md This is a basic example of how to use the `fireantsRegistration` tool for a rigid transformation. Ensure you have the necessary input files (`fixed.nii.gz`, `moving.nii.gz`) and specify the output prefix. ```bash fireantsRegistration \ --output output/transform \ --transform Rigid[0.1] \ --metric MI[fixed.nii.gz,moving.nii.gz,gaussian,32] \ --convergence [100x50x25,1e-6,10] \ --shrink-factors 4x2x1 ``` -------------------------------- ### Compare Moments Registration With and Without Scaling Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/moments-scaling.md This example demonstrates how to run moments registration both with and without scale correction and then compare the results. It applies the transformation and samples the moved image. ```python import torch from torch.nn import functional as F from fireants.io.image import Image, BatchedImages from fireants.registration.moments import MomentsRegistration # Load images fixed_img = Image.load_file("fixed.nii.gz", dtype=torch.float32) moving_img = Image.load_file("moving.nii.gz", dtype=torch.float32) fixed_images = BatchedImages([fixed_img]) moving_images = BatchedImages([moving_img]) def run_registration(fixed_images, moving_images, perform_scaling): """Run moments registration and return the moved image.""" moments = MomentsRegistration( scale=4, fixed_images=fixed_images, moving_images=moving_images, moments=2, orientation='rot', loss_type='cc', perform_scaling=perform_scaling, ) moments.optimize() # Apply transformation warp_params = moments.get_warp_parameters(fixed_images, moving_images) grid = F.affine_grid(warp_params['affine'], warp_params['out_shape'], align_corners=True) moved = F.grid_sample( moving_images(), grid.to(moving_images().dtype), mode='bilinear', align_corners=True ) return moved, moments # Without scaling moved_no_scale, reg_no_scale = run_registration(fixed_images, moving_images, False) # With scaling moved_with_scale, reg_with_scale = run_registration(fixed_images, moving_images, True) # Compare loss using the registration's loss function ``` -------------------------------- ### Full 2D square registration workflow Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/keypoint-fidelity.md A complete example demonstrating synthetic image generation, batching, registration, and evaluation. ```python import torch import numpy as np import SimpleITK as sitk from fireants.io.image import Image, BatchedImages from fireants.io.keypoints import Keypoints, BatchedKeypoints, compute_keypoint_distance from fireants.registration.affine import AffineRegistration from fireants.registration.greedy import GreedyRegistration def _square_image_2d(s=128, r=32, device="cpu"): """Create a 2D image with a centered square of half-size r pixels. Returns: (Image, Keypoints in pixel space, Keypoints in torch space) """ grid_y, grid_x = torch.meshgrid( torch.linspace(-1.0, 1.0, s), torch.linspace(-1.0, 1.0, s), indexing="ij", ) half_norm = 2.0 * r / (s - 1) mask = ((torch.abs(grid_x) <= half_norm) & (torch.abs(grid_y) <= half_norm)).float() arr = mask.numpy().astype(np.float32) # Find corners from the binary mask y, x = np.where(arr > 0) ymin, ymax, xmin, xmax = y.min(), y.max(), x.min(), x.max() corners_pixel = torch.tensor([ [float(xmin), float(ymin)], [float(xmax), float(ymin)], [float(xmax), float(ymax)], [float(xmin), float(ymax)], ], dtype=torch.float32, device=device) corners_torch = (2.0 * corners_pixel / (s - 1)) - 1.0 itk = sitk.GetImageFromArray(arr) itk.SetSpacing([1.0, 1.0]) itk.SetOrigin([0.0, 0.0]) img = Image(itk, device=device) kp_pixel = Keypoints(corners_pixel, img, device=device, space="pixel") kp_torch = Keypoints(corners_torch, img, device=device, space="torch") return img, kp_pixel, kp_torch # ----------------------------------------------------------------------------- # Main workflow # ----------------------------------------------------------------------------- device = "cuda" if torch.cuda.is_available() else "cpu" s = 128 r_fixed, r_moving = 32, 24 # Create synthetic images and keypoints img_fixed, _, kp_fixed_torch = _square_image_2d(s=s, r=r_fixed, device=device) img_moving, _, kp_moving_torch = _square_image_2d(s=s, r=r_moving, device=device) # Wrap in batched containers fixed_batch = BatchedImages([img_fixed]) moving_batch = BatchedImages([img_moving]) fixed_kp_batch = BatchedKeypoints([kp_fixed_torch]) moving_kp_batch = BatchedKeypoints([kp_moving_torch]) # Compute initial keypoint distance BEFORE registration initial_dist = compute_keypoint_distance( fixed_kp_batch, moving_kp_batch, space="physical", reduction="mean" ).item() print(f"Initial mean landmark distance: {initial_dist:.4f} (physical units)") # Expected: sqrt(2) * (r_fixed - r_moving) = sqrt(2) * 8 ≈ 11.31 # Run affine registration reg = AffineRegistration( scales=[4, 2, 1], iterations=[200, 100, 50], fixed_images=fixed_batch, moving_images=moving_batch, loss_type="mse", optimizer_lr=1e-2, progress_bar=True, ) reg.optimize() # Apply learned transform to fixed keypoints → predicted positions in moving space moved_kp_batch = reg.evaluate_keypoints(fixed_kp_batch, moving_kp_batch) ``` -------------------------------- ### Install FireANTs Locally Source: https://github.com/rohitrango/fireants/blob/main/README.md Clone the FireANTs repository and install the package locally, including fused CUDA operations. This method ensures all components are available. ```bash git clone https://github.com/rohitrango/fireants cd fireants pip install . cd fused_ops && python setup.py build_ext && python setup.py install && cd .. ``` -------------------------------- ### Build Fused CUDA Operations Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/install.md Compiles and installs the performance-enhancing CUDA extensions. Requires an NVIDIA GPU. ```bash cd fused_ops python setup.py build_ext && python setup.py install cd .. ``` -------------------------------- ### Cross-Correlation Similarity Metric Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/cli.md Example of using the Cross-Correlation (CC) similarity metric with a specified kernel size. Ensure the fixed and moving image paths are correct. ```bash --metric CC[fixed.nii.gz,moving.nii.gz,5] ``` -------------------------------- ### Implement Scale-Aware Loss Function in Python Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/advanced/scale-aware-losses.md Example of a scale-aware loss function that adjusts its kernel size based on the current registration scale. It supports initialization with a single kernel size or a list of sizes corresponding to different scales. ```python import torch from torch import nn from typing import List, Union class ScaleAwareLoss(nn.Module): """ Example scale-aware loss function that adjusts kernel size per scale. """ def __init__( self, kernel_size: Union[int, List[int]] = 3, spatial_dims: int = 3, **kwargs ): super().__init__() self.spatial_dims = spatial_dims # Support both single kernel size and list of kernel sizes self.kernel_size_list = kernel_size if isinstance(kernel_size, (list, tuple)) else None self.kernel_size = kernel_size[0] if isinstance(kernel_size, (list, tuple)) else kernel_size # Initialize state tracking self.scales = None self.iterations = None # Initialize kernel with first size self._initialize_kernel(self.kernel_size) def _initialize_kernel(self, kernel_size: int): """Initialize or update the kernel based on kernel size.""" # Example: create a simple averaging kernel self.kernel = torch.ones(kernel_size) / kernel_size self.kernel.requires_grad = False def set_scales(self, scales: List[float]) -> None: """ Called once during registration initialization. Args: scales: List of scale factors (e.g., [8.0, 4.0, 2.0, 1.0]) """ self.scales = scales if self.kernel_size_list: assert len(self.kernel_size_list) == len(self.scales), \ f"kernel_size_list must have the same length as scales, " \ f"got {len(self.kernel_size_list)} vs {len(self.scales)}" def set_iterations(self, iterations: List[int]) -> None: """ Called once during registration initialization. Args: iterations: List of iteration counts per scale (e.g., [200, 100, 50, 25]) """ self.iterations = iterations def set_current_scale_and_iterations(self, scale: float, iters: int) -> None: """ Called at the start of each scale during optimization. This is where you update the loss function's state based on the current scale. Args: scale: Current scale factor (e.g., 8.0, 4.0, 2.0, 1.0) iters: Current iteration count for this scale """ if self.kernel_size_list and self.scales is not None: # Find the index of the current scale idx = self.scales.index(scale) new_kernel_size = self.kernel_size_list[idx] # Only update if kernel size changed if new_kernel_size != self.kernel_size: self.kernel_size = new_kernel_size self._initialize_kernel(self.kernel_size) # Optionally update other scale-dependent parameters here def forward(self, pred: torch.Tensor, target: torch.Tensor) -> torch.Tensor: """ Forward pass - uses current kernel_size which may have been updated by set_current_scale_and_iterations. """ # Your loss computation here using self.kernel_size # ... return loss ``` -------------------------------- ### Access CLI Help Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/cli.md Displays detailed help information for the registration tool. ```bash fireantsRegistration --help ``` -------------------------------- ### Initialize Keypoints with Image Reference Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/keypoint-fidelity.md Create a Keypoints object by providing coordinates, a reference Image, device, and the coordinate space. The Image provides geometry context. ```python from fireants.io.image import Image from fireants.io.keypoints import Keypoints # Assume you have an Image (e.g. from load_file or a synthetic image) image = Image.load_file("fixed.nii.gz", device="cuda") # Coordinates: (N, dims) in pixel, physical, or torch space # - keypoints: tensor or numpy array, shape (N, 2) for 2D or (N, 3) for 3D # - image: the Image object (defines geometry) # - device: 'cuda' or 'cpu' # - space: 'pixel' | 'physical' | 'torch' — the space in which coordinates are given corners_pixel = ... # e.g. tensor of shape (4, 2) for 4 corners in 2D kp = Keypoints(corners_pixel, image, device="cuda", space="pixel") ``` -------------------------------- ### Serve FireANTs Documentation Locally Source: https://github.com/rohitrango/fireants/blob/main/README.md Build and serve the FireANTs documentation locally using MkDocs. This command should be run from the root of the repository. ```bash mkdocs serve -f docs/mkdocs.yml ``` -------------------------------- ### Optimize Deformable Registration Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 2] Custom loss functions.ipynb Starts the optimization process for the GreedyRegistration. This performs the deformable alignment of the moving image to the fixed image. ```python start = time() deformable.optimize() end = time() ``` -------------------------------- ### Convergence Parameters for Registration Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/cli.md Illustrates how to set convergence parameters, including iterations per resolution scale, tolerance, and the convergence window. These should match the `--shrink-factors`. ```bash --convergence [100x50x25x10,1e-6,10] ``` -------------------------------- ### Get shapes of fixed and moving masks Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 2] Custom loss functions.ipynb Retrieves and prints the shapes of the fixed and moving masks. This is useful for verifying image dimensions before and after registration. ```python # note that the fixed and moving images have different shapes fixed_mask.shape, moving_mask.shape ``` -------------------------------- ### Run Registration via Command-Line Interface Source: https://context7.com/rohitrango/fireants/llms.txt Execute registration workflows using CLI tools compatible with ANTs command patterns. ```bash # Basic registration using CLI fireantsRegistration \ --fixed fixed.nii.gz \ --moving moving.nii.gz \ --output output_prefix_ \ --transform Affine \ --metric CC \ --iterations 200x100x50 \ --scales 4x2x1 # Deformable registration with affine initialization fireantsRegistration \ --fixed fixed.nii.gz \ --moving moving.nii.gz \ --output result_ \ --transform SyN \ --metric CC \ --cc-kernel-size 7 \ --iterations 200x100x50 \ --scales 4x2x1 \ --smooth-warp 0.5 \ --smooth-grad 1.0 \ --optimizer Adam \ --lr 0.5 # View all options fireantsRegistration --help ``` -------------------------------- ### Executing Affine Registration Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/quickstart.md Initialize and run the affine registration process. ```python # create affine registration object affine = AffineRegistration(scales, iterations, batch1, batch2, optimizer=optim, optimizer_lr=lr, cc_kernel_size=5) # run registration start = time() affine.optimize(); torch.cuda.synchronize() end = time() ``` -------------------------------- ### Configure Input Parameters Source: https://github.com/rohitrango/fireants/blob/main/fireants/scripts/template/README.md Define the source image list and initial template path in the YAML configuration. ```yaml image_list_file: /path/to/your/image_paths.txt num_subjects: 8 # null for all subjects ``` ```yaml init_template_path: /path/to/initial/template.nii.gz # null to create from average ``` -------------------------------- ### Import FireANTs and Dependencies Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 1] Basic Usage.ipynb Initializes the environment and imports required modules for image processing and registration. ```python %load_ext autoreload %autoreload 2 from fireants.io import Image, BatchedImages from fireants.registration.affine import AffineRegistration from fireants.registration.greedy import GreedyRegistration import matplotlib.pyplot as plt import SimpleITK as sitk from time import time ``` -------------------------------- ### Load fixed and moving masks for registration Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 2] Custom loss functions.ipynb Loads the corresponding masks for the fixed and moving images. Masks are used to guide the registration process, particularly for segmentation-based alignment. ```python fixed_mask = BatchedImages(Image.load_file("lung_masks/01_Fixed.nii.gz")) moving_mask = BatchedImages(Image.load_file("lung_masks/01_Moving.nii.gz")) ``` -------------------------------- ### Execute Multi-Stage Registration Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/cli.md Performs a complete registration pipeline including rigid, affine, and SyN stages with moment initialization. ```bash fireantsRegistration \ --output results/registration \ --device cuda:0 \ --winsorize-image-intensities [0.005,0.995] \ --initial-moving-transform [fixed.nii.gz,moving.nii.gz,2] \ --transform Rigid[0.03] \ --metric MI[fixed.nii.gz,moving.nii.gz,gaussian,16] \ --convergence [100x50x25x10,1e-6,10] \ --shrink-factors 8x4x2x1 \ --transform Affine[0.03] \ --metric CC[fixed.nii.gz,moving.nii.gz,5] \ --convergence [100x50x25x10,1e-4,10] \ --shrink-factors 8x4x2x1 \ --transform SyN[0.2] \ --metric MSE[fixed.nii.gz,moving.nii.gz] \ --convergence [100x70x50x20,1e-4,10] \ --shrink-factors 8x4x2x1 \ --verbose ``` -------------------------------- ### Advanced Configuration Options Source: https://github.com/rohitrango/fireants/blob/main/fireants/scripts/template/README.md Settings for multi-modal templates, additional file saving, and performance tuning. ```yaml init_template_path: /path/to/t1.nii.gz,/path/to/t2.nii.gz ``` ```yaml save_additional: image_file: ["/path/to/labels.txt"] image_prefix: ["labels_"] image_suffix: [".nii.gz"] is_segmentation: [true] ``` ```yaml batch_size: 8 ``` ```yaml tmpdir: /path/to/temp ``` -------------------------------- ### Initialize Affine Registration Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 1] Basic Usage.ipynb Configures the parameters and creates an AffineRegistration object. ```python # specify some values scales = [4, 2, 1] # scales at which to perform registration iterations = [200, 100, 50] optim = 'Adam' lr = 3e-3 # create affine registration object affine = AffineRegistration(scales, iterations, batch1, batch2, optimizer=optim, optimizer_lr=lr, cc_kernel_size=5) ``` -------------------------------- ### Perform Moment Matching Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/advanced/moments.md Initializes and optimizes the registration process using fixed and moving image batches. ```python from fireants.registration.moments import MomentsRegistration moments = MomentsRegistration(fixed_images=fixed_images_batch, \ moving_images=moving_images_batch, \ **dict(args)) moments.optimize() ``` -------------------------------- ### Execute Template Building Source: https://github.com/rohitrango/fireants/blob/main/fireants/scripts/template/README.md Run the template builder using torchrun for single or distributed processing. ```bash torchrun --nproc-per-node=1 build_template.py ``` ```bash torchrun --nproc-per-node=1 build_template.py --config-name your_config.yaml ``` ```bash torchrun --nproc_per_node=8 build_template.py ``` -------------------------------- ### Configure Logging and Debugging Source: https://github.com/rohitrango/fireants/blob/main/fireants/scripts/template/README.md Enable verbose output for monitoring the registration process. ```yaml debug: True verbose: True ``` -------------------------------- ### Initialize GreedyRegistration with Levenberg-Marquardt Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/levenberg-marquardt.md Configure the registration process using the 'levenberg' optimizer by passing it to the GreedyRegistration constructor. ```python from fireants.io.image import BatchedImages, Image from fireants.registration.greedy import GreedyRegistration fixed_image = Image.load_file("fixed.nii.gz") moving_image = Image.load_file("moving.nii.gz") fixed_batch = BatchedImages([fixed_image]) moving_batch = BatchedImages([moving_image]) reg = GreedyRegistration( scales=[8, 4, 2, 1], iterations=[200, 150, 100, 50], fixed_images=fixed_batch, moving_images=moving_batch, loss_type="fusedcc", loss_params={"smooth_nr": 1e-5, "smooth_dr": 1e-5}, cc_kernel_size=7, optimizer="levenberg", # <-- selects LM optimizer optimizer_lr=0.75, ) reg.optimize() moved = reg.evaluate(fixed_batch, moving_batch) ``` -------------------------------- ### Configure Initial Moving Transform Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/cli.md Specifies the initial alignment method using moment matching between fixed and moving images. ```bash --initial-moving-transform [fixed.nii.gz,moving.nii.gz,2] ``` -------------------------------- ### Run Registration Optimization Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 1] Basic Usage.ipynb Executes the registration process and measures the runtime. ```python # run registration start = time() affine.optimize() end = time() ``` ```python print("Runtime", end - start, "seconds") ``` -------------------------------- ### Run template construction with torchrun Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/template.md Execute the template building script using distributed processing across multiple GPUs. ```bash #!/bin/bash torchrun --nproc_per_node=8 build_template.py --config_name oasis_deformable ``` -------------------------------- ### Multi-stage Registration Transforms Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/cli.md Shows how to define multiple transformation stages (Rigid, Affine, SyN) for a multi-stage registration pipeline. Each transform can have specific parameters. ```bash --transform Rigid[0.1] \ --transform Affine[0.05] \ --transform SyN[0.2,Adam,0.25,0.5] ``` -------------------------------- ### Perform Affine Image Registration Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/advanced/rigidaffine.md This snippet demonstrates affine registration, which can optionally be initialized with the results from a prior rigid registration. Ensure images are loaded and batched similarly to rigid registration. ```python # get rigid registration matrix as optional initialization for affine registration rigid_matrix = rigid_reg.get_rigid_matrix() # create affine registration object affine_reg = AffineRegistration(scales, iterations, fixed_batch, moving_batch, optimizer=optim, optimizer_lr=lr, init_rigid=rigid_matrix, # optionally initialized with rigid matrix cc_kernel_size=5) affine_reg.optimize() ``` -------------------------------- ### Configure Template Creation Options Source: https://github.com/rohitrango/fireants/blob/main/fireants/scripts/template/README.md Set iteration counts, shape averaging, smoothing, and image processing preferences. ```yaml template_iterations: 6 ``` ```yaml shape_avg: true ``` ```yaml num_laplacian: 2 laplace_params: learning_rate: 0.5 itk_scale: true ``` ```yaml normalize_images: True save_as_uint8: False ``` -------------------------------- ### Setting Affine Registration Parameters Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/quickstart.md Define the configuration for the affine registration process. ```python # specify some values scales = [4, 2, 1] # scales at which to perform registration iterations = [200, 100, 50] optim = 'Adam' lr = 3e-3 ``` -------------------------------- ### Create Conda Environment Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/install.md Initializes a dedicated Python 3.10 environment for FireANTs. ```bash conda create -n fireants python=3.10 ``` -------------------------------- ### Initialize Rigid Registration with Moments Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/advanced/moments.md Uses the rotation and translation matrices derived from moment matching to initialize a rigid registration. ```python # retrieve rotation and translation matrices from moment matching init_moment_rigid = moments.get_rigid_moment_init() init_moment_transl = moments.get_rigid_transl_init() rigid = RigidRegistration(fixed_images=fixed_images_batch, \ moving_images=moving_images_batch, \ init_translation=init_moment_transl, \ init_moment=init_moment_rigid, \ **dict(args)) ``` -------------------------------- ### Initialize Affine Registration with Moments Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/advanced/moments.md Uses the rigid matrix derived from moment matching to initialize an affine registration. ```python # retrieve rigid matrix from moment matching init_rigid = moments.get_affine_init() affine = AffineRegistration(fixed_images=fixed_images_batch, \ moving_images=moving_images_batch, \ init_rigid=init_rigid, \ **dict(args)) ``` -------------------------------- ### Configure Registration Pipeline Stages Source: https://github.com/rohitrango/fireants/blob/main/fireants/scripts/template/README.md Specify parameters for moments, rigid, affine, and deformable registration stages. ```yaml do_moments: True moments: scale: 4 moments: 1 ``` ```yaml do_rigid: True rigid: iterations: [200, 100, 25] scales: [4, 2, 1] loss_type: cc ``` ```yaml do_affine: True affine: iterations: [200, 100, 25] scales: [4, 2, 1] loss_type: cc ``` ```yaml do_deform: True deform_algo: greedy # or 'syn' deform: iterations: [200, 100, 50] scales: [4, 2, 1] optimizer_lr: 0.25 smooth_warp_sigma: 0.5 smooth_grad_sigma: 1.0 cc_kernel_size: 5 loss_type: fusedcc ``` -------------------------------- ### Initialize GreedyRegistration Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 1] Basic Usage.ipynb Configures the registration process with specified scales, iterations, and optimization parameters. ```python reg = GreedyRegistration(scales=[4, 2, 1], iterations=[200, 100, 25], fixed_images=batch1, moving_images=batch2, cc_kernel_size=5, deformation_type='compositive', smooth_grad_sigma=0.5, optimizer='adam', optimizer_lr=0.5, init_affine=affine.get_affine_matrix().detach()) ``` -------------------------------- ### Initialize and optimize Affine Registration with custom Dice Loss Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 2] Custom loss functions.ipynb Sets up an AffineRegistration object using the custom DiceLossModule and optimizes it. This performs affine alignment using the provided masks. ```python affine = AffineRegistration([6, 4, 2, 1], [200, 100, 50, 20], fixed_mask, moving_mask, \ loss_type='custom', custom_loss=DiceLossModule(), optimizer='Adam', \ optimizer_lr=3e-3, optimizer_params={}, cc_kernel_size=5) aff_start = time() affine.optimize() aff_end = time() moved_mask = affine.evaluate(fixed_mask, moving_mask) ``` -------------------------------- ### Print affine registration runtime Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 2] Custom loss functions.ipynb Calculates and prints the total time taken for the affine registration process. ```python print("Runtime: {:04f} seconds.".format(aff_end - aff_start)) ``` -------------------------------- ### Build FireANTs Docker Image Source: https://github.com/rohitrango/fireants/blob/main/docker/README.md Build the Docker image for FireANTs. Use this command from the root directory of the cloned repository. The image will be tagged as 'fireants'. ```bash docker buildx build -t fireants -f docker/Dockerfile . ``` -------------------------------- ### Prepare Images with Mask Channels Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/masked-losses.md Use apply_mask_to_image and generate_image_mask_allones to ensure both fixed and moving images have a mask channel as the last dimension. ```python from fireants.io.image import BatchedImages, Image from fireants.io.imagemask import apply_mask_to_image, generate_image_mask_allones from fireants.registration.greedy import GreedyRegistration # Load fixed and moving images and your ROI mask (e.g. moving_mask) fixed_image = Image.load_file("fixed.nii.gz") moving_image = Image.load_file("moving.nii.gz") moving_mask = Image.load_file("moving_roi.nii.gz") # same shape as moving_image # Fixed: no mask → use all-ones mask so we have [image, mask] with mask=1 everywhere fixed_with_mask = apply_mask_to_image(fixed_image, generate_image_mask_allones(fixed_image)) # Moving: append real mask → [image, mask] moving_with_mask = apply_mask_to_image(moving_image, moving_mask) fixed_batch = BatchedImages([fixed_with_mask]) moving_batch = BatchedImages([moving_with_mask]) ``` -------------------------------- ### Configure Output Settings Source: https://github.com/rohitrango/fireants/blob/main/fireants/scripts/template/README.md Define the directory for saved templates and control the frequency of saving. ```yaml save_dir: ./saved_templates save_every: 1 # Save every N iterations save_init_template: true save_moved_images: false # Save registered images from final iteration ``` -------------------------------- ### Run Keypoint Fidelity Plot Script Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/keypoint-fidelity.md Execute the helper script to generate plots for keypoint fidelity visualization. Run this from the repository root. ```bash python docs/scripts/generate_keypoint_fidelity_plot.py ``` -------------------------------- ### Set Registration Device Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/cli.md Defines the hardware device for registration execution, defaulting to cuda:0. ```bash --device cuda:1 ``` -------------------------------- ### Specify Output Path for Warped Image Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/cli.md Demonstrates how to specify both the output prefix for transforms and the exact path for the warped image using the `--output` argument. ```bash --output output/myregistration,output/warped.nii.gz ``` -------------------------------- ### Import required modules Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 1] Basic Usage.ipynb Initial imports for Jacobian calculation and tensor operations. ```python from fireants.utils.imageutils import jacobian import torch ``` -------------------------------- ### Initialize Deformable Registration from Affine Source: https://context7.com/rohitrango/fireants/llms.txt Uses an existing affine transformation matrix to initialize the deformable registration process on intensity images. ```python fixed_img = BatchedImages([Image.load_file("fixed_lung.nii.gz")]) moving_img = BatchedImages([Image.load_file("moving_lung.nii.gz")]) deformable = GreedyRegistration( scales=[6, 4, 2, 1], iterations=[200, 150, 75, 25], fixed_images=fixed_img, moving_images=moving_img, cc_kernel_size=5, smooth_grad_sigma=6, smooth_warp_sigma=0.4, optimizer="Adam", optimizer_lr=0.25, init_affine=affine.get_affine_matrix().detach() # Initialize from mask alignment ) deformable.optimize() ``` -------------------------------- ### Clone FireANTs Repository Source: https://github.com/rohitrango/fireants/blob/main/docker/README.md Clone the FireANTs repository to your local machine. This is the first step before building the Docker image. ```bash git clone https://github.com/rohitrango/fireants cd fireants ``` -------------------------------- ### Perform affine registration with custom loss Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/customloss.md Executes the affine registration process using the previously defined DiceLossModule. ```python affine = AffineRegistration([6, 4, 2, 1], [200, 100, 50, 20], fixed_mask, moving_mask, \ loss_type='custom', custom_loss=DiceLossModule(), optimizer='Adam', \ optimizer_lr=3e-3, optimizer_params={}, cc_kernel_size=5) aff_start = time() affine.optimize() aff_end = time() ``` -------------------------------- ### Importing FireANTs Modules Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/quickstart.md Initial imports required for image loading, registration, and visualization. ```python from fireants.io import Image, BatchedImages from fireants.registration.affine import AffineRegistration from fireants.registration.greedy import GreedyRegistration import matplotlib.pyplot as plt import SimpleITK as sitk from time import time ``` -------------------------------- ### Custom Loss Functions for Registration Source: https://context7.com/rohitrango/fireants/llms.txt Demonstrates how to implement and use a custom PyTorch module as a loss function for registration tasks, such as Dice loss for binary masks. ```python from fireants.registration.affine import AffineRegistration from fireants.registration.greedy import GreedyRegistration from fireants.io import Image, BatchedImages import torch from torch import nn # Define custom Dice loss for binary masks class DiceLossModule(nn.Module): def __init__(self, smooth=1e-5): super().__init__() self.smooth = smooth def forward(self, moved_seg, fixed_seg, *args, **kwargs): # Flatten to [B, N] moved_flat = moved_seg.flatten(1) fixed_flat = fixed_seg.flatten(1) # Compute Dice coefficient intersection = (moved_flat * fixed_flat).sum(1) union = moved_flat.sum(1) + fixed_flat.sum(1) dice = (2 * intersection + self.smooth) / (union + self.smooth) return 1 - dice.mean() # Return loss (1 - Dice) # Load binary masks fixed_mask = BatchedImages([Image.load_file("fixed_lung_mask.nii.gz")]) moving_mask = BatchedImages([Image.load_file("moving_lung_mask.nii.gz")]) # Affine registration using Dice loss on masks affine = AffineRegistration( scales=[6, 4, 2, 1], iterations=[200, 100, 50, 20], fixed_images=fixed_mask, moving_images=moving_mask, loss_type="custom", # Use custom loss custom_loss=DiceLossModule(), # Pass custom module optimizer="Adam", optimizer_lr=3e-3 ) affine.optimize() ``` -------------------------------- ### Examine Affine Transformation Matrices Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/moments-scaling.md Retrieves and prints the affine matrices to analyze the impact of scaling on the transformation. ```python # Get affine matrices affine_no_scale = reg_no_scale.get_affine_init() affine_with_scale = reg_with_scale.get_affine_init() print("Affine matrix WITHOUT scaling:") print(affine_no_scale[0].cpu().numpy()) print("\nAffine matrix WITH scaling:") print(affine_with_scale[0].cpu().numpy()) # The difference shows the scaling component print("\nDifference (scaling effect):") print((affine_with_scale[0] - affine_no_scale[0]).cpu().numpy()) ``` -------------------------------- ### Load images and masks for registration Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/customloss.md Initializes fixed and moving images and masks using BatchedImages for the registration pipeline. ```python from fireants.io import Image, BatchedImages from fireants.registration.affine import AffineRegistration from fireants.registration.greedy import GreedyRegistration import matplotlib.pyplot as plt from time import time import torch from torch import nn # load images and masks # here we're combining the image loading and batch loading fixed_image = BatchedImages(Image.load_file("lung_images/01_Fixed.nii.gz")) moving_image = BatchedImages(Image.load_file("lung_images/01_Moving.nii.gz")) fixed_mask = BatchedImages(Image.load_file("lung_masks/01_Fixed.nii.gz")) moving_mask = BatchedImages(Image.load_file("lung_masks/01_Moving.nii.gz")) ``` -------------------------------- ### Configure Custom LM Damping Parameters Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/levenberg-marquardt.md Pass custom damping hyper-parameters via the optimizer_params dictionary to control the optimizer's behavior. ```python reg = GreedyRegistration( scales=[8, 4, 2, 1], iterations=[200, 150, 100, 50], fixed_images=fixed_batch, moving_images=moving_batch, loss_type="fusedcc", loss_params={"smooth_nr": 1e-5, "smooth_dr": 1e-5}, cc_kernel_size=7, optimizer="levenberg", optimizer_lr=0.75, optimizer_params={ "lambda_init": 0.1, # start with stronger damping "lambda_increase_factor": 5.0, # retreat faster on bad steps "lambda_decrease_factor": 0.7, # loosen damping faster on good steps }, ) reg.optimize() ``` -------------------------------- ### Executing Deformable Registration Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/quickstart.md Run the greedy deformable registration initialized with the previous affine matrix. ```python reg = GreedyRegistration(scales=[4, 2, 1], iterations=[200, 100, 25], fixed_images=batch1, moving_images=batch2, cc_kernel_size=5, deformation_type='compositive', smooth_grad_sigma=1, optimizer='adam', optimizer_lr=0.5, init_affine=affine.get_affine_matrix().detach()) start = time() reg.optimize() end = time() ``` -------------------------------- ### Loading and Batching Images Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/quickstart.md Load MRI scans using the Image class and prepare them for registration using BatchedImages. ```python # load the images image1 = Image.load_file("atlas_2mm_1000_3.nii.gz") image2 = Image.load_file("atlas_2mm_1001_3.nii.gz") # batchify them (we only have a single image per batch, but we can pass multiple images) batch1 = BatchedImages([image1]) batch2 = BatchedImages([image2]) ``` -------------------------------- ### Optimize Registration Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 1] Basic Usage.ipynb Executes the optimization process and measures the runtime. ```python start = time() reg.optimize() end = time() ``` ```python print("Runtime", end - start, "seconds") ``` -------------------------------- ### Check Device Configuration Source: https://github.com/rohitrango/fireants/blob/main/tutorials/[Tutorial 1] Basic Usage.ipynb Verifies the compute device being used by the batch object. ```python # check device name print(batch1().device) ``` -------------------------------- ### Perform GreedyRegistration Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/keypoint-fidelity.md Configures and executes a GreedyRegistration optimization process. ```python reg = GreedyRegistration( scales=[2, 1], iterations=[120, 60], fixed_images=fixed_batch, moving_images=moving_batch, loss_type="mse", smooth_warp_sigma=0.5, smooth_grad_sigma=1.0, progress_bar=False, ) reg.optimize() moved_kp_batch = reg.evaluate_keypoints(fixed_kp_batch, moving_kp_batch) ``` -------------------------------- ### Visualizing Affine Registration Results Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/quickstart.md Display the fixed, moved, and moving images after affine registration. ```python moved = transformed_images[-1] # visualize the images fig, ax = plt.subplots(1, 3, figsize=(21, 7)) ax[0].imshow(batch1()[0, 0, :, :, 48].cpu().numpy(), 'gray'); ax[0].invert_yaxis(); ax[0].axis('off') ax[1].imshow(moved[0, 0, :, :, 48].detach().cpu().numpy(), 'gray'); ax[1].invert_yaxis(); ax[1].axis('off') ax[2].imshow(batch2()[0, 0, :, :, 48].cpu().numpy(), 'gray'); ax[2].invert_yaxis(); ax[2].axis('off') # set titles ax[0].set_title("Fixed Image", fontsize=20) ax[1].set_title("Moved Image", fontsize=20) ax[2].set_title("Moving Image", fontsize=20) ``` -------------------------------- ### Construct Anatomical Templates Source: https://context7.com/rohitrango/fireants/llms.txt Build templates from multiple subjects using distributed GPU processing and configuration files. ```bash # Run template construction with 8 GPUs torchrun --nproc_per_node=8 fireants/scripts/template/build_template.py \ --config_name oasis_deformable # Example config file (oasis_deformable.yaml): # init_template_path: null # or path to initial template # num_iterations: 5 # registration_stages: # - type: moments # - type: affine # scales: [8, 4, 2] # iterations: [200, 100, 50] # - type: greedy # scales: [4, 2, 1] # iterations: [100, 75, 50] # shape_averaging: true # num_laplacian: 3 ``` -------------------------------- ### Visualize registration masks Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/customloss.md Displays the fixed, moved, and moving masks to verify the affine registration results. ```python # Visualize the masks fig, ax = plt.subplots(1, 3, figsize=(21, 7)) ax[0].imshow(fixed_mask()[0, 0, :, 200].cpu().numpy(), 'gray'); ax[0].invert_yaxis(); ax[0].axis('off') ax[1].imshow(moved_mask[0, 0, :, 200].detach().cpu().numpy(), 'gray'); ax[1].invert_yaxis(); ax[1].axis('off') ax[2].imshow(moving_mask()[0, 0, :, 200].cpu().numpy(), 'gray'); ax[2].invert_yaxis(); ax[2].axis('off') # set titles ax[0].set_title("Fixed Mask", fontsize=20) ax[1].set_title("Moved Mask", fontsize=20) ax[2].set_title("Moving Mask", fontsize=20) ``` -------------------------------- ### Winsorize Image Intensities Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/cli.md Clips image intensities to specified quantiles or percentiles to mitigate outlier effects. ```bash --winsorize-image-intensities [0.01,0.99] ``` -------------------------------- ### Loading and inspecting results Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/levenberg-marquardt.md Shows how to load the saved Dice scores using NumPy and print summary statistics. ```python import numpy as np dice = np.load("results/levenberg_dice_scores.npy") # shape: [N_pairs, n_labels] print(f"Mean Dice: {dice.mean():.4f}") print(f"Per-label mean: {dice.mean(axis=0)}") print(f"Worst label: label {dice.mean(axis=0).argmin() + 1} " f"({dice.mean(axis=0).min():.4f})") ``` -------------------------------- ### Initialize Affine Registration with Center of Frame Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/advanced/rigidaffine.md Initialize affine registration by aligning the physical centers of the fixed and moving images. This sets the initial translation to `c_m - c_f` and the linear part to identity. ```python affine_reg = AffineRegistration(scales, iterations, fixed_batch, moving_batch, init_rigid="cof", # identity + translation c_m - c_f optimizer=optim, optimizer_lr=lr) ``` -------------------------------- ### GreedyRegistration with Levenberg-Marquardt Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/howto/levenberg-marquardt.md Configuring the GreedyRegistration class to use the Levenberg-Marquardt optimizer. ```APIDOC ## GreedyRegistration Configuration ### Description Initializes the GreedyRegistration class with the 'levenberg' optimizer. The optimizer uses a damping parameter λ to adjust step sizes based on loss performance. ### Parameters #### Request Body - **optimizer** (string) - Required - Set to 'levenberg' to enable the LM optimizer. - **optimizer_lr** (float) - Required - The overall step size multiplier. - **optimizer_params** (dict) - Optional - Dictionary containing: - **lambda_init** (float or 'auto') - Initial damping value (default: 1e-2). - **lambda_increase_factor** (float) - Growth factor when loss increases (default: 1.5). - **lambda_decrease_factor** (float) - Shrinkage factor when loss decreases (default: 0.975). ### Request Example { "optimizer": "levenberg", "optimizer_lr": 0.75, "optimizer_params": { "lambda_init": 0.1, "lambda_increase_factor": 5.0, "lambda_decrease_factor": 0.7 } } ``` -------------------------------- ### Apply warp with antsApplyTransforms Source: https://github.com/rohitrango/fireants/blob/main/docs/docs/quickstart.md Executes the standard ANTs command-line tool using the exported warp file. ```bash !antsApplyTransforms -d 3 -i atlas_2mm_1001_3.nii.gz -r atlas_2mm_1000_3.nii.gz -t 1000_1001_warp.nii.gz -o antsMoved.nii.gz ```