R/antsrSurf.R

Defines functions antsrVol antsrSurf

Documented in antsrSurf antsrVol

#' 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()
  }
}
stnava/ANTsR documentation built on April 16, 2024, 12:17 a.m.