diff --git a/examples/registration/atlas_poi_transfer_leg/example.ipynb b/examples/registration/atlas_poi_transfer_leg/example.ipynb index c2af9d94..741f76bf 100644 --- a/examples/registration/atlas_poi_transfer_leg/example.ipynb +++ b/examples/registration/atlas_poi_transfer_leg/example.ipynb @@ -59,14 +59,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "from TPTBox.segmentation.TotalVibeSeg import run_totalvibeseg\n", - "\n", - "path_to_ct = \"...\"\n", - "out_seg = \"seg.nii.gz\"\n", - "ddevice = \"cpu\" #\"cuda\" / \"mps\"\n", - "run_totalvibeseg(path_to_ct,out_seg=out_seg,override=False,gpu=1,ddevice=ddevice,dataset_id=10,keep_size=True)" - ] + "source": "from TPTBox.segmentation import run_vibeseg\n\npath_to_ct = \"...\"\nout_seg = \"seg.nii.gz\"\nddevice = \"cpu\" # \"cuda\" / \"mps\"\nrun_vibeseg(path_to_ct, out_seg=out_seg, override=False, gpu=1, ddevice=ddevice, dataset_id=10, keep_size=True)\n" }, { "cell_type": "markdown", @@ -130,58 +123,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "#Step 1\n", - "from pathlib import Path\n", - "\n", - "from atlas_poi_transfer import parse_coordinates_to_poi, prep_Atlas\n", - "\n", - "from TPTBox import POI, to_nii\n", - "from TPTBox.core.vert_constants import Full_Body_Instance, Lower_Body\n", - "\n", - "##########################################\n", - "#Settings\n", - "text_file_is_left_leg = True\n", - "file_text = \"010__left.txt\"\n", - "segmentation_path = \"/DATA/NAS/datasets_processed/CT_fullbody/dataset-watrinet/source/Dataset001_all/0001/bone.nii.gz\"\n", - "out_folder = Path(\"/DATA/NAS/datasets_processed/CT_fullbody/dataset-watrinet/atlas\")\n", - "atlas_id = 1\n", - "##########################################\n", - "# Load segmentation\n", - "seg = to_nii(segmentation_path,True)\n", - "\n", - "if not text_file_is_left_leg:\n", - " axis = seg.get_axis(\"R\")\n", - " if axis == 0:\n", - " target = seg.set_array(seg.get_array()[::-1]).copy()\n", - " elif axis == 1:\n", - " target = seg.set_array(seg.get_array()[:, ::-1]).copy()\n", - " elif axis == 2:\n", - " target = seg.set_array(seg.get_array()[:, :, ::-1]).copy()\n", - "assert text_file_is_left_leg, \"Not implement: Flip NII and POI\"\n", - "# Prep atlas\n", - "atlas_path = out_folder/f\"atlas{atlas_id:03}.nii.gz\"\n", - "atlas_cms_poi_path = out_folder/f\"atlas{atlas_id:03}_cms_poi.json\" # Center of mass\n", - "atlas_poi_path = out_folder/f\"atlas{atlas_id:03}_poi.json\"\n", - "prep_Atlas(target,atlas_path,atlas_cms_poi_path,text_file_is_left_leg)\n", - "\n", - "\n", - "poi = parse_coordinates_to_poi(file_text, True).to_other(seg) if \".txt\" in file_text else POI.load(file_text).resample_from_to(seg)\n", - "if not text_file_is_left_leg:\n", - " for k1, k2, (x, y, z) in poi.items():\n", - " axis = poi.get_axis(\"R\")\n", - " if axis == 0:\n", - " poi[k1, k2] = (poi.shape[0] - 1 - x, y, z)\n", - " elif axis == 1:\n", - " poi[k1, k2] = (x, poi.shape[1] - 1 - y, z)\n", - " elif axis == 2:\n", - " poi[k1, k2] = (x, y, poi.shape[2] - 1 - z)\n", - " else:\n", - " raise ValueError(axis)\n", - "poi.level_one_info=Full_Body_Instance\n", - "poi.level_two_info=Lower_Body\n", - "poi.to_global().save(atlas_poi_path)\n" - ] + "source": "#Step 1\nfrom pathlib import Path\n\nfrom atlas_poi_transfer_leg_ct import parse_coordinates_to_poi, prep_Atlas\n\nfrom TPTBox import POI, to_nii\nfrom TPTBox.core.vert_constants import Full_Body_Instance, Lower_Body\n\n##########################################\n#Settings\ntext_file_is_left_leg = True\nfile_text = \"010__left.txt\"\nsegmentation_path = \"/DATA/NAS/datasets_processed/CT_fullbody/dataset-watrinet/source/Dataset001_all/0001/bone.nii.gz\"\nct_path = \"/DATA/NAS/datasets_processed/CT_fullbody/dataset-watrinet/source/Dataset001_all/0001/ct.nii.gz\"\nout_folder = Path(\"/DATA/NAS/datasets_processed/CT_fullbody/dataset-watrinet/atlas\")\natlas_id = 1\n##########################################\n# Load segmentation\nseg = to_nii(segmentation_path,True)\n\nif not text_file_is_left_leg:\n axis = seg.get_axis(\"R\")\n if axis == 0:\n target = seg.set_array(seg.get_array()[::-1]).copy()\n elif axis == 1:\n target = seg.set_array(seg.get_array()[:, ::-1]).copy()\n elif axis == 2:\n target = seg.set_array(seg.get_array()[:, :, ::-1]).copy()\nassert text_file_is_left_leg, \"Not implement: Flip NII and POI\"\n# Prep atlas\natlas_path = out_folder/f\"atlas{atlas_id:03}.nii.gz\"\nct_atlas_path = out_folder/f\"atlas{atlas_id:03}_ct.nii.gz\" # cropped CT saved next to the atlas\natlas_cms_poi_path = out_folder/f\"atlas{atlas_id:03}_cms_poi.json\" # Center of mass\natlas_poi_path = out_folder/f\"atlas{atlas_id:03}_poi.json\"\nprep_Atlas(seg, ct_path, atlas_path, ct_atlas_path, atlas_cms_poi_path, atlas_left=text_file_is_left_leg)\n\n\npoi = parse_coordinates_to_poi(file_text, True).to_other(seg) if \".txt\" in file_text else POI.load(file_text).resample_from_to(seg)\nif not text_file_is_left_leg:\n for k1, k2, (x, y, z) in poi.items():\n axis = poi.get_axis(\"R\")\n if axis == 0:\n poi[k1, k2] = (poi.shape[0] - 1 - x, y, z)\n elif axis == 1:\n poi[k1, k2] = (x, poi.shape[1] - 1 - y, z)\n elif axis == 2:\n poi[k1, k2] = (x, y, poi.shape[2] - 1 - z)\n else:\n raise ValueError(axis)\npoi.level_one_info=Full_Body_Instance\npoi.level_two_info=Lower_Body\npoi.to_global().save(atlas_poi_path)\n" }, { "cell_type": "markdown", @@ -217,36 +159,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "#Step 1\n", - "from pathlib import Path\n", - "\n", - "from atlas_poi_transfer import Register_Point_Atlas\n", - "\n", - "from TPTBox import POI, to_nii\n", - "\n", - "##########################################\n", - "#Settings\n", - "target_seg_path = \"/DATA/NAS/datasets_processed/CT_fullbody/dataset-watrinet/source/Dataset001_all/0003/bone.nii.gz\"#TODO Path to target seg\n", - "s = str(target_seg_path).split('.')[0]\n", - "split_leg_path = s + \"_seg-left-right-split_msk.nii.gz\"\n", - "out_new_pois = s + \"_desc-leg_poi.json\"\n", - "out_new_pois_nii = s + \"_desc-leg_poi.nii.gz\"\n", - "atlas_id = 1\n", - "ddevice = \"cuda\"\n", - "gpu = 0\n", - "##########################################\n", - "# Atlas\n", - "atlas_p = out_folder/f\"atlas{atlas_id:03}.nii.gz\"\n", - "atlas_centroids = out_folder/f\"atlas{atlas_id:03}_cms_poi.json\" # Center of mass\n", - "atlas_poi_path = out_folder/f\"atlas{atlas_id:03}_poi.json\"\n", - "# Load segmentation\n", - "target = to_nii(target_seg_path,True)\n", - "atlas = to_nii(atlas_p,True)\n", - "\n", - "#Creating this object will start the registration\n", - "registration_obj = Register_Point_Atlas(target,atlas,split_leg_path=split_leg_path,atlas_centroids=atlas_centroids,gpu=gpu,ddevice=ddevice, verbose=0)" - ] + "source": "#Step 1\nfrom pathlib import Path\n\nfrom atlas_poi_transfer_leg_ct import Register_Point_Atlas\n\nfrom TPTBox import POI, to_nii\n\n##########################################\n#Settings\ntarget_seg_path = \"/DATA/NAS/datasets_processed/CT_fullbody/dataset-watrinet/source/Dataset001_all/0003/bone.nii.gz\"#TODO Path to target seg\ns = str(target_seg_path).split('.')[0]\nsplit_leg_path = s + \"_seg-left-right-split_msk.nii.gz\"\nout_new_pois = s + \"_desc-leg_poi.json\"\nout_new_pois_nii = s + \"_desc-leg_poi.nii.gz\"\natlas_id = 1\nddevice = \"cuda\"\ngpu = 0\n##########################################\n# Atlas\natlas_p = out_folder/f\"atlas{atlas_id:03}.nii.gz\"\natlas_centroids = out_folder/f\"atlas{atlas_id:03}_cms_poi.json\" # Center of mass\natlas_poi_path = out_folder/f\"atlas{atlas_id:03}_poi.json\"\n# Load segmentation\ntarget = to_nii(target_seg_path,True)\natlas = to_nii(atlas_p,True)\n\n#Creating this object will start the registration\nregistration_obj = Register_Point_Atlas(target,atlas,split_leg_path=split_leg_path,atlas_centroids=atlas_centroids,gpu=gpu,ddevice=ddevice, verbose=0)\n" }, { "cell_type": "code", @@ -321,4 +234,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/examples/registration/atlas_poi_transfer_leg/example.py b/examples/registration/atlas_poi_transfer_leg/example.py index 2e80189d..6d4bb309 100644 --- a/examples/registration/atlas_poi_transfer_leg/example.py +++ b/examples/registration/atlas_poi_transfer_leg/example.py @@ -14,6 +14,7 @@ text_file_is_left_leg = True file_text = "/DATA/NAS/tools/TPTBox/examples/atlas_poi_transfer_leg/010__left.txt" segmentation_path = "/DATA/NAS/datasets_processed/CT_fullbody/dataset-watrinet/source/Dataset001_all/0001/bone.nii.gz" +ct_path = "/DATA/NAS/datasets_processed/CT_fullbody/dataset-watrinet/source/Dataset001_all/0001/ct.nii.gz" out_folder = Path("/DATA/NAS/datasets_processed/CT_fullbody/dataset-watrinet/atlas2") atlas_id = 1 ########################################## @@ -31,9 +32,10 @@ assert text_file_is_left_leg, "Not implement: Flip NII and POI" # Prep atlas atlas_path = out_folder / f"atlas{atlas_id:03}.nii.gz" +ct_atlas_path = out_folder / f"atlas{atlas_id:03}_ct.nii.gz" # cropped CT saved next to the atlas atlas_cms_poi_path = out_folder / f"atlas{atlas_id:03}_cms_poi.json" # Center of mass atlas_poi_path = out_folder / f"atlas{atlas_id:03}_poi.json" -prep_Atlas(seg, atlas_path, atlas_cms_poi_path, text_file_is_left_leg) +prep_Atlas(seg, ct_path, atlas_path, ct_atlas_path, atlas_cms_poi_path, atlas_left=text_file_is_left_leg) poi = parse_coordinates_to_poi(file_text, True).to_other(seg) if ".txt" in file_text else POI.load(file_text).resample_from_to(seg) diff --git a/tutorials/tutorial_Dataset_processing.ipynb b/tutorials/tutorial_Dataset_processing.ipynb index c5251ffe..86e2d299 100644 --- a/tutorials/tutorial_Dataset_processing.ipynb +++ b/tutorials/tutorial_Dataset_processing.ipynb @@ -896,54 +896,14 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "from pathlib import Path\n", - "\n", - "from TPTBox import NII, Location, Vertebra_Instance, calc_poi_from_subreg_vert, to_nii\n", - "from TPTBox.registration import Point_Registration, ridged_points_from_poi\n", - "\n", - "# Example registration two sagittal images, like for compensating movement between scans.\n", - "poi_fixed = calc_poi_from_subreg_vert(nii_instance1, nii_semantic1, subreg_id=[Location.Vertebra_Corpus, Location.Spinosus_Process]).round(\n", - " 2\n", - ")\n", - "poi_moving = calc_poi_from_subreg_vert(nii_instance2, nii_semantic2, subreg_id=[Location.Vertebra_Corpus, Location.Spinosus_Process]).round(\n", - " 2\n", - ")\n", - "\n", - "registration_object: Point_Registration = ridged_points_from_poi(poi_fixed, poi_moving, c_val=0)\n", - "\n", - "# Move image\n", - "moved_nii = registration_object.transform_nii(image2)\n", - "print(moved_nii, \"\\n\", image2, \"\\n\")\n", - "# Move poi\n", - "moved_poi = registration_object.transform_poi(poi_moving).round(1)\n", - "print(moved_poi, \"\\n\", poi_moving, \"\\n\")\n" - ] + "source": "from pathlib import Path\n\nfrom TPTBox import NII, Location, Vertebra_Instance, calc_poi_from_subreg_vert, to_nii\nfrom TPTBox.registration import Point_Registration, ridged_points_from_poi\n\n# Example registration two sagittal images, like for compensating movement between scans.\npoi_fixed = calc_poi_from_subreg_vert(nii_instance1, nii_semantic1, subreg_id=[Location.Vertebra_Corpus, Location.Spinosus_Process]).round(\n 2\n)\npoi_moving = calc_poi_from_subreg_vert(nii_instance2, nii_semantic2, subreg_id=[Location.Vertebra_Corpus, Location.Spinosus_Process]).round(\n 2\n)\n\nregistration_object: Point_Registration = ridged_points_from_poi(poi_fixed, poi_moving)\n\n# Move image\nmoved_nii = registration_object.transform_nii(image2)\nprint(moved_nii, \"\\n\", image2, \"\\n\")\n# Move poi\nmoved_poi = registration_object.transform_poi(poi_moving).round(1)\nprint(moved_poi, \"\\n\", poi_moving, \"\\n\")\n" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "from TPTBox import NII, Location, Vertebra_Instance, calc_poi_from_subreg_vert\n", - "from TPTBox.registration import Point_Registration, ridged_points_from_poi\n", - "\n", - "# Example registration two sagittal images, like for compensating movement between scans.\n", - "poi_fixed = calc_poi_from_subreg_vert(nii_instance1, nii_semantic1, subreg_id=[Location.Vertebra_Corpus, Location.Spinosus_Process]).round(\n", - " 2\n", - ")\n", - "poi_moving = calc_poi_from_subreg_vert(nii_instance2, nii_semantic2, subreg_id=[Location.Vertebra_Corpus, Location.Spinosus_Process]).round(\n", - " 2\n", - ")\n", - "registration_object: Point_Registration = ridged_points_from_poi(poi_fixed, poi_moving, c_val=0)\n", - "# Move image\n", - "moved_nii = registration_object.transform_nii(image2, output_space=fixed_image)\n", - "print(moved_nii, \"\\n\", image2, \"\\n\")\n", - "# Move poi\n", - "moved_poi = registration_object.transform_poi(poi_moving).round(1)\n", - "print(moved_poi, \"\\n\", poi_moving, \"\\n\")\n" - ] + "source": "from TPTBox import NII, Location, Vertebra_Instance, calc_poi_from_subreg_vert\nfrom TPTBox.registration import Point_Registration, ridged_points_from_poi\n\n# Example registration two sagittal images, like for compensating movement between scans.\npoi_fixed = calc_poi_from_subreg_vert(nii_instance1, nii_semantic1, subreg_id=[Location.Vertebra_Corpus, Location.Spinosus_Process]).round(\n 2\n)\npoi_moving = calc_poi_from_subreg_vert(nii_instance2, nii_semantic2, subreg_id=[Location.Vertebra_Corpus, Location.Spinosus_Process]).round(\n 2\n)\nregistration_object: Point_Registration = ridged_points_from_poi(poi_fixed, poi_moving)\n# Move image\nmoved_nii = registration_object.transform_nii(image2, output_space=fixed_image)\nprint(moved_nii, \"\\n\", image2, \"\\n\")\n# Move poi\nmoved_poi = registration_object.transform_poi(poi_moving).round(1)\nprint(moved_poi, \"\\n\", poi_moving, \"\\n\")\n" }, { "cell_type": "code", @@ -980,62 +940,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "from TPTBox import NII, Location, Vertebra_Instance, calc_poi_from_subreg_vert\n", - "from TPTBox.registration import Point_Registration, ridged_points_from_poi\n", - "from TPTBox.segmentation.VibeSeg.vibeseg import extract_vertebra_bodies_from_VibeSeg\n", - "\n", - "# Example registration axial and sagittal with points.\n", - "# T2w axial points are computed from the vibe segment.\n", - "dataset = target_folder / \"dataset-tutorial-data-processing\"\n", - "\n", - "nii_instance_path2 = out_paths[\"out_vert\"]\n", - "nii_semantic_path2 = out_paths[\"out_spine\"]\n", - "# We recommend if you registrade spineps points too use at least two points.\n", - "poi_fixed = calc_poi_from_subreg_vert(nii_instance_path, nii_semantic_path, subreg_id=[Location.Vertebra_Corpus]).round(1)\n", - "fixed_image = BIDS_FILE(\n", - " f\"{dataset}/rawdata_stiched/sub-111168223/ses-20230128/T2w/sub-111168223_ses-20230128_sequ-401-stiched_acq-sag_part-inphase_T2w.nii.gz\",\n", - " dataset,\n", - ")\n", - "\n", - "moving_file = BIDS_FILE(\n", - " f\"{dataset}/rawdata_stiched/sub-111168223/ses-20230128/dixon/sub-111168223_ses-20230128_sequ-501-stiched_acq-ax_part-water_dixon.nii.gz\",\n", - " dataset,\n", - ")\n", - "out_file = moving_file.get_changed_path(\n", - " \"nii.gz\", \"msk\", parent=\"derivative\", info={\"seg\": \"VibeSegmentator\", \"mod\": moving_file.bids_format}\n", - ")\n", - "moving_image = to_nii(moving_file)\n", - "out_file = to_nii(out_file, True)\n", - "\n", - "#### Let's move the image, so we see better that the registration is working.\n", - "moving_image.origin = (moving_image.origin[0], moving_image.origin[1], moving_image.origin[2] + 175)\n", - "out_file.origin = moving_image.origin\n", - "####\n", - "\n", - "# Ensure that we count the same as in the T2w sagittal\n", - "num_thoracic_verts = 12\n", - "if Vertebra_Instance.T13.value in poi_fixed.keys_region():\n", - " num_thoracic_verts = 13\n", - "if Vertebra_Instance.T12.value not in poi_fixed.keys_region():\n", - " num_thoracic_verts = 11\n", - "num_lumbar_verts = 5\n", - "if Vertebra_Instance.L6.value in poi_fixed.keys_region():\n", - " num_lumbar_verts = 6\n", - "if Vertebra_Instance.L5.value not in poi_fixed.keys_region():\n", - " num_lumbar_verts = 4\n", - "# Note: this function currently assumes that we see the sacrum in the image.\n", - "nii, poi_moving = extract_vertebra_bodies_from_VibeSeg(out_file, num_lumbar_verts=num_lumbar_verts, num_thoracic_verts=num_thoracic_verts)\n", - "\n", - "registration_object: Point_Registration = ridged_points_from_poi(poi_fixed, poi_moving, c_val=0)\n", - "\n", - "# Move image\n", - "moved_nii = registration_object.transform_nii(moving_image)\n", - "print(moved_nii, \"\\n\", moving_image, \"\\n\")\n", - "# Move poi\n", - "moved_poi = registration_object.transform_poi(poi_moving).round(1)\n", - "print(moved_poi, \"\\n\", poi_moving, \"\\n\")\n" - ] + "source": "from TPTBox import NII, Location, Vertebra_Instance, calc_poi_from_subreg_vert\nfrom TPTBox.registration import Point_Registration, ridged_points_from_poi\nfrom TPTBox.segmentation.VibeSeg.vibeseg import extract_vertebra_bodies_from_VibeSeg\n\n# Example registration axial and sagittal with points.\n# T2w axial points are computed from the vibe segment.\ndataset = target_folder / \"dataset-tutorial-data-processing\"\n\nnii_instance_path2 = out_paths[\"out_vert\"]\nnii_semantic_path2 = out_paths[\"out_spine\"]\n# We recommend if you registrade spineps points too use at least two points.\npoi_fixed = calc_poi_from_subreg_vert(nii_instance_path, nii_semantic_path, subreg_id=[Location.Vertebra_Corpus]).round(1)\nfixed_image = BIDS_FILE(\n f\"{dataset}/rawdata_stiched/sub-111168223/ses-20230128/T2w/sub-111168223_ses-20230128_sequ-401-stiched_acq-sag_part-inphase_T2w.nii.gz\",\n dataset,\n)\n\nmoving_file = BIDS_FILE(\n f\"{dataset}/rawdata_stiched/sub-111168223/ses-20230128/dixon/sub-111168223_ses-20230128_sequ-501-stiched_acq-ax_part-water_dixon.nii.gz\",\n dataset,\n)\nout_file = moving_file.get_changed_path(\n \"nii.gz\", \"msk\", parent=\"derivative\", info={\"seg\": \"VibeSegmentator\", \"mod\": moving_file.bids_format}\n)\nmoving_image = to_nii(moving_file)\nout_file = to_nii(out_file, True)\n\n#### Let's move the image, so we see better that the registration is working.\nmoving_image.origin = (moving_image.origin[0], moving_image.origin[1], moving_image.origin[2] + 175)\nout_file.origin = moving_image.origin\n####\n\n# Ensure that we count the same as in the T2w sagittal\nnum_thoracic_verts = 12\nif Vertebra_Instance.T13.value in poi_fixed.keys_region():\n num_thoracic_verts = 13\nif Vertebra_Instance.T12.value not in poi_fixed.keys_region():\n num_thoracic_verts = 11\nnum_lumbar_verts = 5\nif Vertebra_Instance.L6.value in poi_fixed.keys_region():\n num_lumbar_verts = 6\nif Vertebra_Instance.L5.value not in poi_fixed.keys_region():\n num_lumbar_verts = 4\n# Note: this function currently assumes that we see the sacrum in the image.\nnii, poi_moving = extract_vertebra_bodies_from_VibeSeg(out_file, num_lumbar_verts=num_lumbar_verts, num_thoracic_verts=num_thoracic_verts)\n\nregistration_object: Point_Registration = ridged_points_from_poi(poi_fixed, poi_moving)\n\n# Move image\nmoved_nii = registration_object.transform_nii(moving_image)\nprint(moved_nii, \"\\n\", moving_image, \"\\n\")\n# Move poi\nmoved_poi = registration_object.transform_poi(poi_moving).round(1)\nprint(moved_poi, \"\\n\", poi_moving, \"\\n\")\n" }, { "cell_type": "code", @@ -1192,4 +1097,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} +} \ No newline at end of file diff --git a/tutorials/tutorial_Nifty.ipynb b/tutorials/tutorial_Nifty.ipynb index 6cbd9554..7b75ffc4 100755 --- a/tutorials/tutorial_Nifty.ipynb +++ b/tutorials/tutorial_Nifty.ipynb @@ -142,27 +142,7 @@ "metadata": { "collapsed": false }, - "source": [ - "## Manipulate Nifty\n", - "\n", - "Sometimes, it is vital to resample nifty into isotropic (1,1,1) space.\n", - "This can be done with nifty.rescale()\n", - "\n", - "Important functions are:\n", - "- rescale(voxel_spacing: tuple(float, float, float)) # Rescales the image date to the given resolution\n", - "- reorient(axcodes_to: Ax_Codes) # Reorients the data to the given ax codes (see orientation above)\n", - "- extract_label(label: int) # returns a new array that only contains the given label (useful for segmentations)\n", - "\n", - "- compute_crop_slice() # is used to compute a bounding box around the used space of the image data\n", - "- apply_crop_slice() # is used after compute_crop_slice() to perform the actual cutout of the bounding box\n", - "\n", - "Functions could exist both with and without a \"_\" at the end. The \"_\" version is the inplace variant (will directly modify that object).\n", - "Example:\n", - "\n", - "nii.rescale((\"P\", \"I\", \"R\")) returns a rescaled copy of the array, while\n", - "\n", - "nii.rescale_((\"P\", \"I\", \"R\")) modifies the nii object directly, rescaling it." - ] + "source": "## Manipulate Nifty\n\nSometimes, it is vital to resample nifty into isotropic (1,1,1) space.\nThis can be done with nifty.rescale()\n\nImportant functions are:\n- rescale(voxel_spacing: tuple(float, float, float)) # Rescales the image date to the given resolution\n- reorient(axcodes_to: Ax_Codes) # Reorients the data to the given ax codes (see orientation above)\n- extract_label(label: int) # returns a new array that only contains the given label (useful for segmentations)\n\n- compute_crop() # is used to compute a bounding box around the used space of the image data\n- apply_crop() # is used after compute_crop() to perform the actual cutout of the bounding box\n\nFunctions could exist both with and without a \"_\" at the end. The \"_\" version is the inplace variant (will directly modify that object).\nExample:\n\nnii.rescale((\"P\", \"I\", \"R\")) returns a rescaled copy of the array, while\n\nnii.rescale_((\"P\", \"I\", \"R\")) modifies the nii object directly, rescaling it." }, { "cell_type": "code", @@ -209,30 +189,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "crop = bids_nii.compute_crop_slice(dist=10)\n", - "small_nii = bids_nii.apply_crop_slice(crop)\n", - "# do something with small_nii\n", - "# ...\n", - "# Save back to big array\n", - "arr = bids_nii.get_array()\n", - "arr[crop] = small_nii.get_array()\n", - "bids_nii.set_array(arr, inplace=True)" - ] + "outputs": [], + "source": "crop = bids_nii.compute_crop(dist=10)\nsmall_nii = bids_nii.apply_crop(crop)\n# do something with small_nii\n# ...\n# Save back to big array\narr = bids_nii.get_array()\narr[crop] = small_nii.get_array()\nbids_nii.set_array(arr, inplace=True)" }, { "cell_type": "markdown", @@ -257,80 +217,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "# NII\n", - "## Summary\n", - "The `NII` class represents a NIfTI image and provides various methods for manipulating and analyzing the image data.\n", - "\n", - "## Example Usage\n", - "```python\n", - "# Create a NII object from a NIfTI file\n", - "nii = NII(nib.load('image.nii.gz'))\n", - "\n", - "# Access the shape of the image\n", - "shape = nii.shape\n", - "\n", - "# Rescale the image to a new voxel spacing\n", - "rescaled = nii.rescale(voxel_spacing=(2, 2, 2))\n", - "\n", - "# Save the rescaled image to a new file\n", - "rescaled.save('rescaled_image.nii.gz')\n", - "```\n", - "\n", - "## Code Analysis\n", - "### Main functionalities\n", - "- Loading and saving NIfTI images\n", - "- Accessing image properties such as shape, data type, header, affine transformation, orientation, zoom, and origin\n", - "- Reorienting the image to a desired orientation\n", - "- Rescaling the image to a new voxel spacing\n", - "- Applying a crop slice to the image\n", - "- Setting the image array to a new array\n", - "- Eroding and dilating binary segmentation masks\n", - "- Filling holes in segmentation masks\n", - "- Mapping labels to new values\n", - "- Computing the intersection volume between two images\n", - "___\n", - "### Methods\n", - "- `load`: Loads a NIfTI image from a file path\n", - "- `load_bids`: Loads a NIfTI image from a BIDS file object\n", - "- `shape`: Returns the shape of the image\n", - "- `dtype`: Returns the data type of the image\n", - "- `header`: Returns the header of the image\n", - "- `affine`: Returns the affine transformation matrix of the image\n", - "- `orientation`: Returns the orientation of the image\n", - "- `zoom`: Returns the zoom values of the image\n", - "- `origin`: Returns the origin coordinates of the image\n", - "- `rotation`: Returns the rotation matrix of the image\n", - "- `get_c_val`: Returns the contrast value of the image\n", - "- `get_seg_array`: Returns the segmentation array of the image\n", - "- `get_array`: Returns the image array\n", - "- `set_array`: Sets the image array to a new array\n", - "- `reorient`: Reorients the image to a desired orientation\n", - "- `compute_crop_slice`: Computes the minimum slice to crop the image\n", - "- `apply_crop_slice`: Applies a crop slice to the image\n", - "- `rescale`: Rescales the image to a new voxel spacing\n", - "- `resample_from_to`: Resamples the image to the voxel mapping of another image\n", - "- `n4_bias_field_correction`: Performs N4 bias field correction on the image\n", - "- `match_histograms`: Matches the histogram of the image to a reference image\n", - "- `get_plane`: Determines the orientation plane of the image\n", - "- `erode_msk`: Erodes the binary segmentation mask\n", - "- `dilate_msk`: Dilates the binary segmentation mask\n", - "- `fill_holes`: Fills holes in the segmentation mask\n", - "- `map_labels`: Maps labels in the segmentation mask to new values\n", - "- `unique`: Returns the unique labels in the segmentation mask\n", - "- `volumes`: Computes the volumes of the labels in the segmentation mask\n", - "- `extract_label`: Extracts a single label from the segmentation mask\n", - "- `remove_labels`: Removes specified labels from the segmentation mask\n", - "- `apply_mask`: Applies a mask to the image\n", - "- `multiply`: Multiplies the image by a scalar value\n", - "- `save`: Saves the image to a NIfTI file\n", - "___\n", - "### Fields\n", - "- `nii`: The NIfTI image object\n", - "- `seg`: A boolean indicating whether the image is a segmentation mask\n", - "- `c_val`: The contrast value of the image\n", - "___\n" - ] + "source": "# NII\n## Summary\nThe `NII` class represents a NIfTI image and provides various methods for manipulating and analyzing the image data.\n\n## Example Usage\n```python\n# Create a NII object from a NIfTI file\nnii = NII(nib.load('image.nii.gz'))\n\n# Access the shape of the image\nshape = nii.shape\n\n# Rescale the image to a new voxel spacing\nrescaled = nii.rescale(voxel_spacing=(2, 2, 2))\n\n# Save the rescaled image to a new file\nrescaled.save('rescaled_image.nii.gz')\n```\n\n## Code Analysis\n### Main functionalities\n- Loading and saving NIfTI images\n- Accessing image properties such as shape, data type, header, affine transformation, orientation, zoom, and origin\n- Reorienting the image to a desired orientation\n- Rescaling the image to a new voxel spacing\n- Applying a crop slice to the image\n- Setting the image array to a new array\n- Eroding and dilating binary segmentation masks\n- Filling holes in segmentation masks\n- Mapping labels to new values\n- Computing the intersection volume between two images\n___\n### Methods\n- `load`: Loads a NIfTI image from a file path\n- `load_bids`: Loads a NIfTI image from a BIDS file object\n- `shape`: Returns the shape of the image\n- `dtype`: Returns the data type of the image\n- `header`: Returns the header of the image\n- `affine`: Returns the affine transformation matrix of the image\n- `orientation`: Returns the orientation of the image\n- `zoom`: Returns the zoom values of the image\n- `origin`: Returns the origin coordinates of the image\n- `rotation`: Returns the rotation matrix of the image\n- `get_c_val`: Returns the contrast value of the image\n- `get_seg_array`: Returns the segmentation array of the image\n- `get_array`: Returns the image array\n- `set_array`: Sets the image array to a new array\n- `reorient`: Reorients the image to a desired orientation\n- `compute_crop`: Computes the minimum slice to crop the image\n- `apply_crop`: Applies a crop slice to the image\n- `rescale`: Rescales the image to a new voxel spacing\n- `resample_from_to`: Resamples the image to the voxel mapping of another image\n- `n4_bias_field_correction`: Performs N4 bias field correction on the image\n- `match_histograms`: Matches the histogram of the image to a reference image\n- `get_plane`: Determines the orientation plane of the image\n- `erode_msk`: Erodes the binary segmentation mask\n- `dilate_msk`: Dilates the binary segmentation mask\n- `fill_holes`: Fills holes in the segmentation mask\n- `map_labels`: Maps labels in the segmentation mask to new values\n- `unique`: Returns the unique labels in the segmentation mask\n- `volumes`: Computes the volumes of the labels in the segmentation mask\n- `extract_label`: Extracts a single label from the segmentation mask\n- `remove_labels`: Removes specified labels from the segmentation mask\n- `apply_mask`: Applies a mask to the image\n- `multiply`: Multiplies the image by a scalar value\n- `save`: Saves the image to a NIfTI file\n___\n### Fields\n- `nii`: The NIfTI image object\n- `seg`: A boolean indicating whether the image is a segmentation mask\n- `c_val`: The contrast value of the image\n___\n" } ], "metadata": { @@ -354,4 +241,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} +} \ No newline at end of file diff --git a/tutorials/tutorial_POI.ipynb b/tutorials/tutorial_POI.ipynb index d11e502a..b1703e0f 100755 --- a/tutorials/tutorial_POI.ipynb +++ b/tutorials/tutorial_POI.ipynb @@ -64,157 +64,22 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "\n", - "## Code Analysis\n", - "### Main functionalities\n", - "- Represents a collection of centroids used to define points of interest in medical imaging data.\n", - "- Provides methods for manipulating and working with the centroid data.\n", - "___\n", - "### Methods\n", - "- `is_global`: Property indicating whether the POI is a global POI.\n", - "- `zoom`: Property getter for the zoom level.\n", - "- `affine`: Property representing the affine transformation for the image.\n", - "- `clone`: Creates a copy of the POI object with optional attribute overrides.\n", - "- `copy`: Creates a copy of the POI object with optional attribute overrides.\n", - "- `local_to_global`: Converts local coordinates to global coordinates using zoom, rotation, and origin.\n", - "- `global_to_local`: Converts global coordinates to local coordinates using zoom, rotation, and origin.\n", - "- `crop_centroids`: Crops the centroids based on the given origin shift due to the image crop.\n", - "- `shift_all_centroid_coordinates`: Shifts all centroid coordinates based on the given translation vector.\n", - "- `reorient`: Reorients the centroids of an image from the current orientation to the specified orientation.\n", - "- `reorient_centroids_to`: Reorients the centroids to the orientation of a given image.\n", - "- `rescale`: Rescales the centroid coordinates to a new voxel spacing in the current x-y-z-orientation.\n", - "- `map_labels`: Maps regions and subregions to new regions and subregions based on a label map dictionary.\n", - "- `save`: Saves the centroids to a JSON file.\n", - "- `sort`: Sorts the centroids by the sorting list.\n", - "- `make_point_cloud_nii`: Creates point cloud NIfTI images from the centroid coordinates.\n", - "- `filter_points_inside_shape`: Filters out centroid points that are outside the defined shape.\n", - "- `round`: Rounds the centroid coordinates to a specified number of digits.\n", - "- `calculate_distances`: Calculates the distances between the target point and each centroid.\n", - "- `remove_centroid`: Removes centroid points with the specified labels.\n", - "___\n", - "### Fields\n", - "- `orientation`: The orientation of the image.\n", - "- `zoom`: The zoom level of the image.\n", - "- `shape`: The shape of the image.\n", - "- `sorting_list`: The order of the centroid points.\n", - "- `format`: The format of the image.\n", - "- `info`: Additional information stored as key-value pairs.\n", - "- `rotation`: The rotation matrix for the image orientation.\n", - "- `origin`: The origin of the image in millimeters along the x, y, and z axes.\n", - "___\n" - ] + "source": "\n## Code Analysis\n### Main functionalities\n- Represents a collection of centroids used to define points of interest in medical imaging data.\n- Provides methods for manipulating and working with the centroid data.\n___\n### Methods\n- `is_global`: Property indicating whether the POI is a global POI.\n- `zoom`: Property getter for the zoom level.\n- `affine`: Property representing the affine transformation for the image.\n- `clone`: Creates a copy of the POI object with optional attribute overrides.\n- `copy`: Creates a copy of the POI object with optional attribute overrides.\n- `local_to_global`: Converts local coordinates to global coordinates using zoom, rotation, and origin.\n- `global_to_local`: Converts global coordinates to local coordinates using zoom, rotation, and origin.\n- `apply_crop`: Crops the centroids based on the given origin shift due to the image crop.\n- `shift_all_coordinates`: Shifts all centroid coordinates based on the given translation vector.\n- `reorient`: Reorients the centroids of an image from the current orientation to the specified orientation.\n- `rescale`: Rescales the centroid coordinates to a new voxel spacing in the current x-y-z-orientation.\n- `resample_from_to`: Resamples the centroids to the voxel mapping of another image / POI.\n- `map_labels`: Maps regions and subregions to new regions and subregions based on a label map dictionary.\n- `save`: Saves the centroids to a JSON file.\n- `sort`: Sorts the centroids by the sorting list.\n- `make_point_cloud_nii`: Creates point cloud NIfTI images from the centroid coordinates.\n- `filter_points_inside_shape`: Filters out centroid points that are outside the defined shape.\n- `round`: Rounds the centroid coordinates to a specified number of digits.\n- `calculate_distances`: Calculates the distances between the target point and each centroid.\n- `remove_centroid`: Removes centroid points with the specified labels.\n___\n### Fields\n- `orientation`: The orientation of the image.\n- `zoom`: The zoom level of the image.\n- `shape`: The shape of the image.\n- `sorting_list`: The order of the centroid points.\n- `format`: The format of the image.\n- `info`: Additional information stored as key-value pairs.\n- `rotation`: The rotation matrix for the image orientation.\n- `origin`: The origin of the image in millimeters along the x, y, and z axes.\n___\n" }, { "cell_type": "markdown", "metadata": {}, - "source": [ - "# calc_centroids_from_subreg_vert\n", - "## Summary\n", - "The `calc_centroids_from_subreg_vert` function calculates the centroids of a subregion within a vertebral mask. It takes in a vertebral mask image reference and a subregion image reference, along with optional parameters such as the number of decimal places to round the output coordinates, the subregion ID(s) to calculate centroids for, the target orientation of the images, and whether to print progress messages. If a target orientation is specified, the images are reoriented accordingly. If multiple subregion IDs are provided, the function recursively calls itself for each ID and aggregates the centroid coordinates into a `POI` object. The function returns a `POI` object containing the calculated centroid coordinates.\n", - "\n", - "## Example Usage\n", - "```python\n", - "# Calculate centroids for a subregion within a vertebral mask\n", - "vert_msk = NII.load(...,True)\n", - "subreg = NII.load(...,True)\n", - "centroids = calc_centroids_from_subreg_vert(vert_msk, subreg, decimals=1, subreg_id=50)\n", - "\n", - "# Print the centroid coordinates\n", - "print(centroids.centroids)\n", - "```\n", - "\n", - "## Code Analysis\n", - "### Inputs\n", - "- `vert_msk` (Image_Reference): A vertebral mask image reference.\n", - "- `subreg` (Image_Reference): An image reference for the subregion of interest.\n", - "- `decimals` (int, optional): Number of decimal places to round the output coordinates to. Defaults to 1.\n", - "- `subreg_id` (int | Location | list[int | Location], optional): The ID(s) of the subregion(s) to calculate centroids for. Defaults to 50.\n", - "- `axcodes_to` (Ax_Codes | None, optional): A tuple of axis codes indicating the target orientation of the images. Defaults to None.\n", - "- `verbose` (bool, optional): Whether to print progress messages. Defaults to False.\n", - "- `extend_to` (POI | None, optional): An existing POI object to extend with the new centroid values. Defaults to None.\n", - "___\n", - "### Outputs\n", - "- `POI`: A `POI` object containing the calculated centroid coordinates.\n", - "___\n" - ] + "source": "# calc_poi_from_subreg_vert\n## Summary\nThe `calc_poi_from_subreg_vert` function calculates the POIs of a subregion within a vertebral mask. It takes in a vertebral mask image reference and a subregion image reference, along with optional parameters such as the number of decimal places to round the output coordinates, the subregion ID(s) to calculate POIs for, and whether to print progress messages. If multiple subregion IDs are provided, the function computes all of them and aggregates the coordinates into a single `POI` object. The function returns a `POI` object containing the calculated POI coordinates.\n\n## Example Usage\n```python\n# Calculate POIs for a subregion within a vertebral mask\nvert_msk = NII.load(..., True)\nsubreg = NII.load(..., True)\ncentroids = calc_poi_from_subreg_vert(vert_msk, subreg, decimals=1, subreg_id=50)\n\n# Print the coordinates\nprint(centroids.centroids)\n```\n\n## Code Analysis\n### Inputs\n- `vert` (Image_Reference): A vertebral mask image reference.\n- `subreg` (Image_Reference): An image reference for the subregion of interest.\n- `decimals` (int, optional): Number of decimal places to round the output coordinates to. Defaults to 2.\n- `subreg_id` (int | Location | list[int | Location], optional): The ID(s) of the subregion(s) to calculate POIs for. Defaults to 50.\n- `verbose` (bool, optional): Whether to print progress messages. Defaults to False.\n- `extend_to` (POI | None, optional): An existing POI object to extend with the new POI values. Defaults to None.\n- `buffer_file` (str | Path | None, keyword-only): Optional cache file. When provided and existing, the POIs are loaded from it and only missing points are (re-)computed.\n- `save_buffer_file` (bool, keyword-only): If True, persist the resulting POI back to `buffer_file` when new points were added.\n___\n### Outputs\n- `POI`: A `POI` object containing the calculated POI coordinates.\n___\n" }, { "cell_type": "markdown", "metadata": {}, - "source": [ - "# calc_centroids\n", - "## Summary\n", - "The `calc_centroids` function calculates the centroid coordinates of each region in a given mask image.\n", - "\n", - "## Example Usage\n", - "```python\n", - "msk = NII.load(...,True)\n", - "centroids = calc_centroids(msk, decimals=3, vert_id=-1, subreg_id=50, extend_to=None)\n", - "```\n", - "\n", - "## Code Analysis\n", - "### Inputs\n", - "- `msk` (Image_Reference): The input mask image.\n", - "- `decimals` (int, optional): The number of decimal places to round the centroid coordinates to. Default is 3.\n", - "- `vert_id` (int, optional): The fixed value for the first dimension of the centroid coordinates. Default is -1.\n", - "- `subreg_id` (int, optional): The fixed value for the second dimension of the centroid coordinates. Default is 50.\n", - "- `extend_to` (POI | None, optional): An existing Centroids object to add the calculated centroids to. Default is None.\n", - "___\n", - "### Flow\n", - "1. Convert the input mask image to a NII object using the `to_nii` function.\n", - "2. Get the segmentation array from the NII object.\n", - "3. Get the affine transformation matrix from the NII object.\n", - "4. Create an empty `POI_Descriptor` object to store the centroid coordinates.\n", - "5. Get the unique non-zero values from the segmentation array.\n", - "6. Remove any NaN values from the unique values.\n", - "7. Iterate over each unique value:\n", - " - Create a temporary mask array for the current value.\n", - " - Calculate the center of mass of the temporary mask array.\n", - " - Round the centroid coordinates to the specified number of decimal places.\n", - " - Store the centroid coordinates in the `POI_Descriptor` object based on the fixed dimensions.\n", - "8. If `extend_to` is None, create a new `POI` object with the centroid coordinates and return it.\n", - " Otherwise, update the `extend_to` object with the calculated centroid coordinates and return it.\n", - "___\n", - "### Outputs\n", - "- `POI` object: A `POI` object containing the calculated centroid coordinates.\n", - "___\n" - ] + "source": "# calc_centroids\n## Summary\nThe `calc_centroids` function calculates the centroid coordinates of each region in a given mask image.\n\n## Example Usage\n```python\nmsk = NII.load(..., True)\ncentroids = calc_centroids(msk, decimals=3, first_stage=-1, second_stage=50, extend_to=None)\n```\n\n## Code Analysis\n### Inputs\n- `msk` (Image_Reference): The input mask image.\n- `decimals` (int, optional): The number of decimal places to round the centroid coordinates to. Default is 3.\n- `first_stage` (int | Location, optional): The fixed value for the first (region) coordinate of each POI key. Use `-1` to take the value from the mask label instead. Default is `-1`.\n- `second_stage` (int | Location, optional): The fixed value for the second (subregion) coordinate of each POI key. Use `-1` to take the value from the mask label instead. Default is `50`.\n- `extend_to` (POI | None, optional): An existing Centroids object to add the calculated centroids to. Default is None.\n- `inplace` (bool, optional): If True and `extend_to` is provided, mutate it in place instead of copying. Default is False.\n\nExactly one of `first_stage` / `second_stage` must be `-1`; the other is stored as a fixed value.\n___\n### Flow\n1. Convert the input mask image to a NII object using the `to_nii` function.\n2. Get the segmentation array from the NII object.\n3. Get the affine transformation matrix from the NII object.\n4. Create an empty `POI_Descriptor` object to store the centroid coordinates.\n5. Get the unique non-zero values from the segmentation array.\n6. Remove any NaN values from the unique values.\n7. Iterate over each unique value:\n - Create a temporary mask array for the current value.\n - Calculate the center of mass of the temporary mask array.\n - Round the centroid coordinates to the specified number of decimal places.\n - Store the centroid coordinates in the `POI_Descriptor` object based on the fixed dimensions.\n8. If `extend_to` is None, create a new `POI` object with the centroid coordinates and return it.\n Otherwise, update the `extend_to` object with the calculated centroid coordinates and return it.\n___\n### Outputs\n- `POI` object: A `POI` object containing the calculated centroid coordinates.\n___\n" }, { "cell_type": "markdown", "metadata": {}, - "source": [ - "# calc_centroids_labeled_buffered\n", - "## Summary\n", - "The `calc_centroids_labeled_buffered` function computes the centroids of a given mask with respect to a subregion mask. It saves the centroids to a file or loads them from an existing file if it already exists.\n", - "\n", - "## Example Usage\n", - "```python\n", - "# Example 1: Compute centroids and save them to a file\n", - "msk_reference = NII.load(...,True)\n", - "subreg_reference = NII.load(...,True)\n", - "out_path = Path(...)\n", - "centroids = calc_centroids_labeled_buffered(msk_reference,subreg_reference, out_path,override=True)\n", - "\n", - "# Example 2: Load centroids from an existing file\n", - "msk_reference = Image_Reference(...)\n", - "subreg_reference = Image_Reference(...)\n", - "out_path = Path(...)\n", - "centroids = calc_centroids_labeled_buffered(msk_reference, subreg_reference, out_path, override=False)\n", - "```\n", - "\n", - "## Code Analysis\n", - "### Inputs\n", - "\"msk_reference\" is the mask to compute the centroids from, \"subreg_reference\" is the subregion mask to compute the centroids relative to, \"out_path\" is the path to save the computed centroids to, \"subreg_id\" is the ID of the subregion to compute centroids in, \"verbose\" is a flag to print verbose output, \"override\" is a flag to overwrite existing centroids file, \"decimals\" is the number of decimal places to round the computed centroid coordinates to, and \"additional_folder\" is a flag to add a \"/ctd/\" folder to the output file path.\n", - "___\n", - "### Flow\n", - "The function first checks if the output file path is provided or if the mask reference is a BIDS file. If the output path is not provided and the mask reference is a BIDS file, it generates a path based on the label attribute of the file and the subregion ID. If the override flag is False and the output file already exists, the function loads and returns the existing centroids from the file. Otherwise, it computes the centroids using the given mask and subregion references. The computed centroids are then saved to the output file path. The function returns the computed centroids as a Centroids object.\n", - "___\n", - "### Outputs\n", - "The computed centroids, as a Centroids object.\n", - "___\n" - ] + "source": "# calc_poi_labeled_buffered\n## Summary\n`calc_poi_labeled_buffered` (alias for `calc_poi_from_two_segs`) computes the centroids of a given mask with respect to a subregion mask. It saves the centroids to a file or loads them from an existing file if it already exists.\n\n## Example Usage\n```python\n# Example 1: Compute centroids and save them to a file\nmsk_reference = NII.load(..., True)\nsubreg_reference = NII.load(..., True)\nout_path = Path(...)\ncentroids = calc_poi_labeled_buffered(msk_reference, subreg_reference, out_path, override=True)\n\n# Example 2: Load centroids from an existing file\ncentroids = calc_poi_labeled_buffered(msk_reference, subreg_reference, out_path, override=False)\n```\n\n## Code Analysis\n### Inputs\n- `msk_reference` (Image_Reference): The mask to compute the centroids from.\n- `subreg_reference` (Image_Reference | None): The subregion mask to compute the centroids relative to. If None, only `msk_reference` is used.\n- `out_path` (Path | str): The path to save the computed centroids to (required — automatic path generation is deprecated).\n- `subreg_id` (int | Location | list[int | Location] | None, optional): The ID(s) of the subregion(s) to compute centroids in.\n- `verbose` (bool, optional): Flag to print verbose output.\n- `override` (bool, optional): Overwrite an existing centroids file at `out_path`.\n- `decimals` (int, optional): Number of decimal places to round the computed centroid coordinates to. Default is 3.\n- `check_every_point` (bool, optional): If True, re-computes centroids even when `out_path` already exists, so that every point is verified against the source segmentation. Default is True.\n___\n### Flow\nIf the output file exists and `override=False`, the function loads and returns the existing centroids. Otherwise, it computes the centroids using the given mask and subregion references, saves them to `out_path`, and returns them as a `POI` object.\n___\n### Outputs\nThe computed centroids, as a `POI` object.\n___\n" }, { "cell_type": "code", @@ -245,4 +110,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} +} \ No newline at end of file