How to change rgb image into matrix using EBImage? - r

I want to change an image into matrix of numbers in R using EBImage package. I have tried this code but it only output all 1's:
library(EBImage)
img<-readImage("test.jpg")
imageData(img)[1:50,1:60,1]
this is the image

The following example illustrates how to load a grayscale image containing an alpha channel, convert it to single-channel grayscale image, and do some post-processing: crop the border and resize.
library(EBImage)
img <- readImage("http://i.stack.imgur.com/9VTWx.png")
# grayscale images containing an alpha channel are represented in EBImage as
# RGBA images by replicating the grayscale intensities over the red, green and
# blue channels
print(img, short=TRUE)
## Image
## colorMode : Color
## storage.mode : double
## dim : 819 460 4
## frames.total : 4
## frames.render: 1
# convert to grayscale
img <- channel(img, "gray")
# collect matrix indices of non-white pixles
ind <- which(img < 1, arr.ind=TRUE)
# find min/max indices across rows/columns
ind <- apply(ind, 2L, range)
rownames(ind) <- c("min", "max")
ind
## row col
## min 17 7
## max 819 413
# crop the image
img <- img[ind["min","row"]:ind["max","row"], ind["min","col"]:ind["max","col"]]
# resize to specific width and height
img <- resize(img, w=128, h=128)
display(img)
To extract the underlying matrix use imageData(img).

First of all, that's not a JPEG image, but PNG.
Second, it's not RGB, but greyscale + alpha (according to ImageMagick at least), although the alpha channel is completely opaque, so it doesn't hold any actual data.
Third, the reason you're getting all ones is because the section of the image you are choosing is all white, i.e. maximum intensity, which is represented by the value 1.
Try something like imageData(img)[51:100,1:60,1] and see if that doesn't give a different result.

Related

Modify range of color of raster image in R

I take photo with a black background but due to the light, it can have some reflect. In R I would like to change the background to black one (RGB = 0). I would like to select the color with RGB values lower than 80 and change to 0.
I use this code in R:
library(raster)
folder <- "C:/Users/PC/Pictures/"
img <- list.files(folder)
img.raster<-stack(img)
names(img.raster) <- c('r','g','b')
color <- 80
img.black<-img.raster[[1]]
img.black[img.raster$r<color & img.raster$g<color & img.raster$b<color] <- 0
I rebuilt my image using stack
image = stack(img.black, img.black, img.black)
But by doing this I lose information as I have the same layer for R,G and B. If I tried:
image = stack(img.black, img.raster, img.raster)
by this way the dimension of the image is 7 !!
How to select a range of color and change it without modifying the dimension of the image and the other colors. Do I need to use raster or is there another solution ?
Here is how you could do that. Note that I update the color to 255 rather than 0 to be able to see the effect in this example. Also, you used the first layer of RGB as black. I assume you wanted the third.
Example data
library(raster)
img <- stack(system.file("external/rlogo.grd", package="raster"))
plotRGB(img)
Solution
color_threshold <- 80
update_value <- 255 # 0 in your case
black <- 3
i <- all(img < color_threshold)
img[[black]] <- mask(img[[black]], i, maskvalue=1, updatevalue=update_value)
plotRGB(img)
Or perhaps this is what you are after --- update all cells to zero, not just the black channel:
img <- brick(system.file("external/rlogo.grd", package="raster"))
img2 <- mask(img, all(img < 80), maskvalue=1, updatevalue=0)
plotRGB(img2)

Quantize grayscale images

I have grayscale images which I want to quantize to different gray levels.
To be more precise, in the EBImage package, we have a function equalize() which has an argument levels. we can set levels value to 256 or 128 or 64 etc to quantize our grayscale images. (But the equalize() function will perform a histogram equalization of the given grayscale image, which is not preferred for my current situation)
Can somebody suggest a formula or a function which we can use to change the number of gray levels in the given grayscale image.
First convert the format in something continous.
Now pseudocode.
int x = (int) (value / (Quantisation));
(new format) y = x * Quantisation;
It is also possible to compress images that lousy way.
The default image data representation in EBImage is a continuous range between 0 and 1. In order to quantize an image to a given number of levels, first convert it to integers in the range of 0:(levels-1), and then back to 0:1, as in the quantize function from the following example.
library(EBImage)
## sample grayscale image
x = readImage(system.file("images", "sample.png", package="EBImage"))
## function for performing image quantization
quantize = function(img, levels) round(img * (levels-1)) / (levels-1)
## quantize the image
y = quantize(x, levels = 8)
## show the result
display(y)

Finding RGB values from an jpeg image in R

I am trying to find RGB values in R.
The jpeg images that I am using have an object with white background.
Like this one: http://www.wild-wonders.com/blog/wp-content/uploads/2009/11/nba_france_16.jpg
Right now, in order to just select the object, I have to trace each object manually (by plotting dots which makes the selection into a shape that will later be used to get the RGB values). Is there any tools or packages like magic wand tool in photoshop that will automatically select the white background?
Have a look at the functionality provided by the Bioconductor package EBImage, an image processing and analysis toolbox for R. To install the package use:
source("http://bioconductor.org/biocLite.R")
biocLite("EBImage")
The example below illustrates how to automatically extract an object from white background, and get its #rrggbb pixel values. I used a value of 0.95 for thresholding rather than 1.0 (corresponding to white pixels) because of the artifacts introduced by jpeg compression.
library(EBImage)
## load the array representing pixel intensities into R
img <- readImage("http://www.wild-wonders.com/blog/wp-content/uploads/2009/11/nba_france_16.jpg")
## convert to grayscale before thresholding
gray <- channel(img, "gray")
## create a mask separating objects from background
mask <- gray < 0.95
## label objects (connected sets of pixels)
obj <- bwlabel(mask)
## indices of pixels within the object
idx <- which(mask==1, arr.ind=TRUE)
## extract the red, green, and blue pixel intensities
rgb <- cbind(channel(img, "r")[idx],
channel(img, "g")[idx],
channel(img, "b")[idx])
## convert to #RRGGBB representation
rgb(rgb)

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

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?
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)
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
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

Draw a circle in a bitmap image and crop pixels outside circle in R

I'm loading bitmap images into R with dimensions that are roughly 17,000 X 17,000 pixels. I'd like to find a way to draw a circle with a radius (in pixels) of my choosing around the center of the picture and convert all pixels outside of the circle into NA's.
For example, if the radius desired was 500 pixels, all pixels within that distance (500) from the centroid would be kept as is. Any pixel farther than that distance (>= 501) from the centroid would be converted to an NA.
The bitmap images are made up entirely of 1's and 0's so here's a smaller example of what these images look like.
img=matrix(sample(c(1,0),1000000,replace=TRUE),ncol=1000,nrow=1000)
image(0:1000,0:1000,img)
This is a slight variation of the solution by eipi10. It does not use the "melt" function of the reshape package and rather uses subsetting the matrix directly:
# Number of rows and columns in image
nr = 200
nc = 100
# Create image values
set.seed(78)
img <- matrix(sample(c(1,0), nr*nc, prob=c(0.8, 1-0.8), replace=TRUE), ncol=nc, nrow=nr)
center <- c(median(1:nr), median(1:nc)) # center of image
r <- 40 # radius
# setting the matrix element inside the circle to value -1
img[(row(img) - center[1])^2 + (col(img) - center[2])^2 < r^2] <- -1
# plot image
par(mar = c(0, 0, 0, 0))
image(img, useRaster=TRUE, axes=FALSE)
I've created a fake image that's smaller than yours so that the code will run more quickly:
library(plotrix) # To draw a circle
library(reshape2) # For "melt" function
Create a fake image:
# Number of rows and columns in image
nr = 200
nc = 100
# Create image values
set.seed(78)
img = matrix(sample(c(1,0), nr*nc, prob=c(0.8, 1-0.8), replace=TRUE), ncol=nc, nrow=nr)
Now that we have our image, remove points outside the desired circle:
# melt matrix into "long" format
img = melt(id.var=1:nrow(img), img)
names(img) = c("rows","cols","z")
# Find center of image
center=c(median(1:nr), median(1:nc))
# Set desired radial distance from center
r=40
# Set values outside radius to -1 (or some value that can't otherwise appear in
# the matrix). You can set the value to NA, but then you won't be able to
# control the color of the excluded region (it will just be white).
img$z[sqrt((img$rows - center[1])^2 + (img$cols - center[2])^2) > r] = -1
# Plot image. Colors ordered from lowest (-1) to highest (1) value
image(1:nr, 1:nc, matrix(img$z, nrow=nr, byrow=FALSE), col=c("gray80", "green","red"))
# Draw a circle around the selected points
draw.circle(center[1], center[2], r, lwd=2)

Resources