Skip to content

Commit 9c41a5a

Browse files
authored
Merge pull request #454 from zivy/multiSegmentationOverlay
Adding function for overlaying multiple segmentations onto image.
2 parents 69d38da + d81bfb6 commit 9c41a5a

File tree

1 file changed

+106
-2
lines changed

1 file changed

+106
-2
lines changed

Python/05_Results_Visualization.ipynb

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@
925925
"cell_type": "markdown",
926926
"metadata": {},
927927
"source": [
928-
"## Comparing two segmentations\n",
928+
"## Comparing segmentations\n",
929929
"\n",
930930
"In this section we show how to create a binary image illustrating all the locations where two segmentations differ. This is a trivial one liner in SimpleITK.\n",
931931
"\n",
@@ -935,7 +935,9 @@
935935
{
936936
"cell_type": "code",
937937
"execution_count": null,
938-
"metadata": {},
938+
"metadata": {
939+
"scrolled": true
940+
},
939941
"outputs": [],
940942
"source": [
941943
"binary_dilate_filter = sitk.BinaryDilateImageFilter()\n",
@@ -986,6 +988,108 @@
986988
")"
987989
]
988990
},
991+
{
992+
"cell_type": "markdown",
993+
"metadata": {},
994+
"source": [
995+
"When dealing with **multiple binary** segmentations we can overlay the boundaries onto the original image as shown below."
996+
]
997+
},
998+
{
999+
"cell_type": "code",
1000+
"execution_count": null,
1001+
"metadata": {},
1002+
"outputs": [],
1003+
"source": [
1004+
"def overlay_segmentations(\n",
1005+
" image,\n",
1006+
" binary_segmentations,\n",
1007+
" thickness,\n",
1008+
" dilation_radius,\n",
1009+
" colors=[\n",
1010+
" [230, 159, 0], # orange\n",
1011+
" [86, 180, 233], # sky blue\n",
1012+
" [0, 158, 115], # bluish green\n",
1013+
" [240, 228, 66], # yellow\n",
1014+
" [0, 114, 178], # blue\n",
1015+
" [213, 94, 0], # vermilion\n",
1016+
" [204, 121, 167], # reddish purple\n",
1017+
" [153, 153, 153], # gray\n",
1018+
" ],\n",
1019+
"):\n",
1020+
" \"\"\"\n",
1021+
" Parameters\n",
1022+
" ----------\n",
1023+
" image (SimpleITK.Image): Image on which to overlay segmentations. Expected to be a scalar image with a pixel type of sitkUInt8.\n",
1024+
" binary_segmentations (Iterable[SimpleITK.Image]):\n",
1025+
" thickness (Tuple): Thickness of contour or surface along each axis (data is 2D or 3D).\n",
1026+
" dilation_radius (Tuple): Dilation radius along each axis.\n",
1027+
" colors (Iterable[Tuple(3)]): Color to use for each binary segmentation (except black [0,0,0]).\n",
1028+
" The iterable is expected to contain a set of colors with at least as\n",
1029+
" many entries as the binary segmentations. If not, a\n",
1030+
" ValueError is raised. Default setting is the colorblind friendly\n",
1031+
" Okabe-Ito palette minus the first entry which is black\n",
1032+
" (M. Okabe, K. Ito, \"Color universal design (CUD): How to make\n",
1033+
" figures and presentations that are friendly to colorblind people\", 2008.).\n",
1034+
" Returns\n",
1035+
" -------\n",
1036+
" SimpleITK.Image - Original image with segmentation contours/surfaces overlaid onto it in color.\n",
1037+
"\n",
1038+
" Raises\n",
1039+
" ------\n",
1040+
" ValueError - If the number of entries in the colors iterable is less than the number of binary segmentations.\n",
1041+
"\n",
1042+
" \"\"\"\n",
1043+
" if len(binary_segmentations) > len(colors):\n",
1044+
" raise ValueError(\n",
1045+
" \"Number of segmentations is larger than number of colors, not allowed\"\n",
1046+
" )\n",
1047+
" for c in colors:\n",
1048+
" if c == [0, 0, 0]:\n",
1049+
" raise ValueError(\"Colors include black [0,0,0], not allowed\")\n",
1050+
" empty_image = image * 0\n",
1051+
" overlay_boundaries = [\n",
1052+
" sitk.LabelMapContourOverlay(\n",
1053+
" sitk.Cast(seg, sitk.sitkLabelUInt8),\n",
1054+
" empty_image,\n",
1055+
" opacity=1,\n",
1056+
" contourThickness=thickness,\n",
1057+
" dilationRadius=dilation_radius,\n",
1058+
" colormap=color,\n",
1059+
" )\n",
1060+
" for seg, color in zip(binary_segmentations, colors)\n",
1061+
" ]\n",
1062+
"\n",
1063+
" current_image = sitk.Compose([image] * 3)\n",
1064+
" for o_image in overlay_boundaries:\n",
1065+
" current_mask = (\n",
1066+
" sitk.NaryAdd(\n",
1067+
" [\n",
1068+
" sitk.VectorIndexSelectionCast(o_image, 0),\n",
1069+
" sitk.VectorIndexSelectionCast(o_image, 1),\n",
1070+
" sitk.VectorIndexSelectionCast(o_image, 2),\n",
1071+
" ]\n",
1072+
" )\n",
1073+
" == 0\n",
1074+
" )\n",
1075+
" current_image = mask_image_multiply(current_mask, current_image) + o_image\n",
1076+
" return current_image\n",
1077+
"\n",
1078+
"\n",
1079+
"binary_segmentations = [\n",
1080+
" coronal_segmentation_isotropic == lung_label,\n",
1081+
" modified_segmentation == lung_label,\n",
1082+
"]\n",
1083+
"gui.multi_image_display2D(\n",
1084+
" [\n",
1085+
" overlay_segmentations(\n",
1086+
" coronal_255_isotropic, binary_segmentations, [3, 3], [2, 2]\n",
1087+
" )\n",
1088+
" ],\n",
1089+
" figure_size=(6, 3),\n",
1090+
");"
1091+
]
1092+
},
9891093
{
9901094
"cell_type": "markdown",
9911095
"metadata": {},

0 commit comments

Comments
 (0)