#!/usr/bin/env tcsh @global_parse `basename $0` "$*" ; if ($status) exit 0 ## This script re-faces one input dataset, using a master shell dataset to ## write over the subject's 'face' region (which includes a bunch of skull). ## The single command line argument is the name of a T1-weighted dataset. ## *** Note the script name is '@afni_refacer_run' *** ## *** and is not a 'defacer' since it replaces the *** ## *** face instead of just cutting it out! *** ## This script relies on two datasets that are included with AFNI binaries: ## MNI152_2009_template_SSW.nii.gz = MNI skull strip/warp template ## afni_refacer_shell.nii.gz = dataset to replace face region ## The latter dataset was made with the script @afni_refacer_make_master. # ============================================================================ # #set version = "2.0"; set rev_dat = "Jan 23, 2020" # + [PT] put in real option parsing # + also allow user to input fname in truer AFNI-style as # "SOMETHING+orig" and not just SOMETHING+orig.HEAD # + new shell has been created+used here # #set version = "2.1"; set rev_dat = "Jan 26, 2020" # + [PT] choose modes of running differently # + also be able to output all versions of re/defacing at once # #set version = "2.11"; set rev_dat = "Jan 27, 2020" # + [PT] include QC images now # #set version = "2.12"; set rev_dat = "Jan 29, 2020" # + [PT] new opt: can choose cost func # #set version = "2.2"; set rev_dat = "Feb 3, 2020" # + [PT] new opt: -anonymize_output (pretty self-explanatory) # #set version = "2.3"; set rev_dat = "Aug 31, 2021" # + [PT] change default cost to 'lpa' (was 'ls'?) # #set version = "2.31"; set rev_dat = "Sep 27, 2021" # + [PT] chauffeur label_size 3 -> 4, bc imseq.c shifted all sizes # down one level # set version = "2.4"; set rev_dat = "Apr 23, 2022" # + [PT] start optionizing template+shell to use # - also introduce new shell with larger face/neck removal # # ============================================================================ set iset = "" # name of input dset set impref = "" # need a prefix now set odir = '.' set run_mode = "" # also, "REFACE_FACE", "DEFACE" set verb_allin = "" # don't need this verbose, by def (can with opt) set DO_CLEAN = 1 set DO_CHAUFF = 1 # of COURSE users want images set owrite = "" set DO_ANON = 0 # opt: anonymize the output dsets set cost_allin = "lpa" # cost function used; this was orig def ### these dsets are now selectable/alterable at command line # this is a newer shell than (now long ago) original: this one is # symmetric, without gaps in the skull, and more tightly bounded by -1s. set ref_shell = "afni_refacer_shell_sym_1.0.nii.gz" set tset = "MNI152_2009_template_SSW.nii.gz" set all_ok_shell = ( "afni_refacer_shell_sym_1.0.nii.gz" \ "afni_refacer_shell_sym_2.0.nii.gz" ) # ------------------------ read in + interpret cmd line opts ----------------- if ( $#argv == 0 ) goto SHOW_HELP set ac = 1 while ( $ac <= $#argv ) if ( ("$argv[$ac]" == "-h" ) || ("$argv[$ac]" == "-help" )) then goto SHOW_HELP endif if ( "$argv[$ac]" == "-ver" ) then goto SHOW_VERSION endif # ------------------------------------------------------- # required if ( "$argv[$ac]" == "-input" ) then if ( $ac >= $#argv ) goto FAIL_MISSING_ARG @ ac += 1 set iset = "$argv[$ac]" else if ( "$argv[$ac]" == "-prefix" ) then if ( $ac >= $#argv ) goto FAIL_MISSING_ARG @ ac += 1 set impref = `basename "$argv[$ac]"` set odir = `dirname "$argv[$ac]"` # need one of these else if ( "$argv[$ac]" == "-mode_deface" ) then set run_mode = "deface" else if ( "$argv[$ac]" == "-mode_reface" ) then set run_mode = "reface" else if ( "$argv[$ac]" == "-mode_reface_plus" ) then set run_mode = "reface_plus" else if ( "$argv[$ac]" == "-mode_all" ) then set run_mode = "ALL" # ------------------------------------------------------ # opt # [PT: 23 Apr 2022] else if ( "$argv[$ac]" == "-shell" ) then if ( $ac >= $#argv ) goto FAIL_MISSING_ARG @ ac += 1 set ref_shell = "$argv[$ac]" if ( ! ( "${ref_shell}" == "${all_ok_shell[1]}" || \ "${ref_shell}" == "${all_ok_shell[2]}" ) ) then echo "** ERROR: not an allowed shell. Must be one of:" foreach shell ( ${all_ok_shell} ) echo " ${shell}" end goto BAD_EXIT endif else if ( "$argv[$ac]" == "-anonymize_output" ) then set DO_ANON = 1 else if ( "$argv[$ac]" == "-cost" ) then if ( $ac >= $#argv ) goto FAIL_MISSING_ARG @ ac += 1 set cost_allin = "$argv[$ac]" else if ( "$argv[$ac]" == "-no_images" ) then set DO_CHAUFF = 0 else if ( "$argv[$ac]" == "-no_clean" ) then set DO_CLEAN = 0 else if ( "$argv[$ac]" == "-verb_allin" ) then set verb_allin = "-verb" else if ( "$argv[$ac]" == "-overwrite" ) then set owrite = "-overwrite" # ------------------------------------------------------- else echo "** unexpected option #$ac = '$argv[$ac]'" exit 2 endif @ ac += 1 end # ------------------ parse/verify inputs --------------------------- if ( "${run_mode}" == "" ) then echo "** ERROR: need to specify a refacing mode with one of the '-mode_*'" echo " opts" goto BAD_EXIT endif # check main input if ( "${iset}" == "" ) then echo "** ERROR: need to have an input anatomical, at least" goto BAD_EXIT else set check = `3dinfo -prefix "${iset}"` if ( "${check}" == "NO-DSET" ) then echo "** ERROR: can't find input file: ${iset}" goto BAD_EXIT else echo "++ Found input file: ${iset}" endif endif # find MNI template (target for 3dAllineate) set Basedset = `@FindAfniDsetPath -full_path -append_file "${tset}"` if ( "${Basedset}" == '' ) then echo "** ERROR: Failed to find template ${tset} -- exiting :(" goto BAD_EXIT endif # Find AFNI refacer shell (to replace subject face); this is a newer # shell than original: this one is symmetric, without gaps in the # skull, and more tightly bounded by -1s. set mset = `@FindAfniDsetPath -full_path -append_file "${ref_shell}"` if ( "${mset}" == '' ) then echo "** ERROR: Failed to find refacer shell ${ref_shell} -- exiting :(" goto BAD_EXIT endif # need prefix if ( "${impref}" == "" ) then echo "** ERROR: user needs to enter '-prefix ..' for output filename :(" goto BAD_EXIT else ### get base of output prefix # get rid of +orig.{HEAD,BRIK}, +orig set opref = `@GetAfniPrefix ${impref}` # get rid of any .nii.gz, .nii set opref = `basename ${opref} .gz` set opref = `basename ${opref} .nii` # final output prefix base set opref_qc = ${opref}_QC # for auto images # make output dir and working dir set wdir0 = __work_refacer.${opref}.`3dnewid -fun11` set wdir = ${odir}/${wdir0} \mkdir -p ${wdir} endif # if we got to here: good to continue. Brag a bit first. echo "" echo "++ AFNI refacer, version = ${version}" echo "++ AFNI template dataset = $Basedset" echo "++ AFNI refacer shell dataset = $mset" echo "++ Mode for running = $run_mode" echo "" # ============================================================================ # datum (e.g., short or float) of input dataset - for use at end of script set idatum = `3dinfo -datum $iset` # make temp directory, copy input dataset there set nnn = `3dnvals $iset` set dset_orig = tmp.00.INPUT.nii if ( "$nnn" == "1" ) then 3dcopy $iset ${wdir}/${dset_orig} else 3dcalc -a $iset'[0]' -expr a -prefix ${wdir}/${dset_orig} endif cd ${wdir} # ----------------------------------------------------------------------- # Unifize input to a standard T1 image intensity 3dUnifize \ -GM \ -prefix tmp.01.uni.nii \ -ssave tmp.01.uscale.nii \ ${dset_orig} # Align to the MNI template - save only the transform matrix 3dAllineate -base $Basedset'[1]' -weight $Basedset'[2]' \ -source tmp.01.uni.nii -prefix NULL ${verb_allin} \ -warp shift_rotate_scale -cost ${cost_allin} \ -cmass -conv 0.5 \ -source_automask+4 -fineblur 3 -norefinal -twobest 3 \ -num_rtb 33 -1Dmatrix_save tmp.02.mat_a2t.1D # compute the inverse matrix, to transform from MNI back to orig space cat_matvec \ -ONELINE \ tmp.02.mat_a2t.1D -I \ > tmp.03.mat_t2a.1D # transform the refacer shell from MNI back to subject original space # and grid # [PT: Jan 23, 2020] Using NN interp is good here-- less/no gap # outside shell than using linear 3dAllineate \ -1Dmatrix_apply tmp.03.mat_t2a.1D \ -source $mset \ -final NN \ -prefix tmp.04.sh_t2a.nii \ -master ${dset_orig} \ -float ### NB: -ISOLA option "removes isolated stuff" #3dcalc -a tmp.04.sh_t2a.nii -prefix tmp.MM.nii \ # -expr 'ifelse(ispositive(a)*isnegative(a-248),0,a)' -ISOLA # get rid of tiny stuff that might be left around 3dcalc \ -a tmp.04.sh_t2a.nii \ -expr 'a*bool(a)' \ -ISOLA \ -prefix tmp.05.sh_t2a_thr.nii 3drefit -space ORIG tmp.05.sh_t2a_thr.nii # ------------------ hard work done; prep for output ------------------- # scale factor for refacer shell to be about the same intensity as # the input: # ibar = mean of input over refacer shell # mbar = mean of refacer shell # ifac = scale factor for refacer shell to match input (sort of) # This method doesn't allow for duplicating shading artifacts in # the input dataset, but that would be somewhat more work. # (always calculate these things, even if they aren't needed) set ibar = `3dBrickStat -non-zero -mean \ "3dcalc( -a tmp.05.sh_t2a_thr.nii -b $dset_orig -expr step(a-99)*b )"` set mbar = `3dBrickStat -non-zero -mean \ "3dcalc( -a tmp.05.sh_t2a_thr.nii -expr step(a-99)*a )"` set ifac = `ccalc "1.222*${ibar}/${mbar}"` # -------------------------- make output dsets ---------------------------- ### REFACE: replace face+ears ### REFACE_PLUS: replace face+ears+skull # plop the scaled refacer shell 'c' on top of the input 'a': # -- where the shell is positive = step(c)*c # -- zero out anything where the shell is negative = iszero(c)*a # -- since the master shell is negative in the outer volume, # is zero in the 'brain' region, and is positive in the # parts of the volume to be replaced. # entries here are indexed by use_subbr entries for first two, but not # for defacing set reface_type = ( "reface_plus" "reface" "deface" ) set use_subbr = ( ) if ( "${run_mode}" == "ALL" || "${run_mode}" == "reface_plus" ) then set use_subbr = ( ${use_subbr} 0 ) endif if ( "${run_mode}" == "ALL" || "${run_mode}" == "reface" ) then set use_subbr = ( ${use_subbr} 1 ) endif foreach subbr ( ${use_subbr} ) @ idx = ${subbr} + 1 echo "+++ Proc for ${reface_type[${idx}]}" echo " with subbrick ${subbr} and list index ${idx}" 3dcalc \ -a ${dset_orig} \ -c tmp.05.sh_t2a_thr.nii"[${subbr}]" \ -expr "step(c)*c*${ifac}+iszero(c)*a*step(a)" \ -prefix tmp.06.${reface_type[${idx}]}.orig_mskd.nii \ -datum float -ISOLA 3dcalc \ -a tmp.05.sh_t2a_thr.nii"[${subbr}]" \ -expr 'step(a)' \ -datum byte -nscale \ -prefix tmp.07.${reface_type[${idx}]}.sh_t2a_thr_mskd.nii 3dBlurInMask \ -input tmp.06.${reface_type[${idx}]}.orig_mskd.nii \ -mask tmp.07.${reface_type[${idx}]}.sh_t2a_thr_mskd.nii \ -FWHM 2.666 \ -preserve \ -prefix tmp.99.result.${reface_type[${idx}]}.nii end # DEFACE: just remove the 'face' rather than replace it if ( "${run_mode}" == "ALL" || "${run_mode}" == "deface" ) then set subbr = 1 set idx = 3 echo "+++ Proc for ${reface_type[${idx}]}" echo " with subbrick ${subbr} and list index ${idx}" 3dcalc \ -a ${dset_orig} \ -c tmp.05.sh_t2a_thr.nii"[${subbr}]" \ -expr "a*not(bool(c))" \ -prefix tmp.99.result.${reface_type[${idx}]}.nii \ -datum float \ -ISOLA endif # ----- also make a short-valued copy of the result, if practicable ------ if ( "$idatum" == "short" ) then set all_results = `\ls tmp.99.result.*` foreach rr ( ${all_results} ) set mmm = `3dBrickStat -max ${rr}` @ mmm = `ccalc -int $mmm` if ( $mmm < 32000 ) then \mv ${rr} tmp.80.nonshort_result.nii 3dcalc \ -a tmp.80.nonshort_result.nii \ -expr a \ -datum short -nscale \ -prefix ${rr} \rm tmp.80.nonshort_result.nii endif end endif # push output up to the input level (over-writing any existing output) echo "\n++ Output final dsets\n" if ( "${run_mode}" == "ALL" ) then # each of the deface/reface/reface_plus dsets foreach tt ( ${reface_type} ) 3dcopy -echo_edu ${owrite} \ tmp.99.result.${tt}.nii \ ../${opref}.${tt}.nii.gz if ( ${DO_ANON} ) then @djunct_anonymize \ -input ../${opref}.${tt}.nii.gz \ -add_note "@afni_refacer_run created this file" endif # make purdy images: input as ulay, re/defaced vol as olay if ( ${DO_CHAUFF} ) then @chauffeur_afni \ -ulay ${dset_orig} \ -ulay_range "2%" "98%" \ -olay ../${opref}.${tt}.nii.gz \ -func_range_perc_nz 95 \ -cbar "Plasma" \ -pbar_posonly \ -opacity 9 \ -prefix ../${opref_qc}/${opref}.${tt} \ -montx 5 -monty 3 \ -montgap 3 \ -set_xhairs OFF \ -label_mode 1 -label_size 4 endif end # the face and face_plus themselves 3dcalc ${owrite} \ -a tmp.05.sh_t2a_thr.nii"[0]" \ -expr 'a' \ -prefix ../${opref}.face_plus.nii.gz if ( ${DO_ANON} ) then @djunct_anonymize \ -input ../${opref}.face_plus.nii.gz \ -add_note "@afni_refacer_run created this file" endif 3dcalc ${owrite} \ -a tmp.05.sh_t2a_thr.nii"[1]" \ -expr 'a' \ -prefix ../${opref}.face.nii.gz if ( ${DO_ANON} ) then @djunct_anonymize \ -input ../${opref}.face.nii.gz \ -add_note "@afni_refacer_run created this file" endif # make purdy images: input as ulay, re/defaced vol as olay if ( ${DO_CHAUFF} ) then @chauffeur_afni \ -ulay ${dset_orig} \ -ulay_range "2%" "98%" \ -olay ../${opref}.face_plus.nii.gz \ -func_range_perc_nz 95 \ -cbar "Reds_and_Blues_Inv" \ -opacity 5 \ -prefix ../${opref_qc}/${opref}.face_plus \ -montx 5 -monty 3 \ -montgap 3 \ -set_xhairs OFF \ -label_mode 1 -label_size 4 @chauffeur_afni \ -ulay ${dset_orig} \ -ulay_range "2%" "98%" \ -olay ../${opref}.face.nii.gz \ -func_range_perc_nz 95 \ -cbar "Reds_and_Blues_Inv" \ -opacity 5 \ -prefix ../${opref_qc}/${opref}.face \ -montx 5 -monty 3 \ -montgap 3 \ -set_xhairs OFF \ -label_mode 1 -label_size 4 endif else # only outputting one main vol: use the user's choice name 3dcopy -echo_edu ${owrite} \ tmp.99.result.${run_mode}.nii \ ../${impref} # make purdy images: input as ulay, re/defaced vol as olay if ( ${DO_CHAUFF} ) then # easier to know the name of the current tmp file for the # olay! don't know if output is NII or BRIK/HEAD @chauffeur_afni \ -ulay ${dset_orig} \ -ulay_range "2%" "98%" \ -olay tmp.99.result.${run_mode}.nii \ -func_range_perc_nz 95 \ -cbar "Plasma" \ -pbar_posonly \ -opacity 9 \ -prefix ../${opref_qc}/${opref} \ -montx 5 -monty 3 \ -montgap 3 \ -set_xhairs OFF \ -label_mode 1 -label_size 4 endif # output either face or face_plus mask in subj space if ( "${run_mode}" == "deface" || "${run_mode}" == "reface" ) then 3dcalc ${owrite} \ -a tmp.05.sh_t2a_thr.nii"[1]" \ -expr 'a' \ -prefix ../${opref}.face.nii.gz if ( ${DO_ANON} ) then @djunct_anonymize \ -input ../${opref}.face.nii.gz \ -add_note "@afni_refacer_run created this file" endif if ( ${DO_CHAUFF} ) then @chauffeur_afni \ -ulay ${dset_orig} \ -ulay_range "2%" "98%" \ -olay ../${opref}.face.nii.gz \ -func_range_perc_nz 95 \ -cbar "Reds_and_Blues_Inv" \ -opacity 5 \ -prefix ../${opref_qc}/${opref}.face \ -montx 5 -monty 3 \ -montgap 3 \ -set_xhairs OFF \ -label_mode 1 -label_size 4 endif else if ( "${run_mode}" == "reface_plus" ) then 3dcalc ${owrite} \ -a tmp.05.sh_t2a_thr.nii"[0]" \ -expr 'a' \ -prefix ../${opref}.face_plus.nii.gz if ( ${DO_ANON} ) then @djunct_anonymize \ -input ../${opref}.face_plus.nii.gz \ -add_note "@afni_refacer_run created this file" endif if ( ${DO_CHAUFF} ) then @chauffeur_afni \ -ulay ${dset_orig} \ -ulay_range "2%" "98%" \ -olay ../${opref}.face_plus.nii.gz \ -func_range_perc_nz 95 \ -cbar "Reds_and_Blues_Inv" \ -opacity 5 \ -prefix ../${opref_qc}/${opref}.face_plus \ -montx 5 -monty 3 \ -montgap 3 \ -set_xhairs OFF \ -label_mode 1 -label_size 4 endif endif endif cd .. # trash the junk, vamoose the ranch if ( $DO_CLEAN ) then \rm -rf ${wdir0} endif echo "\n++ Done.\n" exit 0 # ============================================================================= # ============================================================================= SHOW_VERSION: echo "$version" goto GOOD_EXIT # ---------------------------------- SHOW_HELP: cat <