Skip to content

Commit

Permalink
Simplify segmentation API and add support for terminologies
Browse files Browse the repository at this point in the history
Segmentation methods now take a single segmentation object (dict) that contains both voxels and metadata.

Added functions to:
- create segmentation object from scratch
- write segmentation object to file
- extract segments from a segmentation based on terminology codes
  • Loading branch information
lassoan committed May 8, 2024
1 parent 0380bb9 commit f3cb324
Show file tree
Hide file tree
Showing 4 changed files with 918 additions and 102 deletions.
99 changes: 92 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,49 @@ pip install slicerio
import slicerio
import json

segmentation_info = slicerio.read_segmentation_info("Segmentation.seg.nrrd")
segmentation = slicerio.read_segmentation("path/to/Segmentation.seg.nrrd", skip_voxels=True)

number_of_segments = len(segmentation_info["segments"])
number_of_segments = len(segmentation["segments"])
print(f"Number of segments: {number_of_segments}")

segment_names = slicerio.segment_names(segmentation_info)
segment_names = slicerio.segment_names(segmentation)
print(f"Segment names: {', '.join(segment_names)}")

segment0 = slicerio.segment_from_name(segmentation_info, segment_names[0])
segment0 = slicerio.segment_from_name(segmentation, segment_names[0])
print("First segment info:\n" + json.dumps(segment0, sort_keys=False, indent=4))
```

### Extract selected segments with chosen label values

#### Extract segments by terminology

Example for getting a 3D NRRD file that has label values assigned based on standard terminology codes.
Terminology is a `dict` that must specify `category` and `type` codes and may optionally also specify `typeModifier`, `anatomicRegion`, and `anatomicRegionModifier`. Each code is specifed by a triplet of "coding scheme designator", "code value", "code meaning" in a list.

Coding scheme designator is typically `SCT` (SNOMED-CT) for clinical images. You can find codes in the [SNOMED-CT browser](https://browser.ihtsdotools.org/). When code exists for "entire X" and "structure of X" then always use the "structure" code ("entire" code has a very strict meaning that is rarely applicable in practice).

Code meaning (third component of codes, such as "Anatomical Structure", "Ribs", "Right") is informational only, it can be used for troubleshooting or displayed to the user, but it is ignored in information processing (e.g., two codes match if their coding scheme designator and code value are the same even if code meaning is different).

```python
import slicerio
import nrrd

input_filename = "path/to/Segmentation.seg.nrrd"
output_filename = "path/to/SegmentationExtracted.seg.nrrd"
segments_to_labels = [
({"category": ["SCT", "123037004", "Anatomical Structure"], "type": ["SCT", "113197003", "Ribs"]}, 1),
({"category": ["SCT", "123037004", "Anatomical Structure"], "type": ["SCT", "39607008", "Lung"], "typeModifier": ["SCT", "24028007", "Right"]}, 3)
]

segmentation = slicerio.read_segmentation(input_filename)
extracted_segmentation = slicerio.extract_segments(segmentation, segments_to_labels)
slicerio.write_segmentation(extracted_segmentation, output_filename)
```

#### Extract segments by name

It is strongly recommended to look up segments by standard terminology codes instead of segment name, as spelling errors and inconsistent use of names often causes mismatch.

```python
import slicerio
import nrrd
Expand All @@ -46,9 +75,65 @@ input_filename = "path/to/Segmentation.seg.nrrd"
output_filename = "path/to/SegmentationExtracted.seg.nrrd"
segment_names_to_labels = [("ribs", 10), ("right lung", 12), ("left lung", 6)]

voxels, header = nrrd.read(input_filename)
extracted_voxels, extracted_header = slicerio.extract_segments(voxels, header, segmentation_info, segment_names_to_labels)
nrrd.write(output_filename, extracted_voxels, extracted_header)
segmentation = slicerio.read_segmentation(input_filename)
extracted_segmentation = slicerio.extract_segments(segmentation, segment_names_to_labels)
slicerio.write_segmentation(extracted_segmentation, output_filename)
```

### Create segmentation file from numpy array

```python
# Create segmentation with two labels (1, 3)
voxels = np.zeros([100, 120, 150])
voxels[30:50, 20:60, 70:100] = 1
voxels[70:90, 80:110, 60:110] = 3

# Image geometry
spacing = [0.5, 0.5, 0.8]
origin = [10, 30, 15]

segmentation = {
"voxels": voxels,
"image": {
"encoding": "gzip",
"ijkToLPS": [[ spacing[0], 0., 0., origin[0]],
[ 0., spacing[1], 0., origin[1]],
[ 0., 0., spacing[2], origin[2]],
[ 0., 0., 0., 1. ]]
},
"segmentation": {
"containedRepresentationNames": ["Binary labelmap", "Closed surface"],
# "masterRepresentation": "Binary labelmap",
# "referenceImageExtentOffset": [0, 0, 0],
},
"segments": [
{
"id": "Segment_1",
"labelValue": 1,
"layer": 0,
"color": [0.9, 0.9, 0.6],
"name": "ribs",
"terminology": {
"contextName": "Segmentation category and type - 3D Slicer General Anatomy list",
"category": ["SCT", "123037004", "Anatomical Structure"],
"type": ["SCT", "113197003", "Rib"] }
},
{
"id": "Segment_2",
"labelValue": 3,
"layer": 0,
"color": [0.9, 0.9, 0.6],
"name": "spine",
"status": "inprogress",
"terminology": {
"contextName": "Segmentation category and type - 3D Slicer General Anatomy list",
"category": ["SCT", "123037004", "Anatomical Structure"],
"type": ["SCT", "122494005", "Cervical spine"] }
},
]
}

slicerio.write_segmentation(segmentation, "path/to/Segmentation.seg.nrrd")
```

### View files in 3D Slicer
Expand Down
5 changes: 3 additions & 2 deletions slicerio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
"""

from .segmentation import extract_segments, read_segmentation_info, segment_from_name, segment_names
from .segmentation import extract_segments, read_segmentation, write_segmentation, segment_from_name, segment_names
from .data_helper import get_testdata_file
from ._version import __version__, __version_info__

__all__ = [
'extract_segments',
'get_testdata_file',
'read_segmentation_info',
'read_segmentation',
'write_segmentation',
'segment_from_name',
'segment_names',
'__version__',
Expand Down
Loading

0 comments on commit f3cb324

Please sign in to comment.