Nothing
# Speed Comparison: Color Walk vs Exact
# Tests the performance of different morphing modes
message("== Speed Comparison for lapr morphing modes ==\n")
suppressPackageStartupMessages({
library(magick)
library(png)
})
# Assume lapr functions are available
# If running standalone, you'll need to source utils_morph.R and have C++ compiled
# Create synthetic test images of different sizes
create_test_pair <- function(size) {
H <- W <- size
arrA <- array(0, c(H, W, 3))
arrB <- array(0, c(H, W, 3))
# Create varied color patterns
for (y in 1:H) {
for (x in 1:W) {
# Image A: radial gradient with some structure
r <- sqrt((x - H/2)^2 + (y - W/2)^2) / (H/2)
arrA[y, x, 1] <- (1 - r) * 255
arrA[y, x, 2] <- (x / W) * 255
arrA[y, x, 3] <- (y / H) * 255
# Image B: different pattern
arrB[y, x, 1] <- (y / H) * 255
arrB[y, x, 2] <- (1 - r) * 255
arrB[y, x, 3] <- (x / W) * 255
}
}
tmpA <- tempfile(fileext = ".png")
tmpB <- tempfile(fileext = ".png")
writePNG(arrA / 255, tmpA)
writePNG(arrB / 255, tmpB)
list(A = tmpA, B = tmpB)
}
# Test configurations
test_configs <- list(
list(mode = "exact", args = list(alpha = 1, beta = 0, patch_size = 1L), label = "exact_β=0"),
list(mode = "exact", args = list(alpha = 1, beta = 0.05, patch_size = 3L), label = "exact_patch3"),
list(mode = "color_walk", args = list(quantize_bits = 6L), label = "color_walk_q6"),
list(mode = "color_walk", args = list(quantize_bits = 5L), label = "color_walk_q5"),
list(mode = "color_walk", args = list(quantize_bits = 7L), label = "color_walk_q7")
)
# Image sizes to test (keep under 100×100 for exact mode - limit is 10,000 pixels)
sizes <- c(16, 32, 64, 96)
# Results storage
results <- list()
cat("\n")
cat(sprintf("%-10s %-20s %12s %12s %15s\n",
"Size", "Mode", "Time (sec)", "Pixels", "μs/pixel"))
cat(strrep("-", 70), "\n")
for (size in sizes) {
# Create test images
pair <- create_test_pair(size)
n_pixels <- size * size
for (cfg in test_configs) {
mode_label <- if (!is.null(cfg$label)) cfg$label else cfg$mode
# Time the morphing operation
timing <- system.time({
tryCatch({
do.call(lapr::pixel_morph, c(list(
imgA = pair$A,
imgB = pair$B,
n_frames = 1L, # Just test assignment computation
fps = 1L,
format = "gif",
outfile = tempfile(fileext = ".gif"),
show = FALSE,
lap_method = "jv",
maximize = FALSE,
downscale_steps = 0L
), list(mode = cfg$mode), cfg$args))
}, error = function(e) {
message("Error for ", mode_label, " at size ", size, ": ", e$message)
})
})
elapsed <- timing["elapsed"]
us_per_pixel <- (elapsed * 1e6) / n_pixels
cat(sprintf("%-10s %-20s %12.4f %12d %15.2f\n",
paste0(size, "×", size),
mode_label,
elapsed,
n_pixels,
us_per_pixel))
results[[length(results) + 1]] <- list(
size = size,
mode = cfg$mode,
label = mode_label,
time_sec = elapsed,
n_pixels = n_pixels,
us_per_pixel = us_per_pixel
)
}
cat("\n")
}
# Summary statistics
cat("\n=== SUMMARY ===\n\n")
# Convert to data frame for easier analysis
df <- do.call(rbind, lapply(results, function(x) {
data.frame(
size = x$size,
mode = x$mode,
label = x$label,
time_sec = x$time_sec,
n_pixels = x$n_pixels,
us_per_pixel = x$us_per_pixel,
stringsAsFactors = FALSE
)
}))
# Average time per mode across all sizes
cat("Average time per mode (across all sizes):\n")
for (mode_label in unique(df$label)) {
subset_df <- df[df$label == mode_label, ]
avg_time <- mean(subset_df$time_sec)
avg_us <- mean(subset_df$us_per_pixel)
cat(sprintf(" %-20s: %.4f sec (%.2f μs/pixel)\n", mode_label, avg_time, avg_us))
}
cat("\n")
# Scaling analysis (how does time grow with N?)
cat("Scaling behavior (time vs N):\n")
for (mode_label in unique(df$label)) {
subset_df <- df[df$label == mode_label, ]
if (nrow(subset_df) >= 2) {
# Simple ratio: time at largest / time at smallest
times <- subset_df$time_sec[order(subset_df$size)]
sizes <- subset_df$size[order(subset_df$size)]
if (times[1] > 0) {
size_ratio <- sizes[length(sizes)] / sizes[1]
time_ratio <- times[length(times)] / times[1]
# Estimate exponent: time ~ N^k, so k = log(time_ratio) / log(size_ratio^2)
k <- log(time_ratio) / log(size_ratio^2)
cat(sprintf(" %-20s: ~O(N^%.2f) [%d×%d is %.1fx slower than %d×%d]\n",
mode_label, k,
sizes[length(sizes)], sizes[length(sizes)],
time_ratio,
sizes[1], sizes[1]))
}
}
}
cat("\n")
cat("Note: Exact modes should be ~O(N^2.5-3) due to LAP solving on N×N matrix\n")
cat(" Color walk should be ~O(K*M^2.5) where K=num_colors, M=avg_pixels_per_color\n")
cat(" With good quantization, K << N, making color_walk much faster for large N\n")
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.