R/ellipsoid_body.R

Defines functions ellipsoid_body

Documented in ellipsoid_body

#' @title Coarse Masking of Image from Z-slicding
#' @description Calculates an Ellipsoid at each slice then stacks them
#'
#' @param x Binary \code{antsImage}
#'
#' @return Array or \code{antsImage} object
#' @export
#' @importFrom ANTsRCore is.antsImage
#' @importFrom stats cov
ellipsoid_body = function(x) {
  bb = as.array(x)
  dimg = dim(bb)
  number_slices = dimg[3]
  dslice = dimg[1:2]
  omat = array(FALSE, dim = dimg)

  # get values that are true for ellipse
  ind = which(bb > 0, arr.ind = TRUE)
  L = lapply(dslice, seq)
  # same for all slices
  X = as.matrix(expand.grid(L))

  # need df for split
  ind = as.data.frame(ind)
  ps = split(ind, ind[,3])
  ps = lapply(ps, function(x){
    as.matrix(x[, 1:2])
  })
  # Getting mu/sigma for ellipse
  vals = lapply(ps, function(x){
    L = list(mu = colMeans(x),
             Sigma = cov(x))
  })
  # Taken from SIBER, but faster because no looping over solve
  pointsToEllipsoid2 = function(X, Sigma, mu) {
    eig <- eigen(Sigma)
    SigSqrt = eig$vectors %*% diag(sqrt(eig$values)) %*% t(eig$vectors)
    xtx = t(SigSqrt) %*% SigSqrt
    ss = solve(xtx)
    xx = t(t(X) - mu)
    Z = ss %*% t(SigSqrt) %*% t(xx)
    Z = t(Z)
  }
  # Taken from SIBER
  ellipseInOut2 = function(Z, p = 0.95, radius = NULL) {
    if (is.null(radius)) {
      radius <- stats::qchisq(p, df = ncol(Z))
    }
    inside <- rowSums(Z^2) < radius
    return(inside)
  }
  for ( i in seq(number_slices)) {
    x = vals[[i]]
    Z = pointsToEllipsoid2(X, Sigma = x$Sigma, mu = x$mu)
    inside = ellipseInOut2(Z = Z, p = 0.95)
    mat = array(inside, dim = dslice)
    omat[,,i] = mat
  }
  if (is.antsImage(x)) {
    omat = as.antsImage(omat, reference = x)
  }
  return(omat)
}
neuroconductor-devel/lungct documentation built on April 1, 2021, 4:40 a.m.