Skip to content

Instantly share code, notes, and snippets.

@echeipesh
Last active July 20, 2020 15:23
Show Gist options
  • Save echeipesh/2d2a18b59d634ecbfd97b7d32bba6164 to your computer and use it in GitHub Desktop.
Save echeipesh/2d2a18b59d634ecbfd97b7d32bba6164 to your computer and use it in GitHub Desktop.
Tiny SpaceNet STAC
{
"id": "tiny-spacenet",
"stac_version": "0.9.0",
"description": "Tiny SpaceNet Subset",
"links": [
{
"rel": "root",
"href": "./catalog.json",
"type": "application/json"
},
{
"rel": "child",
"href": "./label/collection.json",
"type": "application/json"
},
{
"rel": "child",
"href": "./image/collection.json",
"type": "application/json"
}
]
}
{
"id": "image",
"stac_version": "0.9.0",
"description": "Image Chip Collection",
"links": [
{
"rel": "child",
"href": "./train.json",
"type": "application/json"
},
{
"rel": "child",
"href": "./test.json",
"type": "application/json"
},
{
"rel": "item",
"href": "./RGB-PanSharpen_AOI_2_Vegas_img205.json",
"type": "application/json"
},
{
"rel": "item",
"href": "./RGB-PanSharpen_AOI_2_Vegas_img25.json",
"type": "application/json"
},
{
"rel": "root",
"href": "../catalog.json",
"type": "application/json"
},
{
"rel": "parent",
"href": "../catalog.json",
"type": "application/json"
}
],
"extent": {
"spatial": {
"bbox": [
-115.3075176,
36.1686626998,
-115.3004976,
36.1967426999
]
},
"temporal": {
"interval": [
[
"2020-07-20T14:42:30Z",
null
]
]
}
},
"license": "proprietary"
}
{
"type": "Feature",
"stac_version": "0.9.0",
"id": "RGB-PanSharpen_AOI_2_Vegas_img205",
"properties": {
"datetime": "2020-07-20T14:42:31.764580Z"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-115.3004976,
36.1949876999
],
[
-115.3004976,
36.1967426999
],
[
-115.3022526,
36.1967426999
],
[
-115.3022526,
36.1949876999
],
[
-115.3004976,
36.1949876999
]
]
]
},
"bbox": [
-115.3022526,
36.1949876999,
-115.3004976,
36.1967426999
],
"links": [
{
"rel": "collection",
"href": "./collection.json",
"type": "application/json"
},
{
"rel": "root",
"href": "../catalog.json",
"type": "application/json"
},
{
"rel": "parent",
"href": "./train.json",
"type": "application/json"
}
],
"assets": {
"rgb": {
"href": "https://s3.amazonaws.com/azavea-research-public-data/raster-vision/examples/spacenet/RGB-PanSharpen_AOI_2_Vegas_img205.tif",
"type": "image/tiff; application=geotiff",
"title": "RGB Chip"
}
},
"collection": "image"
}
{
"type": "Feature",
"stac_version": "0.9.0",
"id": "RGB-PanSharpen_AOI_2_Vegas_img25",
"properties": {
"datetime": "2020-07-20T14:42:33.017188Z"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-115.3057626,
36.1686626998
],
[
-115.3057626,
36.1704176998
],
[
-115.3075176,
36.1704176998
],
[
-115.3075176,
36.1686626998
],
[
-115.3057626,
36.1686626998
]
]
]
},
"bbox": [
-115.3075176,
36.1686626998,
-115.3057626,
36.1704176998
],
"links": [
{
"rel": "collection",
"href": "./collection.json",
"type": "application/json"
},
{
"rel": "root",
"href": "../catalog.json",
"type": "application/json"
},
{
"rel": "parent",
"href": "./test.json",
"type": "application/json"
}
],
"assets": {
"rgb": {
"href": "https://s3.amazonaws.com/azavea-research-public-data/raster-vision/examples/spacenet/RGB-PanSharpen_AOI_2_Vegas_img25.tif",
"type": "image/tiff; application=geotiff",
"title": "RGB Chip"
}
},
"collection": "image"
}
{
"id": "image-test",
"stac_version": "0.9.0",
"description": "Testing Split",
"links": [
{
"rel": "item",
"href": "./RGB-PanSharpen_AOI_2_Vegas_img25.json",
"type": "application/json"
},
{
"rel": "root",
"href": "../catalog.json",
"type": "application/json"
},
{
"rel": "parent",
"href": "./collection.json",
"type": "application/json"
}
]
}
{
"id": "image-train",
"stac_version": "0.9.0",
"description": "Training Split",
"links": [
{
"rel": "item",
"href": "./RGB-PanSharpen_AOI_2_Vegas_img205.json",
"type": "application/json"
},
{
"rel": "root",
"href": "../catalog.json",
"type": "application/json"
},
{
"rel": "parent",
"href": "./collection.json",
"type": "application/json"
}
]
}
{
"type": "Feature",
"stac_version": "0.9.0",
"id": "buildings_AOI_2_Vegas_img205",
"properties": {
"label:description": "Building Polygons",
"label:type": "vector",
"label:properties": null,
"label:classes": [
[
"building",
"background"
]
],
"label:tasks": [
"segmentation"
],
"datetime": "2020-07-20T14:42:31.764580Z"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-115.3004976,
36.1949876999
],
[
-115.3004976,
36.1967426999
],
[
-115.3022526,
36.1967426999
],
[
-115.3022526,
36.1949876999
],
[
-115.3004976,
36.1949876999
]
]
]
},
"bbox": [
-115.3022526,
36.1949876999,
-115.3004976,
36.1967426999
],
"links": [
{
"rel": "source",
"href": "../image/RGB-PanSharpen_AOI_2_Vegas_img205.json",
"type": "application/json"
},
{
"rel": "collection",
"href": "./collection.json",
"type": "application/json"
},
{
"rel": "root",
"href": "../catalog.json",
"type": "application/json"
},
{
"rel": "parent",
"href": "./train.json",
"type": "application/json"
}
],
"assets": {
"labels": {
"href": "https://s3.amazonaws.com/azavea-research-public-data/raster-vision/examples/spacenet/buildings_AOI_2_Vegas_img205.geojson",
"type": "application/geo+json",
"title": "Building FeatureCollection"
}
},
"stac_extensions": [
"label"
],
"collection": "label"
}
{
"type": "Feature",
"stac_version": "0.9.0",
"id": "buildings_AOI_2_Vegas_img25",
"properties": {
"label:description": "Building Polygons",
"label:type": "vector",
"label:properties": null,
"label:classes": [
[
"building",
"background"
]
],
"label:tasks": [
"segmentation"
],
"datetime": "2020-07-20T14:42:33.017188Z"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-115.3057626,
36.1686626998
],
[
-115.3057626,
36.1704176998
],
[
-115.3075176,
36.1704176998
],
[
-115.3075176,
36.1686626998
],
[
-115.3057626,
36.1686626998
]
]
]
},
"bbox": [
-115.3075176,
36.1686626998,
-115.3057626,
36.1704176998
],
"links": [
{
"rel": "source",
"href": "../image/RGB-PanSharpen_AOI_2_Vegas_img25.json",
"type": "application/json"
},
{
"rel": "collection",
"href": "./collection.json",
"type": "application/json"
},
{
"rel": "root",
"href": "../catalog.json",
"type": "application/json"
},
{
"rel": "parent",
"href": "./test.json",
"type": "application/json"
}
],
"assets": {
"labels": {
"href": "https://s3.amazonaws.com/azavea-research-public-data/raster-vision/examples/spacenet/buildings_AOI_2_Vegas_img25.geojson",
"type": "application/geo+json",
"title": "Building FeatureCollection"
}
},
"stac_extensions": [
"label"
],
"collection": "label"
}
{
"id": "label",
"stac_version": "0.9.0",
"description": "Building Labels Collection",
"links": [
{
"rel": "child",
"href": "./train.json",
"type": "application/json"
},
{
"rel": "child",
"href": "./test.json",
"type": "application/json"
},
{
"rel": "item",
"href": "./buildings_AOI_2_Vegas_img205.json",
"type": "application/json"
},
{
"rel": "item",
"href": "./buildings_AOI_2_Vegas_img25.json",
"type": "application/json"
},
{
"rel": "root",
"href": "../catalog.json",
"type": "application/json"
},
{
"rel": "parent",
"href": "../catalog.json",
"type": "application/json"
}
],
"extent": {
"spatial": {
"bbox": [
-115.3075176,
36.1686626998,
-115.3004976,
36.1967426999
]
},
"temporal": {
"interval": [
[
"2020-07-20T14:42:30Z",
null
]
]
}
},
"license": "proprietary"
}
{
"id": "label-test",
"stac_version": "0.9.0",
"description": "Testing Split",
"links": [
{
"rel": "item",
"href": "./buildings_AOI_2_Vegas_img25.json",
"type": "application/json"
},
{
"rel": "root",
"href": "../catalog.json",
"type": "application/json"
},
{
"rel": "parent",
"href": "./collection.json",
"type": "application/json"
}
]
}
{
"id": "label-train",
"stac_version": "0.9.0",
"description": "Training Split",
"links": [
{
"rel": "item",
"href": "./buildings_AOI_2_Vegas_img205.json",
"type": "application/json"
},
{
"rel": "root",
"href": "../catalog.json",
"type": "application/json"
},
{
"rel": "parent",
"href": "./collection.json",
"type": "application/json"
}
]
}
import os
from pystac import (
Asset,
Catalog,
Collection,
Item,
Link, LinkType,
Extent, SpatialExtent, TemporalExtent,
Extensions, MediaType
)
from pystac.extensions.label import LabelClasses, LabelType
import rasterio
from datetime import datetime, timezone
from shapely.geometry import GeometryCollection, box, shape
from pathlib import Path
class SpaceNetStac(Catalog):
def __init__(self, id, description, title=None, href=None):
super().__init__(id, description, title=title, stac_extensions=[Extensions.LABEL], href=href)
self.base_file_uri = 'https://s3.amazonaws.com/azavea-research-public-data/raster-vision/examples/spacenet'
blank_extent = Extent(SpatialExtent([None, None, None]), TemporalExtent.from_now())
# Label Collection
self.label_collection = Collection('label', "Building Labels Collection", blank_extent)
self.add_child(self.label_collection)
self.label_href_base = os.path.join(os.path.dirname(self.get_self_href()), 'label')
self.label_collection.set_self_href(os.path.join(self.label_href_base, 'collection.json'))
self.label_train_catalog = Catalog('label-train', "Training Split",
href=os.path.join(self.label_href_base, 'train.json'))
self.label_collection.add_child(self.label_train_catalog)
self.label_test_catalog = Catalog('label-test', "Testing Split",
href=os.path.join(self.label_href_base, 'test.json'))
self.label_collection.add_child(self.label_test_catalog)
# Image Collection
self.image_collection = Collection('image', "Image Chip Collection", blank_extent)
self.add_child(self.image_collection)
self.image_href_base = os.path.join(os.path.dirname(self.get_self_href()), 'image')
self.image_collection.set_self_href(os.path.join(self.image_href_base, 'collection.json'))
self.image_train_catalog = Catalog('image-train', "Training Split",
href=os.path.join(self.image_href_base, 'train.json'))
self.image_collection.add_child(self.image_train_catalog)
self.image_test_catalog = Catalog('image-test', "Testing Split",
href=os.path.join(self.image_href_base, 'test.json'))
self.image_collection.add_child(self.image_test_catalog)
def spacenet_cell(self, img_file, label_file):
img_asset_href = os.path.join(self.base_file_uri, img_file)
label_asset_href = os.path.join(self.base_file_uri, label_file)
img_id = Path(img_file).stem
label_id = Path(label_file).stem
# image and labels share bbox for in spacenet dataset
bbox = None
with rasterio.open(img_asset_href) as src:
bbox = list(src.bounds)
# STAC Item describes the source image
image_item = Item(
id=img_id,
href=os.path.join(self.image_href_base, img_id+".json"),
geometry=box(*bbox).__geo_interface__,
bbox=bbox,
datetime=datetime.now(timezone.utc),
properties={},
stac_extensions=None,
collection=self.image_collection)
# STAC Item asset is the actual image chip that was labeled
image_item.add_asset("rgb", Asset(
href=img_asset_href,
title="RGB Chip",
media_type=MediaType.GEOTIFF))
# STAC label item describes the labels and classes
label_item = Item(
id=label_id,
href=os.path.join(self.label_href_base, label_id+".json"),
geometry=box(*bbox).__geo_interface__,
bbox=bbox,
properties={},
datetime=image_item.datetime,
stac_extensions=[Extensions.LABEL],
collection=self.label_collection)
# Apply label extension specific properties
label_item.ext.label.apply(
label_type=LabelType.VECTOR,
label_tasks=['segmentation'],
label_classes=[LabelClasses(['building', 'background'])],
label_description='Building Polygons')
# STAC label item asset is the GeoJSON Feature collection of labels
label_item.ext.label.add_geojson_labels(
href=label_asset_href,
title="Building FeatureCollection")
# STAC label item links to imagery that was used to trace the labels using "source" the rel
label_item.ext.label.add_source(image_item)
self.image_collection.add_item(image_item)
self.label_collection.add_item(label_item)
return (image_item, label_item)
def add_train_set(self, img_file, label_file):
(img, lbl) = self.spacenet_cell(img_file, label_file)
self.image_train_catalog.add_item(img)
self.label_train_catalog.add_item(lbl)
def add_test_set(self, img_file, label_file):
(img, lbl) = self.spacenet_cell(img_file, label_file)
self.image_test_catalog.add_item(img)
self.label_test_catalog.add_item(lbl)
def finalize(self):
"""Update collection extends based on the extent of their children"""
label_bounds = GeometryCollection([shape(s.geometry) for s in self.label_collection.get_all_items()]).bounds
self.label_collection.extent.spatial = SpatialExtent(label_bounds)
image_bounds = GeometryCollection([shape(s.geometry) for s in self.image_collection.get_all_items()]).bounds
self.image_collection.extent.spatial = SpatialExtent(image_bounds)
digraph G {
rankdir=TB;
bgcolor=transparent;
node [style=filled shape=rectangle];
root_catalog -> image_collection -> {
image_train_catalog
image_test_catalog
}
root_catalog -> label_collection -> {
label_train_catalog
label_test_catalog
}
{
label_collection,
label_test_catalog
} -> test_label_item
{
label_collection,
label_train_catalog
} -> train_label_item
{
image_collection,
image_train_catalog
} -> train_image_item
{
image_collection,
image_test_catalog
} -> test_image_item
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment