Skip to content

Commit d81bfb6

Browse files
committed
Adding function for overlaying multiple segmentations onto image.
Useful for showing multiple binary segmentations overlaid onto the same image (multiple manual semantic segmentations or predictions).
1 parent 69d38da commit d81bfb6

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)