Skip to content

Commit

Permalink
Merge pull request #43 from AlanKuurstra/akdev
Browse files Browse the repository at this point in the history
update cfmm_bruker heuristic, switch to forked heudiconv
  • Loading branch information
akhanf authored Aug 20, 2024
2 parents 771dc79 + 854b6b9 commit bb1485d
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 18 deletions.
19 changes: 16 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LABEL maintainer="<[email protected]>"
ENV DCM2NIIXTAG v1.0.20230411

#heudiconv version:
ENV HEUDICONVTAG v0.13.1
ENV HEUDICONVTAG unstacked_dcm

#bids validator version:
ENV BIDSTAG 1.9.7
Expand Down Expand Up @@ -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 \
Expand Down
48 changes: 33 additions & 15 deletions heuristics/cfmm_bruker.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
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)


def infotodict(seqinfo):
"""Heuristic evaluator for determining which runs belong where
Expand All @@ -27,11 +34,9 @@ def infotodict(seqinfo):
FLASH_MT_OFF = create_key('{bids_subject_session_dir}/anat/{bids_subject_session_prefix}_acq-MToff_run-{item:02d}_FLASH')
dwi = create_key('{bids_subject_session_dir}/dwi/{bids_subject_session_prefix}_run-{item:02d}_dwi')

MP2RAGE_T1map = create_key('{bids_subject_session_dir}/anat/{bids_subject_session_prefix}_acq-MP2RAGE_run-{item:02d}_T1map')
MP2RAGE_invs = create_key('{bids_subject_session_dir}/anat/{bids_subject_session_prefix}_acq-Inversions_run-{item:02d}_MP2RAGE')
MP2RAGE_UNI = create_key('{bids_subject_session_dir}/anat/{bids_subject_session_prefix}_acq-UNI_run-{item:02d}_T1w')

MP2RAGE_T1map_l = create_key('{bids_subject_session_dir}/anat/{bids_subject_session_prefix}_acq-LoResMP2RAGE_run-{item:02d}_T1map')
MP2RAGE_invs_l = create_key('{bids_subject_session_dir}/anat/{bids_subject_session_prefix}_acq-LoResInversions_run-{item:02d}_MP2RAGE')
MP2RAGE_UNI_l = create_key('{bids_subject_session_dir}/anat/{bids_subject_session_prefix}_acq-LoResUNI_run-{item:02d}_T1w')

Expand All @@ -42,7 +47,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_invs:[],MP2RAGE_UNI:[],MP2RAGE_invs_l:[],MP2RAGE_UNI_l:[],MEGRE_mag:[],MEGRE_complex:[],T2_TurboRARE:[],BLOCK_EPI:[]}

for idx, s in enumerate(seqinfo):

Expand All @@ -56,23 +64,19 @@ def infotodict(seqinfo):
else:
info[FLASH_MT_ON].append({'item': s.series_id})

elif ('DTI' in s.protocol_name):
elif ('dti' in s.protocol_name.lower()):
info[dwi].append({'item': s.series_id})

elif ('MP2RAGE' in s.series_description.strip()):
elif ('cfmmMP2RAGE' in s.series_description.strip()):
if (s.dim1 > 64):
if ('0001' in s.dcm_dir_name.strip()):
info[MP2RAGE_T1map].append({'item': s.series_id})
elif ('0002' in s.dcm_dir_name.strip()):
info[MP2RAGE_invs].append({'item': s.series_id})
else:
elif ('0002' in s.dcm_dir_name.strip()):
info[MP2RAGE_UNI].append({'item': s.series_id})
else:
if ('0001' in s.dcm_dir_name.strip()):
info[MP2RAGE_T1map_l].append({'item': s.series_id})
elif ('0002' in s.dcm_dir_name.strip()):
info[MP2RAGE_invs_l].append({'item': s.series_id})
else:
elif ('0002' in s.dcm_dir_name.strip()):
info[MP2RAGE_UNI_l].append({'item': s.series_id})

elif ('T2star' in s.series_description.strip()):
Expand All @@ -82,7 +86,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)

0 comments on commit bb1485d

Please sign in to comment.