diff --git a/panoptica/example_config.ipynb b/panoptica/example_config.ipynb index 9e6719b..5734fd2 100644 --- a/panoptica/example_config.ipynb +++ b/panoptica/example_config.ipynb @@ -16,14 +16,14 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Requirement already satisfied: panoptica in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 1)) (0.6.6.post13.dev0+a2f5dd3)\n", + "Requirement already satisfied: panoptica in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 1)) (1.0.0.post2.dev0+2f7d01f)\n", "Requirement already satisfied: auxiliary in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 2)) (0.0.42)\n", "Requirement already satisfied: rich in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 3)) (13.6.0)\n", "Requirement already satisfied: numpy in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 4)) (1.25.2)\n", @@ -60,7 +60,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -90,7 +90,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -102,7 +102,7 @@ " 106, 107, 108, 202, 203, 204, 205, 206, 207, 208], dtype=uint8))" ] }, - "execution_count": 3, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -124,74 +124,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 12, "metadata": {}, "outputs": [ - { - "data": { - "text/html": [ - "
────────────────────────────────────────── Thank you for using panoptica ──────────────────────────────────────────\n",
-              "
\n" - ], - "text/plain": [ - "\u001b[92m────────────────────────────────────────── \u001b[0mThank you for using \u001b[1mpanoptica\u001b[0m\u001b[92m ──────────────────────────────────────────\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
                                     Please support our development by citing                                      \n",
-              "
\n" - ], - "text/plain": [ - " Please support our development by citing \n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
                          https://github.com/BrainLesion/panoptica#citation -- Thank you!                          \n",
-              "
\n" - ], - "text/plain": [ - " \u001b[4;94mhttps://github.com/BrainLesion/panoptica#citation\u001b[0m -- Thank you! \n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n",
-              "
\n" - ], - "text/plain": [ - "\u001b[92m───────────────────────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
\n",
-              "
\n" - ], - "text/plain": [ - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, { "name": "stdout", "output_type": "stream", @@ -208,7 +143,7 @@ " decision_threshold=0.5,\n", ")\n", "\n", - "result, debug_data = evaluator.evaluate(pred_masks, ref_masks)[\"ungrouped\"]" + "result, intermediate_steps_data = evaluator.evaluate(pred_masks, ref_masks)[\"ungrouped\"]" ] }, { @@ -221,7 +156,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -239,16 +174,13 @@ "\n", "+++ GLOBAL +++\n", "Global Binary Dice (global_bin_dsc): 0.9744370224078394\n", - "Global Binary Centerline Dice (global_bin_cldsc): 0.9637064011802574\n", - "Global Binary Average Symmetric Surface Distance (global_bin_assd): 0.1499152780072207\n", - "Global Binary Relative Volume Difference (global_bin_rvd): -0.0006011763989268869\n", "\n", "+++ INSTANCE +++\n", "Segmentation Quality IoU (sq): 0.8328184295330796 +- 0.15186064004517466\n", "Panoptic Quality IoU (pq): 0.8328184295330796\n", "Segmentation Quality Dsc (sq_dsc): 0.900292616009954 +- 0.10253566174957332\n", "Panoptic Quality Dsc (pq_dsc): 0.900292616009954\n", - "Segmentation Quality Assd (sq_assd): 0.250331887879225 +- 0.07696680402317076\n", + "Segmentation Quality ASSD (sq_assd): 0.250331887879225 +- 0.07696680402317076\n", "Segmentation Quality Relative Volume Difference (sq_rvd): 0.0028133049062930553 +- 0.034518928495505724\n", "\n" ] @@ -270,14 +202,14 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Saved config into /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages/panoptica/test_config.yaml\n" + "Saved config into /DATA/NAS/ongoing_projects/hendrik/panoptica/repo/panoptica/test_config.yaml\n" ] } ], @@ -306,14 +238,14 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n" + "\n" ] } ], @@ -324,7 +256,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -335,26 +267,23 @@ "-- Got MatchedInstancePair, will evaluate instances\n", "\n", "+++ MATCHING +++\n", - "Number of instances in reference (num_ref_instances): 22\n", - "Number of instances in prediction (num_pred_instances): 22\n", - "True Positives (tp): 22\n", + "Number of instances in reference (num_ref_instances): 1\n", + "Number of instances in prediction (num_pred_instances): 1\n", + "True Positives (tp): 1\n", "False Positives (fp): 0\n", "False Negatives (fn): 0\n", "Recognition Quality / F1-Score (rq): 1.0\n", "\n", "+++ GLOBAL +++\n", "Global Binary Dice (global_bin_dsc): 0.9744370224078394\n", - "Global Binary Centerline Dice (global_bin_cldsc): 0.9637064011802574\n", - "Global Binary Average Symmetric Surface Distance (global_bin_assd): 0.1499152780072207\n", - "Global Binary Relative Volume Difference (global_bin_rvd): -0.0006011763989268869\n", "\n", "+++ INSTANCE +++\n", - "Segmentation Quality IoU (sq): 0.8328184295330796 +- 0.15186064004517466\n", - "Panoptic Quality IoU (pq): 0.8328184295330796\n", - "Segmentation Quality Dsc (sq_dsc): 0.900292616009954 +- 0.10253566174957332\n", - "Panoptic Quality Dsc (pq_dsc): 0.900292616009954\n", - "Segmentation Quality Assd (sq_assd): 0.250331887879225 +- 0.07696680402317076\n", - "Segmentation Quality Relative Volume Difference (sq_rvd): 0.0028133049062930553 +- 0.034518928495505724\n", + "Segmentation Quality IoU (sq): 0.9501484001456879 +- 0.0\n", + "Panoptic Quality IoU (pq): 0.9501484001456879\n", + "Segmentation Quality Dsc (sq_dsc): 0.9744370224078394 +- 0.0\n", + "Panoptic Quality Dsc (pq_dsc): 0.9744370224078394\n", + "Segmentation Quality ASSD (sq_assd): 0.1499152780072207 +- 0.0\n", + "Segmentation Quality Relative Volume Difference (sq_rvd): -0.0006011763989268869 +- 0.0\n", "\n" ] } diff --git a/panoptica/example_spine_matched_instance.ipynb b/panoptica/example_spine_matched_instance.ipynb index 59d481c..e20a019 100644 --- a/panoptica/example_spine_matched_instance.ipynb +++ b/panoptica/example_spine_matched_instance.ipynb @@ -1,313 +1,405 @@ { - "cells": [ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Use Case: Matched Instances Input\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Dependencies" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Use Case: Matched Instances Input\n" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: panoptica in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 1)) (1.0.0.post2.dev0+2f7d01f)\n", + "Requirement already satisfied: auxiliary in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 2)) (0.0.42)\n", + "Requirement already satisfied: rich in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 3)) (13.6.0)\n", + "Requirement already satisfied: numpy in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 4)) (1.25.2)\n", + "Requirement already satisfied: connected-components-3d<4.0.0,>=3.12.3 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from panoptica->-r requirements.txt (line 1)) (3.12.3)\n", + "Requirement already satisfied: ruamel.yaml<0.19.0,>=0.18.6 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from panoptica->-r requirements.txt (line 1)) (0.18.6)\n", + "Requirement already satisfied: scikit-image<0.23.0,>=0.22.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from panoptica->-r requirements.txt (line 1)) (0.22.0)\n", + "Requirement already satisfied: scipy<2.0.0,>=1.7.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from panoptica->-r requirements.txt (line 1)) (1.11.2)\n", + "Requirement already satisfied: nibabel>=3.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (5.1.0)\n", + "Requirement already satisfied: path>=16.10.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (17.0.0)\n", + "Requirement already satisfied: pathlib>=1.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (1.0.1)\n", + "Requirement already satisfied: pillow>=10.0.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (10.0.0)\n", + "Requirement already satisfied: tifffile>=2023.8.25 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (2023.8.30)\n", + "Requirement already satisfied: markdown-it-py>=2.2.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from rich->-r requirements.txt (line 3)) (3.0.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from rich->-r requirements.txt (line 3)) (2.17.2)\n", + "Requirement already satisfied: mdurl~=0.1 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from markdown-it-py>=2.2.0->rich->-r requirements.txt (line 3)) (0.1.2)\n", + "Requirement already satisfied: packaging>=17 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from nibabel>=3.0->auxiliary->-r requirements.txt (line 2)) (23.1)\n", + "Requirement already satisfied: ruamel.yaml.clib>=0.2.7 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from ruamel.yaml<0.19.0,>=0.18.6->panoptica->-r requirements.txt (line 1)) (0.2.8)\n", + "Requirement already satisfied: networkx>=2.8 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from scikit-image<0.23.0,>=0.22.0->panoptica->-r requirements.txt (line 1)) (3.1)\n", + "Requirement already satisfied: imageio>=2.27 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from scikit-image<0.23.0,>=0.22.0->panoptica->-r requirements.txt (line 1)) (2.31.3)\n", + "Requirement already satisfied: lazy_loader>=0.3 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from scikit-image<0.23.0,>=0.22.0->panoptica->-r requirements.txt (line 1)) (0.3)\n" + ] + } + ], + "source": [ + "!pip install -r requirements.txt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from auxiliary.nifti.io import read_nifti\n", + "from rich import print as pprint\n", + "from panoptica import InputType, Panoptica_Evaluator\n", + "from panoptica.metrics import Metric" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load Data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To demonstrate we use a reference and predicition of spine a segmentation with matched instances.\n", + "\n", + "\n", + "![matched_figure](figures/matched_instance.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Install Dependencies" + "data": { + "text/plain": [ + "(array([ 0, 2, 3, 4, 5, 6, 7, 8, 26, 102, 103, 104, 105,\n", + " 106, 107, 108, 202, 203, 204, 205, 206, 207, 208], dtype=uint8),\n", + " array([ 0, 2, 3, 4, 5, 6, 7, 8, 26, 102, 103, 104, 105,\n", + " 106, 107, 108, 202, 203, 204, 205, 206, 207, 208], dtype=uint8))" ] - }, + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ref_masks = read_nifti(\"./spine_seg/matched_instance/ref.nii.gz\")\n", + "pred_masks = read_nifti(\"./spine_seg/matched_instance/pred.nii.gz\")\n", + "\n", + "# labels are matching\n", + "np.unique(ref_masks), np.unique(pred_masks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Run Evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: panoptica in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 1)) (0.6.6)\n", - "Requirement already satisfied: auxiliary in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 2)) (0.0.42)\n", - "Requirement already satisfied: rich in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 3)) (13.6.0)\n", - "Requirement already satisfied: numpy in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 4)) (1.25.2)\n", - "Requirement already satisfied: connected-components-3d<4.0.0,>=3.12.3 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from panoptica->-r requirements.txt (line 1)) (3.12.3)\n", - "Requirement already satisfied: scikit-image<0.23.0,>=0.22.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from panoptica->-r requirements.txt (line 1)) (0.22.0)\n", - "Requirement already satisfied: scipy<2.0.0,>=1.7.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from panoptica->-r requirements.txt (line 1)) (1.11.2)\n", - "Requirement already satisfied: nibabel>=3.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (5.1.0)\n", - "Requirement already satisfied: path>=16.10.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (17.0.0)\n", - "Requirement already satisfied: pathlib>=1.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (1.0.1)\n", - "Requirement already satisfied: pillow>=10.0.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (10.0.0)\n", - "Requirement already satisfied: tifffile>=2023.8.25 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (2023.8.30)\n", - "Requirement already satisfied: markdown-it-py>=2.2.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from rich->-r requirements.txt (line 3)) (3.0.0)\n", - "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from rich->-r requirements.txt (line 3)) (2.17.2)\n", - "Requirement already satisfied: mdurl~=0.1 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from markdown-it-py>=2.2.0->rich->-r requirements.txt (line 3)) (0.1.2)\n", - "Requirement already satisfied: packaging>=17 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from nibabel>=3.0->auxiliary->-r requirements.txt (line 2)) (23.1)\n", - "Requirement already satisfied: networkx>=2.8 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from scikit-image<0.23.0,>=0.22.0->panoptica->-r requirements.txt (line 1)) (3.1)\n", - "Requirement already satisfied: imageio>=2.27 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from scikit-image<0.23.0,>=0.22.0->panoptica->-r requirements.txt (line 1)) (2.31.3)\n", - "Requirement already satisfied: lazy_loader>=0.3 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from scikit-image<0.23.0,>=0.22.0->panoptica->-r requirements.txt (line 1)) (0.3)\n" - ] - } + "data": { + "text/html": [ + "
────────────────────────────────────────── Thank you for using panoptica ──────────────────────────────────────────\n",
+       "
\n" ], - "source": [ - "!pip install -r requirements.txt" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setup Imports" + "text/plain": [ + "\u001b[92m────────────────────────────────────────── \u001b[0mThank you for using \u001b[1mpanoptica\u001b[0m\u001b[92m ──────────────────────────────────────────\u001b[0m\n" ] + }, + "metadata": {}, + "output_type": "display_data" }, { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "from auxiliary.nifti.io import read_nifti\n", - "from rich import print as pprint\n", - "from panoptica import InputType, Panoptica_Evaluator\n", - "from panoptica.metrics import Metric" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Load Data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To demonstrate we use a reference and predicition of spine a segmentation with matched instances.\n", - "\n", - "\n", - "![matched_figure](figures/matched_instance.png)" + "data": { + "text/html": [ + "
                                     Please support our development by citing                                      \n",
+       "
\n" + ], + "text/plain": [ + " Please support our development by citing \n" ] + }, + "metadata": {}, + "output_type": "display_data" }, { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(array([ 0, 2, 3, 4, 5, 6, 7, 8, 26, 102, 103, 104, 105,\n", - " 106, 107, 108, 202, 203, 204, 205, 206, 207, 208], dtype=uint8),\n", - " array([ 0, 2, 3, 4, 5, 6, 7, 8, 26, 102, 103, 104, 105,\n", - " 106, 107, 108, 202, 203, 204, 205, 206, 207, 208], dtype=uint8))" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } + "data": { + "text/html": [ + "
                          https://github.com/BrainLesion/panoptica#citation -- Thank you!                          \n",
+       "
\n" ], - "source": [ - "ref_masks = read_nifti(\"./spine_seg/matched_instance/ref.nii.gz\")\n", - "pred_masks = read_nifti(\"./spine_seg/matched_instance/pred.nii.gz\")\n", - "\n", - "# labels are matching\n", - "np.unique(ref_masks), np.unique(pred_masks)" + "text/plain": [ + " \u001b[4;94mhttps://github.com/BrainLesion/panoptica#citation\u001b[0m -- Thank you! \n" ] + }, + "metadata": {}, + "output_type": "display_data" }, { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Run Evaluation" + "data": { + "text/html": [ + "
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[92m───────────────────────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\n" ] + }, + "metadata": {}, + "output_type": "display_data" }, { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Panoptic: Start Evaluation\n", - "-- Got MatchedInstancePair, will evaluate instances\n" - ] - } + "data": { + "text/html": [ + "
\n",
+       "
\n" ], - "source": [ - "evaluator = Panoptica_Evaluator(\n", - " expected_input=InputType.MATCHED_INSTANCE,\n", - " decision_metric=Metric.IOU,\n", - " decision_threshold=0.5,\n", - ")\n", - "\n", - "result, debug_data = evaluator.evaluate(pred_masks, ref_masks)[\"ungrouped\"]" + "text/plain": [ + "\n" ] + }, + "metadata": {}, + "output_type": "display_data" }, { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Inspect Results\n", - "The results object allows access to individual metrics and provides helper methods for further processing" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Panoptic: Start Evaluation\n", + "-- Got MatchedInstancePair, will evaluate instances\n" + ] + } + ], + "source": [ + "evaluator = Panoptica_Evaluator(\n", + " expected_input=InputType.MATCHED_INSTANCE,\n", + " decision_metric=Metric.IOU,\n", + " decision_threshold=0.5,\n", + ")\n", + "\n", + "result, intermediate_steps_data = evaluator.evaluate(pred_masks, ref_masks)[\"ungrouped\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inspect Results\n", + "The results object allows access to individual metrics and provides helper methods for further processing" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "+++ MATCHING +++\n", - "Number of instances in reference (num_ref_instances): 22\n", - "Number of instances in prediction (num_pred_instances): 22\n", - "True Positives (tp): 22\n", - "False Positives (fp): 0\n", - "False Negatives (fn): 0\n", - "Recognition Quality / F1-Score (rq): 1.0\n", - "\n", - "+++ GLOBAL +++\n", - "Global Binary Dice (global_bin_dsc): 0.9744370224078394\n", - "Global Binary Centerline Dice (global_bin_cldsc): 0.9637064011802574\n", - "Global Binary Average Symmetric Surface Distance (global_bin_assd): 0.1499152780072207\n", - "Global Binary Relative Volume Difference (global_bin_rvd): -0.0006011763989268869\n", - "\n", - "+++ INSTANCE +++\n", - "Segmentation Quality IoU (sq): 0.8328184295330796 +- 0.15186064004517466\n", - "Panoptic Quality IoU (pq): 0.8328184295330796\n", - "Segmentation Quality Dsc (sq_dsc): 0.900292616009954 +- 0.10253566174957332\n", - "Panoptic Quality Dsc (pq_dsc): 0.900292616009954\n", - "Segmentation Quality Assd (sq_assd): 0.250331887879225 +- 0.07696680402317076\n", - "Segmentation Quality Relative Volume Difference (sq_rvd): 0.0028133049062930553 +- 0.034518928495505724\n", - "\n" - ] - } - ], - "source": [ - "# print all results\n", - "print(result)" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "+++ MATCHING +++\n", + "Number of instances in reference (num_ref_instances): 22\n", + "Number of instances in prediction (num_pred_instances): 22\n", + "True Positives (tp): 22\n", + "False Positives (fp): 0\n", + "False Negatives (fn): 0\n", + "Recognition Quality / F1-Score (rq): 1.0\n", + "\n", + "+++ GLOBAL +++\n", + "Global Binary Dice (global_bin_dsc): 0.9744370224078394\n", + "\n", + "+++ INSTANCE +++\n", + "Segmentation Quality IoU (sq): 0.8328184295330796 +- 0.15186064004517466\n", + "Panoptic Quality IoU (pq): 0.8328184295330796\n", + "Segmentation Quality Dsc (sq_dsc): 0.900292616009954 +- 0.10253566174957332\n", + "Panoptic Quality Dsc (pq_dsc): 0.900292616009954\n", + "Segmentation Quality ASSD (sq_assd): 0.250331887879225 +- 0.07696680402317076\n", + "Segmentation Quality Relative Volume Difference (sq_rvd): 0.0028133049062930553 +- 0.034518928495505724\n", + "\n" + ] + } + ], + "source": [ + "# print all results\n", + "print(result)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
result.pq=0.8328184295330796\n",
-              "
\n" - ], - "text/plain": [ - "result.\u001b[33mpq\u001b[0m=\u001b[1;36m0\u001b[0m\u001b[1;36m.8328184295330796\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } + "data": { + "text/html": [ + "
result.pq=0.8328184295330796\n",
+       "
\n" ], - "source": [ - "# get specific metric, e.g. pq\n", - "pprint(f\"{result.pq=}\")" + "text/plain": [ + "result.\u001b[33mpq\u001b[0m=\u001b[1;36m0\u001b[0m\u001b[1;36m.8328184295330796\u001b[0m\n" ] - }, + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# get specific metric, e.g. pq\n", + "pprint(f\"{result.pq=}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
results dict: \n",
-              "{\n",
-              "    'num_ref_instances': 22,\n",
-              "    'num_pred_instances': 22,\n",
-              "    'tp': 22,\n",
-              "    'fp': 0,\n",
-              "    'fn': 0,\n",
-              "    'prec': 1.0,\n",
-              "    'rec': 1.0,\n",
-              "    'rq': 1.0,\n",
-              "    'global_bin_dsc': 0.9744370224078394,\n",
-              "    'global_bin_cldsc': 0.9637064011802574,\n",
-              "    'global_bin_assd': 0.1499152780072207,\n",
-              "    'global_bin_rvd': -0.0006011763989268869,\n",
-              "    'sq': 0.8328184295330796,\n",
-              "    'sq_std': 0.15186064004517466,\n",
-              "    'pq': 0.8328184295330796,\n",
-              "    'sq_dsc': 0.900292616009954,\n",
-              "    'sq_dsc_std': 0.10253566174957332,\n",
-              "    'pq_dsc': 0.900292616009954,\n",
-              "    'sq_assd': 0.250331887879225,\n",
-              "    'sq_assd_std': 0.07696680402317076,\n",
-              "    'sq_rvd': 0.0028133049062930553,\n",
-              "    'sq_rvd_std': 0.034518928495505724\n",
-              "}\n",
-              "
\n" - ], - "text/plain": [ - "results dict: \n", - "\u001b[1m{\u001b[0m\n", - " \u001b[32m'num_ref_instances'\u001b[0m: \u001b[1;36m22\u001b[0m,\n", - " \u001b[32m'num_pred_instances'\u001b[0m: \u001b[1;36m22\u001b[0m,\n", - " \u001b[32m'tp'\u001b[0m: \u001b[1;36m22\u001b[0m,\n", - " \u001b[32m'fp'\u001b[0m: \u001b[1;36m0\u001b[0m,\n", - " \u001b[32m'fn'\u001b[0m: \u001b[1;36m0\u001b[0m,\n", - " \u001b[32m'prec'\u001b[0m: \u001b[1;36m1.0\u001b[0m,\n", - " \u001b[32m'rec'\u001b[0m: \u001b[1;36m1.0\u001b[0m,\n", - " \u001b[32m'rq'\u001b[0m: \u001b[1;36m1.0\u001b[0m,\n", - " \u001b[32m'global_bin_dsc'\u001b[0m: \u001b[1;36m0.9744370224078394\u001b[0m,\n", - " \u001b[32m'global_bin_cldsc'\u001b[0m: \u001b[1;36m0.9637064011802574\u001b[0m,\n", - " \u001b[32m'global_bin_assd'\u001b[0m: \u001b[1;36m0.1499152780072207\u001b[0m,\n", - " \u001b[32m'global_bin_rvd'\u001b[0m: \u001b[1;36m-0.0006011763989268869\u001b[0m,\n", - " \u001b[32m'sq'\u001b[0m: \u001b[1;36m0.8328184295330796\u001b[0m,\n", - " \u001b[32m'sq_std'\u001b[0m: \u001b[1;36m0.15186064004517466\u001b[0m,\n", - " \u001b[32m'pq'\u001b[0m: \u001b[1;36m0.8328184295330796\u001b[0m,\n", - " \u001b[32m'sq_dsc'\u001b[0m: \u001b[1;36m0.900292616009954\u001b[0m,\n", - " \u001b[32m'sq_dsc_std'\u001b[0m: \u001b[1;36m0.10253566174957332\u001b[0m,\n", - " \u001b[32m'pq_dsc'\u001b[0m: \u001b[1;36m0.900292616009954\u001b[0m,\n", - " \u001b[32m'sq_assd'\u001b[0m: \u001b[1;36m0.250331887879225\u001b[0m,\n", - " \u001b[32m'sq_assd_std'\u001b[0m: \u001b[1;36m0.07696680402317076\u001b[0m,\n", - " \u001b[32m'sq_rvd'\u001b[0m: \u001b[1;36m0.0028133049062930553\u001b[0m,\n", - " \u001b[32m'sq_rvd_std'\u001b[0m: \u001b[1;36m0.034518928495505724\u001b[0m\n", - "\u001b[1m}\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } + "data": { + "text/html": [ + "
results dict: \n",
+       "{\n",
+       "    'num_ref_instances': 22,\n",
+       "    'num_pred_instances': 22,\n",
+       "    'tp': 22,\n",
+       "    'fp': 0,\n",
+       "    'fn': 0,\n",
+       "    'prec': 1.0,\n",
+       "    'rec': 1.0,\n",
+       "    'rq': 1.0,\n",
+       "    'sq': 0.8328184295330796,\n",
+       "    'sq_std': 0.15186064004517466,\n",
+       "    'pq': 0.8328184295330796,\n",
+       "    'sq_dsc': 0.900292616009954,\n",
+       "    'sq_dsc_std': 0.10253566174957332,\n",
+       "    'pq_dsc': 0.900292616009954,\n",
+       "    'sq_assd': 0.250331887879225,\n",
+       "    'sq_assd_std': 0.07696680402317076,\n",
+       "    'sq_rvd': 0.0028133049062930553,\n",
+       "    'sq_rvd_std': 0.034518928495505724,\n",
+       "    'global_bin_dsc': 0.9744370224078394\n",
+       "}\n",
+       "
\n" ], - "source": [ - "# get dict for further processing, e.g. for pandas\n", - "pprint(\"results dict: \", result.to_dict())" + "text/plain": [ + "results dict: \n", + "\u001b[1m{\u001b[0m\n", + " \u001b[32m'num_ref_instances'\u001b[0m: \u001b[1;36m22\u001b[0m,\n", + " \u001b[32m'num_pred_instances'\u001b[0m: \u001b[1;36m22\u001b[0m,\n", + " \u001b[32m'tp'\u001b[0m: \u001b[1;36m22\u001b[0m,\n", + " \u001b[32m'fp'\u001b[0m: \u001b[1;36m0\u001b[0m,\n", + " \u001b[32m'fn'\u001b[0m: \u001b[1;36m0\u001b[0m,\n", + " \u001b[32m'prec'\u001b[0m: \u001b[1;36m1.0\u001b[0m,\n", + " \u001b[32m'rec'\u001b[0m: \u001b[1;36m1.0\u001b[0m,\n", + " \u001b[32m'rq'\u001b[0m: \u001b[1;36m1.0\u001b[0m,\n", + " \u001b[32m'sq'\u001b[0m: \u001b[1;36m0.8328184295330796\u001b[0m,\n", + " \u001b[32m'sq_std'\u001b[0m: \u001b[1;36m0.15186064004517466\u001b[0m,\n", + " \u001b[32m'pq'\u001b[0m: \u001b[1;36m0.8328184295330796\u001b[0m,\n", + " \u001b[32m'sq_dsc'\u001b[0m: \u001b[1;36m0.900292616009954\u001b[0m,\n", + " \u001b[32m'sq_dsc_std'\u001b[0m: \u001b[1;36m0.10253566174957332\u001b[0m,\n", + " \u001b[32m'pq_dsc'\u001b[0m: \u001b[1;36m0.900292616009954\u001b[0m,\n", + " \u001b[32m'sq_assd'\u001b[0m: \u001b[1;36m0.250331887879225\u001b[0m,\n", + " \u001b[32m'sq_assd_std'\u001b[0m: \u001b[1;36m0.07696680402317076\u001b[0m,\n", + " \u001b[32m'sq_rvd'\u001b[0m: \u001b[1;36m0.0028133049062930553\u001b[0m,\n", + " \u001b[32m'sq_rvd_std'\u001b[0m: \u001b[1;36m0.034518928495505724\u001b[0m,\n", + " \u001b[32m'global_bin_dsc'\u001b[0m: \u001b[1;36m0.9744370224078394\u001b[0m\n", + "\u001b[1m}\u001b[0m\n" ] + }, + "metadata": {}, + "output_type": "display_data" } - ], - "metadata": { - "kernelspec": { - "display_name": "helm", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.6" + ], + "source": [ + "# get dict for further processing, e.g. for pandas\n", + "pprint(\"results dict: \", result.to_dict())" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "key SEMANTIC not in intermediate steps, maybe the step was skipped?\n" + ] } + ], + "source": [ + "# To inspect different phases, just use the returned intermediate_steps_data object\n", + "\n", + "intermediate_steps_data.original_prediction_arr # yields input prediction array\n", + "intermediate_steps_data.original_reference_arr # yields input reference array\n", + "\n", + "intermediate_steps_data.prediction_arr(\n", + " InputType.MATCHED_INSTANCE\n", + ") # yields prediction array after instances have been matched\n", + "intermediate_steps_data.reference_arr(\n", + " InputType.MATCHED_INSTANCE\n", + ") # yields reference array after instances have been matched\n", + "\n", + "# The other InputType do not work here, as the input was already a matched instance map, therefore the steps from instance approximation and matching have been skipped\n", + "try:\n", + " intermediate_steps_data.reference_arr(InputType.SEMANTIC)\n", + "except AssertionError as e:\n", + " print(e)\n", + " # Error will indicate the problem" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "helm", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 2 + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 } diff --git a/panoptica/example_spine_matching_algorithm.ipynb b/panoptica/example_spine_matching_algorithm.ipynb new file mode 100644 index 0000000..b623947 --- /dev/null +++ b/panoptica/example_spine_matching_algorithm.ipynb @@ -0,0 +1,261 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Use Case: Unmatched Instances Input" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Dependencies" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: panoptica in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 1)) (1.0.0.post2.dev0+2f7d01f)\n", + "Requirement already satisfied: auxiliary in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 2)) (0.0.42)\n", + "Requirement already satisfied: rich in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 3)) (13.6.0)\n", + "Requirement already satisfied: numpy in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 4)) (1.25.2)\n", + "Requirement already satisfied: connected-components-3d<4.0.0,>=3.12.3 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from panoptica->-r requirements.txt (line 1)) (3.12.3)\n", + "Requirement already satisfied: ruamel.yaml<0.19.0,>=0.18.6 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from panoptica->-r requirements.txt (line 1)) (0.18.6)\n", + "Requirement already satisfied: scikit-image<0.23.0,>=0.22.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from panoptica->-r requirements.txt (line 1)) (0.22.0)\n", + "Requirement already satisfied: scipy<2.0.0,>=1.7.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from panoptica->-r requirements.txt (line 1)) (1.11.2)\n", + "Requirement already satisfied: nibabel>=3.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (5.1.0)\n", + "Requirement already satisfied: path>=16.10.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (17.0.0)\n", + "Requirement already satisfied: pathlib>=1.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (1.0.1)\n", + "Requirement already satisfied: pillow>=10.0.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (10.0.0)\n", + "Requirement already satisfied: tifffile>=2023.8.25 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from auxiliary->-r requirements.txt (line 2)) (2023.8.30)\n", + "Requirement already satisfied: markdown-it-py>=2.2.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from rich->-r requirements.txt (line 3)) (3.0.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from rich->-r requirements.txt (line 3)) (2.17.2)\n", + "Requirement already satisfied: mdurl~=0.1 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from markdown-it-py>=2.2.0->rich->-r requirements.txt (line 3)) (0.1.2)\n", + "Requirement already satisfied: packaging>=17 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from nibabel>=3.0->auxiliary->-r requirements.txt (line 2)) (23.1)\n", + "Requirement already satisfied: ruamel.yaml.clib>=0.2.7 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from ruamel.yaml<0.19.0,>=0.18.6->panoptica->-r requirements.txt (line 1)) (0.2.8)\n", + "Requirement already satisfied: networkx>=2.8 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from scikit-image<0.23.0,>=0.22.0->panoptica->-r requirements.txt (line 1)) (3.1)\n", + "Requirement already satisfied: imageio>=2.27 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from scikit-image<0.23.0,>=0.22.0->panoptica->-r requirements.txt (line 1)) (2.31.3)\n", + "Requirement already satisfied: lazy_loader>=0.3 in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from scikit-image<0.23.0,>=0.22.0->panoptica->-r requirements.txt (line 1)) (0.3)\n" + ] + } + ], + "source": [ + "!pip install -r requirements.txt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from auxiliary.nifti.io import read_nifti\n", + "from rich import print as pprint\n", + "from panoptica import NaiveThresholdMatching, Panoptica_Evaluator, InputType\n", + "from panoptica.utils.segmentation_class import LabelGroup, SegmentationClassGroups" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load Example Data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To demonstrate we use a reference and predicition of spine a segmentation with unmatched instances.\n", + "\n", + "\n", + "![unmatched_instance_figure](figures/unmatched_instance.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([ 0, 2, 3, 4, 5, 6, 7, 8, 26, 102, 103, 104, 105,\n", + " 106, 107, 108, 202, 203, 204, 205, 206, 207, 208], dtype=uint8),\n", + " array([ 0, 3, 4, 5, 6, 7, 8, 9, 26, 103, 104, 105, 106,\n", + " 107, 108, 109, 203, 204, 205, 206, 207, 208, 209], dtype=uint8))" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ref_masks = read_nifti(\"./spine_seg/unmatched_instance/ref.nii.gz\")\n", + "pred_masks = read_nifti(\"./spine_seg/unmatched_instance/pred.nii.gz\")\n", + "\n", + "# labels are unmatched instances\n", + "pred_masks[pred_masks == 27] = 26 # For later\n", + "np.unique(ref_masks), np.unique(pred_masks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define Class Groups" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Define (optionally) semantic groups\n", + "# This means that only instance within one group can be matched to each other\n", + "segmentation_class_groups = SegmentationClassGroups(\n", + " {\n", + " \"vertebra\": LabelGroup(list(range(1, 11))),\n", + " \"ivd\": LabelGroup(list(range(101, 111))),\n", + " \"sacrum\": ([26], True),\n", + " \"endplate\": LabelGroup(list(range(201, 211))),\n", + " }\n", + ")\n", + "# In this case, the label 26 can only be matched with label 26 (thats why have to ensure above that 26 exists in both masks, otherwise they wouldn't be matched)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Let's do it ourselves!\n", + "Panoptica allows you to call everything yourself if you really want to" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "prediction_arr= [ 0 2 3 4 5 6 7 8 26 102 103 104 105 106 107 108 202 204\n", + " 206 207 209 210 211]\n", + "reference_arr= [ 0 2 3 4 5 6 7 8 26 102 103 104 105 106 107 108 202 203\n", + " 204 205 206 207 208]\n" + ] + } + ], + "source": [ + "# Input are unmatched instances, so lets match em!\n", + "from panoptica import Metric\n", + "\n", + "# This will match based on IoU metric, will only match if instance have a IoU of 0.5 or higher and will not allow multiple predictions to be matched to the same reference\n", + "matcher = NaiveThresholdMatching(\n", + " matching_metric=Metric.IOU, matching_threshold=0.5, allow_many_to_one=False\n", + ")\n", + "\n", + "# Now we have to do our processing object ourselves\n", + "from panoptica import UnmatchedInstancePair\n", + "\n", + "unmatched_instance_input = UnmatchedInstancePair(pred_masks, ref_masks)\n", + "\n", + "matched_instance_output = matcher.match_instances(unmatched_instance_input)\n", + "print(\"prediction_arr=\", np.unique(matched_instance_output.prediction_arr))\n", + "print(\"reference_arr=\", np.unique(matched_instance_output.reference_arr))\n", + "\n", + "# Based of this, we see that some references are not sucessfully hit (203, 205, 208)\n", + "# We can also see that we indeed have the same number of prediction instances that got no match, they will be appended afterwards (209, 210, 211)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Let's match 'em all!" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "prediction_arr= [ 0 2 3 4 5 6 7 8 26 102 103 104 105 106 107 108 202 203\n", + " 204 205 206 207 208]\n", + "reference_arr= [ 0 2 3 4 5 6 7 8 26 102 103 104 105 106 107 108 202 203\n", + " 204 205 206 207 208]\n" + ] + } + ], + "source": [ + "# This will match based on IoU metric, will only match if instance have a IoU of 0.0 or higher and will not allow multiple predictions to be matched to the same reference\n", + "matcher = NaiveThresholdMatching(\n", + " matching_metric=Metric.IOU, matching_threshold=0.0, allow_many_to_one=False\n", + ")\n", + "\n", + "matched_instance_output = matcher.match_instances(unmatched_instance_input)\n", + "print(\"prediction_arr=\", np.unique(matched_instance_output.prediction_arr))\n", + "print(\"reference_arr=\", np.unique(matched_instance_output.reference_arr))\n", + "\n", + "# With a threshold of 0.0, we ensure that we match as much as possible.\n", + "# We see, that contrary to before, instances 203, 205, and 208 are now matched" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Do it yourself\n", + "\n", + "Now it is up to you to explore the different matching algorithms and the best setup for your project\n", + "\n", + "Just remember, this setup can have drastic differences in the resulting metrics as well as interpretation of those results. For example, if you always match everything, of course your F1-Score will be 1.0. This becomes meaningless then. Also the choice of metric does matter!" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "brainles", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/panoptica/example_spine_semantic.ipynb b/panoptica/example_spine_semantic.ipynb index 131cb48..44bafff 100644 --- a/panoptica/example_spine_semantic.ipynb +++ b/panoptica/example_spine_semantic.ipynb @@ -16,14 +16,14 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Requirement already satisfied: panoptica in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 1)) (0.6.6.post9.dev0+d25fabc)\n", + "Requirement already satisfied: panoptica in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 1)) (1.0.0.post2.dev0+2f7d01f)\n", "Requirement already satisfied: auxiliary in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 2)) (0.0.42)\n", "Requirement already satisfied: rich in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 3)) (13.6.0)\n", "Requirement already satisfied: numpy in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 4)) (1.25.2)\n", @@ -60,7 +60,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -92,7 +92,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -123,7 +123,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -144,7 +144,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -227,16 +227,13 @@ "\n", "+++ GLOBAL +++\n", "Global Binary Dice (global_bin_dsc): 0.9731641527805414\n", - "Global Binary Centerline Dice (global_bin_cldsc): 0.9623567366028574\n", - "Global Binary Average Symmetric Surface Distance (global_bin_assd): 0.15559863304671395\n", - "Global Binary Relative Volume Difference (global_bin_rvd): 0.0021710740333888085\n", "\n", "+++ INSTANCE +++\n", "Segmentation Quality IoU (sq): 0.7940127477906024 +- 0.11547745015679488\n", "Panoptic Quality IoU (pq): 0.6586696657808406\n", "Segmentation Quality Dsc (sq_dsc): 0.8802182546605446 +- 0.07728416427007168\n", "Panoptic Quality Dsc (pq_dsc): 0.7301810521615881\n", - "Segmentation Quality Assd (sq_assd): 0.2057371092494465 +- 0.1398348236766068\n", + "Segmentation Quality ASSD (sq_assd): 0.2057371092494465 +- 0.1398348236766068\n", "Segmentation Quality Relative Volume Difference (sq_rvd): 0.011340219860617232 +- 0.1217805112447998\n", "\n" ] @@ -244,13 +241,15 @@ ], "source": [ "# print all results\n", - "result, _ = evaluator.evaluate(pred_masks, ref_masks, verbose=False)[\"ungrouped\"]\n", + "result, intermediate_steps_data = evaluator.evaluate(\n", + " pred_masks, ref_masks, verbose=False\n", + ")[\"ungrouped\"]\n", "print(result)" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -274,7 +273,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -290,10 +289,6 @@ " 'prec': 0.8202247191011236,\n", " 'rec': 0.8390804597701149,\n", " 'rq': 0.8295454545454546,\n", - " 'global_bin_dsc': 0.9731641527805414,\n", - " 'global_bin_cldsc': 0.9623567366028574,\n", - " 'global_bin_assd': 0.15559863304671395,\n", - " 'global_bin_rvd': 0.0021710740333888085,\n", " 'sq': 0.7940127477906024,\n", " 'sq_std': 0.11547745015679488,\n", " 'pq': 0.6586696657808406,\n", @@ -303,7 +298,8 @@ " 'sq_assd': 0.2057371092494465,\n", " 'sq_assd_std': 0.1398348236766068,\n", " 'sq_rvd': 0.011340219860617232,\n", - " 'sq_rvd_std': 0.1217805112447998\n", + " 'sq_rvd_std': 0.1217805112447998,\n", + " 'global_bin_dsc': 0.9731641527805414\n", "}\n", "\n" ], @@ -318,10 +314,6 @@ " \u001b[32m'prec'\u001b[0m: \u001b[1;36m0.8202247191011236\u001b[0m,\n", " \u001b[32m'rec'\u001b[0m: \u001b[1;36m0.8390804597701149\u001b[0m,\n", " \u001b[32m'rq'\u001b[0m: \u001b[1;36m0.8295454545454546\u001b[0m,\n", - " \u001b[32m'global_bin_dsc'\u001b[0m: \u001b[1;36m0.9731641527805414\u001b[0m,\n", - " \u001b[32m'global_bin_cldsc'\u001b[0m: \u001b[1;36m0.9623567366028574\u001b[0m,\n", - " \u001b[32m'global_bin_assd'\u001b[0m: \u001b[1;36m0.15559863304671395\u001b[0m,\n", - " \u001b[32m'global_bin_rvd'\u001b[0m: \u001b[1;36m0.0021710740333888085\u001b[0m,\n", " \u001b[32m'sq'\u001b[0m: \u001b[1;36m0.7940127477906024\u001b[0m,\n", " \u001b[32m'sq_std'\u001b[0m: \u001b[1;36m0.11547745015679488\u001b[0m,\n", " \u001b[32m'pq'\u001b[0m: \u001b[1;36m0.6586696657808406\u001b[0m,\n", @@ -331,7 +323,8 @@ " \u001b[32m'sq_assd'\u001b[0m: \u001b[1;36m0.2057371092494465\u001b[0m,\n", " \u001b[32m'sq_assd_std'\u001b[0m: \u001b[1;36m0.1398348236766068\u001b[0m,\n", " \u001b[32m'sq_rvd'\u001b[0m: \u001b[1;36m0.011340219860617232\u001b[0m,\n", - " \u001b[32m'sq_rvd_std'\u001b[0m: \u001b[1;36m0.1217805112447998\u001b[0m\n", + " \u001b[32m'sq_rvd_std'\u001b[0m: \u001b[1;36m0.1217805112447998\u001b[0m,\n", + " \u001b[32m'global_bin_dsc'\u001b[0m: \u001b[1;36m0.9731641527805414\u001b[0m\n", "\u001b[1m}\u001b[0m\n" ] }, @@ -343,6 +336,68 @@ "# get dict for further processing, e.g. for pandas\n", "pprint(\"results dict: \", result.to_dict())" ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "InputType.SEMANTIC\n", + "Prediction array shape = (170, 512, 17) unique_values= [ 0 26 41 42 43 44 45 46 47 48 49 60 61 62 100]\n", + "Reference array shape = (170, 512, 17) unique_values= [ 0 26 41 42 43 44 45 46 47 48 49 60 61 62 100]\n", + "\n", + "InputType.UNMATCHED_INSTANCE\n", + "Prediction array shape = (170, 512, 17) unique_values= [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n", + " 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47\n", + " 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71\n", + " 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89]\n", + "Reference array shape = (170, 512, 17) unique_values= [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n", + " 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47\n", + " 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71\n", + " 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87]\n", + "\n", + "InputType.MATCHED_INSTANCE\n", + "Prediction array shape = (170, 512, 17) unique_values= [ 0 1 2 4 5 6 9 10 12 13 14 15 16 17 18 19 20 21\n", + " 22 23 24 25 26 27 28 29 30 32 33 34 35 36 37 38 39 41\n", + " 42 43 44 45 49 50 51 52 54 55 56 57 58 60 61 62 63 64\n", + " 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82\n", + " 83 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103]\n", + "Reference array shape = (170, 512, 17) unique_values= [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n", + " 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47\n", + " 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71\n", + " 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87]\n", + "\n" + ] + } + ], + "source": [ + "# To inspect different phases, just use the returned intermediate_steps_data object\n", + "\n", + "import numpy as np\n", + "\n", + "intermediate_steps_data.original_prediction_arr # yields input prediction array\n", + "intermediate_steps_data.original_reference_arr # yields input reference array\n", + "\n", + "intermediate_steps_data.prediction_arr(\n", + " InputType.MATCHED_INSTANCE\n", + ") # yields prediction array after instances have been matched\n", + "intermediate_steps_data.reference_arr(\n", + " InputType.MATCHED_INSTANCE\n", + ") # yields reference array after instances have been matched\n", + "\n", + "# This works with all InputType\n", + "for i in InputType:\n", + " print(i)\n", + " pred = intermediate_steps_data.prediction_arr(i)\n", + " ref = intermediate_steps_data.reference_arr(i)\n", + " print(\"Prediction array shape =\", pred.shape, \"unique_values=\", np.unique(pred))\n", + " print(\"Reference array shape =\", ref.shape, \"unique_values=\", np.unique(ref))\n", + " print()" + ] } ], "metadata": { diff --git a/panoptica/example_spine_unmatched_instance.ipynb b/panoptica/example_spine_unmatched_instance.ipynb index ced5e38..d994a5a 100644 --- a/panoptica/example_spine_unmatched_instance.ipynb +++ b/panoptica/example_spine_unmatched_instance.ipynb @@ -23,7 +23,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Requirement already satisfied: panoptica in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 1)) (0.6.6.post9.dev0+d25fabc)\n", + "Requirement already satisfied: panoptica in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 1)) (1.0.0.post2.dev0+2f7d01f)\n", "Requirement already satisfied: auxiliary in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 2)) (0.0.42)\n", "Requirement already satisfied: rich in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 3)) (13.6.0)\n", "Requirement already satisfied: numpy in /opt/anaconda3/envs/seg11panoptdev/lib/python3.11/site-packages (from -r requirements.txt (line 4)) (1.25.2)\n", @@ -244,16 +244,13 @@ "\n", "+++ GLOBAL +++\n", "Global Binary Dice (global_bin_dsc): 0.9631786034883428\n", - "Global Binary Centerline Dice (global_bin_cldsc): 0.9832727462458709\n", - "Global Binary Average Symmetric Surface Distance (global_bin_assd): 0.16583233154456756\n", - "Global Binary Relative Volume Difference (global_bin_rvd): -0.006522448092183933\n", "\n", "+++ INSTANCE +++\n", "Segmentation Quality IoU (sq): 0.9259373047661901 +- 0.009654749671578153\n", "Panoptic Quality IoU (pq): 0.9259373047661901\n", "Segmentation Quality Dsc (sq_dsc): 0.9615183012231253 +- 0.005245540988039026\n", "Panoptic Quality Dsc (pq_dsc): 0.9615183012231253\n", - "Segmentation Quality Assd (sq_assd): 0.16832296646947947 +- 0.01828381629759957\n", + "Segmentation Quality ASSD (sq_assd): 0.16832296646947947 +- 0.01828381629759957\n", "Segmentation Quality Relative Volume Difference (sq_rvd): -0.005930868093584259 +- 0.010871203881221219\n", "\n", "\n", @@ -269,16 +266,13 @@ "\n", "+++ GLOBAL +++\n", "Global Binary Dice (global_bin_dsc): 0.9423566613429801\n", - "Global Binary Centerline Dice (global_bin_cldsc): 0.9785654029223958\n", - "Global Binary Average Symmetric Surface Distance (global_bin_assd): 0.2945667788167613\n", - "Global Binary Relative Volume Difference (global_bin_rvd): 0.02117012587992792\n", "\n", "+++ INSTANCE +++\n", "Segmentation Quality IoU (sq): 0.8897861147389462 +- 0.029181150423413706\n", "Panoptic Quality IoU (pq): 0.8897861147389462\n", "Segmentation Quality Dsc (sq_dsc): 0.9414254100052913 +- 0.016436031942319355\n", "Panoptic Quality Dsc (pq_dsc): 0.9414254100052913\n", - "Segmentation Quality Assd (sq_assd): 0.29013503272997326 +- 0.05544330133482135\n", + "Segmentation Quality ASSD (sq_assd): 0.29013503272997326 +- 0.05544330133482135\n", "Segmentation Quality Relative Volume Difference (sq_rvd): 0.020603174193257762 +- 0.03071580120223084\n", "\n", "\n", @@ -294,16 +288,13 @@ "\n", "+++ GLOBAL +++\n", "Global Binary Dice (global_bin_dsc): 0.9698239455931553\n", - "Global Binary Centerline Dice (global_bin_cldsc): 1.0\n", - "Global Binary Average Symmetric Surface Distance (global_bin_assd): 0.20907172118556794\n", - "Global Binary Relative Volume Difference (global_bin_rvd): -0.011061174622567414\n", "\n", "+++ INSTANCE +++\n", "Segmentation Quality IoU (sq): 0.941415733208399 +- 0.0\n", "Panoptic Quality IoU (pq): 0.941415733208399\n", "Segmentation Quality Dsc (sq_dsc): 0.9698239455931553 +- 0.0\n", "Panoptic Quality Dsc (pq_dsc): 0.9698239455931553\n", - "Segmentation Quality Assd (sq_assd): 0.20907172118556794 +- 0.0\n", + "Segmentation Quality ASSD (sq_assd): 0.20907172118556794 +- 0.0\n", "Segmentation Quality Relative Volume Difference (sq_rvd): -0.011061174622567414 +- 0.0\n", "\n", "\n", @@ -319,16 +310,13 @@ "\n", "+++ GLOBAL +++\n", "Global Binary Dice (global_bin_dsc): 0.6793787581594264\n", - "Global Binary Centerline Dice (global_bin_cldsc): 0.7061452563556313\n", - "Global Binary Average Symmetric Surface Distance (global_bin_assd): 0.3688658918466393\n", - "Global Binary Relative Volume Difference (global_bin_rvd): 0.01340152790366438\n", "\n", "+++ INSTANCE +++\n", "Segmentation Quality IoU (sq): 0.54301762284604 +- 0.01014458743300687\n", "Panoptic Quality IoU (pq): 0.31029578448345146\n", "Segmentation Quality Dsc (sq_dsc): 0.7037824449992637 +- 0.008529812661560601\n", "Panoptic Quality Dsc (pq_dsc): 0.40216139714243637\n", - "Segmentation Quality Assd (sq_assd): 0.33450703853088465 +- 0.010995297631511717\n", + "Segmentation Quality ASSD (sq_assd): 0.33450703853088465 +- 0.010995297631511717\n", "Segmentation Quality Relative Volume Difference (sq_rvd): -0.009548043713894769 +- 0.05397632450411714\n", "\n" ] @@ -338,7 +326,7 @@ "# print all results\n", "results = evaluator.evaluate(pred_masks, ref_masks, verbose=False)\n", "# The groups will have the names specified above\n", - "for groupname, (result, debug) in results.items():\n", + "for groupname, (result, intermediate_steps_data) in results.items():\n", " print()\n", " print(\"### Group\", groupname)\n", " print(result)" @@ -387,10 +375,6 @@ " 'prec': 1.0,\n", " 'rec': 1.0,\n", " 'rq': 1.0,\n", - " 'global_bin_dsc': 0.9631786034883428,\n", - " 'global_bin_cldsc': 0.9832727462458709,\n", - " 'global_bin_assd': 0.16583233154456756,\n", - " 'global_bin_rvd': -0.006522448092183933,\n", " 'sq': 0.9259373047661901,\n", " 'sq_std': 0.009654749671578153,\n", " 'pq': 0.9259373047661901,\n", @@ -400,7 +384,8 @@ " 'sq_assd': 0.16832296646947947,\n", " 'sq_assd_std': 0.01828381629759957,\n", " 'sq_rvd': -0.005930868093584259,\n", - " 'sq_rvd_std': 0.010871203881221219\n", + " 'sq_rvd_std': 0.010871203881221219,\n", + " 'global_bin_dsc': 0.9631786034883428\n", "}\n", "\n" ], @@ -415,10 +400,6 @@ " \u001b[32m'prec'\u001b[0m: \u001b[1;36m1.0\u001b[0m,\n", " \u001b[32m'rec'\u001b[0m: \u001b[1;36m1.0\u001b[0m,\n", " \u001b[32m'rq'\u001b[0m: \u001b[1;36m1.0\u001b[0m,\n", - " \u001b[32m'global_bin_dsc'\u001b[0m: \u001b[1;36m0.9631786034883428\u001b[0m,\n", - " \u001b[32m'global_bin_cldsc'\u001b[0m: \u001b[1;36m0.9832727462458709\u001b[0m,\n", - " \u001b[32m'global_bin_assd'\u001b[0m: \u001b[1;36m0.16583233154456756\u001b[0m,\n", - " \u001b[32m'global_bin_rvd'\u001b[0m: \u001b[1;36m-0.006522448092183933\u001b[0m,\n", " \u001b[32m'sq'\u001b[0m: \u001b[1;36m0.9259373047661901\u001b[0m,\n", " \u001b[32m'sq_std'\u001b[0m: \u001b[1;36m0.009654749671578153\u001b[0m,\n", " \u001b[32m'pq'\u001b[0m: \u001b[1;36m0.9259373047661901\u001b[0m,\n", @@ -428,7 +409,8 @@ " \u001b[32m'sq_assd'\u001b[0m: \u001b[1;36m0.16832296646947947\u001b[0m,\n", " \u001b[32m'sq_assd_std'\u001b[0m: \u001b[1;36m0.01828381629759957\u001b[0m,\n", " \u001b[32m'sq_rvd'\u001b[0m: \u001b[1;36m-0.005930868093584259\u001b[0m,\n", - " \u001b[32m'sq_rvd_std'\u001b[0m: \u001b[1;36m0.010871203881221219\u001b[0m\n", + " \u001b[32m'sq_rvd_std'\u001b[0m: \u001b[1;36m0.010871203881221219\u001b[0m,\n", + " \u001b[32m'global_bin_dsc'\u001b[0m: \u001b[1;36m0.9631786034883428\u001b[0m\n", "\u001b[1m}\u001b[0m\n" ] }, @@ -443,10 +425,85 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "### Group vertebra\n", + "InputType.UNMATCHED_INSTANCE\n", + "Prediction array shape = (164, 399, 17) unique_values= [0 3 4 5 6 7 8 9]\n", + "Reference array shape = (164, 399, 17) unique_values= [0 2 3 4 5 6 7 8]\n", + "\n", + "InputType.MATCHED_INSTANCE\n", + "Prediction array shape = (164, 399, 17) unique_values= [0 2 3 4 5 6 7 8]\n", + "Reference array shape = (164, 399, 17) unique_values= [0 2 3 4 5 6 7 8]\n", + "\n", + "\n", + "### Group ivd\n", + "InputType.UNMATCHED_INSTANCE\n", + "Prediction array shape = (96, 406, 17) unique_values= [ 0 103 104 105 106 107 108 109]\n", + "Reference array shape = (96, 406, 17) unique_values= [ 0 102 103 104 105 106 107 108]\n", + "\n", + "InputType.MATCHED_INSTANCE\n", + "Prediction array shape = (96, 406, 17) unique_values= [ 0 102 103 104 105 106 107 108]\n", + "Reference array shape = (96, 406, 17) unique_values= [ 0 102 103 104 105 106 107 108]\n", + "\n", + "\n", + "### Group sacrum\n", + "InputType.UNMATCHED_INSTANCE\n", + "key UNMATCHED_INSTANCE not in intermediate steps, maybe the step was skipped?\n", + "InputType.MATCHED_INSTANCE\n", + "Prediction array shape = (140, 128, 17) unique_values= [ 0 26]\n", + "Reference array shape = (140, 128, 17) unique_values= [ 0 26]\n", + "\n", + "\n", + "### Group endplate\n", + "InputType.UNMATCHED_INSTANCE\n", + "Prediction array shape = (85, 385, 17) unique_values= [ 0 203 204 205 206 207 208 209]\n", + "Reference array shape = (85, 385, 17) unique_values= [ 0 202 203 204 205 206 207 208]\n", + "\n", + "InputType.MATCHED_INSTANCE\n", + "Prediction array shape = (85, 385, 17) unique_values= [ 0 202 204 206 207 209 210 211]\n", + "Reference array shape = (85, 385, 17) unique_values= [ 0 202 203 204 205 206 207 208]\n", + "\n" + ] + } + ], + "source": [ + "# To inspect different phases, just use the returned intermediate_steps_data object\n", + "\n", + "import numpy as np\n", + "\n", + "for groupname, (result, intermediate_steps_data) in results.items():\n", + " print()\n", + " print(\"### Group\", groupname)\n", + " intermediate_steps_data.original_prediction_arr # yields input prediction array\n", + " intermediate_steps_data.original_reference_arr # yields input reference array\n", + "\n", + " # This works with all phases\n", + " for i in [InputType.UNMATCHED_INSTANCE, InputType.MATCHED_INSTANCE]:\n", + " try:\n", + " print(i)\n", + " pred = intermediate_steps_data.prediction_arr(i)\n", + " ref = intermediate_steps_data.reference_arr(i)\n", + " print(\n", + " \"Prediction array shape =\",\n", + " pred.shape,\n", + " \"unique_values=\",\n", + " np.unique(pred),\n", + " )\n", + " print(\n", + " \"Reference array shape =\", ref.shape, \"unique_values=\", np.unique(ref)\n", + " )\n", + " print()\n", + " except AssertionError as e:\n", + " print(e)\n", + " # This happens because Sacrum class group was set to single_instance, hence the Matching phase is skipped and there is no intermediate result for UNMATCHED_INSTANCE" + ] } ], "metadata": {