From 65615e2c497c961476b26f39ebdcabfb13cf02d8 Mon Sep 17 00:00:00 2001 From: Synchon Mandal Date: Tue, 7 Oct 2025 17:36:05 +0200 Subject: [PATCH 1/4] update: bump junifer-data version to v5 --- junifer/data/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/junifer/data/utils.py b/junifer/data/utils.py index a10e49e10..0446fd29b 100644 --- a/junifer/data/utils.py +++ b/junifer/data/utils.py @@ -24,10 +24,10 @@ __all__ = [ # junifer-data version constant -JUNIFER_DATA_VERSION = "4" +JUNIFER_DATA_VERSION = "5" # junifer-data hexsha constant -JUNIFER_DATA_HEXSHA = "d178bddf383fede04742d7020312a574de47f0ab" +JUNIFER_DATA_HEXSHA = "62a0e3d187259a3c3ba7be638ee39cfb40df0a61" JUNIFER_DATA_PARAMS = { "tag": JUNIFER_DATA_VERSION, -- 2.52.0 From 64322fa6b613b28ad5ee47109730404e06e44bd5 Mon Sep 17 00:00:00 2001 From: Synchon Mandal Date: Tue, 7 Oct 2025 17:38:43 +0200 Subject: [PATCH 2/4] feat: add FreeSurfer 7.4.1 aseg to ParcellationRegistry --- junifer/data/parcellations/_parcellations.py | 114 ++++++++++++++++++ .../parcellations/tests/test_parcellations.py | 21 ++++ 2 files changed, 135 insertions(+) diff --git a/junifer/data/parcellations/_parcellations.py b/junifer/data/parcellations/_parcellations.py index 0f3efafb3..04160b822 100644 --- a/junifer/data/parcellations/_parcellations.py +++ b/junifer/data/parcellations/_parcellations.py @@ -190,6 +190,15 @@ class ParcellationRegistry(BasePipelineDataRegistry): }, } ) + # Add FreeSurfer 7.4.1 aseg + self._builtin.update( + { + "aseg-7_4_1": { + "family": "FreeSurfer", + "space": "fsaverage", + } + } + ) # Update registry with built-in ones self._registry.update(self._builtin) @@ -355,6 +364,7 @@ class ParcellationRegistry(BasePipelineDataRegistry): "Shen", "Yan2023", "Brainnetome", + "FreeSurfer", ]: # Load parcellation and labels if t_family == "Schaefer2018": @@ -394,6 +404,10 @@ class ParcellationRegistry(BasePipelineDataRegistry): **parcellation_definition, ) ) + elif t_family == "FreeSurfer": + parcellation_fname, parcellation_labels = _retrieve_aseg( + resolution=resolution, + ) else: raise_error(f"Unknown parcellation family: {t_family}") @@ -1307,6 +1321,106 @@ def _retrieve_brainnetome( return parcellation_img_path, labels +def _retrieve_aseg( + resolution: Optional[float] = None, +) -> tuple[Path, list[str]]: + """Retrieve aseg generated from FreeSurfer 7.4.1 . + + Parameters + ---------- + resolution : 1.0, optional + The desired resolution of the parcellation to load. If it is not + available, the closest resolution will be loaded. Preferably, use a + resolution higher than the desired one. By default, will load the + highest one (default None). Available resolution for this + parcellation is 1mm. + + Returns + ------- + pathlib.Path + File path to the parcellation image. + list of str + Parcellation labels. + + """ + logger.info("Parcellation parameters:") + logger.info(f"\tresolution: {resolution}") + + _valid_resolutions = [1.0] + _ = closest_resolution(resolution, _valid_resolutions) + + path_prefix = Path("parcellations/FreeSurfer-7_4_1") + parcellation_img_path = get( + file_path=path_prefix / "aseg.nii", + dataset_path=get_dataset_path(), + **JUNIFER_DATA_PARAMS, + ) + parcellation_label_path = get( + file_path=path_prefix / "ASegStatsLUT.txt", + dataset_path=get_dataset_path(), + **JUNIFER_DATA_PARAMS, + ) + # Explicitly indexed to get proper labels + idxs = [ + 2, + 3, + 4, + 5, + 7, + 8, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 24, + 26, + 28, + 30, + 31, + 41, + 42, + 43, + 44, + 46, + 47, + 49, + 50, + 51, + 52, + 53, + 54, + 58, + 60, + 62, + 63, + 77, + 85, + 251, + 252, + 253, + 254, + 255, + ] + labels = ( + pd.read_csv( + parcellation_label_path, + sep=r"\s+", + skiprows=6, + header=None, + index_col=0, + ) + .loc[idxs][1] + .to_list() + ) + + return parcellation_img_path, labels + + def merge_parcellations( parcellations_list: list["Nifti1Image"], parcellations_names: list[str], diff --git a/junifer/data/parcellations/tests/test_parcellations.py b/junifer/data/parcellations/tests/test_parcellations.py index 8832106c0..7fda6784e 100644 --- a/junifer/data/parcellations/tests/test_parcellations.py +++ b/junifer/data/parcellations/tests/test_parcellations.py @@ -941,6 +941,27 @@ def test_retrieve_brainnetome_incorrect_threshold() -> None: ) +def test_aseg() -> None: + """Test FreeSurfer 7.4.1 aseg parcellation.""" + parcellations = list_data(kind="parcellation") + assert "aseg-7_4_1" in parcellations + + # Load parcellation + img, label, img_path, space = load_data( + kind="parcellation", + name="aseg-7_4_1", + target_space="fsaverage", + ) + assert img is not None + assert img_path.name == "aseg.nii" + assert space == "fsaverage" + assert len(label) == 43 + assert_array_equal( + img.header["pixdim"][1:4], + 3 * [1], + ) + + def test_merge_parcellations() -> None: """Test merging parcellations.""" # load some parcellations for testing -- 2.52.0 From 64e5fc846f46f8c357a0f90b813edd680d3b2a07 Mon Sep 17 00:00:00 2001 From: Synchon Mandal Date: Tue, 7 Oct 2025 17:57:28 +0200 Subject: [PATCH 3/4] chore: add changelogs 470.{enh,misc} --- docs/changes/newsfragments/470.enh | 1 + docs/changes/newsfragments/470.misc | 1 + 2 files changed, 2 insertions(+) create mode 100644 docs/changes/newsfragments/470.enh create mode 100644 docs/changes/newsfragments/470.misc diff --git a/docs/changes/newsfragments/470.enh b/docs/changes/newsfragments/470.enh new file mode 100644 index 000000000..2dbc5bc8e --- /dev/null +++ b/docs/changes/newsfragments/470.enh @@ -0,0 +1 @@ +Add FreeSurfer 7.4.1 aseg parcellation to :class:`.ParcellationRegistry` by `Synchon Mandal`_ diff --git a/docs/changes/newsfragments/470.misc b/docs/changes/newsfragments/470.misc new file mode 100644 index 000000000..00042b7bc --- /dev/null +++ b/docs/changes/newsfragments/470.misc @@ -0,0 +1 @@ +Bump ``junifer-data`` to ``v5`` by `Synchon Mandal`_ -- 2.52.0 From aee99bbfce94ec3216a4c6d47b43d0fdc3eb61f4 Mon Sep 17 00:00:00 2001 From: Synchon Mandal Date: Tue, 7 Oct 2025 17:57:55 +0200 Subject: [PATCH 4/4] docs: update parcellation list in builtin.rst --- docs/builtin.rst | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/builtin.rst b/docs/builtin.rst index 6ad2eed67..10683255c 100644 --- a/docs/builtin.rst +++ b/docs/builtin.rst @@ -453,6 +453,16 @@ Available | Architecture | Cerebral Cortex, Volume 26(8), Pages 3508–3526 (2016). | https://doi.org/10.1093/cercor/bhw157 + * - FreeSurfer 7.4.1 anatomical segmentation atlas + - None + - ``aseg-7_4_1`` + - ``fsaverage`` + - 0.0.7 + - | Fischl B, Salat DH, Busa E, et al. + | Whole brain segmentation: automated labeling of neuroanatomical + | structures in the human brain. + | Neuron., Volume 33(3), Pages 341-355 (2002). + | https://doi:10.1016/s0896-6273(02)00569-x Planned @@ -492,12 +502,6 @@ Planned | anatomical nomenclature. | NeuroImage, Volume 53(1), Pages 1–15 (2010). | http://doi.org/10.1016/j.neuroimage.2010.06.010. - * - Fan - - | Fan, L., Li, H., Zhuo, J. et al. - | The human brainnetome atlas: a new brain atlas based on connectional - | architecture. - | Cerebral cortex, Volume 26(8), Pages 3508-3526 (2016). - | https://doi.org/10.1093/cercor/bhw157 * - Buckner - | Buckner, R.L., Krienen, F.M., Castellanos, A., Diaz, J.C., Yeo, B.T.T. | The organization of the human cerebellum estimated by intrinsic -- 2.52.0