Tuesday 20 December 2016

Creating an in memory rasterio Dataset from numpy array


I am reading in a raster using rasterio, and then upsampling the raster as per the example in the documentation:


def upsample_raster(raster):
return raster.read(
out_shape=(raster.height * 2, raster.width * 2, raster.count),
resampling=resampling.bilinear,
)


This seems to work fine, except that this method returns the data in a numpy array.


My current application workflow includes operations such as masking which takes as input rasterio's DatasetReader class.


Thus, I am searching for a way to resample a raster and get the result as a DatasetReader or, without dumping the data to disk and re-opening the file, convert a numpy array into a valid DatasetReader.



Answer



You need to recreate a DatasetReader manually and you can use a MemoryFile to avoid writing to disk.


You can re-use the metadata from the input raster in the DatasetReader, but you'll need to modify the height and width properties and the transform. From documentation:



After these resolution changing operations, the dataset’s resolution and the resolution components of its affine transform property no longer apply to the new arrays.



In the example below note that:




  1. I use a contextmanager so the DatasetReader and MemoryFile objects get cleaned up automatically. This is why I use yield not return in the function

  2. I had to change the order of indexes in raster.read as arrays are (band, row, col) order not (row, col, band) like you used in your snippet.


# Example licensed under cc by-sa 3.0 with attribution required

from contextlib import contextmanager

import rasterio
from rasterio import Affine, MemoryFile

from rasterio.enums import Resampling

# use context manager so DatasetReader and MemoryFile get cleaned up automatically
@contextmanager
def resample_raster(raster, scale=2):
t = raster.transform

# rescale the metadata
transform = Affine(t.a / scale, t.b, t.c, t.d, t.e / scale, t.f)
height = raster.height * scale

width = raster.width * scale

profile = src.profile
profile.update(transform=transform, driver='GTiff', height=height, width=width)

data = raster.read( # Note changed order of indexes, arrays are band, row, col order not row, col, band
out_shape=(raster.count, height, width),
resampling=Resampling.bilinear,
)


with MemoryFile() as memfile:
with memfile.open(**profile) as dataset: # Open as DatasetWriter
dataset.write(data)
del data

with memfile.open() as dataset: # Reopen as DatasetReader
yield dataset # Note yield not return


with rasterio.open('path/to/raster') as src:

with resample_raster(src) as resampled:
print('Orig dims: {}, New dims: {}'.format(src.shape, resampled.shape))
print(repr(resampled))

Orig dims: (4103, 4682), New dims: (8206, 9364)

No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...