joost
joost

Reputation: 159

Converting and saving grayscale image to e.g. viridis colour scheme

Let's say I have this image:

enter image description here

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:

enter image description here

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.

Upvotes: 2

Views: 1276

Answers (2)

fmw42
fmw42

Reputation: 53164

I extracted the Verdis color map from Mathplotpy from https://matplotlib.org/3.1.1/tutorials/colors/colormap-manipulation.html and converted it to a set of colors in ImageMagick format. Then created a 1D color map image and use ImageMagick -clut to apply it to the image.

Input:

enter image description here

convert picture.png \
\( -size 1x1 \
xc:"rgba(0.267004,0.004874,0.329415,1.)" \
xc:"rgba(0.283072,0.130895,0.449241,1.)" \
xc:"rgba(0.262138,0.242286,0.520837,1.)" \
xc:"rgba(0.220057,0.343307,0.549413,1.)" \
xc:"rgba(0.177423,0.437527,0.557565,1.)" \
xc:"rgba(0.143343,0.522773,0.556295,1.)" \
xc:"rgba(0.119512,0.607464,0.540218,1.)" \
xc:"rgba(0.166383,0.690856,0.496502,1.)" \
xc:"rgba(0.319809,0.770914,0.411152,1.)" \
xc:"rgba(0.525776,0.833491,0.288127,1.)" \
xc:"rgba(0.762373,0.876424,0.137064,1.)" \
xc:"rgba(0.993248,0.906157,0.143936,1.)" \
-append \) -clut -evaluate multiply 255 PNG24:picture_verdis.png


Result:

enter image description here

Use PNG8: in place of PNG24: if you want a 8-bit color rather than 24-bit color.

Note that ImageMagick rgb colors are in the range 0 to 255 and Mathplotpy uses the range 0 to 1. So I had to multiply the result by 255 at the end.

Upvotes: 0

Allan Cameron
Allan Cameron

Reputation: 174378

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:

enter image description here

Upvotes: 3

Related Questions