/ mknii
mknii
1 #!/usr/bin/env bash 2 env | grep ^DRYRUN= && DRYRUN=echo || DRYRUN="" 3 # when we are give, change value to "check" 4 [ -v NOECHOCHECK ] && NOECHOCHECK="check" || NOECHOCHECK="" 5 [ ! -v VERBOSE ] && VERBOSE="" 6 verbose(){ [ -n "$VERBOSE" ] && echo "$*" >&2 || :; } 7 8 set_dcm2niix(){ 9 DCM2NIIX="${DCM2NII:-dcm2niix}" 10 command -v "$DCM2NIIX" >/dev/null || DCM2NIIX=dcm2niix_afni 11 ! command -v "$DCM2NIIX" >/dev/null && warn "cannot find dcm2niix or dcm2niix_afni; try export DCM2NIIX=..." && exit 2 12 return 0 13 } 14 15 16 # 17 #run dcm2niix with 3dNotes wrapper. check for existing file 18 # 19 # 20201016WF init 20 # 20210113WF use rename-recent. nest into "main" (source for testing) 21 usage() { 22 cat <<HEREDOC 23 USAGE: 24 $(basename "$0") output.nii.gz path/to/dcm/ 25 26 output.nii.gz - 1st argument is the output nifti. must end in .nii.gz 27 path/to/dcm - 2nd arg must be a folder or single dicom 28 escape spaces in input 29 30 31 will 32 * recursively make directories. be careful. 33 * skip if already exists 34 * add annotation with source directory to nifti. careful not to spill participant information 35 * try to deal with gre fieldmap naming weirdness (if output matches magnitude[12] or phase) 36 use DRYRUN=1 $(basename $0) ... to test 37 HEREDOC 38 exit 1 39 } 40 41 # rename mag and phase 42 # dcm2niix adds e.g. _e2 or _ph 43 # extracted here for testing (t/mknii.bats) 44 # also need to check we have a working 'rename' command 45 # only needed for mag and phase. so only check when we need one of those 46 _rename-recent(){ 47 rename-recent have? >/dev/null || exit 1 # dont convert if we have the wrong rename 48 rename-recent "$@" 49 } 50 rename-mag(){ 51 local pattern='s/[12]?_e(\d.(nii.gz|json))$/$1/' 52 local outdir="$1";shift 53 # if input is magnitude.nii.gz and maginguted_e2.nii.gz 54 # make first look like magnitude_e1 for later rename 55 find $outdir -maxdepth 1 -mtime -1 -name '*magnitude*e2*.nii.gz' | grep -q magnitude && 56 _rename-recent 's/magnitude(.nii.gz|.json)$/magnitude_e1$1/' $outdir "*magnitude.*" 57 _rename-recent "$pattern" "$outdir" "$@" 58 } 59 rename-phase(){ 60 local pattern='s/_e\d+(_ph)?(.nii.gz|.json)$/$2/' 61 _rename-recent "$pattern" "$@" 62 } 63 rename-epi-multiecho(){ 64 local outdir="$1"; shift 65 local outname="$1"; shift 66 if [ -r "$outdir/${outname}_e1.nii.gz" ]; then 67 echo "# trying to rename multiecho seq $outname"; 68 _rename-recent 's/(sbref|bold)_e(\d+).(json|nii.gz)/echo-$2_$1.$3/' "$outdir" "${outname}_e*" 69 fi 70 } 71 72 add_echo_name(){ perl -pe 's/_(bold|sbref).nii.gz/_echo-1_$1.nii.gz/' <<< "$*"; } 73 multiecho_exists(){ 74 # okay to flag nii_out as mutliecho even if it's not 75 # will have been caught earlier 76 local nii_out="$1" 77 for ME_name in "${nii_out/.nii.gz/_e1.nii.gz}" \ 78 "${nii_out/magnitude.nii.gz/magnitude1.nii.gz}" \ 79 "$(add_echo_name "$nii_out")"; do 80 verbose "# checking for multiecho like '$ME_name'" 81 ! test -r "$ME_name" && continue 82 echo "# have '$ME_name', considering that the same as '$nii_out' (set export NOECHOCHECK=1 to go anyway)" 83 return 0 84 done 85 return 1 86 } 87 88 find_multiechos(){ 89 local outdir="$1"; shift 90 local outname="$1"; shift 91 local ext="$1"; shift 92 me_name=$(perl -pe 's/_(bold|sbref)$/_echo-*_$1/' <<< "$outname"); 93 find "$outdir" -maxdepth 1 -type f \ 94 \( -name "$outname$ext" -or -name "$me_name$ext" \) 95 } 96 97 add_json_task(){ 98 local outdir="$1"; shift 99 local outname="$1"; shift 100 local task 101 [[ $outname =~ task-([^-_.]*) ]] && task=${BASH_REMATCH[1]} 102 if [ -z "$task" ]; then 103 echo "WARNING: unknown taskname for $outdir/$outname!"; 104 return 0 105 else 106 verbose "# adding task to json in '$outdir' for '$outname'" 107 find_multiechos "$outdir" "$outname" ".json" | 108 xargs -rI{} grep -L TaskName {} | 109 xargs -rI{} $DRYRUN sed -i "s/^{/{\\n \"TaskName\": \"$task\",/" {} 110 verbose "# finished adding task name to $outdir/$outname.json" 111 fi 112 return 0 113 } 114 115 main(){ 116 set -euo pipefail 117 set_dcm2niix # DCM2NIIX might be dcm2niix_afni or given by user 118 119 [ $# -ne 2 ] && usage 120 nii_out="$1"; shift 121 dcm_folder="$*"; shift 122 [ -r "$nii_out" ] && echo "# have '$nii_out'" && exit 0 123 [ ${nii_out:(-7)} != ".nii.gz" ] && 124 echo "output must have .nii.gz extention!" && exit 1 125 126 test -z "$NOECHOCHECK" && multiecho_exists "$nii_out" && exit 0 127 128 # should let dcm2niix just fail instead of doing the work here? 129 # [ $(find -L "$dcm_folder" \( -type f -or -type l \) -print -quit|wc -l) -le 0 ] && echo "# '$dcm_folder' DNE or is empty?" && exit 1 130 131 outname="$(basename "$nii_out" .nii.gz)" 132 outdir="$(dirname "$nii_out")" 133 [ ! -d "$outdir" ] && $DRYRUN mkdir -p "$outdir" 134 135 #pretimestamp=$(mktemp /tmp/dcmnii_XXXXXX) # -newercm $pretimestamp 136 # TODO: add trap to cleanup file? 137 $DRYRUN $DCM2NIIX -z y -b y -f "$outname" -o "$outdir" "$dcm_folder" 138 [ -n "$DRYRUN" ] && exit 0 139 # if above failed, script would bail (set -e) 140 # so if we don't have the file it's probably has multiple echos 141 case $outname in 142 *magnitude|*magnitude[12]) 143 144 rename-recent have? || exit 1 # dont convert if we have the wrong rename 145 # 20210113 146 # dcm2nii v1.0.2018 (ginger) only puts _e2 on the second echo 147 # if we have _e2 and no _e1, the no _e* version is magnitude1 148 [ -r "$outdir"/*magnitude.nii.gz -a -r "$outdir"/*magnitude_e2.nii.gz ] && 149 rename-recent 's/magnitude\.(nii.gz|json)$/_e1.$1/' "$outdir" "*magnitude\.*" -v 150 151 rename-recent 's/[12]?_e(\d.(nii.gz|json))$/$1/' "$outdir" "$outname*" -v 152 153 # update output for 3dNotes and final check 154 [[ $outname =~ magnitude$ ]] && nii_out="$outdir/${outname}1.nii.gz" 155 ;; 156 *phase|*phasediff) 157 rename-recent have? || exit 1 # dont convert if we have the wrong rename 158 rename-recent 's/_e\d+(_ph)?(.nii.gz|.json)$/$2/' "$outdir" "$outname*" 159 ;; 160 *bold|*sbref) 161 rename-epi-multiecho "$outdir" "$outname" 162 ;; 163 esac 164 165 # add rest taskname to json sidecar 166 167 [[ $outname =~ task-.*_bold ]] && 168 add_json_task "$outdir" "$outname" 169 170 local nii_outs 171 mapfile -t nii_outs < <(find_multiechos "$outdir" "$outname" .nii.gz) 172 173 if [ ${#nii_outs[@]} -le 0 ]; then 174 echo -e "ERROR: did not create '$nii_out'.\n\t'$dcm_folder' has a multi echo sequence??!" 175 echo "NOTE: $0 can deal with this if the output name ends with 'magnitude1.nii.gz' or 'phase.nii.gz'" 176 echo " or for _bold and _sbref files" 177 exit 1 178 fi 179 180 # 3dNotes likes to complain. silence it 181 export AFNI_NIFTI_TYPE_WARN=NO 182 export AFNI_NO_OBLIQUE_WARNING="YES" 183 verbose "# adding 3dNotes" 184 for nii_out_me in "${nii_outs[@]}"; do 185 $DRYRUN 3dNotes -h "$0 $dcm_folder $nii_out" "$nii_out_me" 186 done 187 } 188 [[ "$(caller)" != "0 "* ]] && set +u || main "$@"