|
1 | 1 | # async-geotiff |
2 | 2 |
|
3 | | -Async GeoTIFF and [Cloud-Optimized GeoTIFF][cogeo] (COG) reader for Python, wrapping [`async-tiff`][async-tiff]. |
| 3 | +Fast, async GeoTIFF and [Cloud-Optimized GeoTIFF][cogeo] (COG) reader for Python, wrapping the Rust-based [Async-TIFF][async-tiff] library. |
4 | 4 |
|
5 | 5 | [async-tiff]: https://github.com/developmentseed/async-tiff |
6 | 6 | [cogeo]: https://cogeo.org/ |
7 | 7 |
|
8 | | -## Project Goals: |
| 8 | +## Features |
9 | 9 |
|
10 | | -- Support only for GeoTIFF and Cloud-Optimized GeoTIFF (COG) formats |
11 | | -- Support for reading only, no writing support |
12 | | -- Full type hinting. |
13 | | -- API similar to rasterio where possible. |
14 | | - - We won't support the full rasterio API, but we'll try to when it's possible to implement rasterio APIs with straightforward maintenance requirements. |
15 | | - - For methods where we do intentionally try to match with rasterio, the tests should match against rasterio. |
16 | | -- Initially, we'll try to support a core set of GeoTIFF formats. Obscure GeoTIFF files may not be supported. |
| 10 | +- Read-only support for GeoTIFF and COG formats. |
| 11 | +- High-level, familiar, easy to use API. |
| 12 | +- Performance-focused: |
| 13 | + - Rust core ensures native performance. |
| 14 | + - CPU-bound tasks like image decoding happen in a thread pool, without blocking the async executor. |
| 15 | + - Buffer protocol integration for zero-copy data sharing between Rust and Python. |
| 16 | +- Lightweight with no GDAL dependency. |
| 17 | +- Integration with [obstore] for efficient data access on object stores. |
| 18 | +- Full type hinting for all operations. |
| 19 | +- Broad decompression support: Deflate, LZW, JPEG, JPEG2000, WebP, ZSTD. |
17 | 20 |
|
18 | | -## References |
| 21 | +**Anti-Features** (features explicitly not in scope): |
19 | 22 |
|
20 | | -- aiocogeo: https://github.com/geospatial-jeff/aiocogeo |
| 23 | +- No pixel resampling. |
| 24 | +- No warping/reprojection. |
| 25 | + |
| 26 | +Resampling and warping bring significant additional complexity and are out of scope for this library. |
| 27 | + |
| 28 | +[obstore]: https://developmentseed.org/obstore/latest/ |
| 29 | +[obspec]: https://developmentseed.org/obspec/latest/ |
| 30 | + |
| 31 | +## Example |
| 32 | + |
| 33 | +First create a "store", such as an [`S3Store`][S3Store], [`GCSStore`][GCSStore], [`AzureStore`][AzureStore], or [`LocalStore`][LocalStore] for reading data from AWS S3, Google Cloud, Azure Storage, or local files. Refer to [obstore] documentation for more information. |
| 34 | + |
| 35 | +[S3Store]: https://developmentseed.org/obstore/latest/api/store/aws/#obstore.store.S3Store |
| 36 | +[GCSStore]: https://developmentseed.org/obstore/latest/api/store/gcs/#obstore.store.GCSStore |
| 37 | +[AzureStore]: https://developmentseed.org/obstore/latest/api/store/azure/#obstore.store.AzureStore |
| 38 | +[LocalStore]: https://developmentseed.org/obstore/latest/api/store/local/#obstore.store.LocalStore |
| 39 | + |
| 40 | +```py |
| 41 | +from obstore.store import S3Store |
| 42 | + |
| 43 | +store = S3Store("sentinel-cogs", region="us-west-2", skip_signature=True) |
| 44 | +path = "sentinel-s2-l2a-cogs/12/S/UF/2022/6/S2B_12SUF_20220609_0_L2A/TCI.tif" |
| 45 | +``` |
| 46 | + |
| 47 | +Then open a `GeoTIFF`: |
| 48 | + |
| 49 | +```py |
| 50 | +from async_geotiff import GeoTIFF |
| 51 | + |
| 52 | +geotiff = await GeoTIFF.open(path, store=store) |
| 53 | +``` |
| 54 | + |
| 55 | +On the `GeoTIFF` instance you have metadata about the image, such as its affine transform and Coordinate Reference System: |
| 56 | + |
| 57 | +```py |
| 58 | +geotiff.transform |
| 59 | +# Affine(10.0, 0.0, 300000.0, |
| 60 | +# 0.0, -10.0, 4100040.0) |
| 61 | + |
| 62 | +geotiff.crs |
| 63 | +# <Projected CRS: EPSG:32612> |
| 64 | +# Name: WGS 84 / UTM zone 12N |
| 65 | +``` |
| 66 | + |
| 67 | +For a COG, you can access the overviews, or reduced resolution versions, of the image: |
| 68 | + |
| 69 | +```py |
| 70 | +# Overviews are ordered from finest to coarsest resolution |
| 71 | +# In this case, access the second-coarsest resolution version of the image |
| 72 | +overview = geotiff.overviews[-2] |
| 73 | +``` |
| 74 | + |
| 75 | +Then we can read data from the image. This loads a 512-pixel square from the |
| 76 | +upper-left corner of the selected overview. |
| 77 | + |
| 78 | +```py |
| 79 | +from async_geotiff import Window |
| 80 | + |
| 81 | +window = Window(col_off=0, row_off=0, width=512, height=512) |
| 82 | +array = await overview.read(window=window) |
| 83 | +``` |
| 84 | + |
| 85 | +This `Array` instance has `data`, `mask`, and some other metadata about the fetched array data. |
| 86 | + |
| 87 | +Plot, using [`rasterio.plot.show`](https://rasterio.readthedocs.io/en/stable/api/rasterio.plot.html#rasterio.plot.show) (requires `matplotlib`): |
| 88 | + |
| 89 | +```py |
| 90 | +import rasterio.plot |
| 91 | + |
| 92 | +rasterio.plot.show(array.data) |
| 93 | +``` |
| 94 | + |
| 95 | + |
0 commit comments