lassoan / slicerio

Utilities for reading and writing files created by 3D Slicer
MIT License
34 stars 3 forks source link

Util for creating a `.seg.nrrd` based on existing nrrd + segment names #9

Closed kretes closed 6 months ago

kretes commented 1 year ago

Maybe that's something obvious but what I just needed was a simple tool to name the segments in nrrd.

It turned out that this works to create a valid seg.nrrd for Slicer:

from pathlib import Path
import nrrd

def add_segments(nrrd_data, nrrd_header, segment_names):
    assert len(segment_names) == nrrd_data.shape[0]
    for segment_index, segment_name in enumerate(segment_names):
        prefix = "Segment{0}_".format(segment_index)
        nrrd_header[prefix + "ID"]=str(segment_index)
        nrrd_header[prefix + "Name"]=segment_name
        nrrd_header[prefix + "ColorAutoGenerated"]=1
        nrrd_header[prefix + "LabelValue"]=1
        nrrd_header[prefix + "Layer"]=segment_index
    return nrrd_header

def add_segments_to_nrrd(nrrd_input_path, segment_names):
    nrrd_input_path = Path(nrrd_input_path)
    nrrd_output_path = nrrd_input_path.with_suffix(".seg.nrrd")

    nrrd_data, nrrd_header = nrrd.read(nrrd_input_path)
    new_header = add_segments(nrrd_data, nrrd_header, segment_names)
    with open(nrrd_output_path, "wb") as f:
        nrrd.write(f, nrrd_data, new_header)

Leaving it here for others finding the same need. Would this be something worth adding in this or extended way to slicerio ?

lassoan commented 1 year ago

Thanks for sharing this code. We definitely need to add functions for creating .seg.nrrd files from scratch. Your code looks nice, but it would need to be extended with at least these two features before I would promote it as the way of creating segmentations:

kretes commented 1 year ago

Thanks for the reply!

Shared labelmap makes sense, I will switch to this style for my needs as well. I will post the updated version that will let the user control this behaviour.

Terminologies seems like something that should be done on top of this util. It just defines the segment_names. In my use case segment nnames are dynamic, as I generate seg.nrrd to understand predictions from a nodule detection model. So I put there some metadata like model's confidence.

lassoan commented 1 year ago

It is better not to pollute the segment name with additional metadata. You can put extra information in segment tags (key/value pairs).

These tags are easily accessible in Slicer for Python scripts.

Currently, the tags are only shown in the Data module, but we could also think about making it more easily accessible (maybe show selected tag values in additional columns in the segment list?). In the meantime, you can write a short Python script to retrieve the tags and display them somewhere.

lassoan commented 6 months ago

This feature is available now - see example here: https://github.com/lassoan/slicerio?tab=readme-ov-file#create-segmentation-file-from-numpy-array