2

I am interested in converting a matrix to an image (element value = pixel intensity), a bit like: R - image of a pixel matrix?

However I need the size of the image to be exactly (in pixels) the size of the matrix. So if the matrix is 234x14 so should be the generated image.

Preference for a solution using no additional R package (like in answer to question lined above), but everything would be fine as well.

Community
  • 1
  • 1
StephQ
  • 2,032
  • 3
  • 19
  • 27

3 Answers3

3

One way is to avoid the R devices completely, and rely on the GDAL drivers in rgdal.

m <- matrix(rep(1:234, each = 14), ncol = 14, byrow = TRUE)
l <- list(x = 1:nrow(m), y = 1:ncol(m), z = m)

library(rgdal)
x <- image2Grid(l)
writeGDAL(x, "out.tif")

There are other drivers in GDAL, but "GeoTIFF" is the default, and the defaults will preserve the values accurately (within the numeric limits of R and GDAL). This is just a single band raster, but it will work the same for multiple attributes.

The real limit here is the target you have for the file, and whether it can read the resulting image in the way that you want. GDAL has all the options you would need, but whether the defaults are right and what you really need depends on details.

y <- readGDAL("out.tif")
all.equal(as.image.SpatialGridDataFrame(y)$z, m)
[1] TRUE

Here is a floating point example that shows the numeric limits more realistically:

set.seed(1)

m <- matrix(runif(234 * 14), ncol = 14)
l <- list(x = 1:nrow(m), y = 1:ncol(m), z = m)

library(rgdal)
x <- image2Grid(l)
writeGDAL(x, "out.tif")

y <- readGDAL("out.tif")

all.equal(as.image.SpatialGridDataFrame(y)$z, m)
[1] "Mean relative difference: 1.984398e-08"

Another way is the pnm format that is used by pixmap. See

library(pixmap)

?write.pnm
mdsumner
  • 29,099
  • 6
  • 83
  • 91
  • By any chance, would it be possible to customize the color map and add axis "levels" like in a plain plot() by enlarging the image outside the plotted intensities (thus keeping the 1-pixel-per-value identity)? I am open to using other software if too difficult in R. – StephQ Oct 04 '11 at 14:40
  • I don't know what this means. Can you elaborate, even draw a picture? – mdsumner Oct 04 '11 at 19:33
2

It is an extra package, but you could try pixmap: http://cran.r-project.org/web/packages/pixmap/index.html

If you want animated images, you can write animated gifs from matrices using caTools.

johanvdw
  • 401
  • 3
  • 11
1

Here is an alternative way to solve the problem. Included in the example are ways to add margins with axes information, how to normalize and floor the data to be plotted + use a colour (blue) for a specific level (zero). Substitute and with the specific data you want to use and change {lm, bm, tm, rm} to different values to resize the four margins (all measures in pixels):

maxv <- 500

v <- t(<matrix>)
d <- <vector>
di <- <vector>
dm <- <vector>
nr <- nrow(v)
nc <- ncol(v)

library(grid)
vnorm <- v
for (r in 1:nr) {
  for (c in 1:nc) {
    vnorm[r,c] <- min(1, v[r, nc-c+1]/500)
    if (vnorm[r,c] == 0) {vnorm[r,c] <- "blue"}
    else {vnorm[r,c] <- grey(vnorm[r,c])}
  }
}
vnorm <- t(vnorm)

x <- seq(1, nr)
y <- rep(1, nr)
xrange <- range(d)
yrange <- c(0, 24)

bm <- 90
lm <- 40
tm <- 12
rm <- 12

png(file="graph.png", width=nr+lm+rm, height=nc+tm+bm)
par(mai=c(bm/72, lm/72, tm/72, rm/72))
plot(d, y, ann=FALSE, xlim=xrange, ylim=yrange, axes=FALSE, xaxs="i", yaxs="i")
axis(1, at=dm,labels=dm, col.axis="black", las=2)
axis(2, at=seq(0,24),labels=seq(0,24), col.axis="black", las=2)
rasterImage(vnorm, xrange[1], yrange[1], xrange[2], yrange[2], interpolate=FALSE)
dev.off()
StephQ
  • 2,032
  • 3
  • 19
  • 27