stac-utils / stac-vrt

MIT License
21 stars 2 forks source link

proj:transform and proj:shape in assets #11

Open rmg55 opened 3 years ago

rmg55 commented 3 years ago

It looks like some catalogs have the transform and shape in the assets (I think that is the correct term) rather than the properties. Probably due to the bands/assets have different resolutions. For instance:

import satsearch
URL='https://earth-search.aws.element84.com/v0'
results = satsearch.Search.search(url=URL,
                                  collections=['sentinel-s2-l2a-cogs'],
                                  bbox=[-105.791,39.783,-103.677,41.870],
                                  datetime='2021-02-27/2021-02-27')
stac_catalog = results.query()
#Just use the cogs
stac_items = [f for f in stac_catalog['features'] if f['collection']=='sentinel-s2-l2a-cogs']
stac_items[0]
output ``` {'type': 'Feature', 'stac_version': '1.0.0-beta.2', 'stac_extensions': ['eo', 'view', 'proj'], 'id': 'S2A_30VXK_20210305_0_L2A', 'bbox': [-0.29262403233012585, 58.46076357917498, 0.6099851126869734, 58.612152234653784], 'geometry': {'type': 'Polygon', 'coordinates': [[[0.5967195657827756, 58.46076357917498], [-0.2908733182739893, 58.61116185262608], [-0.29262403233012585, 58.612152234653784], [0.6099851126869734, 58.58996039069121], [0.5967195657827756, 58.46076357917498]]]}, 'properties': {'datetime': '2021-03-05T11:24:56Z', 'platform': 'sentinel-2a', 'constellation': 'sentinel-2', 'instruments': ['msi'], 'gsd': 10, 'view:off_nadir': 0, 'proj:epsg': 32630, 'sentinel:utm_zone': 30, 'sentinel:latitude_band': 'V', 'sentinel:grid_square': 'XK', 'sentinel:sequence': '0', 'sentinel:product_id': 'S2A_MSIL2A_20210305T112111_N0214_R037_T30VXK_20210305T121545', 'sentinel:data_coverage': 3.1, 'eo:cloud_cover': 4.65, 'sentinel:valid_cloud_cover': True, 'created': '2021-03-05T18:17:22.360Z', 'updated': '2021-03-05T18:17:22.360Z'}, 'collection': 'sentinel-s2-l2a-cogs', 'assets': {'thumbnail': {'title': 'Thumbnail', 'type': 'image/png', 'roles': ['thumbnail'], 'href': 'https://roda.sentinel-hub.com/sentinel-s2-l1c/tiles/30/V/XK/2021/3/5/0/preview.jpg'}, 'overview': {'title': 'True color image', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['overview'], 'gsd': 10, 'eo:bands': [{'name': 'B04', 'common_name': 'red', 'center_wavelength': 0.6645, 'full_width_half_max': 0.038}, {'name': 'B03', 'common_name': 'green', 'center_wavelength': 0.56, 'full_width_half_max': 0.045}, {'name': 'B02', 'common_name': 'blue', 'center_wavelength': 0.4966, 'full_width_half_max': 0.098}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/L2A_PVI.tif', 'proj:shape': [343, 343], 'proj:transform': [320, 0, 600000, 0, -320, 6500040, 0, 0, 1]}, 'info': {'title': 'Original JSON metadata', 'type': 'application/json', 'roles': ['metadata'], 'href': 'https://roda.sentinel-hub.com/sentinel-s2-l2a/tiles/30/V/XK/2021/3/5/0/tileInfo.json'}, 'metadata': {'title': 'Original XML metadata', 'type': 'application/xml', 'roles': ['metadata'], 'href': 'https://roda.sentinel-hub.com/sentinel-s2-l2a/tiles/30/V/XK/2021/3/5/0/metadata.xml'}, 'visual': {'title': 'True color image', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['overview'], 'gsd': 10, 'eo:bands': [{'name': 'B04', 'common_name': 'red', 'center_wavelength': 0.6645, 'full_width_half_max': 0.038}, {'name': 'B03', 'common_name': 'green', 'center_wavelength': 0.56, 'full_width_half_max': 0.045}, {'name': 'B02', 'common_name': 'blue', 'center_wavelength': 0.4966, 'full_width_half_max': 0.098}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/TCI.tif', 'proj:shape': [10980, 10980], 'proj:transform': [10, 0, 600000, 0, -10, 6500040, 0, 0, 1]}, 'B01': {'title': 'Band 1 (coastal)', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 60, 'eo:bands': [{'name': 'B01', 'common_name': 'coastal', 'center_wavelength': 0.4439, 'full_width_half_max': 0.027}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B01.tif', 'proj:shape': [1830, 1830], 'proj:transform': [60, 0, 600000, 0, -60, 6500040, 0, 0, 1]}, 'B02': {'title': 'Band 2 (blue)', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 10, 'eo:bands': [{'name': 'B02', 'common_name': 'blue', 'center_wavelength': 0.4966, 'full_width_half_max': 0.098}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B02.tif', 'proj:shape': [10980, 10980], 'proj:transform': [10, 0, 600000, 0, -10, 6500040, 0, 0, 1]}, 'B03': {'title': 'Band 3 (green)', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 10, 'eo:bands': [{'name': 'B03', 'common_name': 'green', 'center_wavelength': 0.56, 'full_width_half_max': 0.045}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B03.tif', 'proj:shape': [10980, 10980], 'proj:transform': [10, 0, 600000, 0, -10, 6500040, 0, 0, 1]}, 'B04': {'title': 'Band 4 (red)', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 10, 'eo:bands': [{'name': 'B04', 'common_name': 'red', 'center_wavelength': 0.6645, 'full_width_half_max': 0.038}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B04.tif', 'proj:shape': [10980, 10980], 'proj:transform': [10, 0, 600000, 0, -10, 6500040, 0, 0, 1]}, 'B05': {'title': 'Band 5', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 20, 'eo:bands': [{'name': 'B05', 'center_wavelength': 0.7039, 'full_width_half_max': 0.019}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B05.tif', 'proj:shape': [5490, 5490], 'proj:transform': [20, 0, 600000, 0, -20, 6500040, 0, 0, 1]}, 'B06': {'title': 'Band 6', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 20, 'eo:bands': [{'name': 'B06', 'center_wavelength': 0.7402, 'full_width_half_max': 0.018}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B06.tif', 'proj:shape': [5490, 5490], 'proj:transform': [20, 0, 600000, 0, -20, 6500040, 0, 0, 1]}, 'B07': {'title': 'Band 7', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 20, 'eo:bands': [{'name': 'B07', 'center_wavelength': 0.7825, 'full_width_half_max': 0.028}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B07.tif', 'proj:shape': [5490, 5490], 'proj:transform': [20, 0, 600000, 0, -20, 6500040, 0, 0, 1]}, 'B08': {'title': 'Band 8 (nir)', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 10, 'eo:bands': [{'name': 'B08', 'common_name': 'nir', 'center_wavelength': 0.8351, 'full_width_half_max': 0.145}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B08.tif', 'proj:shape': [10980, 10980], 'proj:transform': [10, 0, 600000, 0, -10, 6500040, 0, 0, 1]}, 'B8A': {'title': 'Band 8A', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 20, 'eo:bands': [{'name': 'B8A', 'center_wavelength': 0.8648, 'full_width_half_max': 0.033}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B8A.tif', 'proj:shape': [5490, 5490], 'proj:transform': [20, 0, 600000, 0, -20, 6500040, 0, 0, 1]}, 'B09': {'title': 'Band 9', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 60, 'eo:bands': [{'name': 'B09', 'center_wavelength': 0.945, 'full_width_half_max': 0.026}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B09.tif', 'proj:shape': [1830, 1830], 'proj:transform': [60, 0, 600000, 0, -60, 6500040, 0, 0, 1]}, 'B11': {'title': 'Band 11 (swir16)', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 20, 'eo:bands': [{'name': 'B11', 'common_name': 'swir16', 'center_wavelength': 1.6137, 'full_width_half_max': 0.143}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B11.tif', 'proj:shape': [5490, 5490], 'proj:transform': [20, 0, 600000, 0, -20, 6500040, 0, 0, 1]}, 'B12': {'title': 'Band 12 (swir22)', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'gsd': 20, 'eo:bands': [{'name': 'B12', 'common_name': 'swir22', 'center_wavelength': 2.22024, 'full_width_half_max': 0.242}], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/B12.tif', 'proj:shape': [5490, 5490], 'proj:transform': [20, 0, 600000, 0, -20, 6500040, 0, 0, 1]}, 'AOT': {'title': 'Aerosol Optical Thickness (AOT)', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/AOT.tif', 'proj:shape': [1830, 1830], 'proj:transform': [60, 0, 600000, 0, -60, 6500040, 0, 0, 1]}, 'WVP': {'title': 'Water Vapour (WVP)', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/WVP.tif', 'proj:shape': [10980, 10980], 'proj:transform': [10, 0, 600000, 0, -10, 6500040, 0, 0, 1]}, 'SCL': {'title': 'Scene Classification Map (SCL)', 'type': 'image/tiff; application=geotiff; profile=cloud-optimized', 'roles': ['data'], 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/SCL.tif', 'proj:shape': [5490, 5490], 'proj:transform': [20, 0, 600000, 0, -20, 6500040, 0, 0, 1]}}, 'links': [{'rel': 'self', 'href': 'https://earth-search.aws.element84.com/v0/collections/sentinel-s2-l2a-cogs/items/S2A_30VXK_20210305_0_L2A'}, {'rel': 'canonical', 'href': 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/S2A_30VXK_20210305_0_L2A.json', 'type': 'application/json'}, {'title': 'sentinel-s2-l2a-aws/workflow-publish-sentinel/tiles-30-V-XK-2021-3-5-0', 'rel': 'via-cirrus', 'href': 'https://cirrus-earth-search.aws.element84.com/v0/catid/sentinel-s2-l2a-aws/workflow-publish-sentinel/tiles-30-V-XK-2021-3-5-0'}, {'title': 'Source STAC Item', 'rel': 'derived_from', 'href': 'https://cirrus-v0-data-1qm7gekzjucbq.s3.us-west-2.amazonaws.com/sentinel-s2-l2a/30/V/XK/2021/3/S2A_30VXK_20210305_0_L2A/S2A_30VXK_20210305_0_L2A.json', 'type': 'application/json'}, {'title': 'sentinel-s2-l2a/workflow-cog-archive/S2A_30VXK_20210305_0_L2A', 'rel': 'via-cirrus', 'href': 'https://cirrus-earth-search.aws.element84.com/v0/catid/sentinel-s2-l2a/workflow-cog-archive/S2A_30VXK_20210305_0_L2A'}, {'rel': 'parent', 'href': 'https://earth-search.aws.element84.com/v0/collections/sentinel-s2-l2a-cogs'}, {'rel': 'collection', 'href': 'https://earth-search.aws.element84.com/v0/collections/sentinel-s2-l2a-cogs'}, {'rel': 'root', 'href': 'https://earth-search.aws.element84.com/v0/'}]} ```

Perhaps adding a "target_asset" keyword to build_vrt, then update the logic on shapes/transform to somthing like:


if shapes is None:
    if Band==None
        shapes = [stac_item["properties"]["proj:shape"] for stac_item in stac_items]
    else:
        try:
            shapes = [stac_item["properties"]['assets']["proj:shape"] for stac_item in stac_items]
        except KeyError:
            shapes = [stac_item["properties"]['assets'][Band]["proj:shape"] for stac_item in stac_items]

elif len(shapes) != len(stac_items):
    raise ValueError(
            "Number of user-provided 'shapes' does not match the number of "
            "'stac_items' ({} != {})".format(len(shapes), len(stac_items))
        )

Happy to work up a PR if this seems like a good route.

TomAugspurger commented 3 years ago

Yeah, I recall something in the proj extension about "default" assets. Right now the type on shapes is List[Tuple], specifying the shape of each asset. I wonder if it should be a List[Dict[Tuple]], specifying the shape of each band for each asset... I'll need to play with this a bit.

Anyway, agreed that we should have some way to handle this case.

rmg55 commented 3 years ago

Sounds good @TomAugspurger

I updated the original post to change "target_band" to "target_asset". Quickly glancing at build_vrt, is it currently hardcoded to stac_item["assets"]["image"] (line 225)?

In the Sentinel Catalog the assets look like:

stac_items[0]['assets'].keys()
dict_keys(['thumbnail', 'overview', 'info', 'metadata', 'visual', 'B01', 'B02', 'B03', 'B04', 'B05', 'B06', 'B07', 'B08', 'B8A', 'B09', 'B11', 'B12', 'AOT', 'WVP', 'SCL'])

Cheers

TomAugspurger commented 3 years ago

Thanks. Just a general comment that right now stac-vrt bakes in many assumptions about the dataset I tested it on (NAIP on Azure: https://github.com/microsoft/AIforEarthDataSets/blob/main/data/naip.md). So we'll need to generalize things to handle that.

The NAIP dataset stores the four bands in a single COG. The AWS Sentinel data looks to have multiple assets (COGs) per STAC item. So we'll need some way of indicating which assets will be put into the VRT.

Right now we have something like

build_vrt(naip_data, asset_key="image")

which returns a VRT that has multiple bands since the COGs have multiple bands. Would a user ever do something like

build_vrt(sentinel_data, asset_key=["B01", "B02"])

which would return a similar VRT (multiple bands) that have been stacked together?

TomAugspurger commented 3 years ago

which would return a similar VRT (multiple bands) that have been stacked together?

Looking at gdalbuildvrt, the -separate parameter controls this. By default, they're considered tiles in a larger mosaic, but -separate says to treat them as separate bands.

Now, my imagined use case for stac-vrt is for creating a large mosaic from many items. But we can apply the same idea here... I guess we would want some kind of VRT of VRTs, where the "inner" VRTs use a -separate-like behavior to stack the multiple files into separate bands of a single array. Then the outer VRT would mosaic those many VRTs into a single mosaic.

If you have API suggestions it'd be great to hear them. I think my initial preference is to preserve a single build_vrt function, but expand it to handle the case where bands are split across multiple files. Something like concat_assets=["B02", "B03"] would build up the inner VRTs? Or maybe even just assets=["B02", "B03"]. In which case our "current default" would be the hardcoded assets="image".

cc @scottyhq, if you have thoughts on the API design as well. Anything we should consider from xarray?

rmg55 commented 3 years ago

My 2cents would be to use assets=["B02","B03"] and have a concat=BOOL. If concat=False, then return a list of vrt files, if True, then return the single multiband file (gdal -separate version).

Not sure if this is the correct place to put these ideas, but I wanted to mention a few other functionalities that I think would be useful to think about including:

  1. Mosaicing - stitching together a bunch of asset(s)

    • Base Case: STAC items are in the same CRS. Overlap regions determined by the order of the files in the VRT (current implementation)
    • Variable CRS: When stac items have different CRS (aka Sentinel, Landsat), I assume we would need to implement the warping parameters within vrt file to get them into the same geographic projection. Good discussion in the Pangeo Discourse page about why this would be great to have - https://discourse.pangeo.io/t/copernicus-sentiel-2-overlapping-coordinates-between-tiles/1280/10. If keeping rasterio as a dependency, the WarpedVRT function would probably be really useful for this.
    • Overlap Regions: Ability to provide (or have pre-built) pixel functions that can be applied to overlap regions in the mosaic (e.g. mean, max, min, best).
  2. Stacking Items: Stack single band asset from a STAC item and place it into a band in a vrt file (gdal -seperate). This would replace the "band" dimension, with "time". This would not involve any spatial mosaicing. This would need to be a single file per band, because COGs are limited to 3 dimensions (unless there is some way to use the (Multidimensional VRT)[https://gdal.org/drivers/raster/vrt_multidimensional.html#vrt-multidimensional] and have x,y,band,time dimensions).

scottyhq commented 3 years ago

Hi @rmg55 and @TomAugspurger . Very excited about the potential for stac-vrt for both mosaicing and stacking! These ideas are all great. A lot of this discussion has come up over in https://github.com/intake/intake-stac/issues/65, and I'm thinking I'll open a draft PR over there to more easily comment on API ideas. I've found working with several available catalogs has been key given how relevant info can be stored in different places via extensions, there is some churn in itemcollections returned by stac-search results (https://github.com/stac-utils/pystac/issues/256#issuecomment-765663796) versus static catalogs, and not everything is implemented yet in pystac (e.g. https://github.com/stac-utils/pystac/issues/132)

cc @scottyhq, if you have thoughts on the API design as well. Anything we should consider from xarray?

In brief, my recommendation would be to keep the keyword arguments in build_vrt() as close as possible to gdal's buildvrt. for example separate=False by default. I think it's best for starters to focus on the case for data like NAIP, S2, HLS, that is already on a common grid (at least same CRS) to avoid reprojection/WarpedVRT/resampling complications. I've found -resolution='highest' is also handy for the S2 case where different assets can have different ground-sample-distance. I think that is more natural than the default -resolution=average...

As for 'asset' or 'asset_key'... 'asset_key' can be anything for better or worse ('B04', 'visual', 'random-name'). One of my favorite features of intake-stac is the mapping between eo:bands common names to assets though. For example it's really nice as a user to say assets=["red","nir"] and let the code find the matching key.

rmg55 commented 3 years ago

Thanks @scottyhq great points (especially the -resolution arg). Will switch over to the other thread, but just wanted to clarify one point:

focus on the case for data like NAIP, S2, HLS, that is already on a common grid (at least same CRS) to avoid reprojection/WarpedVRT/resampling complications

If working in the same tile (and temporally stacking assets), then yes, we should have a consistent CRS. However, if mosaicing, I don't think this is the case . For instance here is an example with the Sentinel STAC where we would probably want to reproject into a geographic projection (e.g. epsg:4326). Perhaps I am missing something her though?

import satsearch
URL='https://earth-search.aws.element84.com/v0'
results = satsearch.Search.search(url=URL,
                                  collections=['sentinel-s2-l2a-cogs'],
                                  bbox=[-110.791,39.783,-50.677,41.870],
                                  datetime='2021-02-27/2021-02-27')
stac_catalog = results.items().geojson()
for assets in stac_items:
    print('Projection:',
          'epsg:'+str(assets['properties']['proj:epsg']),
          'UTM Zone:',
          assets['properties']['sentinel:utm_zone'],
          'Lat. Band:',
          assets['properties']['sentinel:latitude_band'],
          'Grid Square:',
          assets['properties']['sentinel:grid_square'])
Projection: epsg:32613 UTM Zone: 13 Lat. Band: T Grid Square: DE
Projection: epsg:32613 UTM Zone: 13 Lat. Band: T Grid Square: EE
Projection: epsg:32613 UTM Zone: 13 Lat. Band: T Grid Square: FE
Projection: epsg:32613 UTM Zone: 13 Lat. Band: T Grid Square: GE
Projection: epsg:32614 UTM Zone: 14 Lat. Band: T Grid Square: KK
Projection: epsg:32613 UTM Zone: 13 Lat. Band: T Grid Square: DF
Projection: epsg:32613 UTM Zone: 13 Lat. Band: T Grid Square: EF
Projection: epsg:32613 UTM Zone: 13 Lat. Band: T Grid Square: FF
Projection: epsg:32614 UTM Zone: 14 Lat. Band: T Grid Square: KL
Projection: epsg:32613 UTM Zone: 13 Lat. Band: T Grid Square: GF
Projection: epsg:32613 UTM Zone: 13 Lat. Band: T Grid Square: EG
Projection: epsg:32614 UTM Zone: 14 Lat. Band: T Grid Square: LL
Projection: epsg:32613 UTM Zone: 13 Lat. Band: T Grid Square: FG
Projection: epsg:32614 UTM Zone: 14 Lat. Band: T Grid Square: KM
Projection: epsg:32613 UTM Zone: 13 Lat. Band: T Grid Square: GG
Projection: epsg:32614 UTM Zone: 14 Lat. Band: T Grid Square: LM
Projection: epsg:32615 UTM Zone: 15 Lat. Band: T Grid Square: WE
Projection: epsg:32615 UTM Zone: 15 Lat. Band: T Grid Square: XE
Projection: epsg:32615 UTM Zone: 15 Lat. Band: T Grid Square: YE
Projection: epsg:32616 UTM Zone: 16 Lat. Band: T Grid Square: BK
Projection: epsg:32616 UTM Zone: 16 Lat. Band: T Grid Square: CK
Projection: epsg:32615 UTM Zone: 15 Lat. Band: T Grid Square: WF
Projection: epsg:32615 UTM Zone: 15 Lat. Band: T Grid Square: XF
Projection: epsg:32615 UTM Zone: 15 Lat. Band: T Grid Square: YF
Projection: epsg:32616 UTM Zone: 16 Lat. Band: T Grid Square: BL
Projection: epsg:32616 UTM Zone: 16 Lat. Band: T Grid Square: CL
Projection: epsg:32615 UTM Zone: 15 Lat. Band: T Grid Square: WG
Projection: epsg:32615 UTM Zone: 15 Lat. Band: T Grid Square: XG
Projection: epsg:32615 UTM Zone: 15 Lat. Band: T Grid Square: YG
Projection: epsg:32616 UTM Zone: 16 Lat. Band: T Grid Square: BM
Projection: epsg:32616 UTM Zone: 16 Lat. Band: T Grid Square: CM
Projection: epsg:32617 UTM Zone: 17 Lat. Band: T Grid Square: NE
Projection: epsg:32617 UTM Zone: 17 Lat. Band: T Grid Square: PE
Projection: epsg:32617 UTM Zone: 17 Lat. Band: T Grid Square: QE
Projection: epsg:32618 UTM Zone: 18 Lat. Band: T Grid Square: TK
Projection: epsg:32618 UTM Zone: 18 Lat. Band: T Grid Square: UK
Projection: epsg:32617 UTM Zone: 17 Lat. Band: T Grid Square: NF
Projection: epsg:32617 UTM Zone: 17 Lat. Band: T Grid Square: PF
Projection: epsg:32618 UTM Zone: 18 Lat. Band: T Grid Square: TL
Projection: epsg:32617 UTM Zone: 17 Lat. Band: T Grid Square: QF
Projection: epsg:32618 UTM Zone: 18 Lat. Band: T Grid Square: UL
Projection: epsg:32617 UTM Zone: 17 Lat. Band: T Grid Square: PG
Projection: epsg:32618 UTM Zone: 18 Lat. Band: T Grid Square: VL
Projection: epsg:32617 UTM Zone: 17 Lat. Band: T Grid Square: QG
Projection: epsg:32618 UTM Zone: 18 Lat. Band: T Grid Square: TM
Projection: epsg:32618 UTM Zone: 18 Lat. Band: T Grid Square: UM
Projection: epsg:32618 UTM Zone: 18 Lat. Band: T Grid Square: VM
matthewhanson commented 3 years ago

These are some great features, some random thoughts:

lossyrob commented 3 years ago

Noting here that I'm creating Items where proj:epsg, proj:bbox live at the Item level as a default for any asset, while proj:shape and proj:transform may be Item specific.

PySTAC allows you to pull a property from an asset if available, and if not checks the properties of the Item. e.g. in

asset_key: str = ...
item: pystac.Item = ...
bbox: Optional[List[float]] = item.ext.projection.get_bbox(item.assets[asset_key])

bbox will be pulled from the asset; if the asset doesn't have that property, it's pulled from the item; if the item doesn't have it, it's None.

RichardScottOZ commented 3 years ago

I don't think resolution : average makes sense, either @scottyhq - not for multispectral satellite data, anyway. Landsat 8 - 30s, 15s and 100s for example.

Reprojection - not necessarily geographic @rmg55 - you could have say Australian or European or South American projected coordinate systems for larger scale areas you may want to use - so possibly an option?