How to get a pixel matrix from grayscale image in R?

14,777

Solution 1

The R package png offers the readPNG() function which can read raster graphics (consisting of "pixel matrices") in PNG format into R. It returns either a single matrix with gray values in [0, 1] or three matrices with the RGB values in [0, 1].

For transforming between [0, 1] and {0, ..., 255} simply multiply or divide with 255 and round, if desired.

For transforming between RGB and grayscale you can use for example the desaturate() function from the colorspace package.

As an example, let's download the image you suggested:

download.file("http://www.greenmountaindiapers.com/skin/common_files/modules/Socialize/images/twitter.png",
  destfile = "twitter.png")

Then we load the packages mentioned above:

library("png")
library("colorspace")

First, we read the PNG image into an array x with dimension 28 x 28 x 4. Thus, the image has 28 x 28 pixels and four channels: red, green, blue and alpha (for semi-transparency).

x <- readPNG("twitter.png")
dim(x)
## [1] 28 28  4

Now we can transform this into various other formats: y is a vector of hex character strings, specifying colors in R. yg is the corresponding desaturated color (again as hex character) with grayscale only. yn is the numeric amount of gray. All three objects are arranged into 28 x 28 matrices at the end

y <- rgb(x[,,1], x[,,2], x[,,3], alpha = x[,,4])
yg <- desaturate(y)
yn <- col2rgb(yg)[1, ]/255
dim(y) <- dim(yg) <- dim(yn) <- dim(x)[1:2]

I hope that at least one of these versions is what you are looking for. To check the pixel matrices I have written a small convenience function for visualization:

pixmatplot <- function (x, ...) {
  d <- dim(x)
  xcoord <- t(expand.grid(1:d[1], 1:d[2]))
  xcoord <- t(xcoord/d)
  par(mar = rep(1, 4))
  plot(0, 0, type = "n", xlab = "", ylab = "", axes = FALSE, 
    xlim = c(0, 1), ylim = c(0, 1), ...)
  rect(xcoord[, 2L] - 1/d[2L], 1 - (xcoord[, 1L] - 1/d[1L]), 
    xcoord[, 2L], 1 - xcoord[, 1L], col = x, border = "transparent")
}

For illustration let's look at:

pixmatplot(y)
pixmatplot(yg)

colored and desaturated picture

If you have a larger image and want to bring it to 28 x 28, I would average the gray values from the corresponding rows/columns and insert the results into a matrix of the desired dimension.

Final note: While it is certainly possible to do all this in R, it might be more convenient to use an image manipulation software instead. Depending on what you aim at, it might be easier to just use ImageMagick's mogrify for example:

mogrify -resize 28 -type grayscale twitter.png

Solution 2

Here is an example of converting and drawing an image from a grayscale png. Please ensure installing the relevant packages first.

library(png)
library(RCurl)
myurl = "https://postgis.net/docs/manual-dev/images/apple_st_grayscale.png"
my_image =  readPNG(getURLContent(myurl))
img_mat=my_image[,,1] # will hold the grayscale values divided by 255
img_mat=t(apply(img_mat, 2, rev)) # otherwise the image will be rotated
image(img_mat, col  = gray((0:255)/255)) # plot in grayscale
Share:
14,777
Blain Waan
Author by

Blain Waan

Learner.

Updated on June 30, 2022

Comments

  • Blain Waan
    Blain Waan almost 2 years

    When grayscale images are represented by matrices each element of the matrix determines the intensity of the corresponding pixel. For convenience, most of the current digital files use integer numbers between 0 (to indicate black, the color of minimal intensity) and 255 (to indicate white, maximum intensity), giving a total of 256 = 2^8 different levels of gray.

    Is there a way to get a pixel matrix of graysale images in R whose pixel values will range from 0 to 255?

    It will also be helpful to know if I can resize the images in preferred dimension (say, $28 \times 28$) in R and then convert them into a pixel matrix whose elements range from 0 to 255?

    What happens if the original image is RGB but I want the matrix for grayscale?