Let's say I have this image:
I want to convert the grayscale to a viridis colour schema and save it. I have got it to work using this chuck of code:
system('wget https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Von_einem_Schrecklichen_vnd_Wunderbarlichen_Cometen_so_sich_den_Dienstag_nach_Martini_dieses_lauffenden_M._D._Lxxvij._Jahrs_am_Himmel_erzeiget_hat_%28grayscale%29.png/320px-thumbnail.png')
library(png)
library(viridisLite)
x <- png::readPNG('320px-thumbnail.png')
x <- x[, ,1]
intmat <- x * 255
image(1:nrow(intmat), 1:ncol(intmat), intmat, col=viridis(256))
Which results in this:
I'm very happy with how the colour schema was applied. However, this is not the original image anymore, but just a plot. What I want is to exchange each pixel in the grayscale, and save the converted image as a png again, so without using image()
. I had a look at the image_convert
function in magick, but couldn't figure out how to get the desired behavior.
I'm sure there are ways to do this without reinventing the wheel, but using just the libraries you have loaded, it's fairly straightforward to manipulate the viridis colours to split them into 3 channels and save as png.
Here's a function to do the job for any png:
png_to_viridis <- function(in_file, out_file)
{
PNG_raw <- readBin(in_file, "raw", 10e6)
x <- png::readPNG(PNG_raw)
intmat <- 255 * x[, ,1]
virmat <- viridisLite::viridis(256)[intmat + 1]
virmat <- c(substr(virmat, 2, 3), substr(virmat, 4, 5),
substr(virmat, 6, 7), substr(virmat, 8, 9))
virmat <- as.numeric(as.hexmode(virmat))/255
dim(virmat) <- c(dim(intmat), 4)
png::writePNG(virmat, out_file)
}
So now if I do:
png_to_viridis("https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Von_einem_Schrecklichen_vnd_Wunderbarlichen_Cometen_so_sich_den_Dienstag_nach_Martini_dieses_lauffenden_M._D._Lxxvij._Jahrs_am_Himmel_erzeiget_hat_%28grayscale%29.png/320px-thumbnail.png",
"viridis.png")
I get the following result saved as viridis.png: