|
925 | 925 | "cell_type": "markdown", |
926 | 926 | "metadata": {}, |
927 | 927 | "source": [ |
928 | | - "## Comparing two segmentations\n", |
| 928 | + "## Comparing segmentations\n", |
929 | 929 | "\n", |
930 | 930 | "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", |
931 | 931 | "\n", |
|
935 | 935 | { |
936 | 936 | "cell_type": "code", |
937 | 937 | "execution_count": null, |
938 | | - "metadata": {}, |
| 938 | + "metadata": { |
| 939 | + "scrolled": true |
| 940 | + }, |
939 | 941 | "outputs": [], |
940 | 942 | "source": [ |
941 | 943 | "binary_dilate_filter = sitk.BinaryDilateImageFilter()\n", |
|
986 | 988 | ")" |
987 | 989 | ] |
988 | 990 | }, |
| 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 | + }, |
989 | 1093 | { |
990 | 1094 | "cell_type": "markdown", |
991 | 1095 | "metadata": {}, |
|
0 commit comments