Пример #1
0
    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
Пример #2
0
 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')
Пример #3
0
    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)
Пример #4
0
    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
Пример #5
0
    def wrapper_multiprocessing(self, fileIDs, subjects, modality):
        """To avoid redundancy between CT and MR  registration to common space, this part is wrapped up here """

        working_dir = self.cfg['folders']['nifti']
        prefix = '{}2template'.format(modality)

        # Start multiprocessing framework
        start_multi = time.time()
        status = mp.Queue()
        processes = [
            mp.Process(target=self.ANTsCoregisterMultiprocessing,
                       args=(filename_fixed, filename_moving, no_subj,
                             os.path.join(working_dir, no_subj),
                             'registration', prefix, status))
            for filename_fixed, filename_moving, no_subj in fileIDs
        ]

        for p in processes:
            p.start()

        while any([p.is_alive() for p in processes]):
            while not status.empty():
                filename_fixed, filename_moving, no_subj = status.get()
                print("\tRegistering {} (f) to {} (m), in ANTsPy\n".format(
                    filename_fixed,
                    os.path.split(filename_moving)[1], no_subj))
            time.sleep(0.1)

        for p in processes:
            p.join()

        # Functions creating/updating pipeline log, which documents all steps along with settings
        for subjID in subjects:
            files_processed = [(os.path.split(file_moving)[1],
                                os.path.split(file_fixed)[1])
                               for file_fixed, file_moving, subj_no in fileIDs
                               if subj_no == subjID]
            log_text = "{} successfully registered (@{}) to \n{}, \n\n Mean Duration per subject: {:.2f} " \
                       "secs".format(files_processed[0][0], time.strftime("%Y%m%d-%H%M%S"), files_processed[0][1],
                                     (time.time() - start_multi) / len(subjects))
            Output.logging_routine(text=Output.split_lines(log_text),
                                   cfg=self.cfg,
                                   subject=str(subjID),
                                   module='{}-Registration'.format(modality),
                                   opt=self.cfg['preprocess']['registration'],
                                   project="")

        print(
            '\nIn total, a list of {} subject(s) was processed; {} registration took {:.2f}secs. '
            'overall'.format(len(subjects), modality,
                             time.time() - start_multi))
Пример #6
0
    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)
Пример #7
0
    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)
Пример #8
0
    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()
Пример #9
0
    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)
Пример #10
0
    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()
Пример #11
0
    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')
Пример #12
0
    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)
Пример #13
0
    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'])
Пример #14
0
def RegisterCT2MRI():
    text = "Runs registration of CT imaging (moving) and T1-sequence (fixed) in order to get them into same space. " \
           "The default option (see cfg-file) constitutes three steps: a) Rigid, b) Affine registration and c) " \
           "Symmetric image Normalisation (SyN). For details see 'SyNRA'-option at " \
           "https://github.com/ANTsX/ANTsPy/blob/master/ants/registration/interface.py. Non-default means, that the " \
           "command-line for running ANTsRegistration can be modified according to the file: " \
           "cmdline_ANTsRegistration.txt in the .utils directory. Please make sure to include all terms within *...* " \
           "into the text-file as they will be replaced."
    return Output.split_lines(text)
Пример #15
0
    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]))
Пример #16
0
def RegisterMRI2template():
    text = "Runs registration of MR-imaging (moving) to template sequences (fixed) as defined in the config file in " \
           "order to get them into same space. The default option constitutes three steps: a) Rigid, " \
           "b) Affine registration and c) Symmetric image Normalisation (SyN), although all options available in ANTsPy" \
           "are possible (for details see https://github.com/ANTsX/ANTsPy/blob/master/ants/registration/interface.py. " \
           "Non-default means, that the command-line for running ANTsRegistration can be modified according to " \
           "the file: cmdline_ANTsRegistration.txt in the .utils directory. Please make sure to include all terms " \
           "within *...* into the text-file as they will be replaced."

    return Output.split_lines(text)
Пример #17
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)
Пример #18
0
    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()
Пример #19
0
    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
Пример #20
0
    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'])
            ])
Пример #21
0
    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')
Пример #22
0
    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))
Пример #23
0
    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
Пример #24
0
    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()
Пример #25
0
    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)
Пример #26
0
def LabelFilenameDCM2NII():
    text = "Please enter here the prefix/file information that should be included when saving NIFTI files. " \
           "Characters such as '<', '>', ':', '/' ... MUST be avoided (default is %p_%s). " \
           "From documentation:\n\t %a : antenna (coil) number inserted. For example, the output filename" \
           " 'myName%a' would generate 'myName1', 'myName2', each for each coil. Note that most scans combine data " \
           "from all coils and in these cases this option is ignored. For example, most scans which combine " \
           "data from all coils would simply be called 'myName'\n\t%d :" \
           "series description (0008,103E) inserted. For example, an echo-planar image " \
           "converted with 'myName%d' would yield 'myNameEPI' \n\t%e : echo number " \
           "inserted. For example, a sequence with two echo times converted with the output" \
           "filename 'myName%e' will yield 'myName1' and 'myName2'. Note that most MRI" \
           " sequences only use a single echo time, and in these cases you would only get " \
           "'myName1'.\n\t%f : input folder name inserted. For example, the output " \
           "filename'myName%f' combined with an input folder '/usr/Subj22' will result in " \
           "the output file named'myNameSubj22.nii' \n\t%i : patient ID " \
           "(DICOM tag 0010,0020) inserted. For example, the output filename 'myName%i' " \
           " would convert an image where the patient ID is named 'ID123' to be " \
           " 'myNameID123.nii' \n\t%m : manufacturer name For example, the output filename" \
           " 'myName%m' would convert an image from a GE scanner to 'myNameGE.nii', while " \
           " an image from  Philips would be 'myNamePh.nii', whereas Siemens would be " \
           " 'myNameSi.nii', otherwise the manufacturer is not available ('myNameNA.nii')." \
           " (requires dcm2nii versions from 2015 or later). \n\t%n : subject name (DICOM" \
           " tag 0010,0010) inserted. For example, the output filename 'myName%n' would " \
           " convert an image from John Doe to 'myNameJohnDoe.nii'. This option works best" \
           " if your participant names use only English letters, for other European " \
           " languages you may find it makes some basic conversions ('Müller' will become " \
           " 'Muller'). For non-European languages you will find this option unsatisfactory" \
           ". Perhaps future versions can support DICOM tag 0008,0005. \n\t %p: protocol" \
           " name (DICOM tag 0018,1030) inserted. For example, the output filename" \
           " 'myName%p' would convert image where protocol is named T1 to be 'myNameT1.nii'" \
           " \n\t%q: sequence name (DICOM tag 0018,1020) inserted.For example," \
           " the output filename 'myName%q' would convert a Spin Echo sequence to be " \
           "'myNameSE.nii' (new feature, in versions from 30Aug2015).\n\t%s : series (DICOM " \
           "tag 0020,0011) inserted. For example, the output filename 'myName%s' would " \
           "convert the second series to be 'myName2.nii'. If you want to zero-pad the " \
           "series number, insert the number of digits desired (0..9). For example applying " \
           "the filter 'm%s' when converting 11 series will create files that will cause" \
           " problems for a simple alphabetical sort, e.g. 'm1.nii,m11.nii,m2.nii...m9.nii'." \
           " In contrast specifying 'm%3s' will help sorting (e.g. 'm001.nii,m002.nii" \
           "...m011.nii').\n\t%t : session date and time inserted (DICOM tags 0008,0021 and " \
           "0008,0030). For example, the output filename 'myName%t' would convert an image " \
           "where the session began at 1:23pm on 13 Jan 2014 as 'myName20140113132322.nii' " \
           "\n\t%z : Sequence Name (0018,0024) inserted, so a T1 scan converted with " \
           "'myName%z' might yield 'myNameT1'."

    return Output.split_lines(text)
Пример #27
0
    def __init__(self, parent=None):
        super(QWidget, self).__init__(parent)

        # Load configuration files and general settings
        self.cfg = Configuration.load_config(ROOTDIR)
        if os.path.isdir(self.cfg['folders']['dicom']):
            self.dicomdir = self.cfg['folders']['dicom']
        else:
            self.dicomdir = FileOperations.set_wdir_in_config(self.cfg, foldername='dicom', init=True)

        self.cfg['folders']['dicom'] = self.dicomdir
        self.cfg['folders']['rootdir'] = ROOTDIR
        Configuration.save_config(ROOTDIR, self.cfg)

        # Create general layout
        self.tot_layout = QVBoxLayout(self)
        self.mid_layout = QHBoxLayout(self)

        # ============================    Create upper of  GUI, i.e. working directory   ============================
        self.folderboxDcm2nii = QGroupBox("Directory (DICOM-files)")
        self.HBoxUpperDcm2nii = QVBoxLayout(self.folderboxDcm2nii)
        self.label_dicomdir = QLabel('dicom DIR: {}'.format(self.dicomdir))
        self.HBoxUpperDcm2nii.addWidget(self.label_dicomdir)

        self.btn_dicomdir = QPushButton('Change working \ndirectory')
        self.btn_dicomdir.setFixedSize(150, 40)
        self.btn_dicomdir.clicked.connect(self.change_dicomdir)
        self.btn_savedir = QPushButton('Save directory \nto config file')
        self.btn_savedir.setFixedSize(150, 40)
        self.btn_savedir.setToolTip(Output.split_lines(setToolTips.saveDirButton()))
        self.btn_savedir.clicked.connect(self.save_cfg)

        hlay_upper = QHBoxLayout()
        hlay_upper.addWidget(self.btn_dicomdir)
        hlay_upper.addWidget(self.btn_savedir)
        hlay_upper.addStretch(1)
        self.HBoxUpperDcm2nii.addLayout(hlay_upper)

        # ====================    Create Content for Lists, i.e. input/output      ====================
        self.listboxInputDcm2nii = QGroupBox('Available subjects in working directory')
        self.listboxInput = QVBoxLayout(self.listboxInputDcm2nii)
        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.listboxOutputDcm2nii = QGroupBox('Subjects to process')
        self.listboxOutput = QVBoxLayout(self.listboxOutputDcm2nii)
        self.mOutput = QListWidget()
        self.listboxOutput.addWidget(self.mOutput)

        # First column on the 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 on the 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.clicked.connect(self.settings_show)
        self.btn_run_dcm2niix = QPushButton("Run dcm2niix")
        self.btn_run_dcm2niix.setToolTip(setToolTips.run_dcm2niix())
        self.btn_run_dcm2niix.clicked.connect(self.start_converting)

        hlay_bottom = QHBoxLayout()
        hlay_bottom.addStretch(1)
        hlay_bottom.addWidget(self.btn_preferences)
        hlay_bottom.addWidget(self.btn_run_dcm2niix)
        hlay_bottom.addStretch()

        # ====================    Set all contents to general Layout     =======================
        self.mid_layout.addWidget(self.listboxInputDcm2nii)
        self.mid_layout.addLayout(vlay)
        self.mid_layout.addWidget(self.listboxOutputDcm2nii)
        self.mid_layout.addLayout(vlay2)

        self.tot_layout.addWidget(self.folderboxDcm2nii)
        self.tot_layout.addLayout(self.mid_layout)
        self.tot_layout.addLayout(hlay_bottom)

        try:
            self.mInput.clear()
            items = FileOperations.list_folders(inputdir=self.cfg['folders']['dicom'], prefix='', files2lookfor='')
            items = self.check_for_complete_input(list(items))
            self.add_available_subj(items)
        except FileExistsError:
            print('{} without any valid files/folders, continuing ...'.format(self.dicomdir))

        self.update_buttons_status()
        self.connections()
Пример #28
0
    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")
Пример #29
0
    def dcm2niix_multiprocessing(self, name_subj, no_subj, dcm2niix_bin,
                                 last_idx, total_subj, status):
        """function intended to provide multiprocessing approach to speed up extraction of DICOM data to nifti files"""

        modalities = ['CT', 'MRI']
        if self.logfile:
            log_filename = os.path.join(
                ROOTDIR, 'logs', 'log_DCM2NII_' + str(no_subj + last_idx) +
                time.strftime("%Y%m%d-%H%M%S"))
        else:
            log_filename = os.devnull

        subj_outdir = os.path.join(
            self.outdir,
            self.cfg['folders']['prefix'] + str(no_subj + last_idx))
        FileOperations.create_folder(subj_outdir)
        start_time_subject = time.time()
        keptfiles, deletedfiles = ([] for _ in range(2))

        for mod in modalities:
            status.put((name_subj, mod, no_subj, total_subj))
            input_folder_name = os.path.join(self.inputdir, name_subj + mod)
            # input_folder_files = [f.path for f in os.scandir(input_folder_name)
            #                       if (f.is_dir() and ('100' in f.path or 'DICOM' in f.path or '001' in f.path))]
            input_folder_files = []
            [
                input_folder_files.append(item)
                for item in os.listdir(input_folder_name)
                if (os.path.isdir(os.path.join(input_folder_name, item)) and (
                    '100' in item or 'DICOM' in item or '001' in item))
            ]

            orig_stdout = sys.stdout
            sys.stdout = open(log_filename, 'w')
            for folder in input_folder_files:
                subprocess.call(
                    [
                        dcm2niix_bin,
                        '-a',
                        'y',  # anonimisation of DICOM data
                        '-b',
                        self.cfg['preprocess']['dcm2nii']['BIDSsidecar'][0],
                        '-z',
                        self.cfg['preprocess']['dcm2nii']['OutputCompression']
                        [0],
                        '-f',
                        self.cfg['preprocess']['dcm2nii']['OutputFileStruct'],
                        '-o',
                        subj_outdir,
                        '-w',
                        str(self.cfg['preprocess']['dcm2nii']
                            ['NameConflicts']),
                        '-v',
                        str(self.cfg['preprocess']['dcm2nii']['Verbosity']),
                        '-x',
                        str(self.cfg['preprocess']['dcm2nii']['ReorientCrop']),
                        folder
                    ],
                    stdout=sys.stdout,
                    stderr=subprocess.STDOUT)

            sys.stdout.close()
            sys.stdout = orig_stdout

            files_kept, files_deleted = self.select_sequences(subj_outdir)
            keptfiles.extend(files_kept)
            deletedfiles.extend(files_deleted)

        # Functions creating/updating pipeline log, which document individually all steps along with settings
        log_text = "{} files successfully converted: {}, \n\nand {} deleted: {}.\nDuration: {:.2f} secs" \
            .format(len(set(keptfiles)),
                    '\n\t{}'.format('\n\t'.join(os.path.split(x)[1] for x in sorted(set(keptfiles)))),
                    len(set(deletedfiles)),
                    '\n\t{}'.format('\n\t'.join(os.path.split(x)[1] for x in sorted(set(deletedfiles)))),
                    time.time() - start_time_subject)
        Output.logging_routine(text=Output.split_lines(log_text),
                               cfg=self.cfg,
                               subject=self.cfg['folders']['prefix'] +
                               str(no_subj),
                               module='dcm2nii',
                               opt=self.cfg['preprocess']['dcm2nii'],
                               project="")
Пример #30
0
def run_dcm2niix():
    text = "Before running this script, please make sure that the prefrences are set properly. moreover it is " \
           "recommended to name DICOM folders xxxCT and xxxMRI or one of both. cDBS will specifically look for these " \
           "folders to convert DICOM data from."

    return Output.split_lines(text)