From ea5873637016b9b90cb5c0dcd6b31fdb076e18dd Mon Sep 17 00:00:00 2001 From: Alan Kuurstra Date: Tue, 13 Aug 2024 15:13:07 -0400 Subject: [PATCH] update cfmm_bruker heuristic --- Dockerfile | 19 ++++++++++++++++--- heuristics/cfmm_bruker.py | 33 ++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5bbf3a6..68c257c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ LABEL maintainer="" ENV DCM2NIIXTAG v1.0.20230411 #heudiconv version: -ENV HEUDICONVTAG v0.13.1 +ENV HEUDICONVTAG unstacked_dcm #bids validator version: ENV BIDSTAG 1.9.7 @@ -37,9 +37,22 @@ RUN apt-get update -qq \ && apt-get install -y -q --no-install-recommends \ python3=3.9.2-3 \ python3-pip=20.3.4-4+deb11u1 \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ - && pip install --no-cache-dir heudiconv==${HEUDICONVTAG} + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +RUN apt-get update -qq \ + && apt-get install -y -q --no-install-recommends \ + git \ + python3-setuptools \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ + && git clone https://github.com/AlanKuurstra/heudiconv.git /src/heudiconv \ + && git -C /src/heudiconv checkout ${HEUDICONVTAG} +WORKDIR /src/heudiconv +RUN python3 -m pip install --no-cache-dir -r /src/heudiconv/requirements.txt \ + && python3 -m pip install --no-cache-dir versioningit \ + && python3 /src/heudiconv/setup.py install + +# install pybruker for cfmm_bruker heuristic +RUN python3 -m pip install --no-cache-dir pybruker --index-url https://gitlab.com/api/v4/projects/29466867/packages/pypi/simple # install BIDS Validator RUN apt-get update -qq \ diff --git a/heuristics/cfmm_bruker.py b/heuristics/cfmm_bruker.py index 8f18adf..1982267 100644 --- a/heuristics/cfmm_bruker.py +++ b/heuristics/cfmm_bruker.py @@ -1,6 +1,12 @@ -import os +from heudiconv.utils import set_readonly, save_json +import json +import logging +from pybruker.jcamp import jcamp_read +import pydicom -def create_key(template, outtype=('nii.gz'), annotation_classes=None): +lgr = logging.getLogger("heudiconv") + +def create_key(template, outtype=('nii.gz',), annotation_classes=None): if template is None or not template: raise ValueError('Template must be a valid format string') return (template, outtype, annotation_classes) @@ -42,7 +48,10 @@ def infotodict(seqinfo): T2_TurboRARE = create_key('{bids_subject_session_dir}/anat/{bids_subject_session_prefix}_acq-TurboRARE_run-{item:02d}_T2w') - info = { FLASH_T1:[],FLASH_MT_ON:[],FLASH_MT_OFF:[],dwi:[],MP2RAGE_T1map:[],MP2RAGE_invs:[],MP2RAGE_UNI:[],MP2RAGE_T1map_l:[],MP2RAGE_invs_l:[],MP2RAGE_UNI_l:[],MEGRE_mag:[],MEGRE_complex:[],T2_TurboRARE:[]} + # where does bids_subject_session_prefix come from? or item? heudiconv special variables? can we get the task type (visual/audio) somehow? + BLOCK_EPI = create_key('{bids_subject_session_dir}/func/{bids_subject_session_prefix}_task-unknown_acq-BlockEPI_run-{item:02d}_bold') + + info = { FLASH_T1:[],FLASH_MT_ON:[],FLASH_MT_OFF:[],dwi:[],MP2RAGE_T1map:[],MP2RAGE_invs:[],MP2RAGE_UNI:[],MP2RAGE_T1map_l:[],MP2RAGE_invs_l:[],MP2RAGE_UNI_l:[],MEGRE_mag:[],MEGRE_complex:[],T2_TurboRARE:[],BLOCK_EPI:[]} for idx, s in enumerate(seqinfo): @@ -82,7 +91,21 @@ def infotodict(seqinfo): info[MEGRE_mag].append({'item': s.series_id}) elif ( 'T2_TurboRARE' in s.series_description.strip()): info[T2_TurboRARE].append({'item': s.series_id}) - - + elif ( 'blockEPI' in s.series_description.strip()): + info[BLOCK_EPI].append({'item': s.series_id}) return info + +def custom_callable(outfile, outtype, infiles): + dcm_filename = infiles[0] + bruker_parameters_jcamp = pydicom.read_file(dcm_filename, stop_before_pixels=True).get((0x0177, 0x1100)) + if bruker_parameters_jcamp: + jcamp_dict = jcamp_read(bruker_parameters_jcamp.value) + scaninfo_filename = outfile + '.json' + lgr.info(f"Adding bruker parameters to {scaninfo_filename}") + with open(scaninfo_filename, 'r') as f: + info_dict = json.load(f) + info_dict['cfmm_bruker_parameters'] = jcamp_dict + # if blockEPI then use bruker parameters to create events.tsv + save_json(scaninfo_filename, info_dict) + set_readonly(scaninfo_filename)