#' Apply transforms to images.
#'
#' Apply a transform list to map an image from one domain to another. In image
#' registration, one computes mappings between (usually) pairs of images.
#' These transforms are often a sequence of increasingly complex maps, e.g.
#' from translation, to rigid, to affine to deformation. The list of such
#' transforms is passed to this function to interpolate one image domain
#' into the next image domain, as below. The order matters strongly and the
#' user is advised to familiarize with the standards established in examples.
#'
#' @param fixed fixed image defining domain into which the moving image is
#' transformed.
#' @param moving moving image to be mapped to fixed space.
#' @param transformlist character vector of transforms generated by antsRegistration where
#' each transform is a filename.
#' @param interpolator Choice of interpolator. Supports partial matching.
#' \describe{
#' \item{linear}{}
#' \item{nearestNeighbor}{}
#' \item{multiLabel}{ for label images but genericlabel is preferred}
#' \item{gaussian}{}
#' \item{bSpline}{}
#' \item{cosineWindowedSinc}{}
#' \item{welchWindowedSinc}{}
#' \item{hammingWindowedSinc}{}
#' \item{lanczosWindowedSinc}{}
#' \item{genericLabel}{ use this for label images}
#' }
#' @param imagetype choose 0/1/2/3 mapping to scalar/vector/tensor/time-series
#' @param whichtoinvert optional list of booleans, same length as transforms.
#' whichtoinvert[i] is TRUE if transformlist[i] is a matrix, and the matrix should
#' be inverted. If transformlist[i] is a warp field, whichtoinvert[i] must be FALSE.
#'
#' If the transform list is a matrix followed by a warp field, whichtoinvert
#' defaults to c(TRUE,FALSE). Otherwise it defaults to rep(FALSE, length(transformlist)).
#' @param compose if it is a character string pointing to a valid file location,
#' this will force the function to return a composite transformation filename.
#' @param verbose print command and run verbose application of transform.
#' @param ... extra parameters
#' @return an antsImage or transformation filename is output. 1 -- Failure
#' @author Shrinidhi KL, Avants BB
#' @examples
#'
#' # will give the full form of help
#' antsApplyTransforms("-h")
#' # see antsRegistration
#' # example 1 - simplified
#' fixed <- ri(1)
#' moving <- ri(2)
#' fixed <- resampleImage(fixed, c(64, 64), 1, 0)
#' moving <- resampleImage(moving, c(68, 68), 1, 0)
#' mytx <- antsRegistration(
#' fixed = fixed, moving = moving,
#' typeofTransform = "SyN", verbose = TRUE, printArgs = TRUE
#' )
#' mywarpedimage <- antsApplyTransforms(
#' fixed = fixed, moving = moving,
#' transformlist = mytx$fwdtransforms
#' )
#' testthat::expect_true(antsImagePhysicalSpaceConsistency(mywarpedimage, fixed))
#' invwarped_image <- antsApplyTransforms(
#' fixed = moving, moving = fixed,
#' transformlist = mytx$invtransforms
#' )
#' testthat::expect_true(antsImagePhysicalSpaceConsistency(invwarped_image, moving))
#' # full access via listing the inputs in standard ANTs format
#'
#' res1 <- antsApplyTransforms(
#' fixed = fixed, moving = moving,
#' transformlist = mytx$fwdtransforms[2],
#' whichtoinvert = 1, verbose = TRUE
#' )
#' cfile <- antsApplyTransforms(
#' fixed = fixed, moving = moving,
#' transformlist = mytx$fwdtransforms,
#' compose = tempfile()
#' )
#' cimg <- antsImageRead(cfile)
#' cout <- antsApplyTransforms(
#' fixed = fixed, moving = moving,
#' transformlist = cimg
#' )
#' testthat::expect_error(
#' antsApplyTransforms(
#' fixed = fixed, moving = moving,
#' transformlist = cimg, whichtoinvert = 1
#' ), "nnot invert transform"
#' )
#' testthat::expect_error(
#' antsApplyTransforms(
#' fixed = fixed, moving = moving,
#' transformlist = cimg, whichtoinvert = c(1, 2)
#' ), "same length"
#' )
#' testthat::expect_error(antsApplyTransforms(
#' fixed = fixed, moving = moving,
#' transformlist = ""
#' ))
#'
#' @seealso \code{\link{antsRegistration}}
#' @export antsApplyTransforms
antsApplyTransforms <- function(
fixed,
moving,
transformlist = "",
interpolator = c(
"linear",
"nearestNeighbor",
"multiLabel",
"gaussian",
"bSpline",
"cosineWindowedSinc",
"welchWindowedSinc",
"hammingWindowedSinc",
"lanczosWindowedSinc",
"genericLabel"
),
imagetype = 0, whichtoinvert = NA,
compose = NA, verbose = FALSE, ...) {
if (is.character(fixed)) {
if (fixed == "-h") {
ANTsRCore::AntsApplyTransforms(.int_antsProcessArguments(
list("-h")
))
return()
}
}
if (missing(fixed) | missing(moving) | missing(transformlist)) {
print("missing inputs")
return(NA)
}
interpolator[1] <- paste(tolower(substring(interpolator[1], 1, 1)),
substring(interpolator[1], 2),
sep = "", collapse = " "
)
interpOpts <- c(
"linear",
"nearestNeighbor",
"multiLabel",
"gaussian",
"bSpline",
"cosineWindowedSinc",
"welchWindowedSinc",
"hammingWindowedSinc",
"lanczosWindowedSinc",
"genericLabel"
)
interpolator <- match.arg(interpolator, interpOpts)
# if (is.antsImage(moving)) {
# moving = antsImageClone(moving)
# }
# if (is.antsImage(fixed)) {
# fixed = antsImageClone(fixed)
# }
if (is.antsImage(transformlist)) {
warning("transformlist is an antsImage, creating a temporary file")
tfile <- tempfile(fileext = ".nii.gz")
antsImageWrite(transformlist, filename = tfile)
transformlist <- tfile
}
if (!is.character(transformlist)) {
warning("transformlist is not a character vector")
}
args <- list(fixed, moving, transformlist, interpolator, ...)
if (!is.character(fixed)) {
moving <- check_ants(moving)
if (fixed@class[[1]] == "antsImage" & moving@class[[1]] == "antsImage") {
for (i in 1:length(transformlist)) {
if (!file.exists(transformlist[i])) {
stop(paste("Transform ", transformlist[i], " does not exist.", sep = ""))
}
}
inpixeltype <- fixed@pixeltype
warpedmovout <- antsImageClone(moving)
f <- fixed
m <- moving
if ((moving@dimension == 4) & (fixed@dimension == 3) &
(imagetype == 0)) {
stop("Set imagetype 3 to transform time series images.")
}
mytx <- list()
# If whichtoinvert is NA, then attempt to guess the right thing to do
#
# If the transform list is (affine.mat, warp), whichtoinvert = c("T", "F")
#
# else whichtoinvert = rep("F", length(transformlist))
if (all(is.na(whichtoinvert))) {
if (length(transformlist) == 2 & grepl("\\.mat$", transformlist[1]) & !(grepl("\\.mat$", transformlist[2]))) {
whichtoinvert <- c(TRUE, FALSE)
} else {
whichtoinvert <- rep(FALSE, length(transformlist))
}
}
if (length(whichtoinvert) != length(transformlist)) {
stop("Transform list and inversion list must be the same length")
}
for (i in c(1:length(transformlist))) {
ismat <- FALSE
if (grepl("\\.mat$", transformlist[i]) || grepl("\\.txt$", transformlist[i])) {
ismat <- TRUE
}
if (whichtoinvert[i] && !(ismat)) {
# Can't invert a warp field, user should pass inverseWarp directly. Something wrong
stop(paste("Cannot invert transform ", i, " ( ", transformlist[i], " ), because it is not a matrix. ", sep = ""))
}
if (whichtoinvert[i]) {
mytx <- list(mytx, "-t", paste("[", transformlist[i], ",1]",
sep = ""
))
} else {
mytx <- list(mytx, "-t", transformlist[i])
}
}
if (is.na(compose)) {
args <- list(
d = fixed@dimension, i = m, o = warpedmovout, r = f, n = interpolator,
unlist(mytx)
)
}
tfn <- paste(compose, "comptx.nii.gz", sep = "")
if (!is.na(compose)) {
mycompo <- paste("[", tfn, ",1]", sep = "")
args <- list(
d = fixed@dimension, i = m, o = mycompo, r = f,
n = interpolator, unlist(mytx)
)
}
myargs <- .int_antsProcessArguments(c(args))
for (jj in c(1:length(myargs))) {
if (!is.na(myargs[jj])) {
if (myargs[jj] == "-") {
myargs2 <- rep(NA, (length(myargs) - 1))
myargs2[1:(jj - 1)] <- myargs[1:(jj - 1)]
myargs2[jj:(length(myargs) - 1)] <- myargs[(jj + 1):(length(myargs))]
myargs <- myargs2
}
}
}
myverb <- as.numeric(verbose)
if (verbose) print(myargs)
ANTsRCore::AntsApplyTransforms(c(myargs, "-z", 1, "-v", myverb, "--float", 1, "-e", imagetype))
if (is.na(compose)) {
return(antsImageClone(warpedmovout, inpixeltype))
}
if (!is.na(compose)) if (file.exists(tfn)) {
return(tfn)
} else {
return(NA)
}
}
# Get here if fixed, moving, transformlist are not missing, fixed is not of type character,
# and fixed and moving are not both of type antsImage
stop(paste0(
"fixed, moving, transformlist are not missing,",
" fixed is not of type character,",
" and fixed and moving are not both of type antsImage"
))
return(1)
}
# if ( Sys.info()['sysname'] == 'XXX' ) { mycmd<-.antsrParseListToString( c(args)
# ) system( paste('antsApplyTransforms ', mycmd$mystr ) ) return( antsImageRead(
# mycmd$outimg, as.numeric(mycmd$outdim) ) ) }
ANTsRCore::AntsApplyTransforms(.int_antsProcessArguments(
c(args, "-z", 1, "--float", 1, "-e", imagetype)
))
}
# .antsrParseListToString <- function(mylist, outimg = NA, outdim = NA) {
# mystr <- ""
# len <- length(mylist)
# outimg <- ""
# outdim <- 11
# for (x in 1:len) {
# if (is.antsImage(mylist[[x]])) {
# tfn <- paste(tempdir(), "img", x, ".nii.gz", sep = "")
# antsImageWrite(mylist[[x]], tfn)
# mystr <- paste(mystr, tfn)
# outdim <- mylist[[x]]@dimension
# if (typeof(mylist[[x - 1]]) == "character") {
# if (mylist[[x - 1]] == "-o")
# outimg <- tfn
# }
# if (typeof(mylist[[x - 1]]) != "S4")
# if (mylist[[x - 1]] == "-o")
# outimg <- tfn
# } else mystr <- paste(mystr, toString(mylist[[x]]))
# }
# mystr <- sub(",", " ", mystr)
# mystr <- sub(" - ", " ", mystr)
# mystr <- sub("-t,", "-t ", mystr)
# mystr <- sub(", ", " ", mystr)
# return(list(mystr = mystr, outimg = outimg, outdim = outdim))
# }
#
# ..antsrParseListToString2 <- function(mylist, outimg = NA, outdim = NA) {
# mystr <- ""
# outimg <- ""
# outdim <- 11
# len <- length(mylist)
# for (x in 1:len) {
# mystr <- paste(mystr, " -", names(mylist)[x], " ", sep = "")
# if (is.antsImage(mylist[[x]])) {
# tfn <- paste(tempdir(), "img", x, ".nii.gz", sep = "")
# antsImageWrite(mylist[[x]], tfn)
# mystr <- paste(mystr, tfn)
# outdim <- mylist[[x]]@dimension
# if (names(mylist)[x] == "o")
# outimg <- tfn
# } else mystr <- paste(mystr, toString(mylist[[x]]))
# }
# mystr <- sub(",", " ", mystr)
# mystr <- sub(" - ", " ", mystr)
# mystr <- sub("-t,", "-t ", mystr)
# mystr <- sub(", ", " ", mystr)
# return(list(mystr = mystr, outimg = outimg, outdim = outdim))
# }
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.