Example #1
0
def subj_data_from_dicoms(ctx, crumb_path, arg_name, verbose=False):
    """ Print a list of folder_name -> NUK id. The NUK ID is calculated from
    the first DICOM file found in the end of the `dicom_path`.

    Parameters
    ----------
    crumb_path: str
        Path with Crumbs to the DICOM files, e.g.,
        /home/hansel/data/{subj_id}/{session}/{acq}/{dcm_file}

    arg_name: str
        Name of the argument in `dicom_path` of the subj_id

    Returns
    -------
    subj_data: dict of subj records
        A dict with records of the information extracted from the DICOM files
        as well as the calculated NUK Pseudonym.
    """
    if verbose:
        verbose_switch(verbose)

    crumb = Crumb(os.path.expanduser(os.path.abspath(crumb_path)), ignore_list=['.*'])
    if not crumb.has_crumbs():
        raise ValueError('Expected a path with crumb arguments, e.g., '
                         '"/home/hansel/data/{group}/{sid}/{session}"')
    subj_nuks = []
    for path in crumb.ls(arg_name):
        log.info('Reading DICOMs in {}.'.format(path))
        subj_path = path.split()[0]
        subj = _read_dcm_until_valid(subj_path)
        if subj is None:
            log.info('Could not find a valid DICOM in {}.'.format(subj_path))
        else:
            subj_nuks.append(subj)

    return subj_nuks
Example #2
0
def _get_plot_file_pairs(
        background: hansel.Crumb,
        foreground: hansel.Crumb) -> Iterable[Tuple[str, Union[str, None]]]:
    if background is None and foreground is not None:
        background = foreground

    if not foreground:
        return ((bg, None) for bg in background.ls(make_crumbs=False))

    if not background.has_crumbs() and not foreground.has_crumbs():
        return [(background.ls(make_crumbs=False)[0],
                 foreground.ls(make_crumbs=False)[0])]

    if foreground.has_crumbs() and background.has_crumbs():
        background_args = tuple(background.open_args())
        foreground_args = tuple(foreground.open_args())
        if background_args != foreground_args:
            raise click.BadParameter(
                'Make sure that background and foreground have the same crumb arguments. '
                'Got {}, and {}.'.format(background_args, foreground_args))

        try:
            intersect_values = hansel.intersection(background, foreground)
        except KeyError as ke:
            raise click.BadParameter(
                'Make sure that background and foreground have the same crumb arguments. '
                'Got {}, and {}.'.format(background_args,
                                         foreground_args)) from ke
        else:
            return ((background.build_paths(crumb_args, make_crumbs=False)[0],
                     foreground.build_paths(crumb_args, make_crumbs=False)[0])
                    for crumb_args in intersect_values)

    bg_files = []
    fg_files = []
    if background.has_crumbs():
        bg_files = list(background.ls(make_crumbs=False))
        fg_files = [foreground.ls(make_crumbs=False)[0]] * len(bg_files)

    if foreground.has_crumbs():
        fg_files = list(foreground.ls(make_crumbs=False))
        bg_files = [background.ls(make_crumbs=False)[0]] * len(fg_files)

    return zip(bg_files, fg_files)
Example #3
0
def dcm2nii(ctx, input_crumb_path, output_dir, regex='fnmatch', ncpus=3):
    """ Convert all DICOM files within `input_crumb_path` into NifTI in `output_folder`.

    Will copy only the NifTI files reoriented by MRICron's dcm2nii command.
    Will rename the NifTI files that are matched with recognized modalities to the short
    modality name from config.ACQ_PATTERNS.

    Parameters
    ----------
    input_dir: str
        A crumb path str indicating the whole path until the DICOM files.
        Example: '/home/hansel/data/{group}/{subj_id}/{session_id}/{acquisition}/{dcm_file}

        The crumb argument just before the last one will be used as folder container reference
        for the DICOM series.

    output_dir: str
        The root folder path where to save the tree of nifti files.
        Example: '/home/hansel/nifti'
        This function will create the same tree as the crumbs in input_crumb_path, hence
        for the example above the output would have the following structure:
        '/home/hansel/nifti/{group}/{subj_id}/{session_id}/{nifti_file}'

        Where {nifti_file} will take the name from the {acquisition} or from the
        patterns in ACQ_PATTERNS in `config.py` file.

    regex: str
        The regular expression syntax you may want to set in the Crumbs.
        See hansel.Crumb documentation for this.

    ncpus: int
        this says the number of processes that will be launched for dcm2nii in parallel.
    """
    from boyle.dicom.convert import convert_dcm2nii

    input_dir = os.path.expanduser(input_crumb_path)
    output_dir = os.path.expanduser(output_dir)

    if not os.path.exists(output_dir):
        log.info('Creating output folder {}.'.format(output_dir))
        os.makedirs(output_dir)
    else:
        log.info('Output folder {} already exists, this will overwrite/merge '
                 'whatever is inside.'.format(output_dir))

    input_dir = Crumb(input_dir, regex=regex, ignore_list=['.*'])

    if not input_dir.has_crumbs():
        raise ValueError(
            'I am almost sure that this cannot work if you do not '
            'use crumb arguments in the input path, got {}.'.format(input_dir))

    acq_folder_arg, last_in_arg = tuple(input_dir.all_args())[-2:]
    out_arg_names = [
        '{' + arg + '}' for arg in tuple(input_dir.all_args())[:-1]
    ]
    output_dir = Crumb(os.path.join(output_dir, *out_arg_names),
                       regex=regex,
                       ignore_list=['.*'])

    src_dst = []
    acquisitions = input_dir.ls(acq_folder_arg, make_crumbs=True)
    for acq in acquisitions:
        out_args = acq.arg_values.copy()
        acq_out = output_dir.replace(**out_args)

        out_dir = os.path.dirname(acq_out.path)
        out_file = os.path.basename(acq_out.path) + '.nii.gz'
        os.makedirs(out_dir, exist_ok=True)

        src_dst.append((acq.split()[0], out_dir, out_file))

    if ncpus > 1:
        import multiprocessing as mp
        pool = mp.Pool(processes=ncpus)
        results = [
            pool.apply_async(convert_dcm2nii, args=(dr, ss, dst))
            for dr, ss, dst in src_dst
        ]
        _ = [p.get() for p in results]
    else:
        _ = [convert_dcm2nii(path, sess, dst) for path, sess, dst in src_dst]
Example #4
0
def rename_to_nukid(crumb_path, arg_name, subj_data, verbose_only=False):
    """ Rename the folders at the `arg_name` level using `subj_data` records.
    Will rename from subj_data['DCM Folder'] to subj_data['NUK Pseudonym'].

    Parameters
    ----------
    crumb_path: str
        Path with Crumbs to the DICOM files, e.g.,
        /home/hansel/data/{subj_id}

    arg_name: str
        Name of the argument in `dicom_path` of the subject identification.
        These names should be the same as the ones in 'DCM Folder' value.

    outfile: str

    verbose_only: bool

    Returns
    -------
    src_dsts: list of 2-tuples of str
    """

    def rename_many(src_dsts, verbose_only=False):
        """ For each 2-tuple in src_dsts of file/folder paths will rename the first element to the second.

        Parameters
        ----------
        src_dsts : list of 2-tuple

        verbose_only: bool
            Will not perform the operation will only print them.
        """
        for (src, dst) in src_dsts:
            if not os.path.exists(src):
                raise IOError('Could not find source file {}.'.format(src))

            if os.path.exists(dst):
                if src == dst:
                    continue
                else:
                    raise IOError('Destination path {} already exists.'.format(dst))

            log.info('mv {} -> {}'.format(src, dst))
            if not verbose_only:
                os.rename(src, dst)

    if isinstance(subj_data, pd.DataFrame):
        subjs = subj_data.to_records()
    else:
        subjs = subj_data

    if not Crumb.has_crumbs(Crumb(crumb_path)):
        raise ValueError('Expected a path with crumb arguments, e.g., '
                         '"/home/hansel/data/{group}/{sid}/{session}"')

    crumb = Crumb(os.path.expanduser(os.path.abspath(crumb_path)), ignore_list=['.*'])
    src_dsts = []
    for subj in subjs:
        src_crs = crumb.replace(**{arg_name: subj['DCM Folder']}).unfold()

        for src_cr in src_crs:
            dst_args = src_cr.arg_values.copy()
            dst_args[arg_name] = subj['nukid']

            dst_cr = crumb.replace(**dst_args)
            if not os.path.exists(src_cr.path):
                raise IOError('Could not find folder {} for subject {}.'.format(src_cr, subj))

            if Crumb.has_crumbs(dst_cr.path):
                raise KeyError('The destination path should be fully specified, got {}.'.format(dst_cr))

            src_dsts.append((src_cr.path, dst_cr.path))

    rename_many(src_dsts=src_dsts, verbose_only=verbose_only)

    return src_dsts