How to get input value from mouse click?


#1

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


(Csaba Pinter) #2

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.


#3

@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.


(Csaba Pinter) #4

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.


#5

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.

  • First, the user clicks on a button Get Value (B)
  • Then, in the background, there is a listener that allows user to click somewhere in the volume and get input value
  • Finally, we adjust the Threshold Range cursors (A) with this input value in the GUI

For example, if user clicked on input value = 1125, we will adjust the Thresold Range cursors (A) with +/- 125, so between 1000 and 1250.


(Andras Lasso) #6

We usually use temporary markup nodes for this:

  • User clicks “Get value” button
  • Module creates a markup node, adds an observer for point add event, sets the node as active node (in selection node singleton) and sets mouse interaction mode to Place fiducial mode (in interaction node singleton)
  • User clicks in the image
  • Module is notified about the added fiducial, retrieves its position, then deletes the markup node

#7

@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


(Andras Lasso) #8

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()

#9

@lassoan, This is really helpful, thank you ! Now, it should be easy enough to implement, I’ll let you know if it works.


#10

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()

(Andras Lasso) #11

Instead of calling show() method, add the widget to your module’s GUI the same way as you add any other buttons and widgets.


#12

@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 ?


(Andras Lasso) #13

See example in the script repository: https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#Get_volume_voxel_coordinates_from_markup_fiducial_RAS_coordinates


#14

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.


(Steve Pieper) #15

You just need to use slicer.utils.array to get a numpy array, and then you can index into it.

https://www.slicer.org/wiki/Documentation/Nightly/Developers/Python_scripting#Accessing_Volume_data_as_numpy_array

https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#Get_the_values_of_all_voxels_for_a_label_value


#16

Thank you very much @pieper and @lassoan, all is working.


#17

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]