I mostly use R these days, and sometimes use R to generate the afni commands and execute them on the fly, as in this example. I ran this on a linux machine (with neurodebian); the system2 call in particular may need changing for other OS.
I include the full path to the afni commands (e.g., /usr/local/pkg/linux_openmp_64/1d_tool.py) to avoid path issues; replace as needed for your installation. This code takes two input files: the 4d NIfTI (_functional.nii.gz) and _FD.txt, a single column text file with the FD for each frame in the rows (so the number of rows in _FD.txt is the same as the 4th dimension in the NIfTI). The code then thresholds at FD > 0.9 and writes out a temporary text file (temp.1D, also one column, one row per frame), with 1s for volumes to keep and 0s for frames to censor (not include in the 3dTstat calculation). Of course, you could generate this censor list using whatever metrics or code you wish.
in.path <- "/scratch2/input/"; # path to input files
out.path <- "/scratch2/output/"; # where to write output files
sub.ids <- c("subject1", "subject2"); # subject IDs, as in input file names
for (sid in 1:length(sub.ids)) { # sid <- 1; rid <- 1;
fname.fd <- paste0(in.path, sub.ids[sid], "_FD.txt"); # 1D text file of framewise FD values (or whatever for censoring)
fname.4d <- paste0(in.path, sub.ids[sid], "_functional.nii.gz"); # 3d+time brain image; average each voxel over time
fname.out <- paste0(out.path, sub.ids[sid], "_sdcens.nii.gz"); # output filename (will be written by afni)
if (file.exists(fname.fd) & file.exists(fname.4d) & !file.exists(fname.out)) { # check required files present (or not)
fd.vec <- read.table(fname.fd)[,1]; # read the FD column in as a vector
# make a single-column text file with 0 for volumes to OMIT (censor), 1 for volumes to KEEP.
# this makes a temporary 1D file from the FD values; you can make the file however you need, as long as it's in this format
out.vec <- rep(1, length(fd.vec));
out.vec[which(fd.vec > 0.9)] <- 0; # set volumes above threshold to 0
write.table(out.vec, paste0(out.path, "temp.1D"), row.names=FALSE, col.names=FALSE); # write out temporary file for 1d_tool.py
# these next two commands actually do the work. The first gets the censored volumes (TRs with 0 in temp.1D) in tmp,
# in the afni-required text format (e.g., [5..8,15]).
tmp <- system2("/usr/local/pkg/linux_openmp_64/1d_tool.py", args=paste0("-infile ", out.path, "temp.1D -show_trs_uncensored encoded"), stdout=TRUE);
# now, 3dTstat is called, feeding it the frames in the tmp string.
system2("/usr/local/pkg/linux_openmp_64/3dTstat", args=paste0("-stdev -prefix ", fname.out, " ", fname.4d, "'[", tmp, "]'"), stdout=TRUE);
}
}
The key part is calling 1d_tool.py to generate the list of volumes in the afni-required format (I put it into the tmp variable), then feeding this string back to afni in the 3dTstat command. These strings can be VERY long, which is why I found it easier to build the commands in R rather than directly.
Here are the key afni calls, without the R code:
1d_tool.py -infile /scratch2/output/temp.1D -show_trs_uncensored encoded
3dTstat -stdev -prefix /scratch2/output/subject1_sdcens.nii.gz /scratch2/input/subject1_functional.nii.gz'[0..26,28..138,140..148]'
Here, I copy-pasted the string returned by 1d_tool.py into the '[]' required by 3dTstat.
No comments:
Post a Comment