ANTs icon indicating copy to clipboard operation
ANTs copied to clipboard

Empty deformation field issue with missing or empty binary segmentation masks

Open FlorianScalvini opened this issue 4 months ago • 1 comments

Operating system and version

Ubuntu 22.04

CPU architecture

x86_64 (PC, Intel Mac, other Intel/AMD)

ANTs code version

ANTs Version: 2.6.2.post3-g193e36e Compiled: Jul 1 2025 00:54:20

ANTs installation type

Compiled from source

Summary of the problem

I ran into an issue while performing pairwise registration using segmentation masks. Specifically, I have a list of binary maps, each representing a different anatomical label. The problem occurs when one or more of these binary maps are empty, either because a structure wasn’t annotated in the segmentation or because the structure is missing due to temporal changes in the brain. When such empty maps are included, the registration using the MeanSquare metric terminates prematurely, producing an empty deformation field without reporting any explicit error. My issue is to find a way to handle missing temporal segmentations during the optimization process without completely excluding the affected structures from the registration task, or to determine whether my Python script that formats the shell command contains any errors.

Commands to reproduce the problem.

import os
import argparse


def main(path_source, path_target, path_source_binary_mask, path_target_binary_mask, label_range, gradientStep, transform, output_prefix):
    # Construct the command
    prefix = f'ants_{transform}_gs{gradientStep}'
    prefix += '_seg_'
    cmd = f'antsRegistration -d 3 -o {prefix} '
    cmd += f'--transform {transform}[' + gradientStep + ',2,0] '

    weighting_seg = 1.0 / len(label_range)
    for label in label_range:
        starting_lb_path = os.path.join(path_source_binary_mask, f'{label}.nii.gz')
        current_lb_path = os.path.join(path_target_binary_mask, f'{label}.nii.gz')
        cmd += f'--metric MeanSquares[{current_lb_path}, {starting_lb_path},{weighting_seg}] '

    cmd += '--convergence [1000x500x500x500,1e-6,10] '
    cmd += '--shrink-factors 8x4x2x1 '
    cmd += '--smoothing-sigmas 3x2x1x0vox '
    cmd += '--verbose 1'

    print(cmd)
    os.system(cmd)
    # Apply the transformation
    cmd = f'antsApplyTransforms -d 3 -r {path_target} -i {path_source} -t {prefix}0Warp.nii.gz -o {prefix}_{output_prefix}_Warped.nii.gz '
    print(cmd)
    os.system(cmd)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Test different ANTs parameters to capture folding')
    parser.add_argument('-s', '--source_intensity', help='Source image', type=str)
    parser.add_argument('-t', '--target_intensity', help='Target image', type=str)
    parser.add_argument('-sb', '--source_binary_mask', help='Source folder with binary images (string)', type=str)
    parser.add_argument('-tb', '--target_binary_mask', help='Target folder with binary images (string)', type=str)
    parser.add_argument('-r', '--label_range', help='Label range (e.g. 0-19)', type=int, nargs='+', required=False, default=range(0, 19))
    parser.add_argument('-g', '--gradient', help='Gradient step (string)', type=str, required=False, default='1')
    parser.add_argument('-tf', '--transform', help='Transform type (string)', type=str, required=False, default='SyN')
    parser.add_argument('-o', '--output_prefix', help='Output prefix (string)', type=str, required=False, default='ants_')
    args = parser.parse_args()
    main(path_source=args.source_intensity, path_target=args.target_intensity, path_source_binary_mask=args.source_binary_mask, path_target_binary_mask=args.target_binary_mask, gradientStep=args.gradient, label_range=args.label_range, transform=args.transform, output_prefix=args.output_prefix)

Output of the command with verbose output.

log.txt

Data to reproduce the problem

data.zip

FlorianScalvini avatar Sep 10 '25 09:09 FlorianScalvini

Have you seen the function label_image_registration(...)? Example here.

ntustison avatar Sep 10 '25 13:09 ntustison