From f2b847de4796c13195b78a40f51796eb55dd99b3 Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 28 May 2025 16:41:34 +0200 Subject: [PATCH 01/21] -skull option --- docs/command.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/command.rst b/docs/command.rst index 8992554..77af2a2 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -74,7 +74,8 @@ mandatory parameters * ``_4animal`` : will use bet4animal (FSL) for brain extraction, for faster computation (by default atlas_brex is used) * ``_quick`` : will use hd-bet (Deep Learning) for brain extraction, for faster computation (by default atlas_brex is used) - **NB: ** hd-bet requires a specific version of macapype/skullTo3d, not available by default + +**NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default This option should be used if the coregistration to template in preparation is not performed correctly: @@ -87,7 +88,11 @@ mandatory parameters * ``_noseg`` (at the end) will perform data preparation and brain extraction (no segmentation) **Some options are specific to skullTo3d:** - * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) **NB : ** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra + * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) + +**NB :** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra +**NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined + * ``_noskullmask`` (at the end) will perform realignement to stereo and headmask (only realignement for CT) * ``_noheadmask`` (at the end) will perform only realignement to stereo From 555cbe2217b8881adc0b4962d6beb5f346730edf Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 28 May 2025 16:46:52 +0200 Subject: [PATCH 02/21] NB --- docs/command.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/command.rst b/docs/command.rst index 77af2a2..db4820d 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -75,7 +75,7 @@ mandatory parameters * ``_4animal`` : will use bet4animal (FSL) for brain extraction, for faster computation (by default atlas_brex is used) * ``_quick`` : will use hd-bet (Deep Learning) for brain extraction, for faster computation (by default atlas_brex is used) -**NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default + **NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default This option should be used if the coregistration to template in preparation is not performed correctly: @@ -88,10 +88,12 @@ mandatory parameters * ``_noseg`` (at the end) will perform data preparation and brain extraction (no segmentation) **Some options are specific to skullTo3d:** + * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) -**NB :** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra -**NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined + **NB :** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra + + **NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined * ``_noskullmask`` (at the end) will perform realignement to stereo and headmask (only realignement for CT) * ``_noheadmask`` (at the end) will perform only realignement to stereo From cf0f16e150eb602f880544af63a610279be3c0af Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 28 May 2025 16:52:47 +0200 Subject: [PATCH 03/21] `` --- docs/command.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/command.rst b/docs/command.rst index db4820d..4c8a472 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -93,7 +93,7 @@ mandatory parameters **NB :** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra - **NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined + **NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and ``-deriv`` and ``-padback`` are NOT defined * ``_noskullmask`` (at the end) will perform realignement to stereo and headmask (only realignement for CT) * ``_noheadmask`` (at the end) will perform only realignement to stereo From e5f807c71201300e9ed1d6d40ec3020b5f2131c3 Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 28 May 2025 17:13:33 +0200 Subject: [PATCH 04/21] | --- docs/command.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/command.rst b/docs/command.rst index 4c8a472..2b12162 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -77,16 +77,22 @@ mandatory parameters **NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default +| + This option should be used if the coregistration to template in preparation is not performed correctly: * ``_robustreg`` (at the end) to have a more robust registration (in two steps) +| + Finally, these option are available (to place after SPM or ANTS) and will modify the parameters but can be launched in sequence: * ``_test`` : (at the end) to check if the full pipeline is coherent (will only generate the graph.dot and graph.png) * ``_prep`` (at the end) will perform data preparation (no brain extraction and segmentation) * ``_noseg`` (at the end) will perform data preparation and brain extraction (no segmentation) +| + **Some options are specific to skullTo3d:** * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) From 9524aa781cb3f8e033f76c432976e82d19bd3e89 Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 10:30:08 +0100 Subject: [PATCH 05/21] Tips and tricks --- docs/index.rst | 3 +++ docs/tips_tricks.rst | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 docs/tips_tricks.rst diff --git a/docs/index.rst b/docs/index.rst index 7781d30..c6c2202 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -43,6 +43,8 @@ See :ref:`Commands ` for a description on the avalaible command paramet If ``-deriv``` is provided, see :ref:`Derivatives ` for a descrition of the outputs +Also, check `Tips and Tricks ` on how to format images to improve quality of registration between images and segmentation + Table of contents ****************** @@ -57,6 +59,7 @@ Table of contents derivatives params indiv_params + tips_tricks diff --git a/docs/tips_tricks.rst b/docs/tips_tricks.rst new file mode 100644 index 0000000..7d8fded --- /dev/null +++ b/docs/tips_tricks.rst @@ -0,0 +1,44 @@ +.. _tips_tricks: + +Tips and tricks +*************** + +CT images registration to MRI (be it T1w or T2w) can be somehow tricky. + +Here a few tricks: + +Reorientation can help +###################### + +The -orient LPS corresponds to the direction where the increasing numbers are pointing at (typically RAS in radiological convention) and take the opposite directions (special AFNI...). + +If you want to exchange to axis, change "target" letters accordingly +RPI -> RIP + +If you want to revert one dimension, be careful to modify another axis: +RPI -> RPS becomes LPS to exchange I by S, and good R-L dimension as well + +.. code:: bash + + $ 3drefit -orient LPS sub-Phoenix_ses-01_acq-CT_T2star.nii.gz + +Possibly followed by + +.. code:: bash + + $ fslreorient2std sub-Phoenix_ses-01_acq-CT_T2star.nii.gz sub-Phoenix_ses-01_acq-CT_T2star_reorient.nii.gz + + +Cropping (both T1w et T2w) can help +################################### + +Include the full head for the CT image + +Be careful with Left-Right orientation +###################################### + +Most of the images in our center are acquired in the right direction, but with an encoding matching inverse Left-Right Encoding to the one that is coming out of the MRI + +.. code:: bash + + $ 3drefit -orient LPI sub-Rusty/ses-01/anat/sub-Rusty_ses-01_acq-CT_run-02_T2star.nii.gz From 79b1a60c0efaae3907e2e12c61c48e5089f3cebd Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 10:38:18 +0100 Subject: [PATCH 06/21] ref --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index c6c2202..006acdb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -43,7 +43,7 @@ See :ref:`Commands ` for a description on the avalaible command paramet If ``-deriv``` is provided, see :ref:`Derivatives ` for a descrition of the outputs -Also, check `Tips and Tricks ` on how to format images to improve quality of registration between images and segmentation +Also, check :ref:`Tips and Tricks ` on how to format images to improve quality of registration between images and segmentation Table of contents From 83889f09c53fd3b78871833240a1b6be7b7c68f5 Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 10:41:19 +0100 Subject: [PATCH 07/21] ___ --- docs/.indiv_params.rst.kate-swp | Bin 0 -> 77 bytes docs/tips_tricks.rst | 4 +++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 docs/.indiv_params.rst.kate-swp diff --git a/docs/.indiv_params.rst.kate-swp b/docs/.indiv_params.rst.kate-swp new file mode 100644 index 0000000000000000000000000000000000000000..0dfe6e8dc7a6d7dcefa5bdd06c0860a77c8895e0 GIT binary patch literal 77 zcmZQzU=Z?7EJ;-eE>A2_aLdd|RWQ;sU|?VniR3wVbB^Upt&q<%q~_nctg~9hVn%Qf TP=*;K3&f(X!JbH5#&}l%Jtq<= literal 0 HcmV?d00001 diff --git a/docs/tips_tricks.rst b/docs/tips_tricks.rst index 7d8fded..a94c02d 100644 --- a/docs/tips_tricks.rst +++ b/docs/tips_tricks.rst @@ -1,7 +1,9 @@ +:orphan: + .. _tips_tricks: Tips and tricks -*************** +_______________ CT images registration to MRI (be it T1w or T2w) can be somehow tricky. From 9823a9a03f1b5df4c8d64220599ba48e6f406b50 Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 10:55:38 +0100 Subject: [PATCH 08/21] -skull option # Conflicts: # docs/command.rst --- docs/command.rst | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/docs/command.rst b/docs/command.rst index 2b12162..c30c3b6 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -75,9 +75,7 @@ mandatory parameters * ``_4animal`` : will use bet4animal (FSL) for brain extraction, for faster computation (by default atlas_brex is used) * ``_quick`` : will use hd-bet (Deep Learning) for brain extraction, for faster computation (by default atlas_brex is used) - **NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default - -| +**NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default This option should be used if the coregistration to template in preparation is not performed correctly: @@ -91,15 +89,10 @@ mandatory parameters * ``_prep`` (at the end) will perform data preparation (no brain extraction and segmentation) * ``_noseg`` (at the end) will perform data preparation and brain extraction (no segmentation) -| - - **Some options are specific to skullTo3d:** - * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) - **NB :** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra - - **NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and ``-deriv`` and ``-padback`` are NOT defined +**NB :** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra +**NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined * ``_noskullmask`` (at the end) will perform realignement to stereo and headmask (only realignement for CT) * ``_noheadmask`` (at the end) will perform only realignement to stereo From 4856a05f4efe46a7dcd78fc23340e67e8793088a Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 11:02:27 +0100 Subject: [PATCH 09/21] indent NB --- docs/command.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/command.rst b/docs/command.rst index c30c3b6..a23574b 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -75,7 +75,7 @@ mandatory parameters * ``_4animal`` : will use bet4animal (FSL) for brain extraction, for faster computation (by default atlas_brex is used) * ``_quick`` : will use hd-bet (Deep Learning) for brain extraction, for faster computation (by default atlas_brex is used) -**NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default + **NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default This option should be used if the coregistration to template in preparation is not performed correctly: From 1fa041ce03eb110c2fcb1314523e178252c3dd3e Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 11:05:15 +0100 Subject: [PATCH 10/21] no indent --- docs/command.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/command.rst b/docs/command.rst index a23574b..c30c3b6 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -75,7 +75,7 @@ mandatory parameters * ``_4animal`` : will use bet4animal (FSL) for brain extraction, for faster computation (by default atlas_brex is used) * ``_quick`` : will use hd-bet (Deep Learning) for brain extraction, for faster computation (by default atlas_brex is used) - **NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default +**NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default This option should be used if the coregistration to template in preparation is not performed correctly: From cb21cc064593fedb0566ac19c51d540ed0925d33 Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 11:12:53 +0100 Subject: [PATCH 11/21] indent --- docs/command.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/command.rst b/docs/command.rst index c30c3b6..8d25138 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -88,11 +88,10 @@ mandatory parameters * ``_test`` : (at the end) to check if the full pipeline is coherent (will only generate the graph.dot and graph.png) * ``_prep`` (at the end) will perform data preparation (no brain extraction and segmentation) * ``_noseg`` (at the end) will perform data preparation and brain extraction (no segmentation) - * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) -**NB :** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra -**NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined + **NB :** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra + **NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined * ``_noskullmask`` (at the end) will perform realignement to stereo and headmask (only realignement for CT) * ``_noheadmask`` (at the end) will perform only realignement to stereo From 737998aaa139d211b9e15d2e7e095753629c8616 Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 11:16:41 +0100 Subject: [PATCH 12/21] simplified indent --- docs/command.rst | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/docs/command.rst b/docs/command.rst index 8d25138..ce12bc9 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -73,30 +73,18 @@ mandatory parameters For ``-soft`` value, it is possible to add some key words (e.g. ``-soft ANTS_robustreg_prep``) all these options are available (to place after SPM or ANTS, e.g) and will change the brain extraction: * ``_4animal`` : will use bet4animal (FSL) for brain extraction, for faster computation (by default atlas_brex is used) - * ``_quick`` : will use hd-bet (Deep Learning) for brain extraction, for faster computation (by default atlas_brex is used) - -**NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default - - This option should be used if the coregistration to template in preparation is not performed correctly: - - * ``_robustreg`` (at the end) to have a more robust registration (in two steps) - -| + * ``_quick`` : will use hd-bet (Deep Learning) for brain extraction, for faster computation (by default atlas_brex is used) **NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default + * ``_robustreg`` (at the end) to have a more robust registration (in two steps) . This option should be used if the coregistration to template in preparation is not performed correctly Finally, these option are available (to place after SPM or ANTS) and will modify the parameters but can be launched in sequence: * ``_test`` : (at the end) to check if the full pipeline is coherent (will only generate the graph.dot and graph.png) * ``_prep`` (at the end) will perform data preparation (no brain extraction and segmentation) * ``_noseg`` (at the end) will perform data preparation and brain extraction (no segmentation) - * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) - - **NB :** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra - **NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined - + * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) **NB :** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra **NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined * ``_noskullmask`` (at the end) will perform realignement to stereo and headmask (only realignement for CT) * ``_noheadmask`` (at the end) will perform only realignement to stereo - -------------------- exclusive parameters -------------------- From b86332c9f12c8f36052abef2acb01885acf164df Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 11:21:54 +0100 Subject: [PATCH 13/21] all bold --- docs/command.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/command.rst b/docs/command.rst index ce12bc9..f0fc61d 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -73,7 +73,7 @@ mandatory parameters For ``-soft`` value, it is possible to add some key words (e.g. ``-soft ANTS_robustreg_prep``) all these options are available (to place after SPM or ANTS, e.g) and will change the brain extraction: * ``_4animal`` : will use bet4animal (FSL) for brain extraction, for faster computation (by default atlas_brex is used) - * ``_quick`` : will use hd-bet (Deep Learning) for brain extraction, for faster computation (by default atlas_brex is used) **NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default + * ``_quick`` : will use hd-bet (Deep Learning) for brain extraction, for faster computation (by default atlas_brex is used) **NB: hd-bet requires a specific version of macapype/skullTo3d, not available by default** * ``_robustreg`` (at the end) to have a more robust registration (in two steps) . This option should be used if the coregistration to template in preparation is not performed correctly Finally, these option are available (to place after SPM or ANTS) and will modify the parameters but can be launched in sequence: @@ -81,7 +81,7 @@ mandatory parameters * ``_test`` : (at the end) to check if the full pipeline is coherent (will only generate the graph.dot and graph.png) * ``_prep`` (at the end) will perform data preparation (no brain extraction and segmentation) * ``_noseg`` (at the end) will perform data preparation and brain extraction (no segmentation) - * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) **NB :** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra **NB :** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined + * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) **NB: ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra NB: ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined** * ``_noskullmask`` (at the end) will perform realignement to stereo and headmask (only realignement for CT) * ``_noheadmask`` (at the end) will perform only realignement to stereo @@ -93,8 +93,8 @@ exclusive parameters * ``-params`` : *(mandatory if -species is omitted)* a json file specifiying the global parameters of the analysis. See :ref:`Parameters ` for more details * ``-species`` : *(mandatory if -params is omitted)* followed the NHP species corresponding to the image, e.g. {macaque | marmo } -**NB** marmoT2 can be used for segmenting from the T2w image (by default, T1w is used for marmo) -**NB** macaque_0p5 is available to use downsampled template (faster results) +**NB:** marmoT2 can be used for segmenting from the T2w image (by default, T1w is used for marmo) +**NB:** macaque_0p5 is available to use downsampled template (faster results) ------------------- optional parameters From 0f56ac5b9a3c7c233a33755c1af3cd9baaf0bc3e Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 11:24:21 +0100 Subject: [PATCH 14/21] NB --- docs/command.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/command.rst b/docs/command.rst index f0fc61d..3b65482 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -73,7 +73,7 @@ mandatory parameters For ``-soft`` value, it is possible to add some key words (e.g. ``-soft ANTS_robustreg_prep``) all these options are available (to place after SPM or ANTS, e.g) and will change the brain extraction: * ``_4animal`` : will use bet4animal (FSL) for brain extraction, for faster computation (by default atlas_brex is used) - * ``_quick`` : will use hd-bet (Deep Learning) for brain extraction, for faster computation (by default atlas_brex is used) **NB: hd-bet requires a specific version of macapype/skullTo3d, not available by default** + * ``_quick`` : will use hd-bet (Deep Learning) for brain extraction, for faster computation (by default atlas_brex is used) **NB:** hd-bet requires a specific version of macapype/skullTo3d, not available by default * ``_robustreg`` (at the end) to have a more robust registration (in two steps) . This option should be used if the coregistration to template in preparation is not performed correctly Finally, these option are available (to place after SPM or ANTS) and will modify the parameters but can be launched in sequence: @@ -81,7 +81,7 @@ mandatory parameters * ``_test`` : (at the end) to check if the full pipeline is coherent (will only generate the graph.dot and graph.png) * ``_prep`` (at the end) will perform data preparation (no brain extraction and segmentation) * ``_noseg`` (at the end) will perform data preparation and brain extraction (no segmentation) - * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) **NB: ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra NB: ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined** + * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) **NB:** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra **NB:** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined * ``_noskullmask`` (at the end) will perform realignement to stereo and headmask (only realignement for CT) * ``_noheadmask`` (at the end) will perform only realignement to stereo From 59cb168080eaedfed2d5f04fd1fedf49c794bb5a Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 11:29:08 +0100 Subject: [PATCH 15/21] spaces --- docs/command.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/command.rst b/docs/command.rst index 3b65482..68f9649 100644 --- a/docs/command.rst +++ b/docs/command.rst @@ -81,9 +81,12 @@ mandatory parameters * ``_test`` : (at the end) to check if the full pipeline is coherent (will only generate the graph.dot and graph.png) * ``_prep`` (at the end) will perform data preparation (no brain extraction and segmentation) * ``_noseg`` (at the end) will perform data preparation and brain extraction (no segmentation) + * ``_skull`` after SPM or ANTS if you want to process skull or angio *specific to skullTo3d*; otherwise the main pipelines of macapype will be launched (only brain segmentation will be performed) **NB:** ``_skullnoisypetra`` instead of ``_skull`` available for macaque with issues on petra **NB:** ``-soft skull`` without processing brain is possible, but is still experimental. It only works if ``-skull_dt CT petra`` and -deriv -padback are NOT defined - * ``_noskullmask`` (at the end) will perform realignement to stereo and headmask (only realignement for CT) + * ``_noheadmask`` (at the end) will perform only realignement to stereo + * ``_noskullmask`` (at the end) will perform realignement to stereo and compute headmask (only realignement for CT) + * ``_nofullskullmask`` (at the end) will not perform fullskullmask (only realignement for CT) -------------------- exclusive parameters From 01fd3d734894d66a1c659af0b8e836b906e3da40 Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 12:02:19 +0100 Subject: [PATCH 16/21] rewritten kmeans function --- skullTo3d/nodes/skull.py | 278 ++++++++++++--------------------------- 1 file changed, 85 insertions(+), 193 deletions(-) diff --git a/skullTo3d/nodes/skull.py b/skullTo3d/nodes/skull.py index 0e8377e..e8fe42d 100644 --- a/skullTo3d/nodes/skull.py +++ b/skullTo3d/nodes/skull.py @@ -84,7 +84,7 @@ def calculate_mean(data): def mask_auto_img(img_file, operation, index, - sample_bins, distance, kmeans): + sample_bins, distance, kmeans=True: import os import numpy as np @@ -93,121 +93,9 @@ def mask_auto_img(img_file, operation, index, from scipy.signal import find_peaks - from nipype.utils.filemanip import split_filename as split_f - - def compute_Kmeans(img_arr, operation, index=1, num_clusters=3): - import os - import numpy as np - from sklearn.cluster import KMeans - # Mean function - - def calculate_mean(data): - total = sum(data) - count = len(data) - mean = total / count - return mean - - g = open(os.path.abspath("kmeans.log"), "w+") - - print("Running Kmeans with : ", operation, index, num_clusters) - - g.write("Running Kmeans with : {} {} {}\n".format( - operation, index, num_clusters)) - - # Reshape data to a 1D array (required by k-means) - X = np.copy(img_arr).flatten().reshape(-1, 1) - - kmeans = KMeans(n_clusters=num_clusters, random_state=0) - - # Fit the model to the data and predict cluster labels - cluster_labels = kmeans.fit_predict(X) - - # Split data into groups based on cluster labels - groups = [X[cluster_labels == i].flatten() - for i in range(num_clusters)] - - avail_operations = ["lower", "interval", "higher"] - - assert operation in avail_operations, "Error, \ - {} is not in {}".format(operation, avail_operations) - - assert 0 <= index and index < num_clusters, "Error \ - with index {}".format(index) - - # We must define : the minimum of the second group for the headmask - # we create minimums array, we sort and then take the middle value - minimums_array = np.array([np.amin(group) for group in groups]) - min_sorted = np.sort(minimums_array) - - print("Cluster Min : {}".format( - " ".join(str(val) for val in min_sorted))) - g.write("Cluster Min : {}\n".format( - " ".join(str(val) for val in min_sorted))) - - # We must define : the maximum of the second group for the headmask - # we create maximums array, we sort and then take the middle value - maximums_array = np.array([np.amax(group) for group in groups]) - max_sorted = np.sort(maximums_array) - - print("Cluster Max : {}".format( - " ".join(str(val) for val in max_sorted))) - g.write("Cluster Max : {}\n".format( - " ".join(str(val) for val in max_sorted))) - - # We must define : mean of the second group for the skull extraction - # we create means array, we sort and then take the middle value - means_array = np.array([calculate_mean(group) for group in groups]) - mean_sorted = np.sort(means_array) - - index_sorted = np.argsort(means_array) - - print("Cluster Mean : {}".format( - " ".join(str(int(val)) for val in mean_sorted))) - g.write("Cluster Mean : {}\n".format( - " ".join(str(int(val)) for val in mean_sorted))) - - print("Cluster Indexes = {}".format( - " ".join(str(int(val)) for val in index_sorted))) - g.write("Cluster Indexes = {}\n".format( - " ".join(str(int(val)) for val in index_sorted))) - - print("Indexed cluster ({}): {}".format( - index, index_sorted[index])) - g.write("Indexed cluster ({}): {}\n".format( - index, index_sorted[index])) - - min_thresh = np.amin(groups[index_sorted[index]]) - max_thresh = np.amax(groups[index_sorted[index]]) - - print("Min/max mid group : {} {}".format(min_thresh, - max_thresh)) - g.write("Min/max mid group : {} {}\n".format(min_thresh, - max_thresh)) - - if operation == "lower": - print("Filtering with lower threshold {}".format(min_thresh)) - g.write("Filtering with lower threshold {}\n".format(min_thresh)) - fiter_array = min_thresh < img_arr - - elif operation == "higher": - print("Filtering with higher threshold {}".format(max_thresh)) - g.write("Filtering with higher threshold {}\n".format(max_thresh)) - fiter_array = img_arr < max_thresh - - elif operation == "interval": - print( - "Filtering between lower {} and higher {}".format( - min_thresh, max_thresh)) - g.write( - "Filtering between lower {} and higher {}\n".format( - min_thresh, max_thresh)) - - fiter_array = np.logical_and(min_thresh < img_arr, - img_arr < max_thresh) - - g.close() + from sklearn.cluster import KMeans - return fiter_array + from nipype.utils.filemanip import split_filename as split_f log_file = os.path.abspath("local_minima.log") @@ -271,111 +159,115 @@ def calculate_mean(data): assert operation in ["higher", "interval", "lower"], \ "Error in operation {}".format(operation) - if kmeans: - print("kmeans=True, Skipping local minima") - f.write("kmeans=True, Skipping local minima\n") - proceed = False - else: + print("kmeans=True, Skipping local minima") + f.write("kmeans=True, Skipping local minima\n") - print("Running local minima, then Kmeans if failing") - f.write("Running local minima, then Kmeans if failing\n") - proceed = True + print("Running Kmeans with interval index {}\n".format(index)) + f.write("Running Kmeans with interval index {}\n".format(index)) - if operation == "interval": - if not (isinstance(index, list) and len(index) == 2): - print("Error, index {} should be a list for interval".format( - index)) - proceed = False - if not (peaks.shape[0] > 1): - print("Error, could not find at least two local minima") - proceed = False + g = open(os.path.abspath("kmeans.log"), "w+") - if index[0] < 0 or len(bins[peaks]) <= index[0]: - print("Error, index 0 {} out of peak indexes ".format(index[0])) - proceed = False + print("Running Kmeans with : ", operation, index, num_clusters) - if index[1] < index[0] or len(bins[peaks]) <= index[1]: - print("Error, index 1 {} out of peak indexes ".format(index[1])) - proceed = False + g.write("Running Kmeans with : {} {} {}\n".format( + operation, index, num_clusters)) - if proceed: - index_peak_min = bins[peaks][index[0]] - index_peak_max = bins[peaks][index[1]] + # Reshape data to a 1D array (required by k-means) + X = np.copy(img_arr).flatten().reshape(-1, 1) - print("Keeping interval between {} and {}".format( - index_peak_min, - index_peak_max)) + kmeans = KMeans(n_clusters=num_clusters, random_state=0) - f.write("Keeping interval between {} and {}\n".format( - index_peak_min, index_peak_max)) + # Fit the model to the data and predict cluster labels + cluster_labels = kmeans.fit_predict(X) - filter_arr = np.logical_and( - index_peak_min < img_arr, - img_arr < index_peak_max) + # Split data into groups based on cluster labels + groups = [X[cluster_labels == i].flatten() + for i in range(num_clusters)] - else: + avail_operations = ["lower", "interval", "higher"] - print("Running Kmeans with interval index {}\n".format(index)) - f.write("Running Kmeans with interval index {}\n".format(index)) - filter_arr = compute_Kmeans(img_arr, operation="interval", index=1) + assert operation in avail_operations, "Error, \ + {} is not in {}".format(operation, avail_operations) - elif operation == "higher": - if not isinstance(index, int): - print("Error, index {} should be a integer for higher".format( - index)) - proceed = False + assert 0 <= index and index < num_clusters, "Error \ + with index {}".format(index) - if index < 0 or len(bins[peaks]) <= index: + # We must define : the minimum of the second group for the headmask + # we create minimums array, we sort and then take the middle value + minimums_array = np.array([np.amin(group) for group in groups]) + min_sorted = np.sort(minimums_array) + + print("Cluster Min : {}".format( + " ".join(str(val) for val in min_sorted))) + g.write("Cluster Min : {}\n".format( + " ".join(str(val) for val in min_sorted))) + + # We must define : the maximum of the second group for the headmask + # we create maximums array, we sort and then take the middle value + maximums_array = np.array([np.amax(group) for group in groups]) + max_sorted = np.sort(maximums_array) - print("Error, {} out of peak indexes ".format(index)) - proceed = False + print("Cluster Max : {}".format( + " ".join(str(val) for val in max_sorted))) + g.write("Cluster Max : {}\n".format( + " ".join(str(val) for val in max_sorted))) - if proceed: - index_peak_max = bins[peaks][index] + # We must define : mean of the second group for the skull extraction + # we create means array, we sort and then take the middle value + means_array = np.array([sum(group)/len(group) for group in groups]) + mean_sorted = np.sort(means_array) - f.write("Filtering with higher threshold {}\n".format( - index_peak_max)) - print("Filtering with higher threshold {}\n".format( - index_peak_max)) + index_sorted = np.argsort(means_array) + + print("Cluster Mean : {}".format( + " ".join(str(int(val)) for val in mean_sorted))) + g.write("Cluster Mean : {}\n".format( + " ".join(str(int(val)) for val in mean_sorted))) - filter_arr = img_arr < index_peak_max + print("Cluster Indexes = {}".format( + " ".join(str(int(val)) for val in index_sorted))) + g.write("Cluster Indexes = {}\n".format( + " ".join(str(int(val)) for val in index_sorted))) - else: + print("Indexed cluster ({}): {}".format( + index, index_sorted[index])) + g.write("Indexed cluster ({}): {}\n".format( + index, index_sorted[index])) - print("Running Kmeans with higher index {}\n".format(index)) - f.write("Running Kmeans with higher index {}\n".format(index)) - filter_arr = compute_Kmeans( - img_arr, operation="higher", index=index) + min_thresh = np.amin(groups[index_sorted[index]]) + max_thresh = np.amax(groups[index_sorted[index]]) - elif operation == "lower": - if not isinstance(index, int): - print("Error, index {} should be a integer for lower".format( - index)) - proceed = False + print("Min/max mid group : {} {}".format(min_thresh, + max_thresh)) + g.write("Min/max mid group : {} {}\n".format(min_thresh, + max_thresh)) - if index < 0 or len(bins[peaks]) <= index: + if operation == "lower": + print("Filtering with lower threshold {}".format(min_thresh)) + g.write("Filtering with lower threshold {}\n".format(min_thresh)) + fiter_array = min_thresh < img_arr - print("Error, {} out of peak indexes ".format(index)) - proceed = False + elif operation == "higher": + print("Filtering with higher threshold {}".format(max_thresh)) + g.write("Filtering with higher threshold {}\n".format(max_thresh)) + fiter_array = img_arr < max_thresh - if proceed: - index_peak_min = bins[peaks][index] + elif operation == "interval": + print( + "Filtering between lower {} and higher {}".format( + min_thresh, max_thresh)) + g.write( + "Filtering between lower {} and higher {}\n".format( + min_thresh, max_thresh)) - f.write("Filtering with lower threshold {}\n".format( - index_peak_min)) - print("Filtering with lower threshold {}\n".format( - index_peak_min)) + fiter_array = np.logical_and(min_thresh < img_arr, + img_arr < max_thresh) - filter_arr = index_peak_min < img_arr - else: - print("Running Kmeans with lower index {}\n".format(index)) - f.write("Running Kmeans with lower index {}\n".format(index)) - filter_arr = compute_Kmeans( - img_arr, operation="lower", index=index) + g.close() - new_mask_data[filter_arr] = img_arr[filter_arr] + new_mask_data[fiter_array] = img_arr[fiter_array] print("Before filter: ", np.sum(img_arr != 0.0), "After filter: ", np.sum(new_mask_data != 0.0)) From f7fd5475a9868a22c9a767ea911028ddcf978b0f Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 12:05:18 +0100 Subject: [PATCH 17/21] kmeans --- skullTo3d/nodes/skull.py | 173 +++++++++++++-------------------------- 1 file changed, 59 insertions(+), 114 deletions(-) diff --git a/skullTo3d/nodes/skull.py b/skullTo3d/nodes/skull.py index e8fe42d..8b712fe 100644 --- a/skullTo3d/nodes/skull.py +++ b/skullTo3d/nodes/skull.py @@ -97,16 +97,6 @@ def mask_auto_img(img_file, operation, index, from nipype.utils.filemanip import split_filename as split_f - log_file = os.path.abspath("local_minima.log") - - f = open(log_file, "w+") - - print("Running local minimas with : kmeans=", - kmeans, operation, index, sample_bins, distance) - - f.write("Running local minimas with : kmeans={} {} {} {} {}\n".format( - kmeans, operation, index, sample_bins, distance)) - img_nii = nib.load(img_file) img_arr = np.array(img_nii.dataobj) @@ -124,10 +114,6 @@ def mask_auto_img(img_file, operation, index, nb_bins = (np.rint((np.max(X) - np.min(X))/sample_bins)).astype(int) print("Nb bins: ", nb_bins) - f.write("X shape : {}\n".format(X.shape)) - f.write("X max : {}\n".format(np.round(np.max(X)))) - f.write("Nb bins: {}\n".format(nb_bins)) - # Create a histogram hist, bins, _ = plt.hist(X, bins=nb_bins, alpha=0.5, color='b', label='Histogram') @@ -140,19 +126,6 @@ def mask_auto_img(img_file, operation, index, plt.savefig(os.path.abspath('histogram.png')) plt.clf() - # Find local minima in the histogram - peaks, _ = find_peaks(-hist, distance=distance) - # Use negative histogram for minima - - print("peaks indexes :", peaks) - - print("peak_hist :", hist[peaks]) - print("peak_bins :", bins[peaks]) - - f.write("peaks indexes : {}\n".format(peaks)) - f.write("peak_hist : {}\n".format(hist[peaks])) - f.write("peak_bins : {}\n".format(bins[peaks])) - # filtering new_mask_data = np.zeros(img_arr.shape, dtype=img_arr.dtype) @@ -160,112 +133,84 @@ def mask_auto_img(img_file, operation, index, "Error in operation {}".format(operation) - print("kmeans=True, Skipping local minima") - f.write("kmeans=True, Skipping local minima\n") + with open(os.path.abspath("kmeans.log"), "w+") as g: - print("Running Kmeans with interval index {}\n".format(index)) - f.write("Running Kmeans with interval index {}\n".format(index)) + g.write("Running Kmeans with : {} {} {}\n".format( + operation, index, num_clusters)) + # Reshape data to a 1D array (required by k-means) + X = np.copy(img_arr).flatten().reshape(-1, 1) - g = open(os.path.abspath("kmeans.log"), "w+") + kmeans = KMeans(n_clusters=num_clusters, random_state=0) - print("Running Kmeans with : ", operation, index, num_clusters) + # Fit the model to the data and predict cluster labels + cluster_labels = kmeans.fit_predict(X) - g.write("Running Kmeans with : {} {} {}\n".format( - operation, index, num_clusters)) + # Split data into groups based on cluster labels + groups = [X[cluster_labels == i].flatten() + for i in range(num_clusters)] - # Reshape data to a 1D array (required by k-means) - X = np.copy(img_arr).flatten().reshape(-1, 1) + avail_operations = ["lower", "interval", "higher"] - kmeans = KMeans(n_clusters=num_clusters, random_state=0) + assert operation in avail_operations, "Error, \ + {} is not in {}".format(operation, avail_operations) - # Fit the model to the data and predict cluster labels - cluster_labels = kmeans.fit_predict(X) + assert 0 <= index and index < num_clusters, "Error \ + with index {}".format(index) - # Split data into groups based on cluster labels - groups = [X[cluster_labels == i].flatten() - for i in range(num_clusters)] + # We must define : the minimum of the second group for the headmask + # we create minimums array, we sort and then take the middle value + minimums_array = np.array([np.amin(group) for group in groups]) + min_sorted = np.sort(minimums_array) - avail_operations = ["lower", "interval", "higher"] + g.write("Cluster Min : {}\n".format( + " ".join(str(val) for val in min_sorted))) - assert operation in avail_operations, "Error, \ - {} is not in {}".format(operation, avail_operations) + # We must define : the maximum of the second group for the headmask + # we create maximums array, we sort and then take the middle value + maximums_array = np.array([np.amax(group) for group in groups]) + max_sorted = np.sort(maximums_array) - assert 0 <= index and index < num_clusters, "Error \ - with index {}".format(index) + g.write("Cluster Max : {}\n".format( + " ".join(str(val) for val in max_sorted))) - # We must define : the minimum of the second group for the headmask - # we create minimums array, we sort and then take the middle value - minimums_array = np.array([np.amin(group) for group in groups]) - min_sorted = np.sort(minimums_array) + # We must define : mean of the second group for the skull extraction + # we create means array, we sort and then take the middle value + means_array = np.array([sum(group)/len(group) for group in groups]) + mean_sorted = np.sort(means_array) - print("Cluster Min : {}".format( - " ".join(str(val) for val in min_sorted))) - g.write("Cluster Min : {}\n".format( - " ".join(str(val) for val in min_sorted))) + index_sorted = np.argsort(means_array) - # We must define : the maximum of the second group for the headmask - # we create maximums array, we sort and then take the middle value - maximums_array = np.array([np.amax(group) for group in groups]) - max_sorted = np.sort(maximums_array) + g.write("Cluster Mean : {}\n".format( + " ".join(str(int(val)) for val in mean_sorted))) - print("Cluster Max : {}".format( - " ".join(str(val) for val in max_sorted))) - g.write("Cluster Max : {}\n".format( - " ".join(str(val) for val in max_sorted))) + g.write("Cluster Indexes = {}\n".format( + " ".join(str(int(val)) for val in index_sorted))) - # We must define : mean of the second group for the skull extraction - # we create means array, we sort and then take the middle value - means_array = np.array([sum(group)/len(group) for group in groups]) - mean_sorted = np.sort(means_array) + g.write("Indexed cluster ({}): {}\n".format( + index, index_sorted[index])) - index_sorted = np.argsort(means_array) + min_thresh = np.amin(groups[index_sorted[index]]) + max_thresh = np.amax(groups[index_sorted[index]]) + + g.write("Min/max mid group : {} {}\n".format(min_thresh, + max_thresh)) + + if operation == "lower": + g.write("Filtering with lower threshold {}\n".format(min_thresh)) + fiter_array = min_thresh < img_arr + + elif operation == "higher": + g.write("Filtering with higher threshold {}\n".format(max_thresh)) + fiter_array = img_arr < max_thresh + + elif operation == "interval": + g.write( + "Filtering between lower {} and higher {}\n".format( + min_thresh, max_thresh)) - print("Cluster Mean : {}".format( - " ".join(str(int(val)) for val in mean_sorted))) - g.write("Cluster Mean : {}\n".format( - " ".join(str(int(val)) for val in mean_sorted))) - - print("Cluster Indexes = {}".format( - " ".join(str(int(val)) for val in index_sorted))) - g.write("Cluster Indexes = {}\n".format( - " ".join(str(int(val)) for val in index_sorted))) - - print("Indexed cluster ({}): {}".format( - index, index_sorted[index])) - g.write("Indexed cluster ({}): {}\n".format( - index, index_sorted[index])) - - min_thresh = np.amin(groups[index_sorted[index]]) - max_thresh = np.amax(groups[index_sorted[index]]) - - print("Min/max mid group : {} {}".format(min_thresh, - max_thresh)) - g.write("Min/max mid group : {} {}\n".format(min_thresh, - max_thresh)) - - if operation == "lower": - print("Filtering with lower threshold {}".format(min_thresh)) - g.write("Filtering with lower threshold {}\n".format(min_thresh)) - fiter_array = min_thresh < img_arr - - elif operation == "higher": - print("Filtering with higher threshold {}".format(max_thresh)) - g.write("Filtering with higher threshold {}\n".format(max_thresh)) - fiter_array = img_arr < max_thresh - - elif operation == "interval": - print( - "Filtering between lower {} and higher {}".format( - min_thresh, max_thresh)) - g.write( - "Filtering between lower {} and higher {}\n".format( - min_thresh, max_thresh)) - - fiter_array = np.logical_and(min_thresh < img_arr, - img_arr < max_thresh) - - g.close() + fiter_array = np.logical_and(min_thresh < img_arr, + img_arr < max_thresh) new_mask_data[fiter_array] = img_arr[fiter_array] From 66340c2b02dd2c58d4af5a7ac445623f9e83bb2c Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 16:03:48 +0100 Subject: [PATCH 18/21] only_kmeans --- skullTo3d/nodes/skull.py | 90 +------------------ skullTo3d/pipelines/skull_pipe.py | 4 +- ...egment_macaque_0p5_ants_4animal_skull.json | 11 +-- ...aque_0p5_ants_4animal_skullnoisypetra.json | 11 +-- ..._segment_macaque_0p5_ants_quick_skull.json | 11 +-- ...acaque_0p5_ants_quick_skullnoisypetra.json | 11 +-- ...params_segment_macaque_0p5_ants_skull.json | 11 +-- ...ment_macaque_0p5_ants_skullnoisypetra.json | 11 +-- ...ms_segment_macaque_ants_4animal_skull.json | 3 - ..._macaque_ants_4animal_skullnoisypetra.json | 3 - ...rams_segment_macaque_ants_quick_skull.json | 3 - ...nt_macaque_ants_quick_skullnoisypetra.json | 3 - .../params_segment_macaque_ants_skull.json | 3 - ..._segment_macaque_ants_skullnoisypetra.json | 3 - workflows/params_segment_macaque_skull.json | 3 - .../params_segment_macaque_spm_skull.json | 3 - ...s_segment_macaque_spm_skullnoisypetra.json | 3 - ...rams_segment_marmo_ants_4animal_skull.json | 3 - ...params_segment_marmo_ants_quick_skull.json | 3 - .../params_segment_marmo_ants_skull.json | 3 - ...ms_segment_marmo_ants_skullnoisypetra.json | 3 - workflows/params_segment_marmo_spm_skull.json | 3 - ...ms_segment_marmot2_ants_4animal_skull.json | 3 - .../params_segment_marmot2_ants_skull.json | 3 - .../params_segment_marmot2_spm_skull.json | 3 - 25 files changed, 10 insertions(+), 201 deletions(-) diff --git a/skullTo3d/nodes/skull.py b/skullTo3d/nodes/skull.py index 8b712fe..cf29d1f 100644 --- a/skullTo3d/nodes/skull.py +++ b/skullTo3d/nodes/skull.py @@ -1,90 +1,4 @@ -def mask_auto_threshold(img_file, operation, index): - import numpy as np - import nibabel as nib - from sklearn.cluster import KMeans - - # Mean function - def calculate_mean(data): - total = sum(data) - count = len(data) - mean = total / count - return mean - - img_nii = nib.load(img_file) - img_arr = np.array(img_nii.dataobj) - - # Reshape data to a 1D array (required by k-means) - X = np.copy(img_arr).flatten().reshape(-1, 1) - - print("X shape : ", X.shape) - - # Create a k-means clustering model with 3 clusters - # using k-means++ initialization - - num_clusters = 3 - - kmeans = KMeans(n_clusters=num_clusters, random_state=0) - - # Fit the model to the data and predict cluster labels - cluster_labels = kmeans.fit_predict(X) - - # Split data into groups based on cluster labels - groups = [X[cluster_labels == i].flatten() for i in range(num_clusters)] - - avail_operations = ["min", "mean", "max"] - - assert operation in avail_operations, "Error, \ - {} is not in {}".format(operation, avail_operations) - - assert 0 <= index and index < num_clusters, "Error \ - with index {}".format(index) - - # We must define : the minimum of the second group for the headmask - # we create minimums array, we sort and then take the middle value - minimums_array = np.array([np.amin(group) for group in groups]) - min_sorted = np.sort(minimums_array) - - print("Min : {}".format(" ".join(str(val) for val in min_sorted))) - - # We must define : mean of the second group for the skull extraction - # we create means array, we sort and then take the middle value - means_array = np.array([calculate_mean(group) for group in groups]) - mean_sorted = np.sort(means_array) - - index_sorted = np.argsort(means_array) - - print("Mean : {}".format(" ".join(str(int(val)) for val in mean_sorted))) - - print("Index = {}".format(" ".join(str(int(val)) for val in index_sorted))) - - print("Index mid group : ", index_sorted[index]) - print("Min/max mid group : ", np.amin(groups[index_sorted[index]]), - np.amax(groups[index_sorted[index]])) - - maximums_array = np.array([np.amax(group) for group in groups]) - max_sorted = np.sort(maximums_array) - - print("Max : {}".format(" ".join(str(val) for val in max_sorted))) - - if operation == "min": # for head mask - mask_threshold = min_sorted[index] - print("headmask_threshold : ", mask_threshold) - - elif operation == "mean": # for skull mask - - mask_threshold = mean_sorted[index] - print("skull_extraction_threshold : ", mask_threshold) - - elif operation == "max": # unused - - mask_threshold = max_sorted[index] - print("max threshold : ", mask_threshold) - - return mask_threshold - - -def mask_auto_img(img_file, operation, index, - sample_bins, distance, kmeans=True: +def mask_auto_img(img_file, operation, index): import os import numpy as np @@ -111,7 +25,7 @@ def mask_auto_img(img_file, operation, index, print("X max : ", np.max(X)) print("Round X max : ", np.round(np.max(X))) - nb_bins = (np.rint((np.max(X) - np.min(X))/sample_bins)).astype(int) + nb_bins = (np.rint((np.max(X) - np.min(X))/30)).astype(int) print("Nb bins: ", nb_bins) # Create a histogram diff --git a/skullTo3d/pipelines/skull_pipe.py b/skullTo3d/pipelines/skull_pipe.py index 296d84b..4056a43 100644 --- a/skullTo3d/pipelines/skull_pipe.py +++ b/skullTo3d/pipelines/skull_pipe.py @@ -117,7 +117,7 @@ def _create_head_mask(name="headmask_pipe", params={}, prefix=""): head_auto_mask = NodeParams( interface=niu.Function( input_names=["img_file", "operation", - "index", "sample_bins", "distance", "kmeans"], + "index"], output_names=["mask_img_file"], function=mask_auto_img), params=parse_key(params, prefix + "head_auto_mask"), @@ -658,7 +658,7 @@ def _create_skullmask_ct_pipe(name="skullmask_ct_pipe", params={}): ct_skull_auto_mask = NodeParams( interface=niu.Function( input_names=["img_file", "operation", - "index", "sample_bins", "distance", "kmeans"], + "index"], output_names=["mask_img_file"], function=mask_auto_img), params=parse_key(params, "ct_skull_auto_mask"), diff --git a/workflows/params_segment_macaque_0p5_ants_4animal_skull.json b/workflows/params_segment_macaque_0p5_ants_4animal_skull.json index 5bdf91f..ce03c46 100644 --- a/workflows/params_segment_macaque_0p5_ants_4animal_skull.json +++ b/workflows/params_segment_macaque_0p5_ants_4animal_skull.json @@ -89,11 +89,8 @@ { "t1_head_auto_mask": { - "kmeans": true, "operation": "lower", - "index": 2, - "sample_bins": 30, - "distance": 10 + "index": 2 }, "t1_head_dilate": { @@ -341,9 +338,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, @@ -367,9 +361,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_0p5_ants_4animal_skullnoisypetra.json b/workflows/params_segment_macaque_0p5_ants_4animal_skullnoisypetra.json index 2bc0b05..cdfd8fe 100644 --- a/workflows/params_segment_macaque_0p5_ants_4animal_skullnoisypetra.json +++ b/workflows/params_segment_macaque_0p5_ants_4animal_skullnoisypetra.json @@ -89,11 +89,8 @@ { "t1_head_auto_mask": { - "kmeans": true, "operation": "lower", - "index": 2, - "sample_bins": 30, - "distance": 10 + "index": 2 }, "t1_head_dilate": { @@ -356,9 +353,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, @@ -382,9 +376,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_0p5_ants_quick_skull.json b/workflows/params_segment_macaque_0p5_ants_quick_skull.json index 3e9b5db..7984992 100644 --- a/workflows/params_segment_macaque_0p5_ants_quick_skull.json +++ b/workflows/params_segment_macaque_0p5_ants_quick_skull.json @@ -88,11 +88,8 @@ { "t1_head_auto_mask": { - "kmeans": true, "operation": "lower", - "index": 2, - "sample_bins": 30, - "distance": 10 + "index": 2 }, "t1_head_dilate": { @@ -340,9 +337,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, @@ -366,9 +360,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_0p5_ants_quick_skullnoisypetra.json b/workflows/params_segment_macaque_0p5_ants_quick_skullnoisypetra.json index feee966..00d4e3b 100644 --- a/workflows/params_segment_macaque_0p5_ants_quick_skullnoisypetra.json +++ b/workflows/params_segment_macaque_0p5_ants_quick_skullnoisypetra.json @@ -88,11 +88,8 @@ { "t1_head_auto_mask": { - "kmeans": true, "operation": "lower", - "index": 2, - "sample_bins": 30, - "distance": 10 + "index": 2 }, "t1_head_dilate": { @@ -355,9 +352,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, @@ -381,9 +375,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_0p5_ants_skull.json b/workflows/params_segment_macaque_0p5_ants_skull.json index ad5e562..82cf11f 100644 --- a/workflows/params_segment_macaque_0p5_ants_skull.json +++ b/workflows/params_segment_macaque_0p5_ants_skull.json @@ -94,11 +94,8 @@ { "t1_head_auto_mask": { - "kmeans": true, "operation": "lower", - "index": 2, - "sample_bins": 30, - "distance": 10 + "index": 2 }, "t1_head_dilate": { @@ -346,9 +343,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, @@ -372,9 +366,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_0p5_ants_skullnoisypetra.json b/workflows/params_segment_macaque_0p5_ants_skullnoisypetra.json index a9ebce1..856acef 100644 --- a/workflows/params_segment_macaque_0p5_ants_skullnoisypetra.json +++ b/workflows/params_segment_macaque_0p5_ants_skullnoisypetra.json @@ -94,11 +94,8 @@ { "t1_head_auto_mask": { - "kmeans": true, "operation": "lower", - "index": 2, - "sample_bins": 30, - "distance": 10 + "index": 2 }, "t1_head_dilate": { @@ -361,9 +358,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, @@ -387,9 +381,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_ants_4animal_skull.json b/workflows/params_segment_macaque_ants_4animal_skull.json index bcce5cc..7c872ef 100644 --- a/workflows/params_segment_macaque_ants_4animal_skull.json +++ b/workflows/params_segment_macaque_ants_4animal_skull.json @@ -347,9 +347,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_ants_4animal_skullnoisypetra.json b/workflows/params_segment_macaque_ants_4animal_skullnoisypetra.json index 02fdf92..73be5ad 100644 --- a/workflows/params_segment_macaque_ants_4animal_skullnoisypetra.json +++ b/workflows/params_segment_macaque_ants_4animal_skullnoisypetra.json @@ -358,9 +358,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_ants_quick_skull.json b/workflows/params_segment_macaque_ants_quick_skull.json index c31e14e..9948809 100644 --- a/workflows/params_segment_macaque_ants_quick_skull.json +++ b/workflows/params_segment_macaque_ants_quick_skull.json @@ -345,9 +345,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_ants_quick_skullnoisypetra.json b/workflows/params_segment_macaque_ants_quick_skullnoisypetra.json index 2667dca..fc82eb5 100644 --- a/workflows/params_segment_macaque_ants_quick_skullnoisypetra.json +++ b/workflows/params_segment_macaque_ants_quick_skullnoisypetra.json @@ -357,9 +357,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_ants_skull.json b/workflows/params_segment_macaque_ants_skull.json index 8bc6482..5a9a4f5 100755 --- a/workflows/params_segment_macaque_ants_skull.json +++ b/workflows/params_segment_macaque_ants_skull.json @@ -351,9 +351,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_ants_skullnoisypetra.json b/workflows/params_segment_macaque_ants_skullnoisypetra.json index 80ff68a..9a9d481 100644 --- a/workflows/params_segment_macaque_ants_skullnoisypetra.json +++ b/workflows/params_segment_macaque_ants_skullnoisypetra.json @@ -363,9 +363,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_skull.json b/workflows/params_segment_macaque_skull.json index 1d1e8ce..feefd4c 100644 --- a/workflows/params_segment_macaque_skull.json +++ b/workflows/params_segment_macaque_skull.json @@ -130,9 +130,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_spm_skull.json b/workflows/params_segment_macaque_spm_skull.json index 6f00bdb..086f85e 100644 --- a/workflows/params_segment_macaque_spm_skull.json +++ b/workflows/params_segment_macaque_spm_skull.json @@ -206,9 +206,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_macaque_spm_skullnoisypetra.json b/workflows/params_segment_macaque_spm_skullnoisypetra.json index 4d6ab02..abfee68 100644 --- a/workflows/params_segment_macaque_spm_skullnoisypetra.json +++ b/workflows/params_segment_macaque_spm_skullnoisypetra.json @@ -221,9 +221,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_marmo_ants_4animal_skull.json b/workflows/params_segment_marmo_ants_4animal_skull.json index b470049..c752c9a 100644 --- a/workflows/params_segment_marmo_ants_4animal_skull.json +++ b/workflows/params_segment_marmo_ants_4animal_skull.json @@ -308,9 +308,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_marmo_ants_quick_skull.json b/workflows/params_segment_marmo_ants_quick_skull.json index a076f96..8ace002 100644 --- a/workflows/params_segment_marmo_ants_quick_skull.json +++ b/workflows/params_segment_marmo_ants_quick_skull.json @@ -306,9 +306,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_marmo_ants_skull.json b/workflows/params_segment_marmo_ants_skull.json index a733db0..3c9ffec 100644 --- a/workflows/params_segment_marmo_ants_skull.json +++ b/workflows/params_segment_marmo_ants_skull.json @@ -311,9 +311,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_marmo_ants_skullnoisypetra.json b/workflows/params_segment_marmo_ants_skullnoisypetra.json index bf2395e..4356a7d 100644 --- a/workflows/params_segment_marmo_ants_skullnoisypetra.json +++ b/workflows/params_segment_marmo_ants_skullnoisypetra.json @@ -361,9 +361,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_marmo_spm_skull.json b/workflows/params_segment_marmo_spm_skull.json index a58b2ce..797fd56 100644 --- a/workflows/params_segment_marmo_spm_skull.json +++ b/workflows/params_segment_marmo_spm_skull.json @@ -306,9 +306,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_marmot2_ants_4animal_skull.json b/workflows/params_segment_marmot2_ants_4animal_skull.json index 1a8500a..ae382c6 100644 --- a/workflows/params_segment_marmot2_ants_4animal_skull.json +++ b/workflows/params_segment_marmot2_ants_4animal_skull.json @@ -309,9 +309,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_marmot2_ants_skull.json b/workflows/params_segment_marmot2_ants_skull.json index 292dde1..f3144f1 100755 --- a/workflows/params_segment_marmot2_ants_skull.json +++ b/workflows/params_segment_marmot2_ants_skull.json @@ -307,9 +307,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, diff --git a/workflows/params_segment_marmot2_spm_skull.json b/workflows/params_segment_marmot2_spm_skull.json index 1ab52a0..1eb30b6 100644 --- a/workflows/params_segment_marmot2_spm_skull.json +++ b/workflows/params_segment_marmot2_spm_skull.json @@ -311,9 +311,6 @@ { "ct_skull_auto_mask": { - "kmeans": true, - "sample_bins": 30, - "distance": 10, "operation": "lower", "index": 2 }, From f2f80eb490143b7e34d2e19a68da6c267c690099 Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 16:08:22 +0100 Subject: [PATCH 19/21] default --- skullTo3d/nodes/skull.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skullTo3d/nodes/skull.py b/skullTo3d/nodes/skull.py index cf29d1f..da23292 100644 --- a/skullTo3d/nodes/skull.py +++ b/skullTo3d/nodes/skull.py @@ -1,4 +1,4 @@ -def mask_auto_img(img_file, operation, index): +def mask_auto_img(img_file, operation, index, nb_bins= 30, num_clusters=3): import os import numpy as np From 7db36b4e1f0dbb09a84889106ef552708c7804da Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 16:10:01 +0100 Subject: [PATCH 20/21] f --- skullTo3d/nodes/skull.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/skullTo3d/nodes/skull.py b/skullTo3d/nodes/skull.py index da23292..45f247f 100644 --- a/skullTo3d/nodes/skull.py +++ b/skullTo3d/nodes/skull.py @@ -142,6 +142,4 @@ def mask_auto_img(img_file, operation, index, nb_bins= 30, num_clusters=3): affine=img_nii.affine) nib.save(mask_img, mask_img_file) - f.close() - return mask_img_file From e11380912e4d590bf798d3bc352c54ef9d71c9f1 Mon Sep 17 00:00:00 2001 From: David Meunier Date: Wed, 10 Dec 2025 16:43:51 +0100 Subject: [PATCH 21/21] flake8 --- skullTo3d/nodes/skull.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/skullTo3d/nodes/skull.py b/skullTo3d/nodes/skull.py index 45f247f..f5a8d2d 100644 --- a/skullTo3d/nodes/skull.py +++ b/skullTo3d/nodes/skull.py @@ -1,12 +1,10 @@ -def mask_auto_img(img_file, operation, index, nb_bins= 30, num_clusters=3): +def mask_auto_img(img_file, operation, index, sample_bins=30, num_clusters=3): import os import numpy as np import nibabel as nib import matplotlib.pyplot as plt - from scipy.signal import find_peaks - from sklearn.cluster import KMeans from nipype.utils.filemanip import split_filename as split_f @@ -25,7 +23,7 @@ def mask_auto_img(img_file, operation, index, nb_bins= 30, num_clusters=3): print("X max : ", np.max(X)) print("Round X max : ", np.round(np.max(X))) - nb_bins = (np.rint((np.max(X) - np.min(X))/30)).astype(int) + nb_bins = (np.rint((np.max(X) - np.min(X))/sample_bins)).astype(int) print("Nb bins: ", nb_bins) # Create a histogram @@ -46,7 +44,6 @@ def mask_auto_img(img_file, operation, index, nb_bins= 30, num_clusters=3): assert operation in ["higher", "interval", "lower"], \ "Error in operation {}".format(operation) - with open(os.path.abspath("kmeans.log"), "w+") as g: g.write("Running Kmeans with : {} {} {}\n".format( @@ -62,7 +59,7 @@ def mask_auto_img(img_file, operation, index, nb_bins= 30, num_clusters=3): # Split data into groups based on cluster labels groups = [X[cluster_labels == i].flatten() - for i in range(num_clusters)] + for i in range(num_clusters)] avail_operations = ["lower", "interval", "higher"] @@ -107,8 +104,8 @@ def mask_auto_img(img_file, operation, index, nb_bins= 30, num_clusters=3): min_thresh = np.amin(groups[index_sorted[index]]) max_thresh = np.amax(groups[index_sorted[index]]) - g.write("Min/max mid group : {} {}\n".format(min_thresh, - max_thresh)) + g.write("Min/max mid group : {} {}\n".format( + min_thresh, max_thresh)) if operation == "lower": g.write("Filtering with lower threshold {}\n".format(min_thresh)) @@ -124,7 +121,7 @@ def mask_auto_img(img_file, operation, index, nb_bins= 30, num_clusters=3): min_thresh, max_thresh)) fiter_array = np.logical_and(min_thresh < img_arr, - img_arr < max_thresh) + img_arr < max_thresh) new_mask_data[fiter_array] = img_arr[fiter_array] @@ -132,7 +129,6 @@ def mask_auto_img(img_file, operation, index, nb_bins= 30, num_clusters=3): "After filter: ", np.sum(new_mask_data != 0.0)) # saving mask as nii - path, fname, ext = split_f(img_file) mask_img_file = os.path.abspath(fname + "_autothresh" + ext)