rosscova rosscova - 21 days ago 5
R Question

Read image data into R piece-by-piece

I'm working with some fairly large image files (aerial survey mosaics, generally > 1 billion pixels), such that loading an entire image into memory would be a problem on my system. I would like to bring them into R piece-by-piece, such that I can process them in "grid-wise" sections.

NOTE: I'm not tied to a particular image format, so

tiff
,
png
,
bmp
etc would all be fine as inputs.

I can do something along these lines with
readJPEG
, but this requires loading the entire file into memory first, so it doesn't really solve my problem, but hopefully shows what I'm trying to achieve.

image.file <- "~/Desktop/penguins.jpg"

grid.size <- 100
v <- 3
h <- 1

library( jpeg )
image <- readJPEG( image.file )[ seq.int( (v-1)*grid.size+1, (v)*grid.size, 1 ),
seq.int( (h-1)*grid.size+1, h*grid.size, 1 ), ]


The above loads in only a sample of the image, designated by
grid.size
,
v
, and
h
, such that it would be easy to build this into a loop to analyse an image in sections.

Is it possible to achieve this without loading the entire image into memory? Something like
read.csv
, making use of the
skip
and
n
parameters would be reasonable (it would at least only load the vertical sections one at a time, so much less memory needed than
readJPEG
).

Answer

If you have ImageMagick installed, you can crop the image from the command line before reading it into R. An example using this image: http://www.worldatlas.com/worldmaps/worldpoliticallarge.jpg

To create the cropped image:

x <- 800  ## x and y are offsets
y <- 400
w <- 200  ## width and height of cropped image
h <- 100
filename <- "worldpoliticallarge.jpg"
outname <- "crop.jpg"
cmd <- sprintf("jpegtran -crop %dx%d+%d+%d -copy none %s > %s", w, h, x, y, filename, outname)
system(cmd)

Check to see if the new image contains the region we want:

library(jpeg)
original <- readJPEG(filename)
cropped <- readJPEG(outname)
all.equal(original[(y+1):(y+h), (x+1):(x+w), ], cropped)
# [1] TRUE