I did a quick test, downloaded uberon-full.json
and wrote this little script to convert all anatomical structures into a Slicer terminology json file.
uberonFile = "path/to/uberon-full.json"
terminologyFile = "path/to/uberon.term.json"
import json
import random
with open(uberonFile, 'r', encoding='utf-8') as file_object:
uberon = json.load(file_object)
types = []
for node in uberon["graphs"][0]["nodes"]:
if not node["id"].startswith("http://purl.obolibrary.org/obo/UBERON_"):
continue
if not node.get("lbl"):
# deprecated
continue
types.append({
"CodingSchemeDesignator": "UBERON",
"CodeValue": node["id"].split("_")[-1],
"CodeMeaning": node["lbl"],
"recommendedDisplayRGBValue": [random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)]
})
terminology = {
"SegmentationCategoryTypeContextName": "Segmentation category and type - Uberon anatomical structures",
"@schema": "https://raw.githubusercontent.com/qiicr/dcmqi/master/doc/segment-context-schema.json#",
"SegmentationCodes": {
"Category": [
{
"CodingSchemeDesignator": "SCT", "CodeValue": "123037004", "CodeMeaning": "Anatomical Structure",
"showAnatomy": False,
"Type": types
}
]
}
}
with open(terminologyFile, "w") as f:
json.dump(terminology, f, indent=4)
The result is a small file containing 15574 structures. You can download it from here. You can drag-and-drop it into Slicer and you have all UBERON terms readily selectable - no chance for typos, no need to manually copy codes, etc.
Slicer terminology selector was a bit slow (filtering by name took a few seconds), but after some optimization it is now very fluid. I’ve submit a pull request with the changes, it should be available in the Slicer Preview Release within a few days.
There are a few limitations of this approach:
- The terminology browser in Slicer currently does not use an ontology (shows just a flat list, not possible to jump to parent or get a list of children), so it may be difficult to find the right term. However, you can use the online UBERON browser to explore the various ontologies and find the right term, which you can then very easily find by name in Slicer.
- I’m not sure if you need modifiers. If yes, then you need to find an automated way to figure out what modifiers are relevant for what structures. Maybe something simple like adding
left
and right
modifier to every type that does not have left or right in the name already could cover what is needed.
- Color is now generated randomly. It could make sense to get generic color from the ontologies (e.g., bones are white/yellow, muscles red, arteries deep red, veins blue, etc. maybe with some randomization)
To make the selection easier, it may make sense to also create smaller terminology files for specific projects that contains a subset of this full list. This subset file would have a unique SegmentationCategoryTypeContextName
, for example SlicerMorph Dentition
. I would keep the Anatomical Structure
category for DICOM compatibility. showAnatomy
has to be set to false for anatomical structures (it only makes sense to specify anatomical region selector if the type is not an anatomical structure, e.g., if the type is a needle
then you can specify the anatomical region it is in). I don’t think you need to use modifiers (the UBERON codes seem to usually include it). I would drop all the attributes that you don’t use (context group name, cid, etc.).
It would look something like this:
{
"SegmentationCategoryTypeContextName": "SlicerMorph Dentition",
"@schema": "https://raw.githubusercontent.com/qiicr/dcmqi/master/doc/schemas/segment-context-schema.json#",
"SegmentationCodes": {
"Category": [
{
"CodingSchemeDesignator": "SCT",
"CodeValue": "123037004",
"CodeMeaning": "Anatomical Structure",
"showAnatomy": false,
"Type": [
{
"recommendedDisplayRGBValue": [ 0, 179, 92 ],
"CodeValue": "100022",
"CodingSchemeDesignator": "UBERON",
"CodeMeaning": "Maxillary Molar 1",
"3dSlicerLabel": "maxillary molar 1",
"Modifier": [
{
"recommendedDisplayRGBValue": [0, 179, 92 ],
"CodingSchemeDesignator": "SCT",
"CodeValue": "24028007",
"CodeMeaning": "Right",
"3dSlicerLabel": "right maxillary molar 1",
},
...
]
}
]
}
]
}
}
...