#' @title Image Convolution with Kernel
#'
#' @description \code{filter2D} applies an arbitrary linear filter to an image.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param kernel A matrix representing the convolution kernel.
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @note For color images, the same kernel is applied to each channel of the
#' image. If you want to apply different kernels to each channel, first split
#' the image into separate channels with the \code{\link{split}} and process
#' them individually before merging them using the \code{\link{merge}} function.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' k_edge_detection <- matrix(c(-1, -1, -1, -1, 8, -1, -1, -1, -1), nrow = 3)
#' balloon_edge <- filter2D(balloon, k_edge_detection)
#'
#' @export
filter2D <- function(image, kernel, target = "new", in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (!is.matrix(kernel))
stop("'kernel' must be a matrix.")
if (isImage(target)) {
`_filter2D`(image, kernel, target)
} else if (target == "self") {
`_filter2D`(image, kernel, image)
} else if (target == "new") {
out <- cloneImage(image)
`_filter2D`(image, kernel, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Image Filtering with a Separable Linear Filter
#'
#' @description \code{sepFilter2D} applies a separable linear filter to an image.
#' First, every row of the image is filtered with the 1D kernel \code{kernel_x}.
#' Then, every column of the result is filtered with the 1D kernel \code{kernel_y}.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param kernel_x A vector representing the kernel along the x axis.
#'
#' @param kernel_y A vector representing the kernel along the y axis.
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @note For color images, the same kernel is applied to each channel of the
#' image. If you want to apply different kernels to each channel, first split
#' the image into separate channels with the \code{\link{split}} and process
#' them individually before merging them using the \code{\link{merge}} function.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}, \code{\link{filter2D}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' k_edge_detection_x <- c(1, 2, 1)
#' k_edge_detection_y <- c(1, 0, -1)
#' balloon_edge <- sepFilter2D(balloon, k_edge_detection_x, k_edge_detection_y)
#'
#' @export
sepFilter2D <- function(image, kernel_x, kernel_y, target = "new", in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (isImage(target)) {
`_sepFilter2D`(image, kernel_x, kernel_y, target)
} else if (target == "self") {
`_sepFilter2D`(image, kernel_x, kernel_y, image)
} else if (target == "new") {
out <- cloneImage(image)
`_sepFilter2D`(image, kernel_x, kernel_y, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Blurs an Image Using a Gaussian Filter
#'
#' @description \code{gaussianBlur} convolves the source image with the
#' specified Gaussian kernel. The result is a blurred version of the source
#' image.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param k_height The half-height in pixels of the kernel (default: 5).
#'
#' @param k_width The half-width in pixels of the kernel (default: 5).
#'
#' @param sigma_x The standard deviation of the kernel along the x axis
#' (default: 1).
#'
#' @param sigma_y The standard deviation of the kernel along the y axis
#' (default: 1).
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}, \code{\link{boxFilter}}, \code{\link{blur}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_blur <- gaussianBlur(balloon, 11, 11, 5, 5)
#'
#' @export
gaussianBlur <- function(image, k_height = 5, k_width = 5, sigma_x = 1,
sigma_y = 1, target = "new", in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (isImage(target)) {
`_gaussianBlur`(image, k_height, k_width, sigma_x, sigma_y, target)
} else if (target == "self") {
`_gaussianBlur`(image, k_height, k_width, sigma_x, sigma_y, image)
} else if (target == "new") {
out <- cloneImage(image)
`_gaussianBlur`(image, k_height, k_width, sigma_x, sigma_y, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Blurs an Image Using a Box Filter
#'
#' @description \code{boxFilter} convolves the source image with the
#' specified box kernel (a matrix of 1s). The result is a blurred version of
#' the source image.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param k_height The half-height in pixels of the kernel (default: 5).
#'
#' @param k_width The half-width in pixels of the kernel (default: 5).
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}, \code{\link{blur}}, \code{\link{gaussianBlur}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_blur <- boxFilter(balloon, 11, 11)
#'
#' @export
boxFilter <- function(image, k_height = 5, k_width = 5, target = "new", in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (isImage(target)) {
`_boxFilter`(image, k_height, k_width, target)
} else if (target == "self") {
`_boxFilter`(image, k_height, k_width, image)
} else if (target == "new") {
out <- cloneImage(image)
`_boxFilter`(image, k_height, k_width, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Blurs an Image Using a Normalized Box Filter
#'
#' @description \code{blur} convolves the source image with the specified
#' normalized box kernel (a matrix of 1s divided by the number of pixels in the
#' kernel). The result is a blurred version of the source image.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param k_height The half-height in pixels of the kernel (default: 5).
#'
#' @param k_width The half-width in pixels of the kernel (default: 5).
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}, \code{\link{boxFilter}}, \code{\link{gaussianBlur}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_blur <- blur(balloon, 11, 11)
#'
#' @export
blur <- function(image, k_height = 5, k_width = 5, target = "new", in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (isImage(target)) {
`_blur`(image, k_height, k_width, target)
} else if (target == "self") {
`_blur`(image, k_height, k_width, image)
} else if (target == "new") {
out <- cloneImage(image)
`_blur`(image, k_height, k_width, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Blurs an Image Using a Median Filter
#'
#' @description \code{medianBlur} smoothes an image using a median filter, i.e.
#' the value of each pixel is replaced by the median value of all the pixels in
#' its neighborhood.
#'
#' @param image An 8-bit (8U) \code{\link{Image}} object.
#'
#' @param k_size The half-size in pixels of the kernel (default: 5).
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}, \code{\link{gaussianBlur}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_blur <- medianBlur(balloon, 11)
#'
#' @export
medianBlur <- function(image, k_size = 5, target = "new", in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (image$depth() != "8U")
stop("This is not an 8-bit (8U) Image object.")
if (isImage(target)) {
`_medianBlur`(image, k_size, target)
} else if (target == "self") {
`_medianBlur`(image, k_size, image)
} else if (target == "new") {
out <- cloneImage(image)
`_medianBlur`(image, k_size, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Blurs an Image Using a Square Box Filter
#'
#' @description \code{sqrBoxFilter} calculates the normalized and unnormalized
#' sum of squares of the pixels in a box surrounding focal pixel. The result is
#' a blurred version of the source image.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param k_height The half-height in pixels of the kernel (default: 5).
#'
#' @param k_width The half-width in pixels of the kernel (default: 5).
#'
#' @param normalize Whether the kernel is to be normalized by its area (default:
#' true).
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}, \code{\link{boxFilter}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_blur <- sqrBoxFilter(balloon, 11, 11)
#'
#' @export
sqrBoxFilter <- function(image, k_height = 5, k_width = 5, normalize = TRUE,
target = "new", in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (isImage(target)) {
`_sqrBoxFilter`(image, k_height, k_width, normalize, target)
} else if (target == "self") {
`_sqrBoxFilter`(image, k_height, k_width, normalize, image)
} else if (target == "new") {
out <- cloneImage(image)
`_sqrBoxFilter`(image, k_height, k_width, normalize, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Calculates an Image Derivatives Using a Scharr Operator
#'
#' @description \code{scharr} calculates the x or y derivative of an image using
#' a Scharr operator.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param dx Order of the x derivative. It can only take 2 values: 1 (the
#' default) or 0. If \code{dx=1} then \code{dy} must be zero.
#'
#' @param dy Order of the y derivative. It can only take 2 values: 1 or 0 (the
#' default). If \code{dy=1} then \code{dx} must be zero.
#'
#' @param scale The scale factor for the computed derivative values (default: 1).
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}, \code{\link{sobel}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_scharr <- scharr(balloon)
#'
#' @export
scharr <- function(image, dx = 1, dy = 0, scale = 1, target = "new", in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (!(dx >= 0 & dy >= 0 & dx+dy == 1))
stop("One of dx and dy must be 1. The other must be 0.")
if (isImage(target)) {
`_scharr`(image, dx, dy, scale, target)
} else if (target == "self") {
`_scharr`(image, dx, dy, scale, image)
} else if (target == "new") {
out <- cloneImage(image)
`_scharr`(image, dx, dy, scale, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Calculates an Image Derivatives Using an Extended Sobel Operator
#'
#' @description \code{sobel} calculates the first, second, third, or mixed image
#' derivatives of an image using an extended Sobel operator.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param dx Order of the x derivative (default: 1).
#'
#' @param dy Order of the y derivative (default: 1),
#'
#' @param k_size The half-size in pixels of the kernel (default: 5).
#'
#' @param scale The scale factor for the computed derivative values (default: 1).
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}, \code{\link{laplacian}}, \code{\link{scharr}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_sobel <- sobel(balloon)
#'
#' @export
sobel <- function(image, dx = 1, dy = 1, k_size = 5, scale = 1, target = "new",
in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (isImage(target)) {
`_sobel`(image, dx, dy, k_size, scale, target)
} else if (target == "self") {
`_sobel`(image, dx, dy, k_size, scale, image)
} else if (target == "new") {
out <- cloneImage(image)
`_sobel`(image, dx, dy, k_size, scale, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Calculates the Laplacian of an Image
#'
#' @description \code{laplacian} calculates the Laplacian of the source image by
#' adding up the second x and y derivatives calculated using the Sobel operator.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param k_size The half-size in pixels of the kernel (default: 5).
#'
#' @param scale The scale factor for the computed Laplacian values (default: 1).
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}, \code{\link{sobel}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_laplacian <- laplacian(balloon, 5)
#'
#' @export
laplacian <- function(image, k_size = 5, scale = 1, target = "new", in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (isImage(target)) {
`_laplacian`(image, k_size, scale, target)
} else if (target == "self") {
`_laplacian`(image, k_size, scale, image)
} else if (target == "new") {
out <- cloneImage(image)
`_laplacian`(image, k_size, scale, out)
out
} else {
stop("Invalid target.")
}
}
#' @title First Order Derivatives of an Image with the Sobel Operator
#'
#' @description \code{spatialGradient} calculates the first order derivative of
#' an image in both x and y using a Sobel operator.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param k_size The half-size in pixels of the kernel (default: 5).
#'
#' @return A list containing two \code{\link{Image}} objects, one of for the
#' derivative along the x axis and the other for the derivative along the y axis.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}, \code{\link{sobel}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_gradient <- spatialGradient(balloon, 5)
#'
#' @export
spatialGradient <- function(image, k_size = 5) {
if (!isImage(image))
stop("This is not an Image object.")
list(dx = sobel(image, dx = 1, dy = 0, k_size),
dy = sobel(image, dx = 0, dy = 1, k_size))
}
#' @title Edge-Preserving Noise Reduction with a Bilateral Filter
#'
#' @description \code{bilateralFilter} applies the bilateral filter to an image.
#' This filter can reduce unwanted noise very well while keeping edges fairly
#' sharp. However, it is very slow compared to most filters.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param d The diameter in pixels of the filter neighborhood (default: 5).
#'
#' @param sigma_color The filter standard deviation in the color space
#' (see Note; default: 25).
#'
#' @param sigma_space The filter standard deviation in the coordinate space
#' (see Note; default: 25).
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target} is an \code{\link{Image}} object, the function
#' returns nothing and modifies that \code{\link{Image}} object in place.
#'
#' @note A larger value of \code{sigma_color} means that farther colors within
#' the pixel neighborhood will be mixed together, resulting in larger areas of
#' semi-equal color.
#'
#' @note A larger value of \code{sigma_space} means that farther pixels will
#' influence each other as long as their colors are close enough. When
#' \code{d > 0}, it specifies the neighborhood size regardless of
#' \code{sigma_space}. Otherwise, \code{d} is proportional to \code{sigma_space}.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}, \code{\link{gaussianBlur}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' rnd <- image(array(sample(0:30, nrow(balloon) * ncol(balloon), replace = TRUE),
#' dim = c(nrow(balloon), ncol(balloon), 3)))
#' changeBitDepth(rnd, "8U", target = "self")
#' balloon_noisy <- balloon + rnd
#' balloon_bilateral <- bilateralFilter(balloon_noisy, 25)
#'
#' @export
bilateralFilter <- function(image, d = 5, sigma_color = 25, sigma_space = 25,
target = "new") {
if (!isImage(image))
stop("'image' must be an Image object.")
if (!(image$nchan() %in% c(1, 3)))
stop("'image' must be an Image object with 1 or 3 channels only.")
if (isImage(target)) {
`_bilateralFilter`(image, d, sigma_color, sigma_space, target)
} else if (target == "new") {
out <- cloneImage(image)
`_bilateralFilter`(image, d, sigma_color, sigma_space, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Adaptive Thresholding
#'
#' @description \code{adaptiveThreshold} transforms a grayscale image to a
#' binary image using an adaptive threshold.
#'
#' @param image An an 8-bit (8U) single-channel \code{\link{Image}} object.
#'
#' @param max_value Non-zero value assigned to the pixels for which the
#' condition determined by `threshold_type` is satisfied (default: 255).
#'
#' @param method The name of the adaptive thresholding algorithm to use. It can
#' be either 'mean' - mean of the block_size * block_size neighborhood - or
#' 'gaussian' - Gaussian weighted sum of the block_size * block_size
#' neighborhood (default: 'mean').
#'
#' @param threshold_type The name of the threshold type to use. It can be either
#' 'binary' or 'inverse' (default: 'inverse'). If 'binary', each pixel is replaced
#' by `max_value` if its value is above the adaptive threshold, and by zero
#' otherwise. If 'inverse' each pixel is replaced by zero if its value is above
#' the adaptive threshold, and by `max_value` otherwise.
#'
#' @param block_size Size of a pixel neighborhood that is used to calculate a
#' threshold value for the pixel (default: 31). It must be an odd number
#' greater than 1.
#'
#' @param C Constant subtracted from the mean or weighted mean. Normally, it is
#' positive but may be zero or negative as well (default: 25).
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_gray <- changeColorSpace(balloon, "GRAY")
#' balloon_th <- adaptiveThreshold(balloon_gray)
#'
#' @export
adaptiveThreshold <- function(image, max_value = 255, method = "mean",
threshold_type = "inverse", block_size = 31, C = 25,
target = "new", in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (image$nchan() != 1 || image$depth() != "8U")
stop("'image' must be an 8-bit (8U) single-channel Image object.")
if (max_value <= 0)
stop("'max_value' must be a positive, non-zero value.")
if (!(method %in% c("mean", "gaussian")))
stop("'method' must be either 'mean' or 'gaussian'.")
if (!(threshold_type %in% c("binary", "inverse")))
stop("'threshold_type' must be either 'binary' or 'inverse'.")
if ((block_size %% 2 != 1) | (block_size < 2))
stop("'block_size' must be an odd number greater than 1.")
if (isImage(target)) {
`_adaptiveThreshold`(image, max_value, if (method == "mean") 0 else 1,
if (threshold_type == "binary") 0 else 1,
block_size, C, target)
} else if (target == "self") {
`_adaptiveThreshold`(image, max_value, if (method == "mean") 0 else 1,
if (threshold_type == "binary") 0 else 1,
block_size, C, image)
} else if (target == "new") {
out <- cloneImage(image)
`_adaptiveThreshold`(image, max_value, if (method == "mean") 0 else 1,
if (threshold_type == "binary") 0 else 1,
block_size, C, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Thresholding
#'
#' @description \code{threshold} transforms an image to a binary image.
#'
#' @param image An an 8-bit (8U) or 32-bit floating (32F) \code{\link{Image}}
#' object.
#'
#' @param thresh A numeric threshold value (default: 127).
#'
#' @param max_value Non-zero value assigned to the pixels for which the
#' condition determined by `threshold_type` is satisfied (default: 255). It is
#' used only if \code{threshold_type} is set to "binary" or "inverse".
#'
#' @param method The name of the automated thresholding algorithm to use. It can
#' be any of the following:
#' \itemize{
#' \item{"none":}{the user-defined `threshold` value is used (the default).}
#' \item{"ImageJ":}{the default auto thresholding algorithm of ImageJ.}
#' \item{"Huang":}{Huang’s fuzzy thresholding method.}
#' \item{"Huang2":}{alternative implementation of Huang’s method by J. Schindelin.}
#' \item{"Intermodes":}{assuming a bimodal histogram, the threshold is the
#' halfway point between the two modes.}
#' \item{"IsoData":}{iterative procedure based on the isodata algorithm of
#' Ridler and Calvar.}
#' \item{"Li":}{Li’s Minimum Cross Entropy thresholding method based on the
#' iterative version of the algorithm.}
#' \item{"MaxEntropy":}{Kapur-Sahoo-Wong (Maximum Entropy) thresholding method.}
#' \item{"Mean":}{the mean of grey levels of the image is used as the threshold.}
#' \item{"MinErrorI":}{an iterative implementation of Kittler and Illingworth’s
#' Minimum Error thresholding.}
#' \item{"Minimum":}{similar to the Intermodes method but the threshold is the
#' minimum value between the two modes after iterative smoothing.}
#' \item{"Moments":}{Tsai’s moment-preserving thresolding method.}
#' \item{"Otsu":}{Otsu’s threshold clustering method.}
#' \item{"Percentile":}{assumes the fraction of foreground pixels to be 0.5.}
#' \item{"RenyiEntropy":}{similar to the MaxEntropy method, but using Renyi’s
#' entropy instead.}
#' \item{"Shanbhag":}{Shanbhag's information-based thresolding method.}
#' \item{"Triangle":}{the triangle thresholding method by Zack, Rogers, and Latt.}
#' \item{"Yen":}{Yen’s thresholding method.}
#' }
#' Details about the functioning of each method can be found at
#' \url{https://imagej.net/plugins/auto-threshold}.
#'
#' @param threshold_type The name of the threshold type to use. It can be any of
#' the following:
#' \itemize{
#' \item{"binary":}{each pixel is replaced by `max_value` if its value is above
#' the threshold, and by zero otherwise (the default).}
#' \item{"inverse":}{each pixel is replaced by zero if its value is above the
#' threshold, and by `max_value` otherwise.}
#' \item{"truncate":}{each pixel is replaced by `threshold` if its value is
#' above the threshold, and is unchanged otherwise.}
#' \item{"to_zero":}{each pixel is replaced by zero if its value is below the
#' threshold, and is unchanged otherwise.}
#' \item{"to_zero_inverse":}{each pixel is replaced by zero if its value is
#' above the threshold, and is unchanged otherwise.}
#' }
#'
#' @param mask A single-channel (GRAY) 8-bit (8U) \code{\link{Image}} object
#' with the same dimensions as \code{image}. This can be used to mask out
#' pixels that should not be considered when calculating the threshold (pixels
#' set to 0 in the mask will be ignored during the threshold calculation).
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @references \itemize{ \item{Huang, L-K & Wang, M-J J (1995), "Image
#' thresholding by minimizing the measure of fuzziness", Pattern Recognition
#' 28(1): 41-51} \item{Prewitt, JMS & Mendelsohn, ML (1966), "The analysis of
#' cell images", Annals of the New York Academy of Sciences 128: 1035-1053}
#' \item{Ridler, TW & Calvard, S (1978), "Picture thresholding using an
#' iterative selection method", IEEE Transactions on Systems, Man and
#' Cybernetics 8: 630-632} \item{Li, CH & Lee, CK (1993), "Minimum Cross
#' Entropy Thresholding", Pattern Recognition 26(4): 617-625} \item{Li, CH &
#' Tam, PKS (1998), "An Iterative Algorithm for Minimum Cross Entropy
#' Thresholding", Pattern Recognition Letters 18(8): 771-776} \item{Sezgin, M
#' & Sankur, B (2004), "Survey over Image Thresholding Techniques and
#' Quantitative Performance Evaluation", Journal of Electronic Imaging 13(1):
#' 146-165} \item{Kapur, JN; Sahoo, PK & Wong, ACK (1985), "A New Method for
#' Gray-Level Picture Thresholding Using the Entropy of the Histogram",
#' Graphical Models and Image Processing 29(3): 273-285} \item{Glasbey, CA
#' (1993), "An analysis of histogram-based thresholding algorithms", CVGIP:
#' Graphical Models and Image Processing 55: 532-537} \item{Kittler, J &
#' Illingworth, J (1986), "Minimum error thresholding", Pattern Recognition
#' 19: 41-47} \item{Prewitt, JMS & Mendelsohn, ML (1966), "The analysis of
#' cell images", Annals of the New York Academy of Sciences 128: 1035-1053}
#' \item{Tsai, W (1985), "Moment-preserving thresholding: a new approach",
#' Computer Vision, Graphics, and Image Processing 29: 377-393} \item{Otsu, N
#' (1979), "A threshold selection method from gray-level histograms", IEEE
#' Trans. Sys., Man., Cyber. 9: 62-66, doi:10.1109/TSMC.1979.4310076}
#' \item{Doyle, W (1962), "Operation useful for similarity-invariant pattern
#' recognition", Journal of the Association for Computing Machinery 9:
#' 259-267, doi:10.1145/321119.321123} \item{Kapur, JN; Sahoo, PK & Wong, ACK
#' (1985), "A New Method for Gray-Level Picture Thresholding Using the Entropy
#' of the Histogram", Graphical Models and Image Processing 29(3): 273-285}
#' \item{Shanbhag, Abhijit G. (1994), "Utilization of information measure as a
#' means of image thresholding", Graph. Models Image Process. (Academic Press,
#' Inc.) 56 (5): 414--419, ISSN 1049-9652} \item{Zack GW, Rogers WE, Latt SA
#' (1977), "Automatic measurement of sister chromatid exchange frequency", J.
#' Histochem. Cytochem. 25 (7): 74153, PMID 70454} \item{Yen JC, Chang FJ,
#' Chang S (1995), "A New Criterion for Automatic Multilevel Thresholding",
#' IEEE Trans. on Image Processing 4 (3): 370-378, ISSN 1057-7149,
#' doi:10.1109/83.366472} \item{Sezgin, M & Sankur, B (2004), "Survey over
#' Image Thresholding Techniques and Quantitative Performance Evaluation",
#' Journal of Electronic Imaging 13(1): 146-165} }
#'
#' @section Acknowledgements: Gabriel Landini coded all of these functions in
#' Java. These java functions were then translated to C++ by Rory Nolan.
#'
#' @seealso \code{\link{Image}}, \code{\link{autothreshold}},
#' \code{\link{niBlackThreshold}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_gray <- changeColorSpace(balloon, "GRAY")
#' balloon_th <- threshold(balloon_gray)
#'
#' @export
threshold <- function(image, thresh = 127, max_value = 255, method = "none",
threshold_type = "binary", mask = NULL, target = "new",
in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (!(image$depth() %in% c("8U", "32F")))
stop("'image' must be an 8-bit (8U) or 32-bit floating (32F) Image object.")
if (max_value <= 0)
stop("'max_value' must be a positive, non-zero value.")
if (!is.numeric(thresh))
stop("'thresh' must be a numeric value.")
if (method != "none") {
r <- c(floor(min(min(image))), ceiling(max(max(image)) + 1))
n <- diff(r) + 1
m <- imhist(image, mask = mask, nbins = n, range = r)
dt <- apply(m[, 2:ncol(m), drop = FALSE], 1, sum)
minimum <- m[min(which(dt != 0)), 1]
dt <- dt[min(which(dt != 0)):max(which(dt != 0))]
}
thresh <- switch(method,
none = thresh,
ImageJ = `_autothreshIJ`(dt) + minimum,
Huang = `_autothreshHuang`(dt) + minimum,
Huang2 = `_autothreshHuang2`(dt) + minimum,
Intermodes = `_autothreshIM`(dt) + minimum,
IsoData = `_autothreshIsoData`(dt) + minimum,
Li = `_autothreshLi`(dt) + minimum,
MaxEntropy = `_autothreshME`(dt) + minimum,
Mean = `_autothreshMean`(dt) + minimum,
MinErrorI = `_autothreshMinErrorI`(dt) + minimum,
Minimum = `_autothreshMinimum`(dt) + minimum,
Moments = `_autothreshMoments`(dt) + minimum,
Otsu = `_autothreshOtsu`(dt) + minimum,
Percentile = `_autothreshPercentile`(dt) + minimum,
RenyiEntropy = `_autothreshRenyiEntropy`(dt) + minimum,
Shanbhag = `_autothreshShanbhag`(dt) + minimum,
Triangle = `_autothreshTriangle`(dt) + minimum,
Yen = `_autothreshYen`(dt) + minimum,
stop("This is not a valid method."))
t_type <- switch(threshold_type,
binary = 0,
inverse = 1,
truncate = 2,
to_zero = 3,
to_zero_inverse = 4,
stop("This is not a valid threshold type."))
if (isImage(target)) {
void <- `_threshold`(image, thresh, max_value, t_type, target)
} else if (target == "self") {
void <- `_threshold`(image, thresh, max_value, t_type, image)
} else if (target == "new") {
out <- cloneImage(image)
void <- `_threshold`(image, thresh, max_value, t_type, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Automated Thresholding
#'
#' @description \code{autothreshold} computes the threshold for binarizing an
#' image using an automated method.
#'
#' @param image An an 8-bit (8U) or 32-bit floating (32F) \code{\link{Image}}
#' object.
#'
#' @param method The name of the automated thresholding algorithm to use. It can
#' be any of the following:
#' \itemize{
#' \item{"none":}{the user-defined `threshold` value is used (the default).}
#' \item{"ImageJ":}{the default auto thresholding algorithm of ImageJ.}
#' \item{"Huang":}{Huang’s fuzzy thresholding method.}
#' \item{"Huang2":}{alternative implementation of Huang’s method by J. Schindelin.}
#' \item{"Intermodes":}{assuming a bimodal histogram, the threshold is the
#' halfway point between the two modes.}
#' \item{"IsoData":}{iterative procedure based on the isodata algorithm of
#' Ridler and Calvar.}
#' \item{"Li":}{Li’s Minimum Cross Entropy thresholding method based on the
#' iterative version of the algorithm.}
#' \item{"MaxEntropy":}{Kapur-Sahoo-Wong (Maximum Entropy) thresholding method.}
#' \item{"Mean":}{the mean of grey levels of the image is used as the threshold.}
#' \item{"MinErrorI":}{an iterative implementation of Kittler and Illingworth’s
#' Minimum Error thresholding.}
#' \item{"Minimum":}{similar to the Intermodes method but the threshold is the
#' minimum value between the two modes after iterative smoothing.}
#' \item{"Moments":}{Tsai’s moment-preserving thresolding method.}
#' \item{"Otsu":}{Otsu’s threshold clustering method.}
#' \item{"Percentile":}{assumes the fraction of foreground pixels to be 0.5.}
#' \item{"RenyiEntropy":}{similar to the MaxEntropy method, but using Renyi’s
#' entropy instead.}
#' \item{"Shanbhag":}{Shanbhag's information-based thresolding method.}
#' \item{"Triangle":}{the triangle thresholding method by Zack, Rogers, and Latt.}
#' \item{"Yen":}{Yen’s thresholding method.}
#' }
#' Details about the functioning of each method can be found at
#' \url{https://imagej.net/plugins/auto-threshold}.
#'
#' @param mask A single-channel (GRAY) 8-bit (8U) \code{\link{Image}} object
#' with the same dimensions as \code{image}. This can be used to mask out
#' pixels that should not be considered when calculating the threshold (pixels
#' set to 0 in the mask will be ignored during the threshold calculation).
#'
#' @return A numerical value.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @references \itemize{ \item{Huang, L-K & Wang, M-J J (1995), "Image
#' thresholding by minimizing the measure of fuzziness", Pattern Recognition
#' 28(1): 41-51} \item{Prewitt, JMS & Mendelsohn, ML (1966), "The analysis of
#' cell images", Annals of the New York Academy of Sciences 128: 1035-1053}
#' \item{Ridler, TW & Calvard, S (1978), "Picture thresholding using an
#' iterative selection method", IEEE Transactions on Systems, Man and
#' Cybernetics 8: 630-632} \item{Li, CH & Lee, CK (1993), "Minimum Cross
#' Entropy Thresholding", Pattern Recognition 26(4): 617-625} \item{Li, CH &
#' Tam, PKS (1998), "An Iterative Algorithm for Minimum Cross Entropy
#' Thresholding", Pattern Recognition Letters 18(8): 771-776} \item{Sezgin, M
#' & Sankur, B (2004), "Survey over Image Thresholding Techniques and
#' Quantitative Performance Evaluation", Journal of Electronic Imaging 13(1):
#' 146-165} \item{Kapur, JN; Sahoo, PK & Wong, ACK (1985), "A New Method for
#' Gray-Level Picture Thresholding Using the Entropy of the Histogram",
#' Graphical Models and Image Processing 29(3): 273-285} \item{Glasbey, CA
#' (1993), "An analysis of histogram-based thresholding algorithms", CVGIP:
#' Graphical Models and Image Processing 55: 532-537} \item{Kittler, J &
#' Illingworth, J (1986), "Minimum error thresholding", Pattern Recognition
#' 19: 41-47} \item{Prewitt, JMS & Mendelsohn, ML (1966), "The analysis of
#' cell images", Annals of the New York Academy of Sciences 128: 1035-1053}
#' \item{Tsai, W (1985), "Moment-preserving thresholding: a new approach",
#' Computer Vision, Graphics, and Image Processing 29: 377-393} \item{Otsu, N
#' (1979), "A threshold selection method from gray-level histograms", IEEE
#' Trans. Sys., Man., Cyber. 9: 62-66, doi:10.1109/TSMC.1979.4310076}
#' \item{Doyle, W (1962), "Operation useful for similarity-invariant pattern
#' recognition", Journal of the Association for Computing Machinery 9:
#' 259-267, doi:10.1145/321119.321123} \item{Kapur, JN; Sahoo, PK & Wong, ACK
#' (1985), "A New Method for Gray-Level Picture Thresholding Using the Entropy
#' of the Histogram", Graphical Models and Image Processing 29(3): 273-285}
#' \item{Shanbhag, Abhijit G. (1994), "Utilization of information measure as a
#' means of image thresholding", Graph. Models Image Process. (Academic Press,
#' Inc.) 56 (5): 414--419, ISSN 1049-9652} \item{Zack GW, Rogers WE, Latt SA
#' (1977), "Automatic measurement of sister chromatid exchange frequency", J.
#' Histochem. Cytochem. 25 (7): 74153, PMID 70454} \item{Yen JC, Chang FJ,
#' Chang S (1995), "A New Criterion for Automatic Multilevel Thresholding",
#' IEEE Trans. on Image Processing 4 (3): 370-378, ISSN 1057-7149,
#' doi:10.1109/83.366472} \item{Sezgin, M & Sankur, B (2004), "Survey over
#' Image Thresholding Techniques and Quantitative Performance Evaluation",
#' Journal of Electronic Imaging 13(1): 146-165} }
#'
#' @section Acknowledgements: Gabriel Landini coded all of these functions in
#' Java. These java functions were then translated to C++ by Rory Nolan.
#'
#' @seealso \code{\link{Image}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_gray <- changeColorSpace(balloon, "GRAY")
#' th <- autothreshold(balloon_gray)
#'
#' @export
autothreshold <- function(image, method = "ImageJ", mask = NULL) {
if (!isImage(image))
stop("This is not an Image object.")
if (!(image$depth() %in% c("8U", "32F")))
stop("'image' must be an 8-bit (8U) or 32-bit floating (32F) Image object.")
r <- c(floor(min(min(image))), ceiling(max(max(image)) + 1))
n <- diff(r) + 1
m <- imhist(image, mask = mask, nbins = n, range = r)
dt <- apply(m[, 2:ncol(m), drop = FALSE], 1, sum)
minimum <- m[min(which(dt != 0)), 1]
dt <- dt[min(which(dt != 0)):max(which(dt != 0))]
switch(method,
ImageJ = `_autothreshIJ`(dt) + minimum,
Huang = `_autothreshHuang`(dt) + minimum,
Huang2 = `_autothreshHuang2`(dt) + minimum,
Intermodes = `_autothreshIM`(dt) + minimum,
IsoData = `_autothreshIsoData`(dt) + minimum,
Li = `_autothreshLi`(dt) + minimum,
MaxEntropy = `_autothreshME`(dt) + minimum,
Mean = `_autothreshMean`(dt) + minimum,
MinErrorI = `_autothreshMinErrorI`(dt) + minimum,
Minimum = `_autothreshMinimum`(dt) + minimum,
Moments = `_autothreshMoments`(dt) + minimum,
Otsu = `_autothreshOtsu`(dt) + minimum,
Percentile = `_autothreshPercentile`(dt) + minimum,
RenyiEntropy = `_autothreshRenyiEntropy`(dt) + minimum,
Shanbhag = `_autothreshShanbhag`(dt) + minimum,
Triangle = `_autothreshTriangle`(dt) + minimum,
Yen = `_autothreshYen`(dt) + minimum,
stop("This is not a valid method."))
}
#' @title Invert Colors
#'
#' @description \code{invert} returns an image which colors are the linear
#' inverse of that of the original image.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param target The location where the results should be stored. It can take 3
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{"self":}{the results are stored back into \code{image} (faster but
#' destructive).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same dimensions, number of channels, and
#' bit depth as \code{image}, an error may be thrown.}
#' }
#'
#' @param in_place Deprecated. Use \code{target} instead.
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target="self"}, the function returns nothing and modifies
#' \code{image} in place. If \code{target} is an \code{\link{Image}} object,
#' the function returns nothing and modifies that \code{\link{Image}} object in
#' place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{Image}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' balloon_inv <- invert(balloon)
#'
#' @export
invert <- function(image, target = "new", in_place = NULL) {
if (!missing(in_place)) {
if (in_place) {
warning("in_place is deprecated. Use target='self' instead.")
target <- "self"
} else {
warning("in_place is deprecated. Use target='new' instead.")
target <- "new"
}
}
if (!isImage(image))
stop("This is not an Image object.")
if (isImage(target)) {
`_not`(image, target)
} else if (target == "self") {
`_not`(image, image)
} else if (target == "new") {
out <- cloneImage(image)
`_not`(image, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Gabor Filter Kernels
#'
#' @description \code{getGaborKernel} is a convenience function to create Gabor
#' kernels that can be used to filter images with \code{\link{filter2D}}.
#'
#' @param width The width in pixels of the kernel (default: 31).
#'
#' @param height The height in pixels of the kernel (default: 31).
#'
#' @param sigma The standard deviation of the Gaussian envelope (default: 5).
#'
#' @param theta The orientation of the normal to the parallel stripes of a Gabor
#' function (default: \code{\link{pi}}).
#'
#' @param lambda The wavelength of the sinusoidal factor (default: 31).
#'
#' @param gamma The spatial aspect ratio (default: 5).
#'
#' @param psi A phase offset (default: 0).
#'
#' @return A matrix of Gabor coefficients.
#'
#' @note For more details about Gabor filter equations and parameters,
#' see: \href{https://en.wikipedia.org/wiki/Gabor_filter}{Gabor filter}.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{filter2D}}
#'
#' @examples
#' getGaborKernel()
#'
#' @export
getGaborKernel <- function(width = 31, height = 31, sigma = 5, theta = pi,
lambda = 31, gamma = 5, psi = 0) {
`_getGaborKernel`(width, height, sigma, theta, lambda, gamma, psi)
}
#' @title Structuring Elements
#'
#' @description \code{getStructuringElement} is a convenience function to create
#' structuring elements with defined shapes that can be used to filter images
#' with \code{\link{filter2D}}.
#'
#' @param k_shape A string corresponding to the shape of the structuring element.
#' Valid kernel shapes are:
#' \itemize{
#' \item{"rectangle" (the default):}{}
#' \item{"cross"}{}
#' \item{"ellipse"}{}
#' }
#'
#' @param k_height The half-height in pixels of the structuring element.
#'
#' @param k_width The half-width in pixels of the structuring element.
#'
#' @param anchor A 2-element numeric vector defining the anchor position within
#' the cross-shaped structuring element. The default value (−1,−1) means that
#' the anchor is at the center. Note that only the shape of a cross-shaped
#' kernel depends on the anchor position.
#'
#' @return A matrix of 0s and 1s.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{filter2D}}
#'
#' @examples
#' getStructuringElement()
#'
#' @export
getStructuringElement <- function(k_shape = "rectangle", k_height = 5, k_width = 5,
anchor = c(-1, -1)) {
sh <- switch(k_shape,
"rectangle" = 0,
"cross" = 1,
"ellipse" = 2,
stop("This is not a valid kernel shape"))
`_getStructuringElement`(sh, k_width, k_height, anchor[1], anchor[2])
}
#' @title Pyramid Downsampling
#'
#' @description \code{prDown} blurs an image and then downsamples it.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param target The location where the results should be stored. It can take 2
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same number of channels, and bit depth
#' as \code{image}, an error may be thrown. The dimensions of \code{target}
#' must satisfy the following conditions:
#' \itemize{
#' \item{}{\code{ abs(ncol(target) * 2 - ncol(image)) <= 2 }}
#' \item{}{\code{ abs(nrow(target) * 2 - nrow(image)) <= 2 }}
#' }
#' }
#' }
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target} is an \code{\link{Image}} object, the function
#' returns nothing and modifies that \code{\link{Image}} object in place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{pyrUp}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' small_balloon <- pyrDown(balloon)
#'
#' @export
pyrDown <- function(image, target = "new") {
if (!isImage(image))
stop("This is not an Image object.")
if (isImage(target)) {
if (target$nchan() != image$nchan() | target$depth() != image$depth())
stop("target is not of the same type and depth as image.")
`_pyrDown`(image, target)
} else if (target == "new") {
out <- resize(image, (image$nrow() + 1) / 2, (image$ncol() + 1) / 2)
`_pyrDown`(image, out)
out
} else {
stop("Invalid target.")
}
}
#' @title Pyramid Upsampling
#'
#' @description \code{prUp} upsamples an image and then blurs it.
#'
#' @param image An \code{\link{Image}} object.
#'
#' @param target The location where the results should be stored. It can take 2
#' values:
#' \itemize{
#' \item{"new":}{a new \code{\link{Image}} object is created and the results
#' are stored inside (the default).}
#' \item{An \code{\link{Image}} object:}{the results are stored in another
#' existing \code{\link{Image}} object. This is fast and will not replace the
#' content of \code{image} but will replace that of \code{target}. Note that
#' if \code{target} does not have the same number of channels, and bit depth
#' as \code{image}, an error may be thrown. The dimensions of \code{target}
#' must satisfy the following conditions:
#' \itemize{
#' \item{}{\code{ abs(ncol(target) - ncol(image) * 2) <= ncol(target) \%\% 2 }}
#' \item{}{\code{ abs(nrow(target) - nrow(image) * 2) <= nrow(target) \%\% 2 }}
#' }
#' }
#' }
#'
#' @return If \code{target="new"}, the function returns an \code{\link{Image}}
#' object. If \code{target} is an \code{\link{Image}} object, the function
#' returns nothing and modifies that \code{\link{Image}} object in place.
#'
#' @author Simon Garnier, \email{garnier@@njit.edu}
#'
#' @seealso \code{\link{pyrDown}}
#'
#' @examples
#' balloon <- image(system.file("sample_img/balloon1.png", package = "Rvision"))
#' big_balloon <- pyrUp(balloon)
#'
#' @export
pyrUp <- function(image, target = "new") {
if (!isImage(image))
stop("This is not an Image object.")
if (isImage(target)) {
if (target$nchan() != image$nchan() | target$depth() != image$depth())
stop("target is not of the same type and depth as image.")
`_pyrUp`(image, target)
} else if (target == "new") {
out <- zeros(image$nrow() * 2, image$ncol() * 2, image$nchan(),
image$depth(), image$space)
`_pyrUp`(image, out)
out
} else {
stop("Invalid target.")
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.