3
\$\begingroup\$

I am developing a workflow to perform a variety of operations on raster dataset using rasterio. My previous workflow involved lots of I/O when performing such operations on raster files. I would like to change the workflow so to process raster data in-memory. I am using rasterio.MemoryFile() class to achieve that. Here some of my code:

@contextmanager
def mem_file(arr, metadata, *to_del_arr):
    """
    Create and yield a Datareader using a numpy array
    and raster metadata
    """
    with rasterio.MemoryFile() as memfile:
        with memfile.open(**metadata) as src: # Open as DatasetWriter
            if arr.ndim == 2:
                src.write_band(1, arr)
            else:
                src.write(arr.astype(metadata['dtype']))
            for arr in to_del_arr:
                del arr

        with memfile.open() as src:  # Reopen as DatasetReader
            yield src

@contextmanager
def resample_raster(src, scale=2):
    """
    resample raster
    """
    t = src.transform

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

    new_meta = copy.deepcopy(src.meta)
    new_meta.update(transform=transform, driver='GTiff', height=height,
                    width=width)

    # resampling
    arr = src.read(resampling=rasterio.enums.Resampling.nearest)
    return mem_file(arr, new_meta, arr)



@contextmanager
def create_raster_mask(src, vals):
    """
    create a raster mask

    """
    arr = src.read()
    mask_arr = np.ma.MaskedArray(arr, np.in1d(arr, vals))
    new_meta = copy.deepcopy(src.meta)
    new_meta.update(driver='GTiff', nbits=1)
    return mem_file(mask_arr.mask, new_meta, arr, mask_arr)


@contextmenager
def another_operation(src):
    pass

The idea is to chain this operations together to build a workflow. Right now I can do that like so:


if __name__ == "__main__":
    with rasterio.open("tests/T37MBN_20190628T073621_SCL_20m.jp2") as src:
        print(src.meta)
        with resample_raster(src) as resampled:
            print(resampled.meta)
            with create_raster_mask(resampled, [3,7,8,9,10]) as mask:
                print(mask.meta)

But I would like to avoid such nested structure and have something more like:

if __name__ == "__main__":
    with rasterio.open("tests/T37MBN_20190628T073621_SCL_20m.jp2") as src:
        final = create_raster_mask(resample_raster(src))
        print(final.meta)

Is there a way I can achieve that? Thanks

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.