Trying to process a large satellite image (~10GB). For memory efficient processing chunk of image (block
/tile
) is being loaded into memory in each iteration.
The sample code for this as below:
def process_image(src_img, dst_img, band_id=1):
with rasterio.open(src_img) as src:
kwargs = src.meta
tiles = src.block_windows(band_id)
with rasterio.open(dst_img, 'w', **kwargs) as dst:
for idx, window in tiles:
print("Processing Block: ", idx[0]+1, ", ", idx[1]+1)
src_data = src.read(band_id, window=window)
dst_data = src_data ** 2 # Do the Processing Here
dst.write_band( band_id, dst_data, window=window)
return 0
However, for any kind of processing which requires kernel wise operation (such as any convolve
filter like smoothing
) this leads to an issue in processing near the edges of the blocks. To address this, each block should be slightly overlapped as shown below:
My objective is to load the blocks as the following where the amount of overlap can be adjusted according to the need.
So far I did not find any straight forward way to achieve this. I would be grateful for any help in this regard.
You can just expand your windows:
import rasterio as rio
from rasterio import windows
def overlapping_blocks(src, overlap=0, band=1):
nols, nrows = src.meta['width'], src.meta['height']
big_window = windows.Window(col_off=0, row_off=0, width=nols, height=nrows)
for ji, window in src.block_windows(band):
if overlap == 0:
yield ji, window
else:
col_off = window.col_off - overlap
row_off = window.row_off - overlap
width = window.width + overlap * 2
height = window.height + overlap * 2
yield ji, windows.Window(col_off, row_off, width, height).intersection(big_window)
And you would use it like so:
def process_image(src_img, dst_img, band_id=1):
with rasterio.open(src_img) as src:
kwargs = src.meta
with rasterio.open(dst_img, 'w', **kwargs) as dst:
for idx, window in overlapping_block_windows(src, overlap=1, band=band_id):
print("Processing Block: ", idx[0]+1, ", ", idx[1]+1)
src_data = src.read(band_id, window=window)
dst_data = src_data ** 2 # Do the Processing Here
dst.write_band( band_id, dst_data, window=window)
return 0
And here is a way to overlap both block windows and non-block windows, with an additional argument boundless
to specify whether to extend windows beyond the raster extent, useful for boundless reading:
from itertools import product
import rasterio as rio
from rasterio import windows
def overlapping_windows(src, overlap, width, height, boundless=False):
""""width & height not including overlap i.e requesting a 256x256 window with
1px overlap will return a 258x258 window (for non edge windows)"""
offsets = product(range(0, src.meta['width'], width), range(0, src.meta['height'], height))
big_window = windows.Window(col_off=0, row_off=0, width=src.meta['width'], height=src.meta['height'])
for col_off, row_off in offsets:
window = windows.Window(
col_off=col_off - overlap,
row_off=row_off - overlap,
width=width + overlap * 2,
height=height + overlap * 2)
if boundless:
yield window
else:
yield window.intersection(big_window)
def overlapping_blocks(src, overlap=0, band=1, boundless=False):
big_window = windows.Window(col_off=0, row_off=0, width=src.meta['width'], height=src.meta['height'])
for ji, window in src.block_windows(band):
if overlap == 0:
yield window
else:
window = windows.Window(
col_off=window.col_off - overlap,
row_off=window.row_off - overlap,
width=window.width + overlap * 2,
height=window.height + overlap * 2)
if boundless:
yield window
else:
yield window.intersection(big_window)
Output windows:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With