Create a script to use TotalSegmentator from script for 2 small tasks

Hi,
I have a small project and being pretty new to programming, I’m having difficulties finding the right code to call some option.

Let me describe what I’m trying to do and the steps. I also have an other question not absolutely related to this subject, but if some of you want to help, always appreciated.

I need to segment the Femur, patela, fibulla and tibia of a CT scan. The best option I found was TotalSegmentator. To do so, I do a first segmentation with total to get the femur (as it’s separated from the appendicular bone licenced bones segmented). I run it on normal (not fast to get the best quality). I then have a segmentation of multiple bones with the femur.

I then return to TotalSegmentator, select “Appendicular bones” for the segmentation of tibia, patella and fibulla and run it on normal without forgetting the “Create new segmentation on Apply” option. This creates a new segmentation with all the bones with the three of interest.

I then want to move the bones I want in the second segmentation and the ones to delete in the first.

So in step, my scripts need to do these :

  1. Segmentation task → total
  2. Apply
  3. select normal mode
  4. wait for segmentation to finish
  5. segmentation task → appendicular …
  6. Segmentation → Create new segmentation on Apply
  7. Apply
  8. wait for segmentation to finish
  9. move the desired segmentation to second group and move unwanted in first group

To give you an idea of my level of programming, here’s what I got so far
slicer.util.selectModule(“TotalSegmentator”)

All help is welcomed!

After a week, I arrived to this script. It runs TotalSegmentator on “Total” and “Appendicular bones” and keeps only the interested bones. Finally, it changes the name of certain bones to uniform the names.

Here it is for future reference :
import slicer
from qt import QProgressDialog

slicer.app.pythonConsole().clear()

def show_progress(message):
“”“Display modal progress dialog.”“”
progress = QProgressDialog()
progress.setLabelText(message)
progress.setCancelButton(None)
progress.setWindowModality(2) # ApplicationModal
progress.setMinimum(0)
progress.setMaximum(0)
progress.show()
slicer.app.processEvents()
return progress

def run_total_segmentator(volumeNode, task, segmentationName, fast=True):
logic = slicer.modules.totalsegmentator.widgetRepresentation().self().logic
segmentationNode = slicer.mrmlScene.AddNewNodeByClass(“vtkMRMLSegmentationNode”, segmentationName)

progress = show_progress(f"Running TotalSegmentator: {task}...")
logic.process(
    inputVolume=volumeNode,
    outputSegmentation=segmentationNode,
    task=task,
    fast=fast
)
progress.close()
print(f"✅ Finished: {segmentationName}")
return segmentationNode

Step 1 – Get the first scalar volume in the scene

volumeNode = slicer.mrmlScene.GetFirstNodeByClass(“vtkMRMLScalarVolumeNode”)
if not volumeNode:
raise RuntimeError(“:cross_mark: No scalar volume found in the scene.”)

Step 2 – Run first segmentation with task=“total”

seg1 = run_total_segmentator(volumeNode, task=“total”, segmentationName=“Seg_Total”, fast=False)

Step 3 – Run second segmentation with task=“appendicular_bones”

seg2 = run_total_segmentator(volumeNode, task=“appendicular_bones”, segmentationName=“Seg_Appendicular”, fast=False)

print(“:white_check_mark: Both segmentations complete. ‘Seg_Appendicular’ is now visible.”)

Step 4 - Remove all unnecessary segments except Fibula, Tibia, Fémur and Patella

Keywords to keep (case-insensitive)

keywords_to_keep = [‘left femur’, ‘patella’, ‘tibia’, ‘fibula’]

Create new segmentation node to collect matching segments

newSegNode = slicer.mrmlScene.AddNewNodeByClass(“vtkMRMLSegmentationNode”, “FilteredSegments”)

Ensure it has a display node

if not newSegNode.GetDisplayNode():
newSegNode.CreateDefaultDisplayNodes()

Get all existing segmentation nodes BEFORE creating the new one

existingSegmentNodes = list(slicer.util.getNodes(‘vtkMRMLSegmentationNode*’).values())

Loop through original segmentation nodes only

for segNode in existingSegmentNodes:
if segNode == newSegNode:
continue

segmentation = segNode.GetSegmentation()
segmentIdsToCopy = []

# Identify segments to keep
for i in range(segmentation.GetNumberOfSegments()):
    segmentId = segmentation.GetNthSegmentID(i)
    segmentName = segmentation.GetSegment(segmentId).GetName()
    segmentNameLower = segmentName.lower()
    if any(keyword in segmentNameLower for keyword in keywords_to_keep):
        print(f"Keeping segment: {segmentName}")
        segmentIdsToCopy.append(segmentId)
    else:
        print(f"Discarding segment: {segmentName}")

# Copy segments to new node and rename if needed
for segmentId in segmentIdsToCopy:
    existingSegmentIds = set(newSegNode.GetSegmentation().GetSegmentIDs())
    success = newSegNode.GetSegmentation().CopySegmentFromSegmentation(segmentation, segmentId)
    if success:
        newSegmentIds = set(newSegNode.GetSegmentation().GetSegmentIDs()) - existingSegmentIds
        if newSegmentIds:
            newSegmentId = newSegmentIds.pop()
            originalName = segmentation.GetSegment(segmentId).GetName().lower()
            if 'left femur' in originalName:
                newSegNode.GetSegmentation().GetSegment(newSegmentId).SetName('Femur')
            elif 'tibia' in originalName:
                newSegNode.GetSegmentation().GetSegment(newSegmentId).SetName('Tibia')

# Remove original segmentation node from scene
print(f"Removing original segmentation node: {segNode.GetName()}")
slicer.mrmlScene.RemoveNode(segNode)