1.. _windowrw: 2 3Windowed reading and writing 4============================ 5 6Beginning in rasterio 0.3, you can read and write "windows" of raster files. 7This feature allows you to work on rasters that are larger than your 8computers RAM or process chunks of large rasters in parallel. 9 10Windows 11------- 12 13A window is a view onto a rectangular subset of a raster dataset and is 14described in rasterio by column and row offsets and width and height 15in pixels. These may be ints or floats. 16 17.. code-block:: python 18 19 from rasterio.windows import Window 20 21 Window(col_off, row_off, width, height) 22 23Windows may also be constructed from numpy array index tuples or slice objects. 24Only int values are permitted in these cases. 25 26.. code-block:: python 27 28 Window.from_slices((row_start, row_stop), (col_start, col_stop)) 29 Window.from_slices(slice(row_start, row_stop), slice(col_start, col_stop)) 30 31If height and width keyword arguments are passed to ``from_slices``, relative 32and open-ended slices may be used. 33 34.. code-block:: python 35 36 Window.from_slices(slice(None), slice(None), height=100, width=100) 37 # Window(col_off=0.0, row_off=0.0, width=100.0, height=100.0) 38 39 Window.from_slices(slice(10, -10), slice(10, -10), height=100, width=100) 40 # Window(col_off=10, row_off=10, width=80, height=80) 41 42Reading 43------- 44 45Here is an example of reading a 256 row x 512 column subset of the rasterio 46test file. 47 48.. code-block:: pycon 49 50 >>> import rasterio 51 >>> with rasterio.open('tests/data/RGB.byte.tif') as src: 52 ... w = src.read(1, window=Window(0, 0, 512, 256)) 53 ... 54 >>> print(w.shape) 55 (256, 512) 56 57Writing 58------- 59 60Writing works similarly. The following creates a blank 500 column x 300 row 61GeoTIFF and plops 37,500 pixels with value 127 into a window 30 pixels down from 62and 50 pixels to the right of the upper left corner of the GeoTIFF. 63 64.. code-block:: python 65 66 image = numpy.ones((150, 250), dtype=rasterio.ubyte) * 127 67 68 with rasterio.open( 69 '/tmp/example.tif', 'w', 70 driver='GTiff', width=500, height=300, count=1, 71 dtype=image.dtype) as dst: 72 dst.write(image, window=Window(50, 30, 250, 150), indexes=1) 73 74The result: 75 76.. image:: http://farm6.staticflickr.com/5503/11378078386_cbe2fde02e_o_d.png 77 :width: 500 78 :height: 300 79 80Decimation 81---------- 82 83If the write window is smaller than the data, the data will be decimated. 84Below, the window is scaled to one third of the source image. 85 86.. code-block:: python 87 88 with rasterio.open('tests/data/RGB.byte.tif') as src: 89 b, g, r = (src.read(k) for k in (1, 2, 3)) 90 # src.height = 718, src.width = 791 91 92 write_window = Window.from_slices((30, 269), (50, 313)) 93 # write_window.height = 239, write_window.width = 263 94 95 with rasterio.open( 96 '/tmp/example.tif', 'w', 97 driver='GTiff', width=500, height=300, count=3, 98 dtype=r.dtype) as dst: 99 for k, arr in [(1, b), (2, g), (3, r)]: 100 dst.write(arr, indexes=k, window=write_window) 101 102And the result: 103 104.. image:: http://farm4.staticflickr.com/3804/11378361126_c034743079_o_d.png 105 :width: 500 106 :height: 300 107 108Data windows 109------------ 110 111Sometimes it is desirable to crop off an outer boundary of NODATA values around 112a dataset: 113 114.. code-block:: python 115 116 from rasterio.windows import get_data_window 117 118 with rasterio.open('tests/data/RGB.byte.tif') as src: 119 window = get_data_window(src.read(1, masked=True)) 120 # window = Window(col_off=13, row_off=3, width=757, height=711) 121 122 kwargs = src.meta.copy() 123 kwargs.update({ 124 'height': window.height, 125 'width': window.width, 126 'transform': rasterio.windows.transform(window, src.transform)}) 127 128 with rasterio.open('/tmp/cropped.tif', 'w', **kwargs) as dst: 129 dst.write(src.read(window=window)) 130 131Window transforms 132----------------- 133 134The affine transform of a window can be accessed using a dataset's 135``window_transform`` method: 136 137.. code-block:: pycon 138 139 >>> import rasterio 140 >>> from rasterio.windows import Window 141 >>> win = Window(256, 256, 128, 128) 142 >>> with rasterio.open('tests/data/RGB.byte.tif') as src: 143 ... src_transform = src.transform 144 ... win_transform = src.window_transform(win) 145 ... 146 >>> print(src_transform) 147 | 300.04, 0.00, 101985.00| 148 | 0.00,-300.04, 2826915.00| 149 | 0.00, 0.00, 1.00| 150 >>> print(win_transform) 151 | 300.04, 0.00, 178794.71| 152 | 0.00,-300.04, 2750104.30| 153 | 0.00, 0.00, 1.00| 154 155Window utilities 156---------------- 157 158Basic union and intersection operations are available for windows, to 159streamline operations across dynamically created windows for a series of bands 160or datasets with the same full extent. 161 162.. code-block:: python 163 164 >>> from rasterio import windows 165 >>> # Full window is ((0, 1000), (0, 500)) 166 >>> window1 = Window(10, 100, 490, 400) 167 >>> window2 = Window(50, 10, 200, 140) 168 >>> windows.union(window1, window2) 169 Window(col_off=10, row_off=10, width=490, height=490) 170 >>> windows.intersection(window1, window2) 171 Window(col_off=50, row_off=100, width=200, height=50) 172 173 174Blocks 175------ 176 177Raster datasets are generally composed of multiple blocks of data and 178windowed reads and writes are most efficient when the windows match the 179dataset's own block structure. When a file is opened to read, the shape 180of blocks for any band can be had from the block_shapes property. 181 182.. code-block:: pycon 183 184 >>> with rasterio.open('tests/data/RGB.byte.tif') as src: 185 ... for i, shape in enumerate(src.block_shapes, 1): 186 ... print((i, shape)) 187 ... 188 (1, (3, 791)) 189 (2, (3, 791)) 190 (3, (3, 791)) 191 192 193The block windows themselves can be had from the block_windows function. 194 195.. code-block:: pycon 196 197 >>> with rasterio.open('tests/data/RGB.byte.tif') as src: 198 ... for ji, window in src.block_windows(1): 199 ... print((ji, window)) 200 ... 201 ((0, 0), ((0, 3), (0, 791))) 202 ((1, 0), ((3, 6), (0, 791))) 203 ... 204 205This function returns an iterator that yields a pair of values. The second is 206a window tuple that can be used in calls to `read` or `write`. The first 207is the pair of row and column indexes of this block within all blocks of the 208dataset. 209 210You may read windows of data from a file block-by-block like this. 211 212.. code-block:: pycon 213 214 >>> with rasterio.open('tests/data/RGB.byte.tif') as src: 215 ... for ji, window in src.block_windows(1): 216 ... r = src.read(1, window=window) 217 ... print(r.shape) 218 ... break 219 ... 220 (3, 791) 221 222Well-bred files have identically blocked bands, but GDAL allows otherwise and 223it's a good idea to test this assumption in your code. 224 225.. code-block:: pycon 226 227 >>> with rasterio.open('tests/data/RGB.byte.tif') as src: 228 ... assert len(set(src.block_shapes)) == 1 229 ... for ji, window in src.block_windows(1): 230 ... b, g, r = (src.read(k, window=window) for k in (1, 2, 3)) 231 ... print((ji, r.shape, g.shape, b.shape)) 232 ... break 233 ... 234 ((0, 0), (3, 791), (3, 791), (3, 791)) 235 236The block_shapes property is a band-ordered list of block shapes and 237`set(src.block_shapes)` gives you the set of unique shapes. Asserting that 238there is only one item in the set is effectively the same as asserting that all 239bands have the same block structure. If they do, you can use the same windows 240for each. 241