#' Render a function onto a surface.
#'
#' Use a system call to \code{antsSurf} in order to render a function onto
#' a surface. This requires \code{antsSurf} to be in the environment as well
#' as \code{ConvertScalarImageToRGB}, both available in Advanced Normalization
#' Tools software on github.
#'
#' @param x input antsImage defining the surface on which to render
#' @param y input antsImage list defining the function to render
#' on the surface. these image(s) should be in the same space as \code{x}.
#' @param z input antsImage list mask for each \code{y} function to render
#' on the surface. these image(s) should be in the same space as \code{y}.
#' @param quantlimits lower and upper quantile limits for overlay
#' @param colormap character, one of: grey, red, green, blue, copper, jet, hsv,
#' spring, summer, autumn, winter, hot, cool, overunder, custom
#' @param alpha transparency vector for underlay and each overlay, default zero
#' @param inflationFactor number of inflation iterations to run
#' @param smoothingSigma gaussian smooth the overlay by this sigma
#' @param rotationParams 3 Rotation angles expressed in degrees or a matrix of
#' rotation parameters that will be applied in sequence.
#' @param overlayLimits absolute lower and upper limits for functional overlay.
#' this parameter will override \code{quantlimits}. Currently, this will set
#' levels above \code{overlayLimits[2]} to \code{overlayLimits[2]}. Can be a
#' list of length of y.
#' @param backgroundColor a three entry vector where each entry is in the range of 0 to 255 and corresponds to red green and blue color channels. Alternatively, pass a string white or black.
#' @param filename prefix filename for output pngs
#' @param antspath pass the ANTSPATH here otherwise we try to detect it from environment
#' @param verbose prints the command used to call \code{antsSurf}
#' @return no output
#' @author Avants BB, Tustison NJ
#' @examples
#' \dontrun{
#'
#' myantspath <- Sys.getenv("ANTSPATH")
#' surf_ex <- file.path(myantspath, "antsSurf")
#' if (file.exists(surf_ex)) {
#' ch2i <- antsImageRead(getANTsRData("ch2"))
#' ch2seg <- thresholdImage(ch2i, "Otsu", 3)
#' wm <- thresholdImage(ch2seg, 3, 3)
#' wm2 <- smoothImage(wm, 1) %>% thresholdImage(0.5, Inf)
#' kimg <- weingartenImageCurvature(ch2i, 1.5) %>% smoothImage(1)
#' rp1 <- matrix(c(90, 180, 90), ncol = 3)
#' rp2 <- matrix(c(90, 180, 270), ncol = 3)
#' rp3 <- matrix(c(90, 180, 180), ncol = 3)
#' rp <- rbind(rp1, rp3, rp2)
#' antsrSurf(
#' x = wm2, y = list(kimg), z = list(wm2 %>% iMath("MD", 3)),
#' inflationFactor = 255, overlayLimits = c(-0.3, 0.3), verbose = TRUE,
#' rotationParams = rp, filename = tempfile()
#' )
#'
#' fn <- getANTsRData("surf")
#' img <- antsImageRead(fn) # see antsSurf on github for data
#' wm <- thresholdImage(img, 3, 4)
#' wm <- thresholdImage(img, 3, 4) %>% iMath("FillHoles")
#' wm <- wm %>% thresholdImage(1, 2)
#' wms <- smoothImage(wm, 1.0)
#' wmk <- weingartenImageCurvature(wms, 1.5, 0)
#' # will display to screen
#' antsrSurf(
#' x = wm, y = list(wmk %>% smoothImage(1)), z = list(wm %>% iMath("MD", 1)),
#' rotationParams = c(270, 0, 90), overlayLimits = c(-0.4, 0.4)
#' )
#' # surface and two overlays
#' blob <- antsImageRead(getANTsRData("blob"))
#' blob[1:266, 1:266, 1:100] <- 0
#' z <- list(wm %>% iMath("MD", 1), blob %>% smoothImage(1))
#' antsrSurf(
#' x = wm, y = list(wmk %>% smoothImage(1), blob), z = z,
#' colormap = c("jet", "blue"), alpha = c(1, 0.5, 1),
#' rotationParams = c(270, 0, 90),
#' overlayLimits = list(c(-0.4, 0.4), c(0.9, 1.001))
#' )
#' # separate pos and neg curvature
#' y <- list(
#' thresholdImage(wmk, 0.00, Inf),
#' thresholdImage(wmk, -100, -0.00)
#' )
#' z <- list(
#' y[[1]] %>% iMath("MD", 1),
#' y[[2]] %>% iMath("MD", 1)
#' )
#' antsrSurf(
#' x = wm, y = y, z = z, smoothingSigma = 0.5, alpha = c(1, 1, 1),
#' colormap = c("red", "blue"),
#' inflationFactor = 155, overlayLimits = list(c(0.5, 1.0001), c(0.5, 1.0001)),
#' verbose = TRUE, rotationParams = rp[1, ]
#' )
#' }
#' }
#'
#' @export antsrSurf
antsrSurf <- function(x, y, z,
quantlimits = c(0.1, 0.9),
colormap = "jet",
alpha = NA,
inflationFactor = 25,
smoothingSigma = 0.0,
rotationParams = c(270, 0, 270),
overlayLimits = NA,
backgroundColor,
filename = NA,
antspath = NA,
verbose = FALSE) {
domainImageMap <- NULL
if (any(is.na(alpha))) {
alpha <- rep(1, length(x) + length(y))
}
if (length(z) != length(y)) stop("each y must have a mask in z")
if (is.numeric(overlayLimits)) {
overlayLimits <- list(overlayLimits)
}
# #' @param domainImageMap resamples surf and func to this domain FIXME
# check for needed programs
# first get antspath
if (is.na(antspath)) {
myantspath <- Sys.getenv(c("ANTSPATH"))
} else {
myantspath <- antspath
}
if (nchar(myantspath) == 0 & is.na(antspath)) {
stop("Please set ANTSPATH in your environment")
}
if (!is.na(antspath)) {
myantspath <- antspath
}
ass <- paste(myantspath, "antsSurf", sep = "/")
cvt <- paste(myantspath, "ConvertScalarImageToRGB", sep = "/")
if (!file.exists(ass)) {
stop("This function needs antsSurf in the environment.")
}
if (!file.exists(cvt)) {
stop("This function needs ConvertScalarImageToRGB in the environment.")
}
if (!is.null(domainImageMap)) {
if (is.antsImage(domainImageMap)) {
tx <- new("antsrTransform",
precision = "float",
type = "AffineTransform", dimension = x@dimension
)
x <- applyAntsrTransformToImage(tx, x, domainImageMap)
if (!missing("y")) {
if (is.antsImage(y)) y <- list(y)
for (i in 1:length(y)) {
y[[i]] <-
applyAntsrTransformToImage(tx, y[[i]], domainImageMap,
interpolation = "Linear"
)
}
}
}
}
xfn <- tempfile(fileext = ".nii.gz")
antsImageWrite(x, xfn)
if (is.na(filename)) filename <- tempfile()
if (!is.matrix(rotationParams)) {
rotationParams <- matrix(rotationParams, ncol = 3)
}
if (nrow(rotationParams) > 1) {
if (!usePkg("abind") | !usePkg("png") | !usePkg("grid")) {
print("Need abind, grid and png")
return(NULL)
}
}
pngs <- rep(NA, nrow(rotationParams))
if (missing(backgroundColor)) {
backgroundColor <- "white"
}
if (any(backgroundColor == "black")) {
backgroundColor <- paste("0x0x0x", alpha[1], sep = "")
} else if (any(backgroundColor == "white")) {
backgroundColor <- paste("255x255x255x", alpha[1], sep = "")
} else {
backgroundColor <-
paste(c(backgroundColor, alpha[1]), collapse = "x")
}
backgroundColorS <- "255x255x255x1"
for (myrot in 1:nrow(rotationParams))
{
asscmd <- paste(ass, " -s [ ", xfn, ",", backgroundColorS, "] ")
if (!missing(y)) {
ct <- 0
if (length(colormap) != length(y)) {
colormap <- rep(colormap, length.out = length(y))
}
for (overlay in y)
{
ct <- ct + 1
wms <- smoothImage(overlay, smoothingSigma)
myquants <- quantile(wms[abs(wms) > 0], quantlimits)
if (!all(is.na(overlayLimits))) {
myquants <- overlayLimits[[ct]]
if (all(myquants < 0)) {
# wms = wms * -1.0
# myquants = rev( myquants ) * ( -1.0 )
# wms = wms * thresholdImage( wms, myquants[1] , myquants[2] )
}
if (all(myquants > 0)) {
# wms = wms * thresholdImage( wms, myquants[1] , myquants[2] )
}
} else {
# wms[ wms < quantlimits[1] ] = quantlimits[1]
# wms[ wms > quantlimits[2] ] = quantlimits[2]
}
if (verbose) {
print(paste("overlay quantiles for overlay", ct))
print(myquants)
print("range")
print(range(wms))
}
kblobfn <- tempfile(fileext = ".nii.gz")
antsImageWrite(z[[ct]], kblobfn)
overlayfn <- tempfile(fileext = ".nii.gz")
antsImageWrite(wms, overlayfn)
csvlutfn <- tempfile(fileext = ".csv")
overlayrgbfn <- tempfile(fileext = ".nii.gz")
if (verbose) print(colormap[ct])
cvtcmd <- paste(
cvt, " 3 ", overlayfn, overlayrgbfn,
kblobfn, colormap[ct], " none ", myquants[1], myquants[2], " 0 255", csvlutfn
)
sss <- system(cvtcmd)
if (verbose) print(cvtcmd)
if (verbose) cat("\n")
alphaloc <- alpha[min(c(ct + 1, length(alpha)))]
if (verbose) print(paste("alpha", alphaloc))
asscmd <- paste(asscmd, "-f [ ", overlayrgbfn, ", ", kblobfn, ", ", alphaloc, " ] ")
}
}
if (nrow(rotationParams) == 1) {
asscmd <- paste(
asscmd, " -i ", inflationFactor,
" -d [", paste(rotationParams[myrot, ], collapse = "x"), ",", backgroundColor, "]"
)
} else {
pngext <- myrot
if (myrot < 10) pngext <- paste("0", pngext, sep = "")
if (myrot < 100) pngext <- paste("0", pngext, sep = "")
pngfnloc <- paste(filename, pngext, ".png", sep = "")
system(paste("rm", pngfnloc))
asscmd <- paste(asscmd, " -i ", inflationFactor, " -d ", pngfnloc,
"[", paste(rotationParams[myrot, ], collapse = "x"), ",", backgroundColor, "] ",
sep = ""
)
}
if (verbose) print(asscmd)
sss <- system(asscmd)
Sys.sleep(3)
if (nrow(rotationParams) > 1) pngs[myrot] <- pngfnloc
}
Sys.sleep(3)
if (nrow(rotationParams) > 1) {
mypng <- png::readPNG(pngs[1])
for (i in 2:length(pngs))
{
mypng <- abind::abind(mypng, png::readPNG(pngs[i]), along = 2)
}
png(paste(filename, ".png", sep = ""), width = dim(mypng)[2], height = dim(mypng)[1])
grid::grid.raster(mypng)
dev.off()
}
}
#' Render an image volume with or without overlay.
#'
#' Use a system call to \code{antsVol} in order to render an image. This
#' requires \code{antsVol} to be in the environment as well as
#' \code{ConvertScalarImageToRGB}, both available in Advanced Normalization
#' Tools software on github.
#'
#' @param x input antsImage defining the image to render
#' @param y input antsImage list defining the function to render
#' on the image. these image(s) should be in the same space.
#' @param quantlimits lower and upper quantile limits for overlay
#' @param colormap character, one of: grey, red, green, blue, copper, jet, hsv,
#' spring, summer, autumn, winter, hot, cool, overunder, custom
#' @param rotationParams 3 Rotation angles expressed in degrees or a matrix of
#' rotation parameters that will be applied in sequence.
#' @param overlayLimits absolute lower and upper limits for functional overlay.
#' this parameter will override \code{quantlimits}. Currently, this will set
#' levels above \code{overlayLimits[2]} to \code{overlayLimits[2]}.
#' @param magnificationFactor zooms in on image during rendering
#' @param intensityTruncation lower and upper quantiles at which to truncate intensity
#' @param filename prefix filename for output pngs
#' @param antspath pass the ANTSPATH here otherwise we try to detect it from environment
#' @param verbose prints the command used to call \code{antsVol}
#' @return no output
#' @author Avants BB, Tustison NJ
#' @examples
#' \dontrun{
#' ch2i <- antsImageRead(getANTsRData("mni"))
#' ch2seg <- thresholdImage(ch2i, "Otsu", 3)
#' wm <- thresholdImage(ch2seg, 3, 3)
#' kimg <- weingartenImageCurvature(ch2i, 1.5) %>% smoothImage(1)
#' ap <- path.expand("~/code/ants-src/bin/")
#' rp0 <- matrix(c(90, 180, 90), ncol = 3)
#' rp2 <- matrix(c(0, 0, 0), ncol = 3)
#' rp3 <- matrix(c(270, 90, 90), ncol = 3)
#' rp <- rbind(rp0, rp2, rp3) # pass these as rotationParams
#' antsrVol(wm, list(kimg), quantlimits = c(0.01, 0.99))
#' }
#'
#' @export antsrVol
antsrVol <- function(x, y,
quantlimits = c(0.1, 0.9),
colormap = "jet",
rotationParams = c(270, 0, 270),
overlayLimits = NA,
magnificationFactor = 1.0,
intensityTruncation = c(0.0, 1.0),
filename = NA,
antspath = NA,
verbose = FALSE) {
# check for needed programs
# first get antspath
myantspath <- Sys.getenv(c("ANTSPATH"))
if (nchar(myantspath) == 0 & is.na(antspath)) {
stop("Please set ANTSPATH in your environment")
}
if (!is.na(antspath)) myantspath <- antspath
ass <- file.exists(paste(myantspath, "antsVol", sep = "/"))
cvt <- file.exists(paste(myantspath, "ConvertScalarImageToRGB", sep = "/"))
if (length(ass) == 0) stop("This function needs antsSurf in the environment.")
if (length(cvt) == 0) stop("This function needs ConvertScalarImageToRGB in the environment.")
ass <- paste(myantspath, "antsVol", sep = "/")
cvt <- paste(myantspath, "ConvertScalarImageToRGB", sep = "/")
xfn <- tempfile(fileext = ".nii.gz")
xmod <- antsImageClone(x)
if (intensityTruncation[1] > 0 | intensityTruncation[2] < 1) {
xmod <- iMath(x, "TruncateIntensity", intensityTruncation[1], intensityTruncation[2])
}
antsImageWrite(xmod, xfn)
if (is.na(filename)) filename <- tempfile()
if (!is.matrix(rotationParams)) {
rotationParams <- matrix(rotationParams, ncol = 3)
}
if (nrow(rotationParams) > 1) {
if (!usePkg("abind") | !usePkg("png") | !usePkg("grid")) {
print("Need abind, grid and png")
return(NULL)
}
}
pngs <- rep(NA, nrow(rotationParams))
for (myrot in 1:nrow(rotationParams))
{
assvcmd <- paste(ass, " -i ", xfn, " ", sep = "")
if (!missing(y)) {
ct <- 0
if (length(colormap) != length(y)) {
colormap <- rep(colormap, length.out = length(y))
}
for (overlay in y)
{
ct <- ct + 1
wms <- smoothImage(overlay, 1.0)
myquants <- quantile(overlay[abs(overlay) > 0], quantlimits)
if (!all(is.na(overlayLimits))) {
myquants <- overlayLimits
overlay[overlay < myquants[1]] <- 0
overlay[overlay > myquants[2]] <- myquants[2]
if (verbose) print(myquants)
}
kblob <- thresholdImage(wms, myquants[1], Inf)
kblobfn <- tempfile(fileext = ".nii.gz")
antsImageWrite(kblob, kblobfn)
overlayfn <- tempfile(fileext = ".nii.gz")
antsImageWrite(overlay, overlayfn)
csvlutfn <- tempfile(fileext = ".csv")
overlayrgbfn <- tempfile(fileext = ".nii.gz")
if (verbose) print(colormap[ct])
cvtcmd <- paste(
cvt, " 3 ", overlayfn, overlayrgbfn,
kblobfn, colormap[ct], " none ", myquants[1], myquants[2], " 0 255", csvlutfn
)
sss <- system(cvtcmd)
if (verbose) print(cvtcmd)
if (verbose) cat("\n")
assvcmd <- paste(assvcmd, "-f [ ", overlayrgbfn, ", ", kblobfn, " ] ")
}
}
if (is.na(filename)) {
assvcmd <- paste(
assvcmd,
" -d [", magnificationFactor, ",", paste(rotationParams[myrot, ], collapse = "x"), ",255x255x255] "
)
} else {
pngext <- myrot
if (myrot < 10) pngext <- paste("0", pngext, sep = "")
if (myrot < 100) pngext <- paste("0", pngext, sep = "")
pngfnloc <- paste(filename, pngext, ".png", sep = "")
system(paste("rm", pngfnloc))
assvcmd <- paste(assvcmd, " -d ", pngfnloc,
"[", magnificationFactor, ",",
paste(rotationParams[myrot, ], collapse = "x"), ",255x255x255] ",
sep = ""
)
}
if (verbose) print(assvcmd)
sss <- system(assvcmd)
if (nrow(rotationParams) > 1) pngs[myrot] <- pngfnloc
}
if (nrow(rotationParams) > 1) {
mypng <- png::readPNG(pngs[1])
for (i in 2:length(pngs))
{
mypng <- abind::abind(mypng, png::readPNG(pngs[i]), along = 2)
}
png(paste(filename, ".png", sep = ""), width = dim(mypng)[2], height = dim(mypng)[1])
grid::grid.raster(mypng)
dev.off()
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.