#' WIP: data-driven denoising for ASL MRI
#'
#' Denoises regression based reconstruction of CBF from arterial spin labeling
#'
#' @param boldmatrix input bold matrix
#' @param targety target to predict
#' @param covariates motion or other parameters / nuisance variables
#' @param selectionthresh e.g. 0.1 take 10 percent worst variables for noise
#' estimation
#' @param maxnoisepreds integer search range e.g 1:10
#' @param polydegree eg 4 for polynomial nuisance variables or 'loess'
#' @param crossvalidationgroups prior defined or integer valued
#' @param scalemat boolean
#' @param noisepoolfun function to help select noise pool e.g. max
#' @param usecompcor boolean
#' @param verbose boolean
#' @return matrix is output
#' @author Avants BB
#' @examples
#'
#' # asl<-antsImageRead( getANTsRData("pcasl") )
#' set.seed(1)
#' nvox <- 10*10*10*20
#' dims <- c(10,10,10,20)
#' asl <- makeImage( dims , rnorm( nvox )+500 )
#' aslmean <- getAverageOfTimeSeries( asl )
#' aslmask <- getMask( aslmean )
#' aslmat<-timeseries2matrix( asl, aslmask )
#' for ( i in 1:10 ) aslmat[,i*2]<-aslmat[,i*2]*2
#' asl<-matrix2timeseries( asl, aslmask, aslmat )
#' tc<-as.factor(rep(c("C","T"),nrow(aslmat)/2))
#' dv<-computeDVARS(aslmat)
#' dnz<-aslDenoiseR( aslmat, tc, covariates=dv, selectionthresh=0.1,
#' maxnoisepreds=c(1:2), polydegree=2, crossvalidationgroups=2 )
#' testthat::expect_equal(dnz$R2atBestN, 7, tolerance = 0.5 )
#'
#' \dontrun{
#' # a classic regression approach to estimating perfusion
#' # not recommended, but shows the basic idea.
#' # see ?quantifyCBF for a better approach
#' perfmodel<-lm( aslmat ~ tc + dnz$noiseu )
#' perfimg<-antsImageClone(aslmask)
#' perfimg[ aslmask == 1 ]<-bigLMStats( perfmodel )$beta[1,]
#' m0<-getAverageOfTimeSeries(asl)
#' ctl<-c(1:(nrow(aslmat)/2))*2
#' m0[ aslmask==1 ]<-colMeans(aslmat[ctl,])
#' pcasl.parameters<-list( sequence="pcasl", m0=m0 )
#' cbf <- quantifyCBF( perfimg, aslmask, pcasl.parameters )
#'
#' # default mode network example
#'
#' if ( ! exists("bold") )
#' {
#' bold = antsImageRead( getANTsRData("rsbold") )
#' meanbold = getAverageOfTimeSeries( bold )
#' boldmask = getMask( meanbold )
#' # map to mni
#' mni = antsImageRead( getANTsRData("mni") )
#' mniaal = antsImageRead( getANTsRData("mnia") )
#' mymap = antsRegistration( meanbold * boldmask, mni, typeofTransform='SyNBold',
#' verbose=1 )
#' aalimg = antsApplyTransforms( meanbold, mniaal, mymap$fwdtransforms,
#' interpolator='NearestNeighbor')
#' data("aal",package="ANTsR")
#' timeselect<-10:dim(bold)[4]
#' if ( ! exists("moco") )
#' {
#' moco = antsMotionCalculation( bold, boldmask )
#' }
#' sbold = smoothImage( moco$moco_img , 3.0 )
#' antsImageWrite( boldmask, 'boldmask.nii.gz' )
#' antsImageWrite( meanbold, 'boldmean.nii.gz' )
#' antsImageWrite( aalimg, 'boldaal.nii.gz' )
#' boldmask = boldmask * thresholdImage( aalimg, 1, Inf )
#' }
#' postcing<-aal$label_num[ grep( "Cingulum_Post", aal$label_name ) ]
#' postCingMask = maskImage( boldmask, aalimg,
#' level = as.numeric(postcing), binarize=T )
#' mpostCingMask= antsImageClone( postCingMask ) * 0
#' mpostCingMask[ postCingMask == 0 ] = 1
#' boldmat = timeseries2matrix( sbold, boldmask*mpostCingMask )
#' boldmat = boldmat[timeselect,]
#' boldmat = frequencyFilterfMRI( boldmat, tr=antsGetSpacing(bold)[4], opt='trig' )
#' dmnvec<-( timeseries2matrix( sbold, postCingMask )[timeselect,] )
#' dmnvec = rowMeans(
#' frequencyFilterfMRI( dmnvec, tr=antsGetSpacing(bold)[4], opt='trig' ) )
#' dmnmat = matrix( dmnvec, ncol=1)
#' mocpar = moco$moco_params[ timeselect , 3:14 ]
#' dnz<-aslDenoiseR( boldmat, dmnvec, covariates=mocpar, selectionthresh=0.2,
#' maxnoisepreds=c(2:10), polydegree='loess',
#' crossvalidationgroups=8 )
#' boldmat<-timeseries2matrix(sbold, boldmask)
#' boldmat<-boldmat[timeselect,]
#' boldmat = frequencyFilterfMRI( boldmat, tr=antsGetSpacing(bold)[4], opt='trig' )
#' mdl<-bigLMStats( lm( boldmat ~ dmnvec + dnz$covariates + dnz$noiseu ), 0.001 )
#' betas<-mdl$beta.t[1,]
#' betaImg = makeImage( boldmask, betas )
#' antsImageWrite( betaImg, 'dmnBetas.nii.gz' )
#' # this should give default mode network around beta = 12
#' }
#'
#' @export aslDenoiseR
aslDenoiseR <- function(
boldmatrix,
targety,
covariates = NA,
selectionthresh = 0.1,
maxnoisepreds = 2:12,
polydegree = 'loess',
crossvalidationgroups = 4,
scalemat = F,
noisepoolfun = max,
usecompcor = F,
verbose = F ) {
nvox <- ncol(boldmatrix)
groups <- crossvalidationgroups
if (length(groups) == 1) {
kfolds <- groups
groups <- c()
grouplength <- round(nrow(boldmatrix)/kfolds) - 1
for (k in 1:kfolds) groups <- c(groups, rep(k, grouplength))
groups <- c(rep(1, nrow(boldmatrix) - length(groups)), groups)
}
##### identify low reproducibility voxels
getnoisepool <- function(x, frac = selectionthresh) {
xord <- sort(x)
l <- round(length(x) * frac)
val <- xord[l]
# return( x < val )
return(x < val & x < 0)
}
# overall description of the method 1. regressors include: design + trends +
# noise-pool 2. find noise-pool by initial cross-validation without noise
# regressors 3. cross-validate predictions using different numbers of noise
# regressors 4. select best n for predictors from noise pool 5. return the noise
# mask and the value for n make regressors
timevals <- NA
if (all(is.na(timevals)))
timevals <- 1:nrow(boldmatrix)
#
if (is.numeric(polydegree)) {
if (polydegree > 0) {
p <- stats::poly(timevals, degree = polydegree)
if (!all(is.na(covariates))) {
covariates <- cbind(data.matrix(covariates), p)
} else covariates <- p
}
} else if (polydegree == 'loess') {
timevals <- 1:nrow(boldmatrix)
mean.ts <- apply(boldmatrix, 1, mean)
myloess <- loess(mean.ts ~ timevals)
p <- myloess$fitted
if (!all(is.na(covariates))) {
covariates <- cbind(data.matrix(covariates), p)
} else covariates <- p
}
rawboldmat <- data.matrix(boldmatrix)
svdboldmat <- residuals( lm( rawboldmat ~ 1 + covariates ) )
################### now redo some work w/new hrf
R2base <- crossvalidatedR2( svdboldmat, targety, groups,
covariates = NA )
R2base <- apply(R2base, FUN = noisepoolfun, MARGIN = 2)
noisepool <- getnoisepool(R2base)
if (all(noisepool == TRUE)) {
print("all voxels meet your pvalthresh - try increasing the value")
return(NA)
}
if (all(noisepool == FALSE)) {
print("zero voxels meet your pvalthresh - try decreasing the value")
return(NA)
} else if ( verbose ) print(paste("Noise pool has nvoxels=", sum(noisepool)))
if (scalemat)
svdboldmat <- scale(svdboldmat)
##### should the denoising be done per group / run ?
if (usecompcor)
noiseu <- compcor(svdboldmat, max(maxnoisepreds))
if (!usecompcor)
noiseu <- svd(svdboldmat[, noisepool], nv = 0, nu = max(maxnoisepreds))$u
R2summary <- rep(0, length(maxnoisepreds))
ct <- 1
for (i in maxnoisepreds) {
svdboldmat <- residuals( lm( rawboldmat ~ 1 + covariates + noiseu[, 1:i]))
R2 <- crossvalidatedR2( svdboldmat, targety, groups,
covariates = NA )
R2max <- apply(R2, FUN = max, MARGIN = 2)
if (ct == 1)
R2perNoiseLevel <- R2max else R2perNoiseLevel <- cbind(R2perNoiseLevel, R2max)
R2pos <- R2max[R2max > 0]
R2summary[ct] <- median(R2pos)
if ( verbose ) print(paste("NoiseU:", i, "MeanRSqrd", R2summary[ct]))
ct <- ct + 1
}
scl <- 0.95
if (max(R2summary, na.rm = T) < 0)
scl <- 1.05
mxt <- scl * max(R2summary, na.rm = T)
bestn <- maxnoisepreds[which(R2summary > mxt)[1]]
if (ct == 2)
R2final <- R2perNoiseLevel
if (ct > 2)
R2final <- R2perNoiseLevel[, bestn - min(maxnoisepreds) + 1]
return(list(n = bestn, R2atBestN = R2summary[bestn], noisepool = noisepool, R2base = R2base,
R2final = R2final, noiseu = noiseu[, 1:bestn],
covariates = covariates))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.