spmr_read_nifti <- function(filename="", verbose=TRUE) {
# read in images
require(Rniftilib)
if(verbose) cat("Reading in 4D nifti file... ")
Y <- nifti.image.read(filename)
if(verbose) {
cat("done.\n")
cat("Dimensions: [", dim(Y), "]\n", sep=" ")
}
# repair slope
if(Y$scl.slope == 0) {
Y$scl.slope <- 1
}
#if(verbose) cat("Reading in 4D nifti file... ")
#require(oro.nifti, quietly=TRUE)
#VY <- readNIfTI(filename)
#Y <- VY@.Data * VY@scl_slope + VY@scl_inter
#if(verbose) {
# cat("done.\n")
# cat("Dimensions: [", dim(Y), "]\n", sep=" ")
#}
Y
}
spmr_write_nifti <- function(V, output.file, check=1, datatype=16) {
require(Rniftilib)
# check input
if(!is.array(V)) {
stop("V is not an array")
}
if(missing(output.file)) {
stop("please specify filename for writing nifti image")
} else if(!is.character(output.file)) {
stop("output.file is not a character")
}
# create new nifti object
IMG <- nifti.image.new()
# change dimensions
IMG$dim <- dim(V)
# change filename
check <- nifti.set.filenames(nim=IMG, prefix=output.file,
check=check,
set_byte_order=1) ## FIXME
# change datatype - default = 16 float (32 bits/voxel)
nifti.image.setdatatype(nim=IMG, value=datatype)
# assign data
if(length(dim(V) == 1)) {
IMG[] <- V
} else if(length(dim(V) == 2)) {
IMG[,] <- V
} else if(length(dim(V) == 3)) {
IMG[,,] <- V
} else if(length(dim(V) == 4)) {
IMG[,,,] <- V
} else if(length(dim(V) == 5)) {
IMG[,,,,] <- V
} else if(length(dim(V) == 6)) {
IMG[,,,,,] <- V
}
out <- nifti.image.write(IMG)
invisible(out)
}
spmr_fmri_specify_1stlevel <- function(RT,
units,
fmri_t, fmri_t0,
bf.name,
bf.length=NA, bf.order=NA,
bf.volt,
sess=list(),
fact=NULL,
global,
cvi,
mask=NULL,
output.dir="/tmp",
verbose=TRUE
) {
# create empty SPM object
SPM <- list(xY=list(RT=0,P=character(),VY=NULL),
nscan=numeric( length(sess) ),
xBF=list(),
Sess=list(),
xX=list(K=list()),
xGX=list(iGXcalc="",sGXcalc="",
rg=numeric(),GM=NA, gSF<-numeric()),
xVi=list(form="", V=NULL, Vi=NULL),
xM=list(T=numeric(), TH=numeric(), I=0, VM <- list(),
xs <- list()),
xsDes=list(),
SPMR=list(output.dir=output.dir, verbose=verbose)
)
# create output dir -- we will override everything!!
dir.create(SPM$SPMR$output.dir, showWarnings=FALSE)
# check input + insert default values
if(missing(RT)) stop("RT value is missing")
if(missing(units)) stop("units value is missing")
if(missing(fmri_t)) fmri_t <- defaults.stats.fmri.fmri_t
if(missing(fmri_t0)) fmri_t0 <- defaults.stats.fmri.fmri_t0
if(missing(bf.name)) {
if(defaults.stats.fmri.hrf.derivs[1] == 0 &&
defaults.stats.fmri.hrf.derivs[2] == 0) {
bf.name <- "hrf"
} else if(defaults.stats.fmri.hrf.derivs[1] == 1 &&
defaults.stats.fmri.hrf.derivs[2] == 0) {
bf.name <- "hrf (with time derivative)"
} else if(defaults.stats.fmri.hrf.derivs[1] == 1 &&
defaults.stats.fmri.hrf.derivs[2] == 1) {
bf.name <- "hrf (with time and dispersion derivatives)"
} else {
stop("inconsistent values for defaults.stats.fmri.hrf.derivs")
}
}
if(missing(bf.volt)) bf.volt <- defaults.stats.fmri.volt
if(missing(global)) global <- defaults.stats.fmri.global
if(missing(cvi)) cvi <- defaults.stats.fmri.cvi
if(!is.list(sess) || length(sess) == 0) stop("wrong sess argument")
# insert default values in session/cond (eg. hpf tmod pmod)
for(i in 1:length(sess)) {
if( is.null(sess[[i]]$hpf) ) {
sess[[i]]$hpf <- defaults.stats.fmri.hpf
}
if(!is.list(sess[[i]]$cond) ||
length(sess[[i]]$cond) == 0) stop("wrong cond argument")
for(j in 1:length(sess[[i]]$cond)) {
if( is.null(sess[[i]]$cond[[j]]$tmod) ) {
sess[[i]]$cond[[j]]$tmod <- defaults.stats.fmri.cond.tmod
}
if( is.null(sess[[i]]$cond[[j]]$pmod) ) {
sess[[i]]$cond[[j]]$pmod <- list()
}
}
if( is.null(sess[[i]]$regress) ) {
sess[[i]]$regress <- list()
}
}
## we first read in the 4D nifti files: one per session/subject
###########
## FIXME!!!
## how to 'glue' 4D images into one, along time dimension?
#SPM$SPMR$VY <- VY[[1]]
###########
# this is just a pointer to the data, per session
SPM$SPMR$VY <- vector("list", length=length(sess))
for(i in 1:length(sess)) {
SPM$SPMR$VY[[i]] <- spmr_read_nifti(sess[[i]]$scans)
}
##
## FILE: SPMROOT/config/spm_run_fmri_spec.m
##
SPM$xY$RT <- RT
# basis function variables
xBF <- list()
xBF$UNITS <- units
xBF$T <- fmri_t
xBF$T0 <- fmri_t0
xBF$dt <- RT/fmri_t
xBF$name <- bf.name
xBF$length <- bf.length
xBF$order <- bf.order
xBF$Volterra <- bf.volt
xBF <- spm_get_bf(xBF)
SPM$xBF <- xBF
# session info (TODO: multicondition/multiregression from file!)
for(i in 1:length(sess)) {
## FIXME: nscans is function of number of files!
## SPM$nscan[i] <- length( sess[[i]]$scans )
SPM$nscan[i] <- sess[[i]]$nscans
SPM$xY$P <- c(SPM$xY$P, sess[[i]]$scans)
SPM$Sess[[i]] <- list()
# condition info
U <- vector("list", length=length(sess[[i]]$cond))
for(j in 1:length(sess[[i]]$cond)) {
U[[j]] <- list()
U[[j]]$name <- sess[[i]]$cond[[j]]$name
U[[j]]$ons <- sess[[i]]$cond[[j]]$onset
U[[j]]$dur <- sess[[i]]$cond[[j]]$duration
if(length(U[[j]]$dur) == 1) {
U[[j]]$dur <- U[[j]]$dur * rep(1, length(U[[j]]$ons))
} else if(length(U[[j]]$dur) != length(U[[j]]$ons)) {
stop("Mismatch between number of onset and number of durations")
}
P <- list()
q1 <- 0
# time effects?
if(sess[[i]]$cond[[j]]$tmod > 0) {
P[[1]] <- list()
P[[1]]$name <- "time"
P[[1]]$P <- U[[j]]$ons * RT/60
P[[1]]$h <- sess[[i]]$cond[[j]]$tmod
q1 <- 1
}
# parametric modulation?
if( length(sess[[i]]$cond[[j]]$pmod) > 0 ) {
for(q in 1:length(sess[[i]]$cond[[j]]$pmod)) {
q1 <- q1 + 1
P[[q1]] <- list()
P[[q1]]$name <- sess[[i]]$cond[[j]]$pmod[[q]]$name
P[[q1]]$P <- sess[[i]]$cond[[j]]$pmod[[q]]$param
P[[q1]]$h <- sess[[i]]$cond[[j]]$pmod[[q]]$poly
}
}
if( length(P) == 0 ) {
# P$name <- "none" ## we want to keep length(P) == 0
# P$h <- 0
}
U[[j]]$P <- P
}
SPM$Sess[[i]]$U <- U
# user specified regressors
SPM$Sess[[i]]$C <- list(C=matrix(0,0,0), Cname=character(0))
if(length(sess$regress) > 0) {
C <- sess$regress[[1]]$val
Cname <- sess$regress[[1]]$name
if(length(sess$regress) > 1) {
for(rr in 2:length(sess$regress)) {
C <- cbind(C, sess$regress[[rr]]$val)
Cname <- c(Cname, sess$regress[[rr]]$name)
}
}
SPM$Sess[[i]]$C$C <- C
SPM$Sess[[i]]$C$name <- Cname
}
} # end session
# factorial design
if( !is.null(fact) ) {
SPM$factor <- vector("list", length(fact))
NC <- length( SPM$Sess[[1]]$U ) # number of conditions
CheckNC <- 1
for(i in 1:length(fact)) {
SPM$factor[[i]]$name <- fact[[i]]$name
SPM$factor[[i]]$levels <- fact[[i]]$levels
CheckNC <- CheckNC * SPM$factor[[i]]$levels
}
if(CheckNC != NC) {
stop("factor do not match conditions")
}
} else {
SPM$factor <- list()
}
# Globals
SPM$xGX$iGXcalc <- global
SPM$xGX$sGXcalc <- "mean voxel value"
SPM$xGX$sGMsca <- "session specific"
# High pass filter
SPM$xX$K <- vector("list", length=length(sess))
for(i in 1:length(sess)) {
SPM$xX$K[[i]] <- list()
SPM$xX$K[[i]]$HParam <- sess[[i]]$hpf
}
# Autocorrelation
SPM$xVi$form <- cvi
# Let SPM configure the design
# Mask
if(!is.null(mask)) {
# TODO!!!
}
##
## FILE: SPMROOT/spm_fmri_spm_ui.m
##
# get design matrix
SPM <- spm_fMRI_design(SPM)
nsess <- length(SPM$nscan)
# high-pass filter
K <- vector("list", length=nsess)
for(i in 1:nsess) {
K[[i]] <- list(HParam=SPM$xX$K[[i]]$HParam,
row=SPM$Sess[[i]]$row,
RT=SPM$xY$RT)
}
SPM$xX$K <- spm_filter(K)
# intrinsic autocorrelation (Vi)
cVi <- tolower(SPM$xVi$form)
nscan <- SPM$nscan # could be a vector (if multiple sessions)!
if(is.numeric(cVi)) {
SPM$xVi$Vi <- spm_Ce(nscan, cVi)
cVi <- sprintf("AR(%0.1f)", cVi)
} else if(cVi == "none") {
SPM$xVi$V <- diag(sum(nscan))
cVi <- "i.i.d"
} else { # assume AR(0.2)
SPM$xVi$Vi <- spm_Ce(nscan, 0.2)
cVi <- "AR(0.2)"
}
SPM$xVi$form <- cVi
# at this point, SPM maps the files,
# checks the orientations, and place the handles
# in SPM$xY$VY
#### FIXME: we only use the FIRST SESSION here!!!!! ######
SPM$xY$VY <- (SPM$SPMR$VY[[1L]][] * SPM$SPMR$VY[[1L]]$scl.slope +
SPM$SPMR$VY[[1L]]$scl.inter)
if(verbose) {
cat("Note: we only use the first session for now\n")
cat("size VY data: ", round(object.size(SPM$xY$VY)/(1024^2),3), "Mb\n")
}
# compute Global variate
GM <- 100
if(verbose) cat("Calculating globals ... ")
start.time <- proc.time()[3]
q <- dim(SPM$xY$VY)[4]
g <- apply(SPM$xY$VY, MARGIN=4, spm_global)
#for(i in 1:q) {
# g[i] <- spm_global(SPM$xY$VY[,,,i])
#}
if(verbose) cat("done. [time = ",(proc.time()[3]-start.time),"]\n",sep="")
gSF <- 100/g
if(tolower(SPM$xGX$iGXcalc) == "none") {
# grand-mean scaling (session/subject-specific)
# recommended for fMRI, because the scaling of fMRI data
# can vary between sessions and could mask regional activations
# SPM Book p119
for(i in 1:nsess) {
gSF[SPM$Sess[[i]]$row] <- GM/mean(g[SPM$Sess[[i]]$row])
}
} else {
# "scaling": different scale per scan
# to remove the effect of 'gain' for every image (which is known
# to vary from scan to scan)
}
# Apply gSF to memory-mapped scalefactors to implement scaling
q <- dim(SPM$xY$VY)[4]
for(i in 1:q) {
SPM$xY$VY[,,,i] <- SPM$xY$VY[,,,i] * gSF[i]
}
# place global variates in global structure
SPM$xGX$rg <- g
SPM$xGX$GM <- GM
SPM$xGX$gSF <- gSF
# Masking structure automatically set to 80% of mean
TH <- g * gSF * defaults.mask.thresh
SPM$xM <- list(T=rep(1, q),
TH=TH,
I=0,
VM=list(),
xs=list(Masking="analysis threshold"))
# Design description - for saving and display
ntr <- integer(nsess)
for(i in 1:nsess) {
ntr[i] <- length(SPM$Sess[[i]]$U)
}
SPM$xsDes <- list(
Basis_functions = SPM$xBF$name,
Number_of_sessions = sprintf('%d',nsess),
Trials_per_session = sprintf('%-3d',ntr),
Interscan_interval = sprintf('%0.2f {s}',SPM$xY$RT),
High_pass_Filter = sprintf('Cutoff: %d {s}',SPM$xX$K[[1]]$HParam),
Global_calculation = SPM$xGX$sGXcalc,
Grand_mean_scaling = SPM$xGX$sGMsca,
Global_normalisation = SPM$xGX$iGXcalc)
SPM
}
spmr_fmri_estimate <- function(SPM, method="classical") {
##
## FILE: SPMROOT/config/spm_run_fmri_est.m
##
start.time <- proc.time()[3]
verbose <- SPM$SPMR$verbose
if(tolower(method) == "classical") {
SPM <- spm_spm(SPM)
SPM$xVol$M <- SPM$SPMR$VY[[1L]]$qto.xyz
SPM$xVol$iM <- solve(SPM$xVol$M)
# Automatically set up contrasts for factor designs
## TODO !! ##
} else if(tolower(method) == "bayesian") {
stop("bayesian estimation is not implemented yet")
}
if(verbose) cat("done. [time = ",(proc.time()[3]-start.time),"]\n",sep="")
SPM
}
spmr_contrasts <- function(SPM, consess=list(), delete=0) {
# check/augment consess argument
stopifnot(is.list(consess) && length(consess) > 0)
for(i in 1:length(consess)) {
if(is.null(consess[[i]]$type)) {
if(is.matrix(consess[[i]]$con) && nrow(consess[[i]]$con) > 1) {
consess[[i]]$type <- "tcon"
} else {
consess[[i]]$type <- "fcon"
}
}
if(is.null(consess[[i]]$sessrep)) {
# same contrast for several sessions?
# matlabbatch default is "none" (other options are
# "repl", "replna", "sess", and "both")
# see file SPMROOT/config/spm_cf_con.m
consess[[i]]$sessrep <- "none"
}
}
# delete old contrasts entries in SPM?
if(delete) {
SPM$xCon <- NULL
SPM$xCon <- list()
## TODO!!
}
# get name, STAT, con and sessrep
for(i in 1:length(consess)) {
if(consess[[i]]$type == "tcon") {
name <- consess[[i]]$name
STAT <- "T"
con <- consess[[i]]$contrast
# convert to matrix AND transpose to column vector
if(!is.matrix(con)) {
con <- as.matrix(con)
}
sessrep <- consess[[i]]$sessrep
} else if(consess[[i]]$type == "fcon") {
name <- consess[[i]]$name
STAT <- "F"
con <- consess[[i]]$contrast
# transpose!
con <- t(con)
sessrep <- consess[[i]]$sessrep
} else {
stop("consess type can only be 'tcon' or 'fcon'")
}
if(sessrep != "none") {
stop("support for multiple sessions not implemented yet!")
nsession <- length(SPM$Sess)
if(sessrep == "repl") {
} else if(sessrep == "replna") {
} else if(sessrep == "sess") {
} else if(sessrep == "both") {
}
} else {
cons = list(con)
names = list(name)
}
# loop over created contrasts
for(k in 1:length(cons)) {
# Basic checking of contrast:
# - right number of elements
# - spm_sp("isinspp/eachinspp", sX, c)
c <- spm_conman("ParseCon", cons[[k]], SPM$xX$xKXs, STAT)
# Fill-in the contrast structure
DxCon <- spm_FcUtil(action="Set", name=names[[k]], STAT=STAT,
set_action="c", value=c, sX=SPM$xX$xKXs)
# Append to SPM$xCon
end <- length(SPM$xCon)
SPM$xCon[[end + 1]] <- DxCon
# Compute contrast
SPM <- spm_contrasts(SPM, length(SPM$xCon))
}
} # i in 1:length(consess)
SPM
}
spmr_write_images <- function(SPM, type="SPM", idx) {
type <- tolower(type)
if(type == "beta") {
if(SPM$SPMR$verbose) cat("writing beta images...")
# write beta
for(b in 1:ncol(SPM$xX$X)) {
filename <- paste(SPM$SPMR$output.dir,
sprintf("beta_%04d", b), sep="")
spmr_write_nifti(V=SPM$Vbeta[[b]], output.file=filename, check=0)
}
if(SPM$SPMR$verbose) cat(" done.\n")
}
if(type == "resms") {
if(SPM$SPMR$verbose) cat("writing ResMS image ...")
filename <- paste(SPM$SPMR$output.dir, "ResMS", sep="")
spmr_write_nifti(V=(SPM$VResMS), output.file=filename, check=0)
if(SPM$SPMR$verbose) cat(" done.\n")
}
if(type == "con") {
if(SPM$SPMR$verbose) cat("writing contrast images...")
for(i in 1:length(SPM$xCon)) {
filename <- paste(SPM$SPMR$output.dir,
sprintf("con_%04d", i), sep="")
# NOTE: we rescale to get raw ResSS (just like SPM)!
spmr_write_nifti(V=(SPM$xCon[[i]]$Vcon * SPM$xX$trRV), output.file=filename, check=0)
}
if(SPM$SPMR$verbose) cat(" done.\n")
}
if(type == "spm") {
if(SPM$SPMR$verbose) cat("writing SPM{t/F} maps...")
for(i in 1:length(SPM$xCon)) {
if(SPM$xCon[[i]]$STAT == "F") {
filename <- paste(SPM$SPMR$output.dir,
sprintf("spmF_%04d", i), sep="")
} else if(SPM$xCon[[i]]$STAT == "T") {
filename <- paste(SPM$SPMR$output.dir,
sprintf("spmT_%04d", i), sep="")
} else {
stop("unknown contrast type: ", SPM$xCon[[i]]$type)
}
spmr_write_nifti(V=SPM$xCon[[i]]$Vspm, output.file=filename, check=0)
}
if(SPM$SPMR$verbose) cat(" done.\n")
}
}
spmr_results <- function(SPM,
Ic=1L, thresDesc="FWE", u=0.05, k=0,
type="table") {
# get xSPM
xSPM <- spm_getSPM(SPM, Ic=Ic, thresDesc=thresDesc, u=u, k=k)
# Summary list of local maxima for entire volume of interest
TabDat <- spm_list("List", xSPM)
TabDat
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.