Apply paint using code

I want to put sphere brushes (i want to use paint) on scenes with given coordinates. But i couldnt find a way to use paint effect from segment editor in code. How can i use paint in code and paint the scene just in code().I’ve tried this. but it uses grow from seeds and i dont want that. I just want to paint.

I also tried this but giving me error.

segmentEditorWidget.setActiveEffectByName("Paint")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("BrushRelativeDiameter", "1")  # Brush size relative to the volume size
effect.setParameter("BrushSphere", "1")  # Use a spherical brush
effect.paintApply((255, 255, 674))

The code section you have found is perfect, that’s all you need to do. You can ignore the rest of the script.


I can see the spheres in the 3d view. But i cant see them on the slice views. I tried many times, but it doesnt appear.


masterVolumeNode = volumeNode = slicer.mrmlScene.GetFirstNodeByClass("vtkMRMLScalarVolumeNode")

segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")
segmentationNode.CreateDefaultDisplayNodes() # only needed for display
segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode)

# Create seed segment inside tumor
tumorSeed = vtk.vtkSphereSource()
tumorSeed.SetCenter(255, 255, 494)
tumorSeed.SetRadius(10)
tumorSeed.Update()
segmentationNode.AddSegmentFromClosedSurfaceRepresentation(tumorSeed.GetOutput(), "Tumor", [1.0,0.0,0.0])

# Create seed segment outside tumor
backgroundSeedPositions = [[255, 260, 494], [255, 265, 494], [255, 270, 494], [255, 275, 494], [255, 280, 494], [255, 285, 494]]
append = vtk.vtkAppendPolyData()
for backgroundSeedPosition in backgroundSeedPositions:
  backgroundSeed = vtk.vtkSphereSource()
  backgroundSeed.SetCenter(backgroundSeedPosition)
  backgroundSeed.SetRadius(10)
  backgroundSeed.Update()
  append.AddInputData(backgroundSeed.GetOutput())

append.Update()
backgroundSegmentId = segmentationNode.AddSegmentFromClosedSurfaceRepresentation(append.GetOutput(), "Background", [0.0,1.0,0.0])

This is the code i tried last, coordinates are close to the center in the green slice view but i cant see any paint in slice.
Is there a way to solve this? Or how can i use paint effect? Thanks.

I see you decided to go a different way. This should work as well, but I never used AddSegmentFromClosedSurfaceRepresentation so not sure what it does exactly. When I do this, I tend to create a model node and use slicer.vtkSlicerSegmentationsModuleLogic.ImportModelToSegmentationNode.

As your code does not specify a closed surface representation, the default binary labelmap should be created from the added polydata segments, so not sure. It is always possible that the locations are not correct, so please verify by showing the slices in 3D (or volume render). I’d also check the representations part in the Segmentations module and see what is the master, and also check which representation is shown in 2D (in Display / Advanced I believe). Try to show the closed surface representation in 2D if it is the master for some reason.

Thanks for the reply.

With these 3d spheres, this point markup F1 on the screen, when i put my cursor, looks like around 255,255,494 as you can see in the image(bottom-left). But it doesnt show on the axial slice any paint while showing on the 3d.

When i look at one slice and sphere paints in 3d, it looks like im giving the coordinates wrong. Where should i get the coordinates from?

image

My main goal is to put 2d sphere brushes on some axial slices at the corners. So that it looks quarter sphere on the 3d. So my main goal is to put 2d spheres with paint on axial slice with code, but i cant find any example using paint effect. It should look like this.

It seems that the centerpoint coordinates are not set correctly. If you create an example scene from one of the Slicer sample data sets and share that with us (saved as .mrb, uploaded to dropbox/onedrive/googledrive) and corresponding code snippet then we can tell where things went wrong.

What would you like to segment?

# Generate input data
################################################

masterVolumeNode = volumeNode = slicer.mrmlScene.GetFirstNodeByClass("vtkMRMLScalarVolumeNode")

# Load master volume

# Create segmentation
segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")
segmentationNode.CreateDefaultDisplayNodes() # only needed for display
segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode)

 



start_value = 170
increment = 40
num_iterations = 20

paint_positions = []

for i in range(num_iterations):
    third_element = start_value + i * increment
    paint_positions.extend([
        [0, 0, third_element],
        [0, 511, third_element],
        [511, 0, third_element],
        [511, 511, third_element]
    ])

append = vtk.vtkAppendPolyData()
for paint_position in paint_positions:
  print(paint_position)
  paintSphere = vtk.vtkSphereSource()
  paintSphere.SetCenter(paint_position)
  paintSphere.SetRadius(10)
  paintSphere.Update()
  append.AddInputData(paintSphere.GetOutput())
  
append.Update()

segmentationNode.AddSegmentFromClosedSurfaceRepresentation(append.GetOutput(), "Paint", [1.0,0.0,0.0])

# Run filter
################################################

# Create segment editor to get access to effects
segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
# To show segment editor widget (useful for debugging): segmentEditorWidget.show()
segmentEditorWidget.setMRMLScene(slicer.mrmlScene)

segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentEditorNode")
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
segmentEditorWidget.setSegmentationNode(segmentationNode)
segmentEditorWidget.setSourceVolumeNode(masterVolumeNode)

 
# Clean up and show results
################################################

# Clean up
slicer.mrmlScene.RemoveNode(segmentEditorNode)

# Make segmentation results nicely visible in 3D
segmentationDisplayNode = segmentationNode.GetDisplayNode()

I am segmenting successfully using threshold in other code but i need to put spheres around the corners before exporting this segmentation model as you can see in the previous photos with 4 green quarter spheres, i did that manually but i have to do it in code. I couldnt manage to do that. Seems simple actually, just 4 paint brush in some slices corners in axial view :expressionless:

The problem is that you specified the sphere center positions in voxel (IJK) coordinate system. In the code snippet above the positions are expected in patient (RAS) coordinate system. You can find examples in the script repository how to convert. Alternatively, in a special case like this when you want to paint borders you can get segmentation as a numpy array and modufy that using voxel indices (see examples in script repository).


Thank you very much. Now i converted coordinates and it puts the spheres on axial slices and i can see it. But what i really want is put sphere brushes with paint on corners so only quarter of sphere is shown in 3d view, like above two images with green quarter spheres.

You can set the segment geometry to not include the entire spheres. By the way, if you drew 4 tubes instead of hundreds of spheres then processing could be 100x faster. Or, if you just want to fill the corners then you can use numpy to modify the segment (e.g., segArray[0:5, 0:5] = 1).

I want to fill the corners with sphere paint brush in axial slice.

segArray[0:5, 0:5] = 1

i didnt understand this. Are these 0 and 5 signify slice number? and what does assigning 1 do?

segArray is a numpy array. The code sets the corner voxels to 1 in all axial slices (I think you can use any positive value). See a complete example here.