Run ANTs in Slicer Python Interactor

@simonoxen, @lassoan

Hi all,

I tried Ants extension in Slicer, the registration worked very good. However, I want to write a script and run ANTs from Slicer Python interactor. I am able to import antsRegistration, but can’t find a way to input all the parameters.

The following command generates syntax error. VolumeNodes fix, move, outTrans, outVolume can be defined and used successfully.
antsRegistration --dimensionality 3 --use-histogram-matching 1 --winsorize-image-intensities [0.005,0.995] --float 0 --verbose 1 --interpolation LanczosWindowedSinc --output [outTrans,outVolume] --write-composite-transform 1 --collapse-output-transforms 1 --initial-moving-transform [fix,move,1] --transform Rigid[0.1] --metric MI[fix,move,0.25] --convergence [1000x500x250,1e-6,10] --smoothing-sigmas 3x2x1vox --shrink-factors 8x4x2

Thank you.

Hi, the logic from antsRegistration (scripted) module calls the antsRegistrationCLI module. You can run a registration and see in the log file how the command to antsRegistrationCLI is generated.

You could also mimic how the scripted module works from python. You can see a small test in the module to see how to do this.

Hi Simon,

Thank you for your reply. The code I posted is actually copied from the log file of a successful registration, but when entered in Slicer python interactor it not works. The antsRegistrationCLI module you mentioned, did you mean slicer.cli.run(antsCommand (“parameters here”))? This is not working neither. Could you please provide an example code for testing? Really appreciate your help!

how do you enter it?

no, see SlicerANTs/antsRegistration/antsRegistration.py at master · netstim/SlicerANTs · GitHub on how the CLI is run.

Thank you for the GitHub example, I finally got it to work! Last question, when I run the CLI (antsRegistrationLogic().process()), is there a way to add this argument “wait_for_completion=True”?

I include two steps, ANTs registration and feature extraction in one function. I found that the extraction get no data because it starts before registration complete.

Thanks.

Right now, from process(), this is hardcoded. You can specify the CLI params and then run the CLI module with wait_for_completion=True.

I couldn’t find any CLI params can change “wait_for_completion” status, looks like slicer.cli.run was implemented inside “antsRegistrationLogic().process()”, how could you control it from outside? I changed it to true in the source code and it worked fine, but I wish to find a better way so others can replicate the method. Thank you.

yes, as mentioned, this is hardcoded. You can run slicer.cli.run from python interactor, specifying the cli params.

Hi @simonoxen and @hotsen ,

Could you please provide a sample code to run the registration from Python interactor? How do we pass the arguments to the process() function?

I am passing the following parameters,

sampleParams = {'stages': [{'transformParameters': {'transform': 'Rigid', 'settings': '0.1'}, 'metrics': [{'type': 'MI', 'fixed': '/media/srivathsan/Vol_011_20220119_144127_3D.nii.gz', 'moving': '/media/srivathsan/Vol_005_20220119_143403_3D.nii.gz', 'settings': '1,32,Regular,0.25'}], 'levels': {'steps': [{'convergence': 1000, 'smoothingSigmas': 4, 'shrinkFactors': 12}, {'convergence': 500, 'smoothingSigmas': 3, 'shrinkFactors': 8}, {'convergence': 250, 'smoothingSigmas': 2, 'shrinkFactors': 4}, {'convergence': 0, 'smoothingSigmas': 1, 'shrinkFactors': 2}], 'smoothingSigmasUnit': 'vox', 'convergenceThreshold': 6, 'convergenceWindowSize': 10}, 'masks': {'fixed': None, 'moving': None}}, {'transformParameters': {'transform': 'Affine', 'settings': '0.1'}, 'metrics': [{'type': 'MI', 'fixed': None, 'moving': None, 'settings': '1,32,Regular,0.25'}], 'levels': {'steps': [{'convergence': 1000, 'smoothingSigmas': 4, 'shrinkFactors': 12}, {'convergence': 500, 'smoothingSigmas': 3, 'shrinkFactors': 8}, {'convergence': 250, 'smoothingSigmas': 2, 'shrinkFactors': 4}, {'convergence': 0, 'smoothingSigmas': 1, 'shrinkFactors': 2}], 'smoothingSigmasUnit': 'vox', 'convergenceThreshold': 6, 'convergenceWindowSize': 10}, 'masks': {'fixed': None, 'moving': None}}, {'transformParameters': {'transform': 'SyN', 'settings': '0.1,3,0'}, 'metrics': [{'type': 'MI', 'fixed': None, 'moving': None, 'settings': '1,32'}], 'levels': {'steps': [{'convergence': 100, 'smoothingSigmas': 5, 'shrinkFactors': 10}, {'convergence': 100, 'smoothingSigmas': 3, 'shrinkFactors': 6}, {'convergence': 70, 'smoothingSigmas': 2, 'shrinkFactors': 4}, {'convergence': 50, 'smoothingSigmas': 1, 'shrinkFactors': 2}, {'convergence': 0, 'smoothingSigmas': 0, 'shrinkFactors': 1}], 'smoothingSigmasUnit': 'vox', 'convergenceThreshold': 6, 'convergenceWindowSize': 10}, 'masks': {'fixed': None, 'moving': None}}], 'outputSettings': {'transform': None, 'volume': '/media/srivathsan/antsCli/cliOutput.nii.gz', 'interpolation': 'Linear'}, 'initialTransformSettings': {'initializationFeature': 1}, 'generalSettings': {'dimensionality': 3, 'histogramMatching': 0, 'winsorizeImageIntensities': [0.005, 0.995], 'computationPrecision': 'float'}}

import antsRegistration
antsRegistration.antsRegistrationLogic().process(sampleParams)

But it generates the following error,

Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: process() missing 1 required positional argument: 'outputSettings'

Thank you.

I was passing the wrong arguments. I tried to pass the arguments as in the GitHub example.

antsRegistration.antsRegistrationLogic().process([{'transformParameters': {'transform': 'Rigid', 'settings': '0.1'}, 'metrics': [{'type': 'MI', 'fixed': '/tmp/Slicer-srivathsan/vtkMRMLScalarVolumeNode1.nrrd', 'moving': '/tmp/Slicer-srivathsan/vtkMRMLScalarVolumeNode2.nrrd', 'settings': '1,32,Regular,0.25'}], 'levels': {'steps': [{'convergence': 1000, 'smoothingSigmas': 4, 'shrinkFactors': 12}, {'convergence': 500, 'smoothingSigmas': 3, 'shrinkFactors': 8}, {'convergence': 250, 'smoothingSigmas': 2, 'shrinkFactors': 4}, {'convergence': 0, 'smoothingSigmas': 1, 'shrinkFactors': 2}], 'smoothingSigmasUnit': 'vox', 'convergenceThreshold': 6, 'convergenceWindowSize': 10}, 'masks': {'fixed': None, 'moving': None}}, {'transformParameters': {'transform': 'Affine', 'settings': '0.1'}, 'metrics': [{'type': 'MI', 'fixed': None, 'moving': None, 'settings': '1,32,Regular,0.25'}], 'levels': {'steps': [{'convergence': 1000, 'smoothingSigmas': 4, 'shrinkFactors': 12}, {'convergence': 500, 'smoothingSigmas': 3, 'shrinkFactors': 8}, {'convergence': 250, 'smoothingSigmas': 2, 'shrinkFactors': 4}, {'convergence': 0, 'smoothingSigmas': 1, 'shrinkFactors': 2}], 'smoothingSigmasUnit': 'vox', 'convergenceThreshold': 6, 'convergenceWindowSize': 10}, 'masks': {'fixed': None, 'moving': None}}, {'transformParameters': {'transform': 'SyN', 'settings': '0.1,3,0'}, 'metrics': [{'type': 'MI', 'fixed': None, 'moving': None, 'settings': '1,32'}], 'levels': {'steps': [{'convergence': 100, 'smoothingSigmas': 5, 'shrinkFactors': 10}, {'convergence': 100, 'smoothingSigmas': 3, 'shrinkFactors': 6}, {'convergence': 70, 'smoothingSigmas': 2, 'shrinkFactors': 4}, {'convergence': 50, 'smoothingSigmas': 1, 'shrinkFactors': 2}, {'convergence': 0, 'smoothingSigmas': 0, 'shrinkFactors': 1}], 'smoothingSigmasUnit': 'vox', 'convergenceThreshold': 6, 'convergenceWindowSize': 10}, 'masks': {'fixed': None, 'moving': None}}], {'transform': None, 'volume': '/tmp/Slicer-srivathsan/BFCDJ_vtkMRMLScalarVolumeNode3.nrrd', 'interpolation': 'Linear'}, {'initializationFeature': 1}, {'dimensionality': 3, 'histogramMatching': 0, 'winsorizeImageIntensities': [0.005, 0.995], 'computationPrecision': 'float'})

Though it fixed the previous issue, now I get the following error,
Traceback (most recent call last):

  File "<console>", line 1, in <module>
  File "/home/srivathsan/Slicer-4.13.0-2022-04-17-linux-amd64/NA-MIC/Extensions-30785/SlicerANTs/lib/Slicer-4.13/qt-scripted-modules/antsRegistration.py", line 517, in process
    self.getOrSetCLIParam(stages[0]['metrics'][0]['fixed']) # put in first position. will be used as reference in cli
  File "/home/srivathsan/Slicer-4.13.0-2022-04-17-linux-amd64/NA-MIC/Extensions-30785/SlicerANTs/lib/Slicer-4.13/qt-scripted-modules/antsRegistration.py", line 599, in getOrSetCLIParam
    nodeID = mrmlNode.GetID()
AttributeError: 'str' object has no attribute 'GetID'

Appreciate any help on this.

You need to provide a node object (you provided a filename). You can load a volume and get the node object using slicer.util.loadVolume.

1 Like

Hi Vathsan,
Sorry for the late reply. Just call
antsRegistration.antsRegistrationLogic().process(stages=stages, outputSettings=outputSettings, initialTransformSettings=initialTransformSettings, generalSettings=generalSettings)
and feed all your settings.
For example,
generalSettings = {
‘dimensionality’ : 3,
‘histogramMatching’ : True,
‘winsorizeImageIntensities’ : [0.005,0.995],
‘computationPrecision’ : ‘double’
}

I think the error you got is because you pass a string instead of slicer volume node. Try to create one using Volume = slicer.vtkMRMLScalarVolumeNode() or get an existing one using Volume = slicer.util.getNode(“NodeNameHere”).

Hope this helps.

Hotsen

1 Like

Hi,

Like hotsen, I tried to perform a two steps script, with ANTS registration and then other functions but it is necessary to use “wait_for_completion = True” otherwise the two processes are performed simultaneously.

However I do not understand how the CLI is working. I have no problem to pass the parameters for the antsRegistration.antsRegistrationLogic().process (by using the preset parameters of the github repository and changing the corresponding volume) but I have some problems with the slicer.cli.run function, I don’t understand how to launch it via the python interpreter with the same preset as in the slicerANTs github repository.

Could someone provide an example with the slicer.cli.run function ?

Thank you

Fabien

I would recommend to modify the module logic to accept an optional wait_for_completion argument here:

You could then replace the hardcoded wait_for_completion=False setting here:

If it all works well for you on your computer then you can submit a pull request to the SlicerANTs repository.

Thank you very much Andras,

I have tried first to replace False by True in line 530 and it worked perfectly.

I will try later to modify the module logic to set it as optional.

Best regards

Fabien