Skip to content

Latest commit

 

History

History
501 lines (308 loc) · 17.9 KB

StacItem.md

File metadata and controls

501 lines (308 loc) · 17.9 KB

STAC Item Properties

A STAC item is a metadata container for spatially and temporally bounded earth observation data. The data can be aerial imagery, radar data or other types of earth observation data. A STAC item has metadata properties describing the dataset and Assets that contain information for downloading the data being described. Almost all properties of a STAC item are aspects you can query by using a StacRequest with different types of filters.

Return to README.md

Expand Python Code Sample
from nsl.stac.client import NSLClient
from nsl.stac import StacRequest

stac_request = StacRequest(id='20190822T183518Z_746_POM1_ST2_P')

# get a client interface to the gRPC channel
client = NSLClient()
# for this request we might as well use the search one, as STAC ids ought to be unique
stac_item = client.search_one(stac_request)
Expand Python Print-out
    found NSL_ID <OMITTED> under profile name `default`
    nsl client connecting to stac service at: api.nearspacelabs.net:9090
    
    authorizing NSL_ID: `<OMITTED>`
    attempting NSL authentication against https://api.nearspacelabs.net/oauth/token...
    successfully authenticated with NSL_ID: `<OMITTED>`
    will attempt re-authorization in 60 minutes

Here are the sections where we go into more detail about properties and assets.

Printing out all the data demonstrates what is typically in a StacItem:

Expand Python Code Sample
print(stac_item)
Expand Python Print-out
    id: "20190822T183518Z_746_POM1_ST2_P"
    collection: "NSL_SCENE"
    properties {
      type_url: "nearspacelabs.com/proto/st.protobuf.v1.NslDatast.protobuf.v1.NslData/st.protobuf.v1.NslData"
      value: "\n\340\014\n\03620190822T162258Z_TRAVIS_COUNTY\"\003 \352\0052\03520200702T102306Z_746_ST2_POM1:\03520190822T183518Z_746_POM1_ST2:\03520200702T101632Z_746_ST2_POM1:\03520200702T102302Z_746_ST2_POM1:\03520200702T102306Z_746_ST2_POM1B\03520190822T183518Z_746_POM1_ST2H\001R\374\n\n$\004\304{?\216\371\350=\376\377\306>\300\327\256\275\323rv?2\026*D3Qy6\177>\3675\000\000\200?\022\024\r+}\303\302\025\033;\362A\0353}\367\300%g\232\250@\022\024\r\026}\303\302\025\376?\362A\035\000\367\235@%\232\t\331?\022\024\r\351|\303\302\025\021A\362A\035M\370\033\301%g\016\226\277\022\024\r\201|\303\302\025\3709\362A\035\000\252\245@%\315\3547?\022\024\r\310|\303\302\025\245G\362A\035\232\315l\301%3\347\270\300\022\024\rq|\303\302\025\2149\362A\035\000\376o@%\000(\017@\022\024\rD|\303\302\025oD\362A\0353\323\302\301%\315\306\230\300\022\024\r\031|\303\302\025\035=\362A\035g\277$A%\000\340\231?\022\024\rE|\303\302\025\215I\362A\0353\275z\300%g\020\236\300\022\024\r\345{\303\302\0258C\362A\035\0008\242?%\232\231\226\277\022\024\r\010|\303\302\025!I\362A\0353\377\212\300%\000V\241\300\022\024\r|{\303\302\025\207F\362A\0353\203Y@%\315,\313\276\022\024\r\001{\303\302\025FJ\362A\035g^\025@%\315\010\214?\022\024\r\313z\303\302\025\353H\362A\0353\3377@%g\326\325\277\022\024\rjz\303\302\025\260@\362A\035\315F\006A%g\246[\277\022\024\r\035z\303\302\0254E\362A\035\232\001|@%\232!\265?\022\024\r\330y\303\302\025\320@\362A\0353Sa\300%\000@\245>\022\024\r\362y\303\302\025zE\362A\035\232\221\020\300%3U\206@\022\024\r\337y\303\302\025\210F\362A\035g\246l?%gf\234\276\022\024\r\335y\303\302\025aF\362A\035\000\260\023@%\315,#\277\022\024\r\321y\303\302\025\234F\362A\035\000 7@%\232!\221?\022\024\r\307y\303\302\025\177F\362A\035\232\371\371?%\315\224\225?\022\024\r\213y\303\302\025\350@\362A\0353\'\343\300%3g&\300\022\024\r\300y\303\302\025\tF\362A\035\315h\312@%g\266\013?\022\024\r_y\303\302\025\236A\362A\035\315\340\311@%3\363j>\022\024\r\271x\303\302\025G?\362A\0353\334\272\301%gb\201\300\022\024\r\307x\303\302\025WG\362A\035\000|6\301%\232\231i>\022\024\r\200x\303\302\025\016F\362A\035\315\007\244\301%\315L\000>\022\024\rqx\303\302\025jI\362A\035\315\254\007\301%\232E\247?\022\024\rjx\303\302\025(I\362A\035\232\305\000\301%\315L\'>\022\024\r\027x\303\302\025\356A\362A\035\232I\246?%\315\004\246\277\022\024\r\010x\303\302\025AB\362A\035\232y\305\300%\315\3740?\022\024\r\032x\303\302\0257D\362A\0353\003\275\277%\232\311.?\022\024\r\002x\303\302\025&C\362A\035\315\014\301\277%g*2@\022\024\r\361w\303\302\025\330B\362A\035\000T\347\300%\232\235\025\300\022\024\r\372v\303\302\025\030<\362A\0353\323\364?%gNt\300\022\024\r;w\303\302\025\273I\362A\03533\335>%\232\025\213?\022\024\r\324v\303\302\025QC\362A\035\315,\305\277%\232\375\035@\022\024\r\340v\303\302\025@G\362A\035\315@\234\300%\232)\342?\022\024\r\312v\303\302\025yC\362A\035\315\214\247\276%g\246\375>\022\024\r\222v\303\302\025\233A\362A\035\315\334\244?%g\366\035\277\022\024\r\256v\303\302\025\\F\362A\0353G\204@%\232A\017@\022\024\rov\303\302\025\215=\362A\035\232\325\340@%3\263\033\276\022\024\r\206v\303\302\025SC\362A\0353\263k?%3\363\177\276\022\024\r\267v\303\302\025NK\362A\035\315\0148\277%3\323\000>\022\024\r\255v\303\302\025kK\362A\035gf4\277%\000\312\201\277\022\024\r)v\303\302\025\316=\362A\035\232\271Z\277%\315\014\375\277\022\024\r_v\303\302\025\356H\362A\035\315\004n@%3\243\240\276\022\024\r7v\303\302\025\350H\362A\0353#\212@%g~\272?\022\024\r\314u\303\302\025Y;\362A\035\000\000F=%gF\253?\022\024\r\276u\303\302\025q>\362A\0353/\234\300%g\246T\277\022\024\r\266u\303\302\025\321>\362A\035\315 \272\300%3SW\300\022\024\r\307u\303\302\025\211A\362A\035\000$\264\300%3\243\r\277\022\024\r\360u\303\302\025RK\362A\0353\347\231@%\315\325\036\300\022\024\r\262u\303\302\025\035F\362A\0353\2633\276%\232i3?\032#m_3009743_sw_14_1_20160928_20161129\"Y\t&\2068NM\357\"A\021\003\3272rL\217IA\031\267G\014x\260\375\"A!\202I\225>\020\222IA*3\0221+proj=utm +zone=14 +datum=NAD83 +units=m +no_defs*\005\r\205[\"A2\005\r\000\356\\@:\005\r\227\210\306AB\005\r\205E\257@\022\315\001\n e502fe83507f0d28c826f33619a678e9\022\03120200806T033934Z_SWIFTERA\030\010 \377\377\377\377\377\377\377\377\377\001(A0\0018\340\025@\330\247\004H\270\275\004R\03620190822T162258Z_TRAVIS_COUNTYR\03120200701T112634Z_SWIFTERAR\03120200701T112634Z_SWIFTERAR\03120200701T112634Z_SWIFTERAX\263\027"
    }
    assets {
      key: "GEOTIFF_RGB"
      value {
        href: "https://api.nearspacelabs.net/download/20190822T162258Z_TRAVIS_COUNTY/Published/REGION_0/20190822T183518Z_746_POM1_ST2_P.tif"
        type: "image/vnd.stac.geotiff"
        eo_bands: RGB
        asset_type: GEOTIFF
        cloud_platform: GCP
        bucket_manager: "Near Space Labs"
        bucket_region: "us-central1"
        bucket: "swiftera-processed-data"
        object_path: "20190822T162258Z_TRAVIS_COUNTY/Published/REGION_0/20190822T183518Z_746_POM1_ST2_P.tif"
      }
    }
    assets {
      key: "THUMBNAIL_RGB"
      value {
        href: "https://api.nearspacelabs.net/download/20190822T162258Z_TRAVIS_COUNTY/Published/REGION_0/20190822T183518Z_746_POM1_ST2_P.png"
        type: "image/png"
        eo_bands: RGB
        asset_type: THUMBNAIL
        cloud_platform: GCP
        bucket_manager: "Near Space Labs"
        bucket_region: "us-central1"
        bucket: "swiftera-processed-data"
        object_path: "20190822T162258Z_TRAVIS_COUNTY/Published/REGION_0/20190822T183518Z_746_POM1_ST2_P.png"
      }
    }
    geometry {
      wkb: "\001\006\000\000\000\001\000\000\000\001\003\000\000\000\001\000\000\000\005\000\000\000\352\244L\267\311oX\300\316\340\320\247\234I>@\241\273\2606\267oX\300<\002\205\'EG>@\031\003\203\307\266nX\3001z\244\372\233G>@CCAI\306nX\300\326\013\351\023\343I>@\352\244L\267\311oX\300\316\340\320\247\234I>@"
      proj {
        epsg: 4326
      }
      envelope {
        xmin: -97.7466867683867
        ymin: 30.278398961994966
        xmax: -97.72990596574927
        ymax: 30.288621181865743
        proj {
          epsg: 4326
        }
      }
      simple: STRONG_SIMPLE
    }
    bbox {
      xmin: -97.7466867683867
      ymin: 30.278398961994966
      xmax: -97.72990596574927
      ymax: 30.288621181865743
      proj {
        epsg: 4326
      }
    }
    datetime {
      seconds: 1566498918
      nanos: 505476000
    }
    observed {
      seconds: 1566498918
      nanos: 505476000
    }
    created {
      seconds: 1596743811
      nanos: 247169000
    }
    updated {
      seconds: 1612193286
      nanos: 12850810
    }
    platform_enum: SWIFT_2
    platform: "SWIFT_2"
    instrument_enum: POM_1
    instrument: "POM_1"
    constellation: "UNKNOWN_CONSTELLATION"
    mission_enum: SWIFT
    mission: "SWIFT"
    gsd {
      value: 0.20000000298023224
    }
    eo {
    }
    view {
      off_nadir {
        value: 9.42326831817627
      }
      azimuth {
        value: -74.85270690917969
      }
      sun_azimuth {
        value: 181.26959228515625
      }
      sun_elevation {
        value: 71.41288757324219
      }
    }
    

In addition to spatial and temporal details there are also details about the capturing device. We use both strings (to stay compliant with STAC JSON) and enum fields for these details. The platform_enum and platform is the model of the vehicle holding the sensor. The instrument_enum and instrument is the sensor that collected the scenes. In our case we're using mission_enum and mission to represent a class of flight vehicles that we're flying. In the case of the Landsat satellite program the breakdown would be:

  • platform_enum: enum.PLATFORM.LANDSAT_8
  • sensor_enum: enum.SENSOR.OLI_TIRS
  • mission_enum: enum.MISSION.LANDSAT
  • platform: "LANDSAT_8"
  • sensor: "OLI_TIRS"
  • mission: "LANDSAT"

ID Temporal and Spatial

Every STAC Item has a unique id, a datetime/observation, and a geometry/bbox (bounding-box).

Expand Python Code Sample
print("STAC Item id: {}\n".format(stac_item.id))
print("STAC Item observed: {}".format(stac_item.observed))
print("STAC Item datetime: {}".format(stac_item.datetime))
print("STAC Item bbox: {}".format(stac_item.bbox))
print("STAC Item geometry: {}".format(stac_item.geometry))
Expand Python Print-out
    STAC Item id: 20190822T183518Z_746_POM1_ST2_P
    
    STAC Item observed: seconds: 1566498918
    nanos: 505476000
    
    STAC Item datetime: seconds: 1566498918
    nanos: 505476000
    
    STAC Item bbox: xmin: -97.7466867683867
    ymin: 30.278398961994966
    xmax: -97.72990596574927
    ymax: 30.288621181865743
    proj {
      epsg: 4326
    }
    
    STAC Item geometry: wkb: "\001\006\000\000\000\001\000\000\000\001\003\000\000\000\001\000\000\000\005\000\000\000\352\244L\267\311oX\300\316\340\320\247\234I>@\241\273\2606\267oX\300<\002\205\'EG>@\031\003\203\307\266nX\3001z\244\372\233G>@CCAI\306nX\300\326\013\351\023\343I>@\352\244L\267\311oX\300\316\340\320\247\234I>@"
    proj {
      epsg: 4326
    }
    envelope {
      xmin: -97.7466867683867
      ymin: 30.278398961994966
      xmax: -97.72990596574927
      ymax: 30.288621181865743
      proj {
        epsg: 4326
      }
    }
    simple: STRONG_SIMPLE
    

As you can see above, the id is a string value. The format of the id is typically not guessable (ours is based of off the time the data was processed, the image index, the platform and the sensor).

The observed and datetime fields are the same value. STAC specification uses a generic field datetime to define the spatial component, the S, in STAC. We wanted a more descriptive variable, so we use observed, as in, the moment the scene was captured. This is a UTC timestamp in seconds and nano seconds.

The bbox field describes the xmin, ymin, xmax, and ymax points that describe the bounding box that contains the scene. The sr field has an epsg wkid. In this case the 4326 wkid indicates WGS-84

The geometry field has subfields wkb, sr, and simple. The wkb is a well known binary geometry format preferred for it's size. sr is the same as in the bbox. simple can be ignored.

Below we demonstrate how you can create python datetime objects:

Expand Python Code Sample
from datetime import datetime
print("UTC Observed Scene: {}".format(datetime.utcfromtimestamp(stac_item.observed.seconds)))
print("UTC Processed Data: {}".format(datetime.utcfromtimestamp(stac_item.created.seconds)))
print("UTC Updated Metadata: {}".format(datetime.utcfromtimestamp(stac_item.updated.seconds)))
Expand Python Print-out
    UTC Observed Scene: 2019-08-22 18:35:18
    UTC Processed Data: 2020-08-06 19:56:51
    UTC Updated Metadata: 2021-02-01 15:28:06

Updated is when the metadata was last updated. Typically that will be right after it's processed timestamp.

Below is a demo of using shapely to get at the geometry data.

Expand Python Code Sample
from shapely.geometry import Polygon
from shapely.wkb import loads

print("wkt printout of polygon:\n{}\n".format(loads(stac_item.geometry.wkb)))
print("centroid of polygon:\n{}\n".format(loads(stac_item.geometry.wkb).centroid))
print("bounds:\n{}\n".format(Polygon.from_bounds(stac_item.bbox.xmin, 
                                                 stac_item.bbox.ymin, 
                                                 stac_item.bbox.xmax, 
                                                 stac_item.bbox.ymax)))
Expand Python Print-out
    wkt printout of polygon:
    MULTIPOLYGON (((-97.7466867683867 30.28754662370266, -97.74555747279238 30.27839896199497, -97.72990596574927 30.27972380176124, -97.73085242627444 30.28862118186574, -97.7466867683867 30.28754662370266)))
    
    centroid of polygon:
    POINT (-97.738289581264 30.28357703330576)
    
    bounds:
    POLYGON ((-97.7466867683867 30.27839896199497, -97.7466867683867 30.28862118186574, -97.72990596574927 30.28862118186574, -97.72990596574927 30.27839896199497, -97.7466867683867 30.27839896199497))
    

Assets

Each STAC item should have at least one asset. An asset should be all the information you'll need to download the asset in question. For Near Space Labs customers, you'll be using the href, but you can also see the private bucket details of the asset. In protobuf the asset map has a key for each asset available. There's no part of the STAC specification for defining key names. Near Space Labs typically uses the data type, the optical bands and the cloud storage provider to construct a key name.

Expand Python Code Sample
from nsl.stac import Asset, utils
from nsl.stac.enum import AssetType
def print_asset(asset: Asset):
    asset_name = AssetType(asset.asset_type).name
    print(" href: {}".format(asset.href))
    print(" type: {}".format(asset.type))
    print(" protobuf enum number and name: {0}, {1}".format(asset.asset_type, asset_name))
    print()

print("there are {} assets".format(len(stac_item.assets)))
print(AssetType.THUMBNAIL.name)
print_asset(utils.get_asset(stac_item, asset_type=AssetType.THUMBNAIL))

print(AssetType.GEOTIFF.name)
print_asset(utils.get_asset(stac_item, asset_type=AssetType.GEOTIFF))
Expand Python Print-out
    there are 2 assets
    THUMBNAIL
     href: https://api.nearspacelabs.net/download/20190822T162258Z_TRAVIS_COUNTY/Published/REGION_0/20190822T183518Z_746_POM1_ST2_P.png
     type: image/png
     protobuf enum number and name: 9, THUMBNAIL
    
    GEOTIFF
     href: https://api.nearspacelabs.net/download/20190822T162258Z_TRAVIS_COUNTY/Published/REGION_0/20190822T183518Z_746_POM1_ST2_P.tif
     type: image/vnd.stac.geotiff
     protobuf enum number and name: 2, GEOTIFF
    

As you can see above, our data only consists of jpg thumbnails and Geotiffs. But there can be other data stored in Assets in the future.

You can read more details about Assets here

View

Some imagery analysis tools require knowing certain types of angular information. Here's a printout of the information we've collected with data. A summary of View values can be found here.

Expand Python Code Sample
print(stac_item.view)
Expand Python Print-out
    off_nadir {
      value: 9.42326831817627
    }
    azimuth {
      value: -74.85270690917969
    }
    sun_azimuth {
      value: 181.26959228515625
    }
    sun_elevation {
      value: 71.41288757324219
    }
    

These sun_azimuth, sun_elevation, off_nadir and azimuth are all boxed in the google.protobuf.FloatValue type. To get at the value you must access the value field.

Expand Python Code Sample
print("sun_azimuth: {:.5f}".format(stac_item.view.sun_azimuth.value))
print("sun_elevation: {:.5f}".format(stac_item.view.sun_elevation.value))
print("off_nadir: {:.5f}".format(stac_item.view.off_nadir.value))
print("azimuth: {:.5f}".format(stac_item.view.azimuth.value))
Expand Python Print-out
    sun_azimuth: 181.26959
    sun_elevation: 71.41289
    off_nadir: 9.42327
    azimuth: -74.85271

Notice that we're only printing out 5 decimal places. As these are stored as float values, we can't trust any of the precision that Python provides us beyond what we know the data to possess.

You can read more details about electro-optical data here

Return to README.md