def start_process(self): """starts the process linked to the module selected; that is in case of dcm2nii it runs the extraction of nifti- files from the DICOM folder or in case of displayN4corr it displays all nifti files available in the folder""" input2process = [] [ input2process.append(self.mOutput.item(x).text()) for x in range(self.mOutput.count()) ] if not input2process: Output.msg_box( text="At least one folder with data must be selected!", title='No directory selected') elif len(input2process) != 0 and self.option_gui == 'dcm2niix': print('in total, {} folders were selected'.format( len(input2process))) preprocDCM2NII.PreprocessDCM(input2process) elif len( input2process) != 0 and self.option_gui == 'displayNiftiFiles': input_with_path = [] [ input_with_path.extend( glob.glob(self.working_dir + '/**/' + x, recursive=True)) for x in input2process ] Imaging.load_imageviewer( 'itk-snap', input_with_path ) # to-date, only itk-snap available. could be changed
def save_cfg_dicomdir(self): """Function intended to save the DICOM directory once button is pressed""" self.cfg['folders']['dicom'] = self.working_dir Configuration.save_config(self.cfg['folders']["rootdir"], self.cfg) Output.msg_box( text="Folder changed in the configuration file to {}".format( self.working_dir), title='Changed folder')
def start_converting(self): folderlist = [] [folderlist.append(self.mOutput.item(x).text()) for x in range(self.mOutput.count())] print('in total, {} folders were selected'.format(len(folderlist))) if not folderlist: Output.msg_box(text="At least one folder with DICOM data needed!", title="No directory selected") else: preprocDCM2NII.PreprocessDCM(folderlist)
def view_template(self): """this function opens a list dialog and enables selecting NIFTI files for e.g. check the content (identical function as in GUITabPreprocessANTs.py.""" if not self.selected_subj_Gen: Output.msg_box(text="No image selected. Please indicate image(s) to load.", title="No templates selected") return else: template_list = [FileOperations.return_full_filename(self.wdirTemplate, x) for x in self.selected_subj_Gen] Imaging.load_imageviewer('itk-snap', template_list) # to-date, only itk-snap available. could be changed
def save_leadModel(lead_models, intensityProfiles, skelSkalms, filename=''): if not filename: Output.msg_box(text='No filename for saving lead model provided', title='No filename provided') return with open(filename, "wb") as f: pickle.dump(lead_models, f) pickle.dump(intensityProfiles, f) pickle.dump(skelSkalms, f)
def run_n4Bias_corr(self): """wrapper to start the preprocessing, that is the GUI in which the different options for ANTs routines are displayed""" if not self.selected_subj_ANT: Output.msg_box(text="No folder selected. To proceed, please indicate what folder to process. " "(For this option, numerous folders are possible for batch processing)", title="No subject selected") else: msg = "Are you sure you want to de-bias all NIFTI-files in the following folder(s):\n\n" \ "{}".format(''.join('--> {}\n'.format(c) for c in self.selected_subj_ANT)) ret = QMessageBox.question(self, "Start Debiasing", msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if ret == QMessageBox.Yes: N4BiasCorr.BiasCorrection().N4BiasCorrection(subjects=self.selected_subj_ANT)
def redefineDefault(self): """redefines which template is set as default on the right list and in the cfg-file""" if not self.selected_subj_Gen: Output.msg_box(text="No template selected. Please indicate new default one.", title="No data selected") return elif len(self.selected_subj_Gen) > 1: Output.msg_box(text="Please select only one image as default.", title="Too many templates selected") return else: default_template = [FileOperations.return_full_filename(self.wdirTemplate, x) for x in self.selected_subj_Gen] self.cfg['folders']['default_template'] = default_template[0] Configuration.save_config(ROOTDIR, self.cfg) self.run_reload_files()
def run_RegisterMRI2template(self): """Wrapper to run the coregistration routines for the MRI (moving image) to MRI templates (fixed image) specified in the config file using ANTs routines""" if not self.selected_subj_ANT: Output.msg_box(text="No folder selected. To proceed, please indicate what folder to process. " "(For this option, numerous folders are possible for batch processing)", title="No subject selected") else: msg = "Are you sure you want to coregister the preoperative imaging in the following folders:\n\n" \ "{}".format(''.join(' -> {}\n'.format(c) for c in self.selected_subj_ANT)) ret = QMessageBox.question(self, 'MessageBox', msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if ret == QMessageBox.Yes: ANTspyRoutines.RegistrationANTs().CoregisterMRI2template(subjects=self.selected_subj_ANT)
def display_nifti_files(self): """this function enables to select NIFTI files and e.g. compare the results obtained at this step.""" if not self.selected_subj_ANT: Output.msg_box(text="No folder selected. Please select subject.", title="No subject selected") return elif len(self.selected_subj_ANT) > 1: Output.msg_box(text="Please select only one subject to avoid loading too many images", title="Too many subjects selected") return else: image_folder = os.path.join(self.cfg['folders']['nifti'], self.selected_subj_ANT[0]) self.SelectFiles = TwoListGUI(working_directory=image_folder, option_gui="displayNiftiFiles") self.SelectFiles.show()
def CoregisterMRI2template(self, subjects): """Co-Registration of preoperative MRI to specific template""" print('\nStarting Co-Registration for {} subject(s)'.format( len(subjects))) all_files = FileOperations.get_filelist_as_tuple( inputdir=self.cfg['folders']['nifti'], subjects=subjects) sequences = self.cfg['preprocess']['normalisation']['sequences'].split( sep=',') # sequences of interest template = glob.glob( os.path.join( ROOTDIR, 'ext', 'templates', self.cfg['preprocess']['normalisation']['template_image'] + '/*')) fileIDs = [] for idx, seqs in enumerate(sequences): file_template = [ x for x in template if re.search(r'\w+.({}).'.format(seqs), x, re.IGNORECASE) ] # corresponding template if not file_template: Output.msg_box( text= "No template found. Please ensure templates are installed at './ext/templates'", title="Template missing!" ) # TODO install templates by default! return regex_complete = '{}{}'.format( self.cfg['preprocess']['ANTsN4']['prefix'], seqs) files_subj = [ x for x in all_files if x[0].endswith('.nii') and 'run' not in x[0] and re.search(r'\w+(?!_).({}).'.format(regex_complete), x[0], re.IGNORECASE) ] fileIDs.extend( tuple([(file_template[0], file_id, subj) for file_id, subj in files_subj])) if not fileIDs: Output.msg_box( text="No bias-corrected MRI found. Please double-check", title="Preprocessed MRI missing") return self.wrapper_multiprocessing(fileIDs, subjects, 'MRI')
def check_for_complete_input(self, item_list, modalities = ['CT', 'MRI']): """this function ensures, that only those subjects are displayed where MRI and CT data is available in the correct folders (surname_nameMRI or surname_nameCT)""" available_subjects = set([re.split(r'CT|MRI', x)[0] for x in list(item_list)]) item_list_complete = [] [item_list_complete.append(subj) for subj in list(available_subjects) if all([os.path.isdir(os.path.join(self.dicomdir, subj + y)) for y in modalities])] if len(available_subjects) != len(item_list_complete): incomplete = list(set(available_subjects) - set(item_list_complete)) Output.msg_box(text="There is incomplete data or directories have unknown names. Please ensure the presence" " of two folders (surname_nameCT) and (surname_nameMRI) for:" "\n{}".format(''.join(' -> {}\n'.format(c) for c in incomplete)), title="Incomplete data") return set(item_list_complete)
def run_RegisterCT2MRI(self): """Wrapper to run the coregistration routines for the CT (moving image) to the T1-sequence of the MRI (fixed image) using ANTs routines""" if not self.selected_subj_ANT: Output.msg_box(text="No folder selected. To proceed, please indicate what folder to process. " "(For this option, numerous folders are possible for batch processing)", title="No subject selected") else: msg = "Are you sure you want to coregister the postoperative CT imaging in the following folders:\n\n" \ "{}".format(''.join(' -> {}\n'.format(c) for c in self.selected_subj_ANT)) ret = QMessageBox.question(self, 'MessageBox', msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if ret == QMessageBox.Yes: ANTspyRoutines.RegistrationANTs().CoregisterCT2MRI(subjects=self.selected_subj_ANT, input_folder=self.cfg['folders']['nifti'])
def run_ManualCorrection(self): """wrapper which starts the plotting routine for the detected lead which enables manual corrections""" if len(self.selected_subj_ANT) != 1: Output.msg_box(text="Please select one and only one subject", title="Subjects selected") return else: msg = "Are you sure you want to process the following subject:\n\n" \ "{}".format(''.join(' -> {}\n'.format(c) for c in self.selected_subj_ANT)) ret = QMessageBox.question(self, 'MessageBox', msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if ret == QMessageBox.Yes: plotElecModel.PlotRoutines(subject=self.selected_subj_ANT[0], inputfolder=os.path.join( self.niftidir, self.selected_subj_ANT[0]))
def run_LeadDetectionPaCER(self): """wrapper to start lead detection with PaCER routines translated to python; original data can be found at: https://github.com/adhusch/PaCER/""" if len(self.selected_subj_ANT) > 1: Output.msg_box( text= "Please select only one subject, as multiprocessing for lead detection is not intended", title="Too many subjects selected") return else: msg = "Are you sure you want to process the following subject:\n\n" \ "{}".format(''.join(' -> {}\n'.format(c) for c in self.selected_subj_ANT)) ret = QMessageBox.question(self, 'MessageBox', msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if ret == QMessageBox.Yes: LeadDetectionRoutines.PaCER_script( subjects=self.selected_subj_ANT)
def VisualiseLeadDetection(self): """wrapper to start comparisons between pre- and post-processed images after N4BiasCorrection""" if not self.selected_subj_ANT: Output.msg_box( text= "No folder selected. To proceed, please select at least one.", title="No subject selected") return elif len(self.selected_subj_ANT) > 1: Output.msg_box(text="Please select only one subj.", title="Too many subjects selected") return else: image_folder = os.path.join(self.cfg['folders']['nifti'], self.selected_subj_ANT[0]) self.SelectFiles = TwoListGUI(working_directory=image_folder, option_gui='displayNiftiFiles') self.SelectFiles.show()
def get_default_lead(lead_data): """obtains default lead properties according to the model proposed in the PaCER algorithm @ ./template""" if lead_data[ 'model'] == 'Boston Vercise Directional': # load mat-file to proceed mat_filename = 'boston_vercise_directed.mat' lead_model = loadmat( os.path.join(ROOTDIR, 'ext', 'LeadDBS', mat_filename), 'r')['electrode'] default_positions = { x: np.hstack(vals) for x, vals in lead_model.items() if x.endswith('position') } default_coordinates = np.array(lead_model['coords_mm']) # in [mm] else: Output.msg_box(text="Lead type not yet implemented.", title="Lead type not implemented") return return lead_model, default_positions, default_coordinates
def openDetails(self): """opens details file which has additional information on subjects """ import subprocess fileName = os.path.join(self.cfg['folders']['nifti'], 'subjdetails.csv') if os.path.isfile(fileName): if sys.platform == 'linux': subprocess.Popen(['xdg-open', ''.join(fileName)]) else: os.system('open"%s"' % fileName) subprocess.run(['open', fileName], check=True) else: Output.msg_box( text="Subject details unavailable, creating empty csv-file!", title="Detail file not found") subprocess.call([ 'touch', '{}subjdetails.csv'.format(self.cfg['folders']['nifti']) ])
def CoregisterCT2MRI(self, subjects, input_folder, fixed_image='reg_run[0-9]_bc_t1'): """Co-registration of postoperative CT to preoperative MRI for further analyses in same space; before registration presence of registered MRI data is ensured to avoid redundancy""" print('\nStarting co-registration for {} subject(s)'.format( len(subjects))) allfiles = FileOperations.get_filelist_as_tuple(inputdir=input_folder, subjects=subjects) self.check_for_normalisation(subjects) regex_complete = ['CT_', '{}_'.format(fixed_image.upper())] included_sequences = [ x for x in list( filter(re.compile(r"^(?!~).*").match, regex_complete)) ] file_ID_CT, file_ID_MRI = ([] for _ in range(2)) [ file_ID_CT.append(x) for x in allfiles if 'run' not in x[0] and re.search( r'\w+{}.'.format(included_sequences[0]), x[0], re.IGNORECASE) and x[0].endswith('.nii') ] [ file_ID_MRI.append(x) for x in allfiles # for simplicity written in a second line as regexp is slightly different if re.search(r'\w+(?!_).({}).'.format(included_sequences[1]), x[0], re.IGNORECASE) and x[0].endswith('.nii') ] if not file_ID_MRI: Output.msg_box(text="Bias-corrected MRI not found!", title="Preprocessed MRI unavailable") return fileIDs = list(FileOperations.inner_join(file_ID_CT, file_ID_MRI)) self.wrapper_multiprocessing(fileIDs, subjects, 'CT')
def __init__(self, _folderlist): self.logfile = True self.cfg = Configuration.load_config(ROOTDIR) self.DCM2NIIX_ROOT = os.path.join(ROOTDIR, 'ext', 'dcm2niix') if not os.path.isdir(self.cfg['folders']['dicom']): Output.msg_box( text="Please indicate a correct folder in the main GUI", title="Wrong folder") else: self.inputdir = self.cfg['folders']['dicom'] subjlist = self.create_subjlist(_folderlist) if not os.path.isdir(self.DCM2NIIX_ROOT): Output.msg_box( text= "Extracting imaging data from DICOM-files not successful because of wrong " "folder for 'dcm2niix'.", title="Wrong folder!") return if not os.path.isdir(self.cfg['folders']['nifti']): print( "\nDirectory for output is invalid; assuming same base and creating folder named 'nifti' therein!" ) self.outdir = os.path.join( os.path.split(self.inputdir)[0], 'nifti') if not os.path.isdir(self.outdir): os.mkdir(self.outdir) else: self.outdir = self.cfg['folders']['nifti'] lastsubj = self.get_index_nifti_folders( self.outdir, prefix=self.cfg['folders']['prefix']) self.create_csv_subjlist(subjlist, int(lastsubj)) self.convert_dcm2nii(subjlist, last_idx=int(lastsubj))
def load_leadModel(inputdir, filename): """Function loading results from [preprocLeadCT.py] which emulates the PaCER toolbox""" if not inputdir: Output.msg_box( text="No input folder provided, please double-check!", title="Missing input folder") return elif not os.path.isfile(filename): Output.msg_box( text= "Models for electrode unavailable, please run detection first!", title="Models not available") return else: with open( filename, "rb" ) as model: # roughly ea_loadreconstruction in the LeadDBS script lead_models = pickle.load(model) intensityProfiles = pickle.load(model) skelSkalms = pickle.load(model) return lead_models, intensityProfiles, skelSkalms
def show_nifti_files(self): """this function opens a list dialog and enables selecting NIFTI files for e.g. check the content (identical function as in GUITabPreprocessANTs.py.""" if not self.selected_subj_Gen: Output.msg_box( text= "No folder selected. To proceed, please indicate what folder to process.", title="No subject selected") return elif len(self.selected_subj_Gen) > 1: Output.msg_box( text= "Please select only one folder to avoid excessive image load", title="Number of selected files") return else: image_folder = os.path.join(self.cfg['folders']['nifti'], self.selected_subj_Gen[0]) self.SelectFiles = TwoListGUI(working_directory=image_folder, option_gui='displayNiftiFiles') self.SelectFiles.show()
def get_settings_from_config(self): """function which enters the settings according to cfg variable which is loaded""" if self.cfg == "": print() Output.msg_box( title="Warning", text= "No default settings found, please double check the folder content. " "Continuing with same settings.") else: if self.cfg["preprocess"]["dcm2nii"]["BIDSsidecar"] == 'yes': self.rbtnBIDSy.setChecked(True) else: self.rbtnBIDSn.setChecked(True) if self.cfg["preprocess"]["dcm2nii"]["OutputCompression"] == 'yes': self.rbtnCompressiony.setChecked(True) else: self.rbtnCompressionn.setChecked(True) if self.cfg["preprocess"]["dcm2nii"]["Verbosity"] == 0: self.rbtnVerbosity0.setChecked(True) elif self.cfg["preprocess"]["dcm2nii"]["Verbosity"] == 1: self.rbtnVerbosity1.setChecked(True) else: self.rbtnVerbosity2.setChecked(True) self.lineEditFilename.setText( self.cfg["preprocess"]["dcm2nii"]["OutputFileStruct"]) self.lineEditIncludeFiles.setText( self.cfg["preprocess"]["dcm2nii"]["IncludeFiles"]) if self.cfg["preprocess"]["dcm2nii"]["ReorientCrop"] == 'yes': self.rbtnReorientCropy.setChecked(True) else: self.rbtnReorientCropn.setChecked(True)
def __init__(self, working_directory, _option_gui, parent=None): super(QWidget, self).__init__(parent) self.cfg = Configuration.load_config(ROOTDIR) self.option_gui = _option_gui # ============================ Different options available ============================ if self.option_gui == 'dcm2niix': working_dir = self.cfg['folders']['dicom'] self.working_dir = working_dir if os.path.isdir( working_dir) else os.getcwd() options = { 'folderbox_title': "Directory (DICOM-files)", 'str_labelDir': 'DICOM DIR: {}'.format(self.working_dir), 'runBTN_label': 'Run processing' } elif self.option_gui == 'displayNiftiFiles': if not working_directory: Output.msg_box( text="Please provide a valid folder. Terminating this GUI.", title="No folder provided") self.close() return else: self.working_dir = working_directory options = { 'folderbox_title': "Directory (nifti-files)", 'str_labelDir': 'subjects\' DIR: {}'.format(self.working_dir), 'runBTN_label': 'View files' } else: Output.msg_box( text= "Please provide a valid option such as 'dcm2niix' or 'displayNiftiFiles'. " "Terminating the GUI", title="Wrong input as option") self.close() return # ============================ Start creating layout ============================ # Create general layout self.tot_layout = QVBoxLayout(self) self.mid_layout = QHBoxLayout(self) # ============================ Create upper of GUI, i.e. working directory ============================ self.label_folderbox = QGroupBox(options["folderbox_title"]) self.HBoxUpperTwoListGUI = QVBoxLayout(self.label_folderbox) self.label_workingdir = QLabel(options["str_labelDir"]) self.HBoxUpperTwoListGUI.addWidget(self.label_workingdir) self.btn_workingdir = QPushButton('Change working \ndirectory') self.btn_workingdir.setFixedSize(150, 40) self.btn_workingdir.setDisabled(True) if self.option_gui == 'dcm2niix': self.btn_workingdir.setEnabled(True) self.btn_workingdir.clicked.connect(self.change_workingdir) self.btn_savedir = QPushButton('Save directory \nto config file') self.btn_savedir.setFixedSize(150, 40) self.btn_savedir.setDisabled(True) if self.option_gui == 'dcm2niix': self.btn_savedir.setEnabled(True) self.btn_savedir.setToolTip( Output.split_lines(setToolTips.saveDirButton())) self.btn_savedir.clicked.connect(self.save_cfg_dicomdir) hlay_upper = QHBoxLayout() hlay_upper.addWidget(self.btn_workingdir) hlay_upper.addWidget(self.btn_savedir) hlay_upper.addStretch(1) self.HBoxUpperTwoListGUI.addLayout(hlay_upper) # ==================== Create Content for Lists, i.e. input/output ==================== self.listboxInputGUITwoList = QGroupBox( 'Available items in working directory') self.listboxInput = QVBoxLayout(self.listboxInputGUITwoList) self.mInput = QListWidget() self.listboxInput.addWidget(self.mInput) self.mButtonToAvailable = QPushButton("<<") self.mBtnMoveToAvailable = QPushButton(">") self.mBtnMoveToSelected = QPushButton("<") self.mButtonToSelected = QPushButton(">>") self.mBtnUp = QPushButton("Up") self.mBtnDown = QPushButton("Down") self.listboxOutputGUITwoLIst = QGroupBox('Items to process') self.listboxOutput = QVBoxLayout(self.listboxOutputGUITwoLIst) self.mOutput = QListWidget() self.listboxOutput.addWidget(self.mOutput) # First column (Left side) vlay = QVBoxLayout() vlay.addStretch() vlay.addWidget(self.mBtnMoveToAvailable) vlay.addWidget(self.mBtnMoveToSelected) vlay.addStretch() vlay.addWidget(self.mButtonToAvailable) vlay.addWidget(self.mButtonToSelected) vlay.addStretch() # Second column (Right side) vlay2 = QVBoxLayout() vlay2.addStretch() vlay2.addWidget(self.mBtnUp) vlay2.addWidget(self.mBtnDown) vlay2.addStretch() # ==================== Lower part of GUI, i.e. Preferences/Start estimation ==================== self.btn_preferences = QPushButton("Preferences") self.btn_preferences.setDisabled(True) self.btn_preferences.clicked.connect(self.settings_show) if self.option_gui == 'dcm2niix': self.btn_preferences.setEnabled(True) self.btn_run_command = QPushButton(options["runBTN_label"]) if self.option_gui == 'dcm2niix': self.btn_run_command.setToolTip(setToolTips.run_dcm2niix()) else: self.btn_run_command.setToolTip( setToolTips.run_CheckRegistration()) self.btn_run_command.clicked.connect(self.start_process) hlay_bottom = QHBoxLayout() hlay_bottom.addStretch(1) hlay_bottom.addWidget(self.btn_preferences) hlay_bottom.addWidget(self.btn_run_command) hlay_bottom.addStretch() # ==================== Set all contents to general Layout ======================= self.mid_layout.addWidget(self.listboxInputGUITwoList) self.mid_layout.addLayout(vlay) self.mid_layout.addWidget(self.listboxOutputGUITwoLIst) self.mid_layout.addLayout(vlay2) self.tot_layout.addWidget(self.label_folderbox) self.tot_layout.addLayout(self.mid_layout) self.tot_layout.addLayout(hlay_bottom) try: self.mInput.clear() if self.option_gui == 'dcm2niix': items = FileOperations.list_folders(self.working_dir, prefix='') else: items = FileOperations.list_files_in_folder( inputdir=self.working_dir, contains='', suffix='nii') self.addAvailableItems(items) except FileExistsError: print('{} without any valid files/folders, continuing ...'.format( self.working_dir)) self.update_buttons_status() self.connections()
def save_cfg(self): """Function intended to save the DICOM directory once button is pressed""" self.cfg['folders']['dicom'] = self.dicomdir Configuration.save_config(self.cfg['folders']['rootdir'], self.cfg) Output.msg_box(text="Folder changed in configuration to {}".format(self.dicomdir), title="Changed folder")
def PaCER_script(subjects, inputfolder=''): """wrapper script for all steps included in the PaCER algorithm""" print("\nLead detection of {} subject(s)".format(len(subjects))) inputfolder = cfg['folders']['nifti'] if not inputfolder else inputfolder # select default input folder LW = LeadWorks() # load the class including necessary functions # Look for data files containing CT imaging including the brainMask and load this into workspace available_files = FileOperations.get_filelist_as_tuple(inputdir=inputfolder, subjects=subjects) regex2lookfor = 'reg_' + 'run[0-9]', 'brainmask_' file_id_CTimaging = [file_tuple for file_tuple in available_files if re.search(r'\w.({}).'.format(regex2lookfor[0]), file_tuple[0], re.IGNORECASE) and file_tuple[0].endswith('.nii') and 'CT' in file_tuple[0]] file_id_brainMask = [file_tuple for file_tuple in available_files if re.search(r'\w.({}).'.format(regex2lookfor[1]), file_tuple[0], re.IGNORECASE) and file_tuple[0].endswith('.nii')] if any(t > 2 for t in [len(k) for k in file_id_CTimaging]): print("More than one files for imaging or brainmask available. Please double-check!") return if not file_id_brainMask: warnings.warn(message="\tNo brain mask was found, trying to obtain a mask using ANTSpyNET routines") regex2lookforT1 = cfg['preprocess']['normalisation']['prefix'] + 'run' file_id_T1 = [file_tuple for file_tuple in available_files if re.search(r'\w.({}).'.format(regex2lookforT1), file_tuple[0], re.IGNORECASE) and 't1' in file_tuple[0] and file_tuple[0].endswith('.nii')] if not file_id_T1: Output.msg_box(text='No T1-sequence imaging available. BrainMask extraction impossible.', title='T1 sequences missing")') return else: T1imaging = ants.image_read(file_id_T1[0][0]) file_id_brainMask = Imaging.create_brainmask(input_folder=inputfolder, subj=''.join(subjects), registered_images=T1imaging) file_id_brainMask = [file_id_brainMask] if type(file_id_brainMask) == tuple else file_id_brainMask fileID = list(FileOperations.inner_join(file_id_brainMask, file_id_CTimaging)) # joins all to single list metal_threshold = int(cfg['lead_detection']['PaCER']['metal_threshold']) elecModels, intensityProfiles, skelSkalms = LW.electrodeEstimation(fileID[0], threshold=metal_threshold) elecModels, skelSkalms, intensityProfiles, _ = \ LeadProperties.estimate_hemisphere(elecModels, intensityProfiles, skelSkalms) # returns hemisphere from coords. filename_save = os.path.join(os.path.join(inputfolder, subjects[0]), 'elecModels_' + subjects[0] + '.pkl') with open(filename_save, "wb") as f: pickle.dump(elecModels, f) pickle.dump(intensityProfiles, f) pickle.dump(skelSkalms, f) sides = ['left', 'right'] rotation_default, rotation_mod = [{k: [] for k in sides} for _ in range(2)] for s in sides: rotation_default[s] = function_wrapper(subj=subjects[0], side=s) rotation_mod[s] = Configuration.rotation_dict_mod() # creates an empty array to save modified data later filename_save = os.path.join(os.path.join(inputfolder, subjects[0]), 'rotation_' + subjects[0] + '.pkl') with open(filename_save, "wb") as f: pickle.dump(rotation_default, f) pickle.dump(rotation_mod, f) print("Finished with lead detection!") # TODO: it does not return to the empty command line. return