Hello,
I am looking to add a button in my extension GUI. The button should allow a user to click somewhere on the volume to retrieve the input value where is clicked.
Can someone say if it’s possible ? In Python.
Thank you,
zenox
Hello,
I am looking to add a button in my extension GUI. The button should allow a user to click somewhere on the volume to retrieve the input value where is clicked.
Can someone say if it’s possible ? In Python.
Thank you,
zenox
Without knowing the purpose and details of your module, I’d probably add a markups fiducial list that the user fills with clicking around. Then you can very easily get the voxel value under those fiducials.
@cpinter, Thank you very much for your answer.
The purpose is just to retrieve the value of input where the user clicked somewhere in a volume.
I will look at the official documentation to find an example of code, then try to implement this feature in my module.
Yes but the best way to do it could be very different depending of the bigger picture (real-time or not - interaction vs analysis, number of points, etc.), so it could be useful if you described the purpose of the module and the value picking.
Ok, the goal is to retrieve the value of 1 point to adjust my GUI and help the user of the extension. And this is not for real-time.
For example, if user clicked on input value = 1125, we will adjust the Thresold Range cursors (A) with +/- 125, so between 1000 and 1250.
We usually use temporary markup nodes for this:
@lassoan, Thank you very much for your answer.
Now, that’s more clear for me.
I will come back here if I don’t find a way to implement it in my module.
Have a good day,
zenox
You can use qSlicerMarkupsPlaceWidget to all the steps that I described above. The code below creates a button that places a markup (and it also provides signals that you can observe):
# Temporary markups node
markupsNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsFiducialNode")
def placementModeChanged(active):
print("Placement: " +("active" if active else "inactive"))
# You can inspect what is in the markups node here, delete the temporary markup node, etc.
# Create and set up widget that contains a single "place markup" button. The widget can be placed in the module GUI.
placeWidget = slicer.qSlicerMarkupsPlaceWidget()
placeWidget.setMRMLScene(slicer.mrmlScene)
placeWidget.setCurrentNode(markupsNode)
placeWidget.buttonsVisible=False
placeWidget.placeButton().show()
placeWidget.connect('activeMarkupsFiducialPlaceModeChanged(bool)', placementModeChanged)
placeWidget.show()
@lassoan, This is really helpful, thank you ! Now, it should be easy enough to implement, I’ll let you know if it works.
It works, but opens a new window with the button.
Do you know how I could attach it to my “Get Value” button in the GUI ?
I define my widget to display a button:
def setup(self):
self.getValueButton = qt.QPushButton("Get Value")
self.getValueButton.toolTip = "Get value from image"
self.getValueButton.enabled = False
self.getValueButton.connect('clicked(bool)', self.onGetValueButton)
A function to create a markup node, switch to Place fiducial mode and retrieve click position:
def getMousePointValue(self):
return position
A function connected to my button:
def onGetValueButton(self):
position = self.getMousePointValue()
Instead of calling show()
method, add the widget to your module’s GUI the same way as you add any other buttons and widgets.
@lassoan, Oh obviously… it works ! And I can retrieve markup’s position without problem.
In the screenshot of my first post, I have 2 volumes (input.nrrd and segmentation.nrrd).
I don’t find a way to retrieve the input value (here 1125) at markup’s position, have you an idea ?
See example in the script repository: Documentation/Nightly/ScriptRepository - Slicer Wiki
Ok, I can retrieve the voxel coordinates of my input volume without problem. But I don’t know how to access the value with theses coordinates, like volume[x, y , z] = 1125 ? Sorry, I’m really a noob with Slicer.
You just need to use slicer.utils.array
to get a numpy array, and then you can index into it.
I put a part of code here, that could help others in the futur:
def getMousePointValue(self, volumeNode, markupsNode):
# Get point coordinate in RAS
point_ras = [0, 0, 0, 1]
# Get number of markups
num_fids = markupsNode.GetNumberOfFiducials()
# Get coordinates of last markup
markupsNode.GetNthFiducialWorldCoordinates(num_fids - 1, point_ras)
# Apply that transform to get volume's RAS coordinates
transform_ras_to_volume_ras = vtk.vtkGeneralTransform()
slicer.vtkMRMLTransformNode.GetTransformBetweenNodes(None, volumeNode.GetParentTransformNode(), transform_ras_to_volume_ras)
point_volume_ras = transform_ras_to_volume_ras.TransformPoint(point_ras[0:3])
# Get voxel coordinates from physical coordinates
volume_ras_to_ijk = vtk.vtkMatrix4x4()
volumeNode.GetRASToIJKMatrix(volume_ras_to_ijk)
point_ijk = [0, 0, 0, 1]
volume_ras_to_ijk.MultiplyPoint(np.append(point_volume_ras, 1.0), point_ijk)
point_ijk = [ int(round(c)) for c in point_ijk[0:3] ]
# Get markup's position
x, y, z = point_ijk[0], point_ijk[1], point_ijk[2]
# Get volume as slicer array
a = arrayFromVolume(volumeNode)
# Get value at markup's position
value = a[z,y,x]