Nothing
#'@title Render Convolution
#'
#'@description Takes an image and applies a convolution operation to it, using
#'a user-supplied or built-in kernel. Edges are calculated by limiting the size
#'of the kernel to only that overlapping the actual image (renormalizing the
#'kernel for the edges).
#'
#'@param image 3-layer RGB/4-layer RGBA array, `rayimg` class, or filename of an image.
#'@param filename Default `NULL`. The filename of the image to be saved. If this is not given, the image will be plotted instead.
#'@param kernel Default `gaussian`. By default, an 11x11 Gaussian kernel with a mean
#'of `0` and a standard deviation of `1`, running from `-kernel_extent` to `kernel_extent`.
#'If numeric, this will be the standard deviation of the normal distribution. If a
#'matrix, it will be used directly as the convolution kernel (but resized always to be an odd number
#'of columns and rows).
#'@param kernel_dim Default `11`. The dimension of the `gaussian` kernel. Ignored
#'if user specifies their own kernel.
#'@param kernel_extent Default `3`. Extent over which to calculate the kernel.
#'@param absolute Default `TRUE`. Whether to take the absolute value of the convolution.
#'@param min_value Default `NULL`. If numeric, specifies the minimum value (for any color channel)
#'for a pixel to have the convolution performed.
#'@param include_alpha Default `FALSE`. Whether to include the alpha channel in the convolution.
#'@param preview Default `TRUE`. Whether to plot the convolved image, or just to return the values.
#'@param progress Default `TRUE`. Whether to display a progress bar.
#'@return A `rayimg` RGBA array.
#'@export
#'@examplesIf interactive() || identical(Sys.getenv("IN_PKGDOWN"), "true")
#'#Perform a convolution with the default gaussian kernel
#'plot_image(dragon)
#'#Perform a convolution with the default gaussian kernel
#'render_convolution(dragon, preview = TRUE)
#'#Increase the width of the kernel
#'render_convolution(dragon, kernel = 2, kernel_dim=21,kernel_extent=6, preview = TRUE)
#'#Perform edge detection using an edge detection kernel
#'edge = matrix(c(-1,-1,-1,-1,8,-1,-1,-1,-1),3,3)
#'render_convolution(render_bw(dragon), kernel = edge, preview = TRUE, absolute=FALSE)
#'#Perform edge detection with Sobel matrices
#'sobel1 = matrix(c(1,2,1,0,0,0,-1,-2,-1),3,3)
#'sobel2 = matrix(c(1,2,1,0,0,0,-1,-2,-1),3,3,byrow=TRUE)
#'sob1 = render_convolution(render_bw(dragon), kernel = sobel1)
#'sob2 = render_convolution(render_bw(dragon), kernel = sobel2)
#'sob_all = sob1 + sob2
#'plot_image(sob1)
#'plot_image(sob2)
#'plot_image(sob_all)
#'
#'#Only perform the convolution on bright pixels (bloom)
#'render_convolution(dragon, kernel = 5, kernel_dim=24, kernel_extent=24,
#' min_value=1, preview = TRUE)
#'#Use a built-in kernel:
#'render_convolution(dragon, kernel = generate_2d_exponential(falloff=2, dim=31, width=21),
#' preview = TRUE)
#'#We can also apply this function to matrices:
#'volcano |> image()
#'volcano |>
#' render_convolution(kernel=generate_2d_gaussian(sd=1,dim=31)) |>
#' image()
#'#Use a custom kernel (in this case, an X shape):
#'custom = diag(10) + (diag(10)[,10:1])
#'plot_image(custom)
#'render_convolution(dragon, kernel = custom, preview = TRUE)
render_convolution = function(
image,
kernel = "gaussian",
kernel_dim = 11,
kernel_extent = 3,
absolute = TRUE,
min_value = NULL,
include_alpha = FALSE,
filename = NULL,
preview = FALSE,
progress = FALSE
) {
if (is.character(kernel)) {
if (kernel == "gaussian") {
kernel = generate_2d_gaussian(1, 1, kernel_dim, kernel_extent)
}
}
if (is.numeric(kernel) && length(kernel) == 1) {
kernel = generate_2d_gaussian(kernel, 1, kernel_dim, kernel_extent)
}
if (!is.null(dim(kernel)) && all(dim(kernel) >= 2)) {
if (ncol(kernel) %% 2 == 0) {
newkernel = matrix(0, ncol = ncol(kernel) + 1, nrow = nrow(kernel))
newkernel[, 1:ncol(kernel)] = kernel
kernel = newkernel
}
if (nrow(kernel) %% 2 == 0) {
newkernel = matrix(0, ncol = ncol(kernel), nrow = nrow(kernel) + 1)
newkernel[1:nrow(kernel), ] = kernel
kernel = newkernel
}
}
temp_image = ray_read_image(
image,
convert_to_array = FALSE,
reset_camera_settings = TRUE
)
colorspace = attr(temp_image, "colorspace")
whitepoint = attr(temp_image, "white_current")
imagetype = attr(temp_image, "filetype")
if (any(dim(kernel) > dim(temp_image)[1:2] * 2 + 1)) {
stop(
"kernel dimensions: ",
paste0(dim(kernel), collapse = "x"),
" must not be greater than 2x image dimensions: ",
paste0(dim(temp_image)[1:2], collapse = "x"),
", plus one (here, ",
paste0(dim(temp_image)[1:2] * 2 + 1, collapse = "x"),
")."
)
}
bloom_matrix = matrix(TRUE, nrow = nrow(temp_image), ncol = ncol(temp_image))
if (length(dim(temp_image)) == 3) {
if (!is.null(min_value)) {
bool_value = rep(TRUE, length = length(temp_image[,, 1]))
for (i in seq_along(dim(temp_image)[3])) {
bool_value = bool_value & temp_image[,, i] <= min_value
}
bloom_matrix[bool_value] = FALSE
}
} else {
if (!is.null(min_value)) {
bloom_matrix[temp_image <= min_value] = FALSE
}
}
temp_image_final = temp_image
if (imagetype != "matrix") {
channels = dim(temp_image)[3]
if (!include_alpha && (channels == 2 || channels == 4)) {
max_channel = channels - 1
} else {
max_channel = channels
}
for (i in seq_len(max_channel)) {
temp_image_final[,, i] = convolution_cpp(
temp_image[,, i],
kernel = kernel,
progbar = progress,
channel = i,
bloom_matrix = bloom_matrix
)
}
} else {
temp_image_final = convolution_cpp(
temp_image,
kernel = kernel,
progbar = progress,
channel = 1,
bloom_matrix = bloom_matrix
)
}
if (absolute) {
temp_image_final = abs(temp_image_final)
}
final_image = ray_read_image(
temp_image_final,
assume_colorspace = colorspace,
assume_white = whitepoint,
source_linear = TRUE
)
handle_image_output(final_image, filename = filename, preview = preview)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.