Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
104 lines (92 sloc) 3.73 KB
# Uses k-means clustering to change the colors of blobs inside images.
#
# Take an image, separate the pixels into k cluster buckets, and recolor
# one or more of those buckets.
#
# Mohit Cheppudia 2011 <mohit@muthanna.com>
#
# Prerequisites:
# - Package 'ReadImages'
# - Package 'cclust'
#
# Examples:
#
# Take the image 'baby.jpeg', convert all but the most common color (largest
# cluster) to grayscale and save to 'baby_recolor.jpeg'. By default it finds
# 10 clusters.
#
# > source("~/path/to/this/recolor.rscript")
# > save_recolor("baby.jpeg", "baby_recolor.jpeg", replacements=1:9)
#
# Find 20 clusters and gray out the three largest clusters.
#
# > save_recolor("baby.jpeg", "baby_recolor.jpeg", replacements=17:20,
# palette_size=20)
#
# Change the color of the largest cluster to green:
#
# > save_recolor("baby.jpeg", "baby_recolor.jpeg", replacements=10,
# rgb_factor=(10/100, 80/100, 10/100))
library(ReadImages)
library(cclust)
# Recolor the imagematrix 'im' using the given parameters:
#
# palette_size: Number of clusters to find.
# replacements: A vector of clusters to replace (smallest to biggest)
# rgb_factors: Factors for distributing intensity among RGB channels. Defaults
# to greyscale (i.e., even intensities acrossl all channels.)
# iterations: Number of iterations for k-means clustering.
#
# Returns a new imagematrix with colors replaced.
recolor <- function(im, palette_size=10, replacements=1:palette_size,
rgb_factors=c(1/3,1/3,1/3), iterations=20) {
# Convert the image into a list of observations, each observation
# is a 3-dimensional vector of RGB. For cclust we represent this
# as 2x3 matrix where each row is an observation and each column
# is a feature (R,G,B).
observations <- matrix(im, ncol=3)
# Run k-means clustering, ask for 'palette_size' clusters, run
# at most 100 iterations until convergence. This call requires the
# 'cclust' package to be installed.
k <- cclust(observations, palette_size, iter.max=iterations)
# We now have the clusters -- sort clusters by size, and replace
# the requested clusters in 'replacements' with new colors.
top <- 1
for (i in order(k$size)) {
# Replace requested clusters with greyscale counterparts
if (any(top == replacements)) {
cluster <- observations[k$cluster == i,]
# Calculate the total intensity of the pixel and redistribute
# to the RGB channels based on their respective requested factors.
intensities <- rowSums(cluster * cluster)
intensities_r <- sqrt(intensities * rgb_factors[1])
intensities_g <- sqrt(intensities * rgb_factors[2])
intensities_b <- sqrt(intensities * rgb_factors[3])
# Update observations with new colors
observations[k$cluster == i,] <- cbind(intensities_r,
intensities_g,
intensities_b)
}
top <- top + 1
}
# Create the final image (with the dimensions of the original image
# and return.
dims = dim(im)
final_im = imagematrix(observations, "rgb", dims[1], dims[2])
final_im
}
# Take a source image from 'image_path', recolor it with the specified
# parameters, and save to 'save_path'.
save_recolor <- function(image_path, save_path, palette_size=10,
replacements=(1:palette_size - 1),
rgb_factors=(c(1/3,1/3,1/3)),
iterations=20) {
im <- read.jpeg(image_path)
fm <- recolor(im, palette_size, replacements, rgb_factors, iterations)
dims = dim(im)
jpeg(save_path, width = dims[2], height=dims[1], quality=90)
# Options to remove margin (prevents rescaling of the image)
par(xpd=NA, mai=c(0,0,0,0))
plot(fm)
dev.off()
}