Fiducial registration Wizard - custom transformation configuration

Hi everyone,
I’m struggling with Fiducial Registration Wizard. So, what I’m trying to do is the following:
The user adds few fiducial points and then User clicks on button and all “To fiducial” points are computed (1) - how do i access module “place fiducial using transform” with my transform via python?

My next following question is how to configure a registration result(2) also via python? I create the new transormation result like following:

imageToProbe = slicer.vtkMRMLLinearTransformNode()
imageToProbe.SetName('ImageToProbe')
slicer.mrmlScene.AddNode(imageToProbe)

Thank you all in advance!
question2

All choices that the user makes on the GUI are saved in the fiducial registration wizard parameter node that you select at the top (by default, its name is “FiducialRegistrationWizard”). You can also change these selections form Python by modifying the node, for example, you can switch to similarity mode and change “Place ‘To’” transform like this:

w=getNode('FiducialRegistrationWizard')
w.SetRegistrationModeToSimilarity()
w.SetProbeTransformToNodeId(somTransform.GetID())

Dear Andras,
Thanks for your suggestion!
But, I can make this work after I select FiducialRegistrationWizard in UI, but directly from “clean start” in python script I get NameError: global name 'getNode' is not defined

To access getNode from a module, you would need to import the function into the namespace or write slicer.util.getNode. However, getNode is only intended for testing and quick interaction using the Python console.

In a Slicer module, you usually ask the user to choose input nodes (using a `qMRMLNodeComboBox’) and/or create nodes that you need. See programming tutorials (in particular, PerkLab tutorials) to get familiar with some of the important concepts.

2 Likes

What i’m trying to do in a script is:

w = slicer.vtkMRMLFiducialRegistrationWizardNode()
w.SetRegistrationModeToSimilarity()
w.SetProbeTransformToNodeId(transformNode.GetID())

But weirdly it does only work from the console, not from the module itself. What am I doing wrong? (also it returns different id for w and for p)
question

You need to add the created node to the scene.
The node that you created was not known to the scene. The node that you later retrieved successfully was the one created by the fiducial registration wizard module (if you open the module GUI and no parameter node has been created yet, then the module GUI creates one for the user’s convenience).

I would recommend to use slicer.mrmlScene.AddNewNodeByClass(). This method creates a new node (that respects any default node properties set in the scene), it adds the created node to the scene, and passes the ownership of the new node to the scene (so that you don’t need to manually UnRegister the created node).

I just don’t get it - when I create nodes like you suggested they are not automatically selected on the UI, I mean they exist in the drop down but i couldn’t find anywhere method to select from the dropdown. Also, it still doesn’t change\add my fiducials using transforms:

    fidReg = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLFiducialRegistrationWizardNode", "Fiducial")
    toFids = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsFiducialNode", "ProbeF")
    imageToProbe = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLLinearTransformNode", "ImageToProbe")

    fidReg.SetRegistrationModeToSimilarity()
    fidReg.SetProbeTransformToNodeId(imageToProbe.GetID())

You can use the fiducial registration wizard module GUI for testing and troubleshooting, but it should not be necessary to select a specific node in the node selector fiducial registration, because the user will use your module’s GUI (that shows all the controls he needs and only those).

Can you explain what is the end goal that you would like to achieve?

In general I’m trying to simplify a calibration for US probe, but more specific - user needs to jump between several modules a lot of times. For this, I extracted buttons from Fiducial registration wizard and placed them on the my new module canvas. I want to avoid user interaction with all these extra settings from fiducial wizard module. For example, generate automatically all “To” points after user had specifies all “From”. I don’t want to show to users all possible options from Fiducial GUI and restrict it as much as possible. That’s why I want to select from the created nodes

That’s great. I think we’ve planned to implement such a module but did not end up doing it (@ungi can you confirm?).

It seems that you are on a good path. You create a vtkMRMLFiducialRegistrationWizardNode from your module and add the minimum necessary buttons to your module GUI. All algorithms (add a fiducial point based on a transform, compute registration, etc.) are implemented in the fiducial registration wizard module logic (accessible as slicer.modules.fiducialregistrationwizard.logic()). For example, you can add fiducials or compute registration result by calling logic methods. You module or your users will not use fiducial registration wizard module widget (GUI) at all.

Correct. We were thinking about a simple ultrasound calibration module. But nobody implemented it yet. Ultrasound calibration is not needed very often. And those users who need a simple GUI (doctors) should probably use a different calibration method, like the one with N-shaped wires. So, there was never a very strong reason to implement a simplified module.

Thank you, Andras!
But I really looked into module logic and i could not find there a method to compute the transformations or for the change of transform type. This function names are just not self-explanatory to me. I added buttons for user to set up From by mouse clicks:

imageF = slicer.qSlicerMarkupsPlaceWidget()
imageF.setMRMLScene(slicer.mrmlScene)
markupsNodeID = slicer.modules.markups.logic().AddNewFiducialNode('ImageF')
imageF.setCurrentNode(slicer.mrmlScene.GetNodeByID(markupsNodeID))
imageF.placeButton().show()
imageF.show()
fiducialFormLayout.addWidget(imageF)

Next, after all points are selected on the sequence, i want to place fiducials using transform, but it does not work from the python script, only works from the console:

    fidReg = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLFiducialRegistrationWizardNode", "Fiducial")
    toFids = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsFiducialNode", "ProbeF")
    imageToProbe = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLLinearTransformNode", "ImageToProbe")

    fidReg.SetRegistrationModeToSimilarity()
    fidReg.SetProbeTransformToNodeId(imageToProbe.GetID())

What i’m missing here?

All computation parameters are stored in the fiducial registration wizard node, so you can set registration mode, etc. there. Logic functions are only needed for actions: computing transformation (using UpdateCalibration, if auto-update is disabled) and adding fiducials (AddFiducial).

See how to add fiducial using the module logic here.

See how to compute the registration transform here.

I don’t have attribute slicer.qSlicerFiducialRegistrationWizardModuleWidget() to access all the logic,
neither methods that you linked in github are not accesible from slicer.modules.fiducialregistrationwizard.logic()

You don’t need to access the GUI. That is only for the user and the fiducial registration wizard module.

I’ve just checked on Slicer-4.10.2 and both AddFdiucial and UpdateCalibration methods of the logic object are available from Python. Did you get an error message when you tried to use them?

But you provided this link as an example how to add transformed fiducial using the module logic. So I want still user to add “From” fiducials, but avoid the user to select the transformation and place fiducials “To” using transforms via code. I don’t see how AddFdiucial and UpdateCalibration methods can help me here, for this i need to access logic from qSlicerFiducialRegistrationWizardModuleWidget.

It is not necessary to call methods of any other module’s widget. All the features that are meant to be used by other modules are implemented in a module’s logic.

The code snippets that I linked show examples of how to use the logic to add new fiducial from transform. I did not suggest to try and call those widget methods from another module.

You already know the transform and markup fiducial nodes in your module (most probably your module creates them and uses them; but if you want, you may also expose it on your module GU). Therefore, based on the example that I linked, to add a fiducial you just need to call this logic method:

slicer.modules.fiducialregistrationwizard.logic().AddFiducial(probeToTransformNode, toMarkupsNode)
1 Like

Oh finally i get it!
Thank you so much for your help and patience!

1 Like

A while ago I played around with making a simple interface for ultrasound calibration in Slicer using the pointer-based method: https://github.com/mholden8/UltrasoundCalibrationWizard/tree/master/PointerBasedUSCalibration. @zapaishchykova you may consider using it as a starting point, but I cannot recall how well it works…

2 Likes