Exemple #1
0
def main():

    # Parse command line arguments
    parser = argparse.ArgumentParser(description='Convert DICOM files to BIDS-compliant Nifty structure')

    parser.add_argument('-d', '--dataset', default='.', help='BIDS dataset directory containing sourcedata subdirectory')

    parser.add_argument('--no-sessions', action='store_true', default=False,
                        help='Do not use session sub-directories')

    parser.add_argument('--overwrite', action='store_true', default=False,
                        help='Overwrite existing files')

    parser.add_argument('--skip_if_pruning', action='store_true', default=False,
                        help='Skip pruning of nonexistent IntendedFor items in json files')
    
    parser.add_argument('--clean_conv_dir', action='store_true', default=False,
                        help='Clean up conversion directory')

    # Parse command line arguments
    args = parser.parse_args()
    dataset_dir = os.path.realpath(args.dataset)
    no_sessions = args.no_sessions
    overwrite = args.overwrite

    print('\n------------------------------------------------------------')
    print('BIDSKIT %s' % __version__)
    print('------------------------------------------------------------')

    # Check for minimum dcm2niix version (mostly for multirecon suffix handling)
    btr.check_dcm2niix_version('v1.0.20181125')

    # Create a BIDS directory tree object to handle file locations
    # Creates directory
    btree = BIDSTree(dataset_dir, overwrite)

    print('\nSource data directory      : %s' % btree.sourcedata_dir)
    print('Working Directory          : %s' % btree.work_dir)
    print('Use Session Directories    : %s' % ('No' if no_sessions else 'Yes'))
    print('Overwrite Existing Files   : %s' % ('Yes' if overwrite else 'No'))

    # Load protocol translation and exclusion info from derivatives/conversion directory
    # If no translator is present, prot_dict is an empty dictionary
    # and a template will be created in the derivatives/conversion directory.
    # This template should be completed by the user and the conversion rerun.
    translator = btree.read_translator()

    if translator and os.path.isdir(btree.work_dir):

        print('\n------------------------------------------------------------')
        print('Pass 2 : Populating BIDS directory')
        print('------------------------------------------------------------')
        first_pass = False

    else:

        print('\n------------------------------------------------------------')
        print('Pass 1 : DICOM to Nifti conversion and translator creation')
        print('------------------------------------------------------------')
        first_pass = True

    subject_dir_list = []

    # Loop over subject directories in DICOM root
    for dcm_sub_dir in glob(btree.sourcedata_dir + '/*/'):

        sid = os.path.basename(dcm_sub_dir.strip('/'))

        # Check that subject ID is legal
        btr.check_subject_session(sid)

        subject_dir_list.append(dataset_dir + "/sub-" + sid)

        print('\n------------------------------------------------------------')
        print('Processing subject ' + sid)
        print('------------------------------------------------------------')

        # Handle subject vs subject/session directory lists
        if no_sessions:
            dcm_dir_list = [dcm_sub_dir]
        else:
            dcm_dir_list = glob(dcm_sub_dir + '/*/')

        # Loop over source data session directories in subject directory
        for dcm_dir in dcm_dir_list:

            # BIDS subject, session and conversion directories
            sub_prefix = 'sub-' + sid

            if no_sessions:

                # If session subdirs aren't being used, *_ses_dir = *sub_dir
                # Use an empty ses_prefix with os.path.join to achieve this
                ses = ''
                ses_prefix = ''

            else:

                ses = os.path.basename(dcm_dir.strip('/'))

                # Check that session ID is legal
                btr.check_subject_session(ses)

                ses_prefix = 'ses-' + ses
                print('  Processing session ' + ses)

            # Working conversion directories
            work_subj_dir = os.path.join(btree.work_dir, sub_prefix)
            work_conv_dir = os.path.join(work_subj_dir, ses_prefix)

            # BIDS source directory directories
            bids_subj_dir = os.path.join(dataset_dir, sub_prefix)
            bids_ses_dir = os.path.join(bids_subj_dir, ses_prefix)

            print('  Working subject directory : %s' % work_subj_dir)
            if not no_sessions:
                print('  Working session directory : %s' % work_conv_dir)
            print('  BIDS subject directory  : %s' % bids_subj_dir)
            if not no_sessions:
                print('  BIDS session directory  : %s' % bids_ses_dir)

            # Safely create working directory for current subject
            # Flag for conversion if no working directory existed
            if not os.path.isdir(work_conv_dir):
                os.makedirs(work_conv_dir)
                needs_converting = True
            else:
                needs_converting = False

            if first_pass or needs_converting:

                # Run dcm2niix conversion into working conversion directory
                print('  Converting all DICOM images in %s' % dcm_dir)
                devnull = open(os.devnull, 'w')
                subprocess.call(['dcm2niix', '-b', 'y', '-z', 'y', '-f', '%n--%d--%q--%s',
                                 '-o', work_conv_dir, dcm_dir],
                                stdout=devnull, stderr=subprocess.STDOUT)

            if not first_pass:

                # Get subject age and sex from representative DICOM header
                dcm_info = bio.dcm_info(dcm_dir)

                # Add line to participants TSV file
                btr.add_participant_record(dataset_dir, sid, dcm_info['Age'], dcm_info['Sex'])

            # Organize dcm2niix output into BIDS subject/session directories
            organize_series(work_conv_dir, first_pass, translator, bids_ses_dir, sid, ses,
                           args.clean_conv_dir, overwrite)

    if first_pass:

        # Create a template protocol dictionary
        btree.write_translator(translator)

    if not args.skip_if_pruning:

        print("\nSubject directories to prune:  " + ", ".join(subject_dir_list))

        for bids_subj_dir in subject_dir_list:
            btr.prune_intendedfors(bids_subj_dir, True)

    # Finally validate that all is well with the BIDS dataset
    if not first_pass:
        btree.validate()

    # Clean exit
    sys.exit(0)
Exemple #2
0
def main():

    # Parse command line arguments
    parser = argparse.ArgumentParser(description='Convert DICOM files to BIDS-compliant Nifty structure')

    parser.add_argument('-d', '--dataset', default='.', help='BIDS dataset directory containing sourcedata subdirectory')

    parser.add_argument('--no-sessions', action='store_true', default=False,
                        help='Do not use session sub-directories')

    parser.add_argument('--overwrite', action='store_true', default=False,
                        help='Overwrite existing files')

    parser.add_argument('--skip_if_pruning', action='store_true', default=False,
                        help='Skip pruning of nonexistent IntendedFor items in json files')
    
    parser.add_argument('--clean_conv_dir', action='store_true', default=False,
                        help='Clean up conversion directory')

    # Parse command line arguments
    args = parser.parse_args()
    dataset_dir = os.path.realpath(args.dataset)
    no_sessions = args.no_sessions
    overwrite = args.overwrite

    print('\n------------------------------------------------------------')
    print('BIDSKIT %s' % __version__)
    print('------------------------------------------------------------')

    # Check for minimum dcm2niix version (mostly for multirecon suffix handling)
    btr.check_dcm2niix_version('v1.0.20181125')

    # Create a BIDS directory tree object to handle file locations
    # Creates directory
    btree = BIDSTree(dataset_dir, overwrite)

    print('\nSource data directory      : %s' % btree.sourcedata_dir)
    print('Working Directory          : %s' % btree.work_dir)
    print('Use Session Directories    : %s' % ('No' if no_sessions else 'Yes'))
    print('Overwrite Existing Files   : %s' % ('Yes' if overwrite else 'No'))

    # Load protocol translation and exclusion info from derivatives/conversion directory
    # If no translator is present, prot_dict is an empty dictionary
    # and a template will be created in the derivatives/conversion directory.
    # This template should be completed by the user and the conversion rerun.
    translator = btree.read_translator()

    if translator and os.path.isdir(btree.work_dir):

        print('\n------------------------------------------------------------')
        print('Pass 2 : Populating BIDS directory')
        print('------------------------------------------------------------')
        first_pass = False

    else:

        print('\n------------------------------------------------------------')
        print('Pass 1 : DICOM to Nifti conversion and translator creation')
        print('------------------------------------------------------------')
        first_pass = True

    subject_dir_list = []

    # Loop over subject directories in DICOM root
    for dcm_sub_dir in glob(btree.sourcedata_dir + '/*/'):

        sid = os.path.basename(dcm_sub_dir.strip('/'))

        # Check that subject ID is legal
        btr.check_subject_session(sid)

        subject_dir_list.append(dataset_dir + "/sub-" + sid)

        print('\n------------------------------------------------------------')
        print('Processing subject ' + sid)
        print('------------------------------------------------------------')

        # Handle subject vs subject/session directory lists
        if no_sessions:
            dcm_dir_list = [dcm_sub_dir]
        else:
            dcm_dir_list = glob(dcm_sub_dir + '/*/')

        # Loop over source data session directories in subject directory
        for dcm_dir in dcm_dir_list:

            # BIDS subject, session and conversion directories
            sub_prefix = 'sub-' + sid

            if no_sessions:

                # If session subdirs aren't being used, *_ses_dir = *sub_dir
                # Use an empty ses_prefix with os.path.join to achieve this
                ses = ''
                ses_prefix = ''

            else:

                ses = os.path.basename(dcm_dir.strip('/'))

                # Check that session ID is legal
                btr.check_subject_session(ses)

                ses_prefix = 'ses-' + ses
                print('  Processing session ' + ses)

            # Working conversion directories
            work_subj_dir = os.path.join(btree.work_dir, sub_prefix)
            work_conv_dir = os.path.join(work_subj_dir, ses_prefix)

            # BIDS source directory directories
            bids_subj_dir = os.path.join(dataset_dir, sub_prefix)
            bids_ses_dir = os.path.join(bids_subj_dir, ses_prefix)

            print('  Working subject directory : %s' % work_subj_dir)
            if not no_sessions:
                print('  Working session directory : %s' % work_conv_dir)
            print('  BIDS subject directory  : %s' % bids_subj_dir)
            if not no_sessions:
                print('  BIDS session directory  : %s' % bids_ses_dir)

            # Safely create working directory for current subject
            # Flag for conversion if no working directory existed
            if not os.path.isdir(work_conv_dir):
                os.makedirs(work_conv_dir)
                needs_converting = True
            else:
                needs_converting = False

            if first_pass or needs_converting:

                # Run dcm2niix conversion into working conversion directory
                print('  Converting all DICOM images in %s' % dcm_dir)
                devnull = open(os.devnull, 'w')
                subprocess.call(['dcm2niix', '-b', 'y', '-z', 'y', '-f', '%n--%d--%q--%s',
                                 '-o', work_conv_dir, dcm_dir],
                                stdout=devnull, stderr=subprocess.STDOUT)

            if not first_pass:

                # Get subject age and sex from representative DICOM header
                dcm_info = bio.dcm_info(dcm_dir)

                # Add line to participants TSV file
                btr.add_participant_record(dataset_dir, sid, dcm_info['Age'], dcm_info['Sex'])

            # Organize dcm2niix output into BIDS subject/session directories
            organize_series(work_conv_dir, first_pass, translator, bids_ses_dir, sid, ses,
                           args.clean_conv_dir, overwrite)

    if first_pass:

        # Create a template protocol dictionary
        btree.write_translator(translator)

    if not args.skip_if_pruning:

        print("\nSubject directories to prune:  " + ", ".join(subject_dir_list))

        for bids_subj_dir in subject_dir_list:
            btr.prune_intendedfors(bids_subj_dir, True)

    # Finally validate that all is well with the BIDS dataset
    if not first_pass:
        btree.validate()

    # Clean exit
    sys.exit(0)
Exemple #3
0
def main():

    # Parse command line arguments
    parser = argparse.ArgumentParser(
        description='Convert DICOM files to BIDS-compliant Nifty structure')

    parser.add_argument(
        '-d',
        '--dataset',
        default='.',
        help='BIDS dataset directory containing sourcedata subdirectory')

    parser.add_argument(
        '-s',
        '--subjects',
        nargs='+',
        default=[],
        help=
        'List of subject IDs to convert (eg --subjects alpha bravo charlie)')

    parser.add_argument('--no-sessions',
                        action='store_true',
                        default=False,
                        help='Do not use session sub-directories')

    parser.add_argument(
        '--no-anon',
        action='store_true',
        default=False,
        help='Do not anonymize BIDS output (eg for phantom data)')

    parser.add_argument('--overwrite',
                        action='store_true',
                        default=False,
                        help='Overwrite existing files')

    parser.add_argument(
        '--skip-if-pruning',
        action='store_true',
        default=False,
        help='Skip pruning of nonexistent IntendedFor items in json files')

    parser.add_argument('--clean-conv-dir',
                        action='store_true',
                        default=False,
                        help='Clean up conversion directory')

    parser.add_argument(
        '--bind-fmaps',
        action='store_true',
        default=False,
        help='Bind fieldmaps to fMRI series using IntendedFor field')

    parser.add_argument('-V',
                        '--version',
                        action='store_true',
                        default=False,
                        help='Display bidskit version number and exit')

    # Parse command line arguments
    args = parser.parse_args()
    dataset_dir = os.path.realpath(args.dataset)
    subject_list = args.subjects
    no_sessions = args.no_sessions
    no_anon = args.no_anon
    overwrite = args.overwrite
    bind_fmaps = args.bind_fmaps

    # Read version from setup.py
    ver = pkg_resources.get_distribution('bidskit').version

    if args.version:
        print('BIDSKIT {}'.format(ver))
        sys.exit(1)

    print('')
    print('------------------------------------------------------------')
    print('BIDSKIT {}'.format(ver))
    print('------------------------------------------------------------')

    # Check for minimum dcm2niix version (mostly for multirecon suffix handling)
    btr.check_dcm2niix_version('v1.0.20181125')

    # Create a BIDS directory tree object to handle file locations
    # Creates directory
    btree = BIDSTree(dataset_dir, overwrite)

    if len(subject_list) > 1:
        subj_to_convert = ' '.join(subject_list)
    else:
        subj_to_convert = 'All'

    print('')
    print('Subjects to convert        : {}'.format(subj_to_convert))
    print('Source data directory      : {}'.format(btree.sourcedata_dir))
    print('Working Directory          : {}'.format(btree.work_dir))
    print('Use Session Directories    : {}'.format(
        'No' if no_sessions else 'Yes'))
    print(
        'Overwrite Existing Files   : {}'.format('Yes' if overwrite else 'No'))
    print('Anonymize BIDS Output      : {}'.format('No' if no_anon else 'Yes'))
    print('Bind fieldmaps             : {}'.format(
        'Yes' if bind_fmaps else 'No'))

    # Load protocol translation and exclusion info from derivatives/conversion directory
    # If no translator is present, prot_dict is an empty dictionary
    # and a template will be created in the derivatives/conversion directory.
    # This template should be completed by the user and the conversion rerun.
    translator = btree.read_translator()

    if translator and os.path.isdir(btree.work_dir):

        print('')
        print('------------------------------------------------------------')
        print('Pass 2 : Populating BIDS directory')
        print('------------------------------------------------------------')
        first_pass = False

    else:

        print('')
        print('------------------------------------------------------------')
        print('Pass 1 : DICOM to Nifti conversion and translator creation')
        print('------------------------------------------------------------')
        first_pass = True

    # Init list of output subject directories
    out_subj_dir_list = []

    # Init list of source subject directories from sourcedata contents if no subjects provided in command line
    if len(subject_list) < 1:
        print('  Creating subject list from sourcedata contents')
        subject_list = []
        for it in os.scandir(btree.sourcedata_dir):
            if it.is_dir():
                subject_list.append(it.name)
        print('  Found {:d} subjects in sourcedata folder'.format(
            len(subject_list)))

    # Loop over subject list (either from sourcedata contents or command line)
    for sid in subject_list:

        print('')
        print('------------------------------------------------------------')
        print('Processing subject {}'.format(sid))
        print('------------------------------------------------------------')

        # Full path to subject directory in sourcedata/
        src_subj_dir = os.path.realpath(os.path.join(btree.sourcedata_dir,
                                                     sid))

        # BIDS subject ID with prefix
        subj_prefix = 'sub-{:s}'.format(sid)

        # Add full path to subject output directory to running list
        out_subj_dir_list.append(os.path.join(dataset_dir, subj_prefix))

        # Create list of DICOM directories to convert
        # This will be either a session or series folder list depending on no-sessions command line flag
        if no_sessions:
            dcm_dir_list = [src_subj_dir]
        else:
            dcm_dir_list = glob(os.path.join(src_subj_dir, '*'))

        # Loop over DICOM directories in subject directory
        for dcm_dir in dcm_dir_list:

            if no_sessions:

                # If session subdirs aren't being used, *_ses_dir = *sub_dir
                # Use an empty ses_prefix with os.path.join to achieve this
                ses = ''
                ses_prefix = ''

            else:

                ses = os.path.basename(os.path.normpath(dcm_dir))

                ses_prefix = 'ses-{:s}'.format(ses)
                print('  Processing session ' + ses)

            # Working conversion directories
            work_subj_dir = os.path.join(btree.work_dir, subj_prefix)
            work_conv_dir = os.path.join(work_subj_dir, ses_prefix)

            # BIDS source directory directories
            bids_subj_dir = os.path.join(dataset_dir, subj_prefix)
            bids_ses_dir = os.path.join(bids_subj_dir, ses_prefix)

            print('  Working subject directory : %s' % work_subj_dir)
            if not no_sessions:
                print('  Working session directory : %s' % work_conv_dir)
            print('  BIDS subject directory  : %s' % bids_subj_dir)
            if not no_sessions:
                print('  BIDS session directory  : %s' % bids_ses_dir)

            # Safely create working directory for current subject
            # Flag for conversion if no working directory exists
            if not os.path.isdir(work_conv_dir):
                os.makedirs(work_conv_dir)
                needs_converting = True
            else:
                needs_converting = False

            if first_pass or needs_converting:

                # Run dcm2niix conversion into working conversion directory
                print('  Converting all DICOM images in %s' % dcm_dir)
                devnull = open(os.devnull, 'w')

                # BIDS anonymization flag - default 'y'
                anon = 'n' if no_anon else 'y'

                # Compose command
                cmd = [
                    'dcm2niix', '-b', 'y', '-ba', anon, '-z', 'y', '-f',
                    '%n--%d--%q--%s', '-o', work_conv_dir, dcm_dir
                ]

                with open(os.devnull, 'w') as devnull:
                    subprocess.run(cmd, stdout=devnull, stderr=devnull)

            if not first_pass:

                # Get subject age and sex from representative DICOM header
                dcm_info = bio.dcm_info(dcm_dir)

                # Add line to participants TSV file
                btr.add_participant_record(dataset_dir, sid, dcm_info['Age'],
                                           dcm_info['Sex'])

            # Organize dcm2niix output into BIDS subject/session directories
            organize_series(work_conv_dir, first_pass, translator,
                            bids_ses_dir, sid, ses, args.clean_conv_dir,
                            overwrite)

    if first_pass:

        # Create a template protocol dictionary
        btree.write_translator(translator)

    if not args.skip_if_pruning:

        print('')
        print('Subject directories to prune:  ' + ', '.join(out_subj_dir_list))

        for bids_subj_dir in out_subj_dir_list:
            btr.prune_intendedfors(bids_subj_dir, True)

    if not first_pass:

        if args.bind_fmaps:

            print('')
            print('Binding nearest fieldmap to each functional series')
            for bids_subj_dir in out_subj_dir_list:
                btr.bind_fmaps(bids_subj_dir)

    # Finally validate that all is well with the BIDS dataset
    if not first_pass:
        btree.validate()

    # Clean exit
    sys.exit(0)
Exemple #4
0
def main():

    # Parse command line arguments
    parser = argparse.ArgumentParser(
        description='Convert DICOM files to BIDS-compliant Nifty structure')

    parser.add_argument(
        '-d',
        '--dataset',
        default='.',
        help='BIDS dataset directory containing sourcedata subdirectory')

    parser.add_argument('--no-sessions',
                        action='store_true',
                        default=False,
                        help='Do not use session sub-directories')

    parser.add_argument(
        '--no-anon',
        action='store_true',
        default=False,
        help='Do not anonymize BIDS output (eg for phantom data)')

    parser.add_argument('--overwrite',
                        action='store_true',
                        default=False,
                        help='Overwrite existing files')

    parser.add_argument(
        '--skip_if_pruning',
        action='store_true',
        default=False,
        help='Skip pruning of nonexistent IntendedFor items in json files')

    parser.add_argument('--clean_conv_dir',
                        action='store_true',
                        default=False,
                        help='Clean up conversion directory')

    # TODO: Implement option for linking nearest fieldmap in time to BOLD series via IntendedFor field
    # parser.add_argument('--nearest_fmap', action='store_true', default=False,
    #                     help='Associate BOLD series with nearest fieldmap in time to series start')

    # Parse command line arguments
    args = parser.parse_args()
    dataset_dir = os.path.realpath(args.dataset)
    no_sessions = args.no_sessions
    no_anon = args.no_anon
    overwrite = args.overwrite
    # nearest_fmap = args.nearest_fmap

    # Read version from setup.py
    ver = pkg_resources.get_distribution('bidskit').version

    print('')
    print('------------------------------------------------------------')
    print('BIDSKIT {}'.format(ver))
    print('------------------------------------------------------------')

    # Check for minimum dcm2niix version (mostly for multirecon suffix handling)
    btr.check_dcm2niix_version('v1.0.20181125')

    # Create a BIDS directory tree object to handle file locations
    # Creates directory
    btree = BIDSTree(dataset_dir, overwrite)

    print('')
    print('Source data directory      : {}'.format(btree.sourcedata_dir))
    print('Working Directory          : {}'.format(btree.work_dir))
    print('Use Session Directories    : {}'.format(
        'No' if no_sessions else 'Yes'))
    print(
        'Overwrite Existing Files   : {}'.format('Yes' if overwrite else 'No'))
    print('Anonymize BIDS Output      : {}'.format('No' if no_anon else 'Yes'))
    # print('Use Nearest Fieldmap       : {}'.format('Yes' if nearest_fmap else 'No'))

    # Load protocol translation and exclusion info from derivatives/conversion directory
    # If no translator is present, prot_dict is an empty dictionary
    # and a template will be created in the derivatives/conversion directory.
    # This template should be completed by the user and the conversion rerun.
    translator = btree.read_translator()

    if translator and os.path.isdir(btree.work_dir):

        print('')
        print('------------------------------------------------------------')
        print('Pass 2 : Populating BIDS directory')
        print('------------------------------------------------------------')
        first_pass = False

    else:

        print('')
        print('------------------------------------------------------------')
        print('Pass 1 : DICOM to Nifti conversion and translator creation')
        print('------------------------------------------------------------')
        first_pass = True

    # Init list of output subject directories
    subject_dir_list = []

    # Loop over list of subject directories in sourcedata directory
    for dcm_sub_dir in glob(btree.sourcedata_dir + os.sep + '*' + os.sep):

        sid = os.path.basename(os.path.normpath(dcm_sub_dir))

        subject_dir_list.append(os.path.join(dataset_dir, 'sub-' + sid))

        print('')
        print('------------------------------------------------------------')
        print('Processing subject ' + sid)
        print('------------------------------------------------------------')

        # Handle subject vs subject/session directory lists
        if no_sessions:
            dcm_dir_list = [dcm_sub_dir]
        else:
            dcm_dir_list = glob(dcm_sub_dir + os.sep + '*' + os.sep)

        # Loop over source data session directories in subject directory
        for dcm_dir in dcm_dir_list:

            # BIDS subject, session and conversion directories
            sub_prefix = 'sub-' + sid

            if no_sessions:

                # If session subdirs aren't being used, *_ses_dir = *sub_dir
                # Use an empty ses_prefix with os.path.join to achieve this
                ses = ''
                ses_prefix = ''

            else:

                ses = os.path.basename(os.path.normpath(dcm_dir))

                ses_prefix = 'ses-' + ses
                print('  Processing session ' + ses)

            # Working conversion directories
            work_subj_dir = os.path.join(btree.work_dir, sub_prefix)
            work_conv_dir = os.path.join(work_subj_dir, ses_prefix)

            # BIDS source directory directories
            bids_subj_dir = os.path.join(dataset_dir, sub_prefix)
            bids_ses_dir = os.path.join(bids_subj_dir, ses_prefix)

            print('  Working subject directory : %s' % work_subj_dir)
            if not no_sessions:
                print('  Working session directory : %s' % work_conv_dir)
            print('  BIDS subject directory  : %s' % bids_subj_dir)
            if not no_sessions:
                print('  BIDS session directory  : %s' % bids_ses_dir)

            # Safely create working directory for current subject
            # Flag for conversion if no working directory existed
            if not os.path.isdir(work_conv_dir):
                os.makedirs(work_conv_dir)
                needs_converting = True
            else:
                needs_converting = False

            if first_pass or needs_converting:

                # Run dcm2niix conversion into working conversion directory
                print('  Converting all DICOM images in %s' % dcm_dir)
                devnull = open(os.devnull, 'w')

                # BIDS anonymization flag - default 'y'
                anon = 'n' if no_anon else 'y'

                # Compose command
                cmd = [
                    'dcm2niix', '-b', 'y', '-ba', anon, '-z', 'y', '-f',
                    '%n--%d--%q--%s', '-o', work_conv_dir, dcm_dir
                ]

                with open(os.devnull, 'w') as devnull:
                    subprocess.run(cmd, stdout=devnull, stderr=devnull)

            if not first_pass:

                # Get subject age and sex from representative DICOM header
                dcm_info = bio.dcm_info(dcm_dir)

                # Add line to participants TSV file
                btr.add_participant_record(dataset_dir, sid, dcm_info['Age'],
                                           dcm_info['Sex'])

            # Organize dcm2niix output into BIDS subject/session directories
            organize_series(work_conv_dir, first_pass, translator,
                            bids_ses_dir, sid, ses, args.clean_conv_dir,
                            overwrite)

    if first_pass:

        # Create a template protocol dictionary
        btree.write_translator(translator)

    if not args.skip_if_pruning:

        print('')
        print('Subject directories to prune:  ' + ', '.join(subject_dir_list))

        for bids_subj_dir in subject_dir_list:
            btr.prune_intendedfors(bids_subj_dir, True)

    # if not first_pass:
    #
    #     if args.nearest_fmap:
    #
    #         print('')
    #         print('Assigning nearest fieldmap to each BOLD series')
    #         btr.intendedfor_nearest_fieldmap(bids_subj_dir)

    # Finally validate that all is well with the BIDS dataset
    if not first_pass:
        btree.validate()

    # Clean exit
    sys.exit(0)