@@ -571,7 +571,13 @@ def write_out_dataset_description_json(input_bids_dir, output_bids_dir=None):
571571
572572
573573def wrap_up_defacing (
574- path_to_dataset , output_dir = None , placement = "adjacent" , remove_existing = True , participant_label_exclude = [], session_label_exclude = []
574+ path_to_dataset ,
575+ output_dir = None ,
576+ placement = "adjacent" ,
577+ remove_existing = True ,
578+ participant_label_exclude = [],
579+ session_label_exclude = [],
580+ indexer = None ,
575581):
576582 """
577583 This function maps the output of this pipeline to the original dataset and depending on the
@@ -609,17 +615,21 @@ def wrap_up_defacing(
609615 :type participant_label_exclude: list, optional
610616 :param session_label_exclude: Excludes set of sessions from the finalized output
611617 :type session_label_exclude: list, optional
618+ :param indexer: Pre-built BIDSLayoutIndexer with exclusion patterns, defaults to None
619+ :type indexer: BIDSLayoutIndexer, optional
612620 :raises ValueError: _description_
613621 """
614- subjects_to_exclude = [f"sub-{ sub } /*" for sub in participant_label_exclude ]
615- sessions_to_exclude = [f"*ses-{ ses } /*" for ses in session_label_exclude ]
616- exclude_total = subjects_to_exclude + sessions_to_exclude
617-
618- # build an indexer
619- exclude = BIDSLayoutIndexer (ignore = exclude_total )
620-
621- # get bids layout of dataset
622- layout = BIDSLayout (path_to_dataset , derivatives = True , validate = False , indexer = exclude )
622+ # Use provided indexer or create one from exclude lists (fallback for compatibility)
623+ if indexer is None :
624+ subjects_to_exclude = [f"sub-{ sub } /*" for sub in participant_label_exclude ]
625+ sessions_to_exclude = [f"*ses-{ ses } /*" for ses in session_label_exclude ]
626+ exclude_total = subjects_to_exclude + sessions_to_exclude
627+ indexer = BIDSLayoutIndexer (ignore = exclude_total )
628+
629+ # get bids layout of dataset using the indexer
630+ layout = BIDSLayout (
631+ path_to_dataset , derivatives = True , validate = False , indexer = indexer
632+ )
623633
624634 # collect defaced images
625635 try :
@@ -632,10 +642,9 @@ def wrap_up_defacing(
632642 sys .exit (1 )
633643
634644 # collect all original images and jsons
635- raw_only = BIDSLayout (path_to_dataset , derivatives = False , indexer = exclude )
636-
637- raw_images_only = raw_only .get (
638- suffix = ["pet" , "T1w" ])
645+ raw_only = BIDSLayout (path_to_dataset , derivatives = False , indexer = indexer )
646+
647+ raw_images_only = raw_only .get (suffix = ["pet" , "T1w" ])
639648
640649 # if output_dir is not None and is not the same as the input dir we want to clear it out
641650 if output_dir is not None and output_dir != path_to_dataset and remove_existing :
@@ -810,6 +819,9 @@ def __init__(
810819 self .session_label = session_label
811820 self .session_label_exclude = session_label_exclude
812821
822+ # Build comprehensive exclusion indexer considering both include and exclude parameters
823+ self .exclude_indexer = self ._build_exclusion_indexer ()
824+
813825 # check if freesurfer license is valid
814826 self .fs_license = check_valid_fs_license ()
815827 if not self .fs_license :
@@ -821,6 +833,64 @@ def __init__(
821833 f"Using freesurfer license at { self .fs_license } found in system env at $FREESURFER_LICENSE"
822834 )
823835
836+ def _build_exclusion_indexer (self ):
837+ """
838+ Build a comprehensive BIDSLayoutIndexer that excludes subjects and sessions based on:
839+ 1. Explicit exclusion lists (participant_label_exclude, session_label_exclude)
840+ 2. Implicit exclusions from include-only lists (participant_label, session_label)
841+
842+ Returns:
843+ BIDSLayoutIndexer: Indexer configured to ignore excluded subjects/sessions
844+ """
845+ # Create a temporary layout to get all available subjects and sessions
846+ temp_layout = BIDSLayout (self .bids_dir , derivatives = False , validate = False )
847+ all_subjects = temp_layout .get_subjects ()
848+ all_sessions = temp_layout .get_sessions ()
849+
850+ # Start with explicitly excluded subjects
851+ excluded_subjects = set (self .participant_label_exclude )
852+
853+ # If specific subjects are requested (include-only), exclude all others
854+ if self .subject and self .subject != "" :
855+ # Handle both string and list formats
856+ if isinstance (self .subject , str ):
857+ included_subjects = [self .subject ] if self .subject else []
858+ else :
859+ included_subjects = self .subject
860+
861+ # Remove 'sub-' prefix if present
862+ included_subjects = [sub .replace ("sub-" , "" ) for sub in included_subjects ]
863+
864+ # Add all subjects not in the include list to exclusions
865+ excluded_subjects .update (
866+ sub for sub in all_subjects if sub not in included_subjects
867+ )
868+
869+ # Start with explicitly excluded sessions
870+ excluded_sessions = set (self .session_label_exclude )
871+
872+ # If specific sessions are requested (include-only), exclude all others
873+ if self .session_label :
874+ # Remove 'ses-' prefix if present
875+ included_sessions = [ses .replace ("ses-" , "" ) for ses in self .session_label ]
876+
877+ # Add all sessions not in the include list to exclusions
878+ excluded_sessions .update (
879+ ses for ses in all_sessions if ses not in included_sessions
880+ )
881+
882+ # Convert to ignore patterns for BIDSLayoutIndexer
883+ ignore_patterns = []
884+
885+ # Add subject exclusion patterns
886+ ignore_patterns .extend ([f"sub-{ sub } /*" for sub in excluded_subjects ])
887+
888+ # Add session exclusion patterns
889+ ignore_patterns .extend ([f"*/ses-{ ses } /*" for ses in excluded_sessions ])
890+
891+ # Build and return the indexer
892+ return BIDSLayoutIndexer (ignore = ignore_patterns )
893+
824894 def run (self ):
825895 """
826896 Runs the defacing workflow given inputs from instiantiation and wraps up defacing by collecting output
@@ -849,7 +919,8 @@ def run(self):
849919 placement = self .placement ,
850920 remove_existing = self .remove_existing ,
851921 participant_label_exclude = self .participant_label_exclude ,
852- session_label_exclude = self .session_label_exclude
922+ session_label_exclude = self .session_label_exclude ,
923+ indexer = self .exclude_indexer ,
853924 )
854925
855926
0 commit comments