├── tests ├── __init__.py └── test_module_demo.py ├── src └── satgpt │ ├── version.py │ ├── __init__.py │ ├── .DS_Store │ ├── module_demo.py │ ├── make_role.py │ └── stacker.py ├── setup.py ├── pyproject.toml ├── reference ├── aws │ └── snippet.txt ├── stac │ ├── collection.json │ ├── client-snippet.txt │ ├── sentinel.json │ └── landsat.json └── rio │ └── snippet.txt ├── .gitignore ├── CHANGELOG.rst ├── setup.cfg ├── README.md └── .github └── workflows └── publish-pipy-test.yml /tests/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/satgpt/version.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.0.4' -------------------------------------------------------------------------------- /src/satgpt/__init__.py: -------------------------------------------------------------------------------- 1 | from .version import __version__ -------------------------------------------------------------------------------- /src/satgpt/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lalligagger/satgpt/HEAD/src/satgpt/.DS_Store -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from setuptools import setup 3 | 4 | if __name__ == "__main__": 5 | # setup for satgpt 6 | setup() -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | # As per https://github.com/pypa/setuptools/blob/main/docs/userguide/quickstart.rst 2 | [build-system] 3 | requires = ["setuptools"] 4 | build-backend = "setuptools.build_meta" -------------------------------------------------------------------------------- /src/satgpt/module_demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | def print_something(something="module test"): 5 | print(something, flush=True) 6 | return something 7 | 8 | if __name__ == '__main__': 9 | print_something() -------------------------------------------------------------------------------- /reference/aws/snippet.txt: -------------------------------------------------------------------------------- 1 | The locations of satellite images will often be S3 buckets, with links provided in e.g. a stac item's alternate.href.s3 2 | 3 | IMPORTANT: If trying to access S3 buckets, always set the 4 | 5 | aws s3 cp s3://bucket-name/path/to/file /local/path --request-payer=requester -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.pyc 3 | 4 | data/ 5 | src/satgpt.egg-info/ 6 | */.DS_Store 7 | 8 | # Distribution / packaging 9 | .Python 10 | build/ 11 | develop-eggs/ 12 | dist/ 13 | downloads/ 14 | eggs/ 15 | .eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | wheels/ 22 | share/python-wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST -------------------------------------------------------------------------------- /tests/test_module_demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | 4 | import unittest 5 | 6 | from satgpt.module_demo import print_something 7 | import sgpt #works 8 | 9 | class TestModuleDemo(unittest.TestCase): 10 | def test_print_something(self): 11 | status = print_something("My value") 12 | self.assertEqual(status, "My value") 13 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | Version 0.0.4: 2 | - Moved role creation to manual script run 3 | - Populated README with basic usage 4 | 5 | Version 0.0.3: 6 | - Fixed custom role creation for satgpt to grab target machine os/ shell 7 | - Added pystac as install dependency for demos 8 | - Added this CHANGELOG 9 | 10 | Version 0.0.2: 11 | - Integrated shell-gpt as a dependency using the custom role feature released in version 0.9.0 -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = satgpt 3 | version = attr: satgpt.__version__ 4 | author = Kevin Lalli 5 | author_email = kevin@opticsinspace.com 6 | description = GPT for satellite mission planning. In development. Get your API keys ready! 7 | long_description = file: README.md, CHANGELOG.rst 8 | #, LICENSE.rst 9 | 10 | #classifiers=['Development Status :: 1 - Planning'], 11 | 12 | # https://setuptools.pypa.io/en/latest/userguide/declarative_config.html#using-a-src-layout 13 | [options] 14 | packages = find: 15 | package_dir = 16 | = src 17 | 18 | install_requires = 19 | fire 20 | dask 21 | pystac 22 | pystac-client 23 | rasterio 24 | stacterm 25 | stackstac 26 | shell-gpt 27 | 28 | setup_requires = 29 | distro 30 | 31 | [options.packages.find] 32 | where = src -------------------------------------------------------------------------------- /reference/stac/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "stac_version": "1.0.0-beta.2", 3 | "id": "stac-examples", 4 | "description": "This catalog contains a variety of STAC Collections and items, in order to give new users a sense of how STAC is used in the real world. Note that it is different from real world implementations as it only has one or two items per catalog or collection. See the [repository readme](https://github.com/stac-utils/stac-examples) for more information about how this repo differs from typical STAC best practices.", 5 | "links": [ 6 | { "rel": "self", "href": ".https://raw.githubusercontent.com/stac-utils/stac-examples/main/catalog.json" }, 7 | { "rel": "child", "href": "./planet/collection.json" }, 8 | { "rel": "child", "href": "./cbers/collection.json" }, 9 | { "rel": "child", "href": "./sentinel-2/collection.json" }, 10 | { "rel": "child", "href": "./landsat8/collection.json" }, 11 | { "rel": "child", "href": "./aster-openeo-gee/collection.json" }, 12 | { "rel": "root", "href": "./catalog.json" } 13 | ] 14 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SatGPT 2 | 3 | GPT for satellite mission planning. In development. Get your API keys ready! 4 | 5 | SatGPT heavily leverages Shell GPT, a command-line UI for OpenAI's completion API, 6 | and its features for custom role creation (as of 04/16/2023). Currently for SatGPT to work, 7 | we need to overwrite the default shell roll using the instructions below. 8 | 9 | ## Installation 10 | 11 | 1. Clone this repo. Installing from source will be more straightforward than PyPi install at this stage. 12 | 13 | 2. From inside repo root, install from source. 14 | 15 | ``` 16 | python -m pip install -e . 17 | ``` 18 | 19 | 3. Overwrite `shell-gpt` default `shell` role with `satgpt` alpha demo. 20 | 21 | ``` 22 | python src/satgpt/make_role.py 23 | ``` 24 | ## Usage 25 | 26 | 1. Start the REPL in shell mode. 27 | 28 | ``` 29 | sgpt --shel --repl temp 30 | ``` 31 | 32 | 2. Request a STAC search using natural language 33 | 34 | ``` 35 | >>> find all landsat 8&9 imagery over washington, DC in April 2023 36 | ``` 37 | 38 | 3. Request edits or additional steps 39 | 40 | ``` 41 | >>> pipe the results to stacterm cal 42 | ``` 43 | 44 | 4. Try other things! 45 | 46 | https://user-images.githubusercontent.com/11700267/233900142-55a38676-32ab-4c78-8226-b338b9b3b876.mov 47 | -------------------------------------------------------------------------------- /.github/workflows/publish-pipy-test.yml: -------------------------------------------------------------------------------- 1 | # https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/ 2 | 3 | name: Publish Python 🐍 distributions 📦 to TestPyPI & PyPI (if tagged) 4 | 5 | on: push 6 | 7 | jobs: 8 | build-n-publish: 9 | # name: Build and publish Python 🐍 distributions 📦 to TestPyPI & PyPI (if tagged) 10 | name: Build and publish Python 🐍 distributions 📦 to PyPI (if tagged) 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Set up Python 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: "3.x" 18 | - name: Install pypa/build 19 | run: >- 20 | python -m 21 | pip install 22 | build 23 | --user 24 | - name: Build a binary wheel and a source tarball 25 | run: >- 26 | python -m 27 | build 28 | --sdist 29 | --wheel 30 | --outdir dist/ 31 | # - name: Publish distribution 📦 to Test PyPI 32 | # # if: startsWith(github.ref, 'refs/tags') 33 | # uses: pypa/gh-action-pypi-publish@release/v1 34 | # with: 35 | # password: ${{ secrets.TEST_PYPI_API_TOKEN }} 36 | # repository-url: https://test.pypi.org/legacy/ 37 | # - name: Publish distribution 📦 to PyPI 38 | # # if: startsWith(github.ref, 'refs/tags') 39 | # uses: pypa/gh-action-pypi-publish@release/v1 40 | # with: 41 | # password: ${{ secrets.PYPI_API_TOKEN }} -------------------------------------------------------------------------------- /reference/rio/snippet.txt: -------------------------------------------------------------------------------- 1 | rio 2 | # Rasterio command line interface for loading and operating on geospatial raster datasets. 3 | # For example, rio can be used to load the contents of a COG on S3 as a virtual file. 4 | # CLI help follows. reference rasterio docs for more details. 5 | Options: 6 | -v, --verbose Increase verbosity. 7 | -q, --quiet Decrease verbosity. 8 | --aws-profile TEXT Select a profile from the AWS credentials file 9 | --aws-no-sign-requests Make requests anonymously 10 | --aws-requester-pays Requester pays data transfer costs 11 | --version Show the version and exit. 12 | --gdal-version 13 | --help Show this message and exit. 14 | Commands: 15 | blocks Write dataset blocks as GeoJSON features. 16 | bounds Write bounding boxes to stdout as GeoJSON. 17 | calc Raster data calculator. 18 | clip Clip a raster to given bounds. 19 | convert Copy and convert raster dataset. 20 | edit-info Edit dataset metadata. 21 | env Print information about the Rasterio environment. 22 | gcps Print ground control points as GeoJSON. 23 | info Print information about a data file. 24 | insp Open a data file and start an interpreter. 25 | mask Mask in raster using features. 26 | merge Merge a stack of raster datasets. 27 | overview Construct overviews in an existing dataset. 28 | rasterize Rasterize features. 29 | rm Delete a dataset. 30 | sample Sample a dataset. 31 | shapes Write shapes extracted from bands or masks. 32 | stack Stack a number of bands into a multiband dataset. 33 | transform Transform coordinates. 34 | warp Warp a raster dataset. -------------------------------------------------------------------------------- /reference/stac/client-snippet.txt: -------------------------------------------------------------------------------- 1 | # STAC API client used for searching and retrieving STAC catalogs, which contain satellite imagery 2 | # retrieve data from the STAC catalogs using requests that adhere to the stac API 3 | # A bbox is defined with no commas, and a space between each coordinate 4 | 5 | IMPORTANT: If the user does not specify a stac-client URL, assume https://landsatlook.usgs.gov/stac-server/ 6 | IMPORTANT: A bbox never has commas when entered in the CLI, always use spaces between the numbers. NO COMMAS IN BBOX. 7 | 8 | Only return properly formatted stac-client CLI commands, as in the examples below. The formatting is very important, 9 | when satellite imagery is requested think step-by-step and ensure that a properly construct the command is returned. 10 | 11 | # get the number of matching items in a catalog serch using --matched 12 | stac-client search https://earth-search.aws.element84.com/v0 -c sentinel-s2-l2a-cogs --bbox -72.5 40.5 -72 41 --matched 13 | 14 | # retrieve all the items as json responses 15 | stac-client search https://earth-search.aws.element84.com/v0 -c sentinel-s2-l2a-cogs --bbox -72.5 40.5 -72 41 16 | 17 | # limit the number of returned items with max-items 18 | stac-client search https://earth-search.aws.element84.com/v0 -c sentinel-s2-l2a-cogs --bbox -72.5 40.5 -72 41 --max-items 10 19 | 20 | # pipe json results to a calendar view using stacterm (don't use --matched, do restrict to a particular datetime) 21 | stac-client search https://earth-search.aws.element84.com/v0 -c sentinel-s2-l2a-cogs --bbox -72.5 40.5 -72 41 --datetime 2020-01-01/2020-01-31 | stacterm cal --label platform 22 | # refer to pystac-client docs for more details. 23 | 24 | # other stac catalogs may have different collection names, and may not have the same collections. refer to the catalog docs for more details. 25 | # landsat land surface temperature (LST) lookup from USGS STAC catalog 26 | stac-client search https://landsatlook.usgs.gov/stac-server/ --collections landsat-c2l2-st --bbox -122.436 47.495 -121.998 47.734 27 | 28 | # landsat surface reflectance (SR) lookup from USGS STAC catalog 29 | stac-client search https://landsatlook.usgs.gov/stac-server/ --collections landsat-c2l2-st --bbox -122.436 47.495 -121.998 47.734 30 | 31 | # using saved results from a STAC search, download the thumbnail of last item to ./data/ 32 | cd ./data/ && curl $(jq -r '.features[-1].assets.thumbnail.href' results.json) -O -J && cd .. 33 | 34 | # sometimes it is helpful to inspect the results with jq. for example, printing the feature's asset names of the first item of a search result saved to json. 35 | # the user may say "band" when they really mean "layer" or "asset"... please forgive them and only assume they are looking for "eo:band" info if they explicitly ask. 36 | cat ./data/items.json | jq -r '.features[-1].assets | keys' 37 | 38 | #The above will list all of the layers, which may or may not have detailed eo:band info. if available, this is how to find 39 | # the detailed band info. (here for landsat's B10/ lwir11). 40 | cat ./data/items.json | jq -r '.features[-1].assets | .lwir11."eo:bands"' 41 | 42 | IMPORTANT: NO COMMAS IN BETWEEN NUMERIC BBOX VALUES. USE SPACES ONLY BETWEEN BBOX VALUES. NO EXECPTIONS. -------------------------------------------------------------------------------- /src/satgpt/make_role.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import json 3 | import os 4 | import platform 5 | from os import getenv, pathsep 6 | from os.path import basename 7 | 8 | 9 | # adapted from https://github.com/TheR1D/shell_gpt/blob/main/sgpt/role.py 10 | def make_satgpt_role(): 11 | from distro import name as distro_name 12 | 13 | operating_systems = { 14 | "Linux": "Linux/" + distro_name(pretty=True), 15 | "Windows": "Windows " + platform.release(), 16 | "Darwin": "Darwin/MacOS " + platform.mac_ver()[0], 17 | } 18 | current_platform = platform.system() 19 | 20 | os_name = operating_systems.get(current_platform, current_platform) 21 | if current_platform in ("Windows", "nt"): 22 | is_powershell = len(getenv("PSModulePath", "").split(pathsep)) >= 3 23 | shell_name = "powershell.exe" if is_powershell else "cmd.exe" 24 | else: 25 | shell_name = basename(getenv("SHELL", "/bin/sh")) 26 | 27 | SATGPT_ROLE = """### 28 | Provide only {shell} commands for {os} without any description. 29 | If there is a lack of details, provide most logical solution. 30 | Ensure the output is a valid shell command. 31 | If multiple steps required try to combine them together. 32 | ____ 33 | 34 | Here are some particular CLI packages to reccomend and their use cases: 35 | 36 | stac-client 37 | Important: when using stac-client DO NOT format bounding boxes like: --bbox 102.5,22.5,103.5,23.5 38 | The correct format is: --bbox 102.5 22.5 103.5 23.5 39 | Important: do not return a stac-client command without providing a URL. If the user does not specify, use https://landsatlook.usgs.gov/stac-server/ 40 | The cannonical stac-client command is: stac-client search URL --bbox BBOX --datetime DT --query QUERY 41 | An example is: 42 | stac-client search https://landsatlook.usgs.gov/stac-server/ --bbox 102.5 22.5 103.5 23.5 --collections landsat-c2l2-sr --datetime 2022-09-01/2023-04-30 --query "eo:cloud_cover<20" 43 | IMPORTANT: NO COMMAS IN BETWEEN NUMERIC BBOX VALUES. USE SPACES ONLY BETWEEN BBOX VALUES. NO EXECPTIONS. 44 | 45 | 46 | Stacker 47 | Stacker is a basic cli tool that wraps stackstac and geogif. 48 | The below example uses a saved stac search and saves an animation of monthly resampled RGB data to test.gif. 49 | 50 | stac-client search https://earth-search.aws.element84.com/v0 --bbox -77.119759 38.791645 -76.909393 38.995548 --datetime 2022-06-01/2022-08-31 > ./data/save-items.json \ 51 | && python src/satgpt/stacker.py --path=data/save-items.json --resolution=20 --bounds_latlon=-77.131,38.979,-76.893,38.811 - to_gif --to=test.gif --resample=1M 52 | 53 | Note the " - to_gif" syntax, where the single hyphen is used to indicate that the command is to be piped to the next command. 54 | Important: Don't forget the space on either side of these separators. It has to be " - to_gif" not " -to_gif" 55 | Important: stac items cannot be piped directly for now, an intermediate save file must be used and it's path passed to stacker using --path 56 | The "to_gif" is the name of the function in the Stacker class that will be called, and its flags can be passed after the command 57 | ____ 58 | """.format( 59 | shell=shell_name, os=os_name 60 | ) 61 | 62 | satgpt_json = { 63 | "name": "shell", 64 | "expecting": "Command", 65 | "variables": { 66 | "shell": shell_name, 67 | "os": os_name, 68 | }, 69 | "role": SATGPT_ROLE, 70 | } 71 | 72 | file_path = getenv("HOME") + "/.config/shell_gpt/roles/shell.json" 73 | 74 | # make directory if it doesn't exist 75 | os.makedirs(os.path.dirname(file_path), exist_ok=True) 76 | with open(file_path, "w") as f: 77 | f.write(json.dumps(satgpt_json, indent=4)) 78 | 79 | 80 | if __name__ == "__main__": 81 | # setup for satgpt 82 | make_satgpt_role() 83 | -------------------------------------------------------------------------------- /src/satgpt/stacker.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | import fire 4 | import pystac 5 | import rasterio as rio 6 | import stackstac 7 | from dask.diagnostics import ProgressBar 8 | from geogif import dgif 9 | from rasterio.session import AWSSession 10 | import warnings 11 | 12 | warnings.simplefilter("ignore", category=RuntimeWarning) 13 | 14 | def read_json_file(file_path): 15 | """ 16 | Reads a JSON file and returns its contents as a string. 17 | 18 | Args: 19 | file_path (str): The path to the JSON file. 20 | 21 | Returns: 22 | str: The contents of the JSON file as a string. 23 | """ 24 | with open(file_path, "r") as f: 25 | return f.read() 26 | 27 | def promote_s3(items): 28 | """ 29 | Updates URLs to use s3. 30 | 31 | Args: 32 | items (list): A list of STAC items. 33 | 34 | Returns: 35 | list: The updated list of STAC items. 36 | """ 37 | print("promoting s3 to primary href") 38 | for item in items: 39 | for a in item["assets"]: 40 | if ( 41 | "alternate" in item["assets"][a] 42 | and "s3" in item["assets"][a]["alternate"] 43 | ): 44 | item["assets"][a]["href"] = item["assets"][a]["alternate"]["s3"]["href"] 45 | item["assets"][a]["href"] = item["assets"][a]["href"].replace( 46 | "usgs-landsat-ard", "usgs-landsat" 47 | ) 48 | return items 49 | 50 | class Stacker: 51 | """ 52 | A class for stacking STAC items and creating GIF animations. 53 | 54 | Attributes: 55 | stack (xarray.Dataset): The stacked STAC items. 56 | qa_mask (xarray.DataArray): The QA mask for the stacked STAC items. 57 | """ 58 | 59 | def __init__(self, path=sys.stdin, *, use_s3=True, **kwargs): 60 | """ 61 | Initializes the Stacker class. 62 | 63 | Args: 64 | path (str): The path to the JSON file containing the STAC items. 65 | use_s3 (bool): Whether to use s3 URLs. Defaults to True. 66 | **kwargs: Additional keyword arguments to pass to stackstac.stack(). 67 | """ 68 | self.load_stack(path, use_s3=use_s3, kwargs=kwargs) 69 | 70 | def load_stack(self, path, use_s3=True, kwargs={}): 71 | """ 72 | Loads and stacks STAC items. 73 | 74 | Args: 75 | path (str): The path to the JSON file containing the STAC items. 76 | use_s3 (bool): Whether to use s3 URLs. Defaults to True. 77 | kwargs (dict): Additional keyword arguments to pass to stackstac.stack(). 78 | 79 | Returns: 80 | Stacker: The Stacker object. 81 | """ 82 | try: 83 | search = json.loads(read_json_file(path))["features"] 84 | except: 85 | # hack to accept raw json 86 | search = json.loads(path.read())["features"] 87 | 88 | if use_s3: 89 | search = promote_s3(search) 90 | 91 | items = pystac.ItemCollection(search) 92 | self.stack = stackstac.stack( 93 | items, 94 | **kwargs, 95 | ) 96 | 97 | self.stack = self.stack.assign_coords( 98 | band=self.stack.common_name.fillna(self.stack.band).rename("band") 99 | ) 100 | 101 | return self 102 | 103 | def make_qa_mask(self): 104 | """ 105 | Creates a QA mask for the stacked STAC items. 106 | 107 | Returns: 108 | Stacker: The Stacker object. 109 | """ 110 | platform = "landsat" 111 | 112 | if platform == "landsat": 113 | mask_bitfields = [1, 2, 3, 4] # dilated cloud, cirrus, cloud, cloud shadow 114 | qa = self.stack.sel(band="qa_pixel").astype("uint16") 115 | 116 | if platform == "sentinel": 117 | mask_bitfields = [ 118 | 1, 119 | 3, 120 | 8, 121 | 9, 122 | 10, 123 | ] # defective/ saturated, cloud shadow, cloud med, cloud high, cirrus 124 | qa = self.stack.sel(band="SCL").astype("uint16") 125 | 126 | bitmask = 0 127 | for field in mask_bitfields: 128 | bitmask |= 1 << field 129 | 130 | bin(bitmask) 131 | self.qa_mask = qa & bitmask 132 | 133 | return self 134 | 135 | def to_gif( 136 | self, 137 | to="./data/animation.gif", 138 | *, 139 | apply_mask=True, 140 | resample="2W", 141 | fill=True, 142 | **kwargs): 143 | """ 144 | Creates a GIF animation from the stacked STAC items. 145 | 146 | Args: 147 | to (str): The path to save the GIF animation. Defaults to "./data/animation.gif". 148 | apply_mask (bool): Whether to apply the QA mask. Defaults to True. 149 | resample (str): The resampling frequency. Defaults to "2W". 150 | fill (bool): Whether to fill missing values. Defaults to True. 151 | **kwargs: Additional keyword arguments to pass to geogif.dgif(). 152 | 153 | Returns: 154 | None 155 | """ 156 | sr = self.stack.sel( 157 | {"band": ["red", "green", "blue"]} 158 | ) 159 | 160 | if apply_mask: 161 | self.make_qa_mask() 162 | sr = sr.where(self.qa_mask == 0) 163 | 164 | if resample: 165 | sr = sr.resample(time=resample).median("time") 166 | 167 | if fill: 168 | sr = sr.ffill("time")[1:] 169 | 170 | aws_session = AWSSession(requester_pays=True) 171 | with rio.Env(aws_session): 172 | with ProgressBar(): 173 | gif_bytes = dgif(sr, bytes=True, **kwargs).compute() 174 | 175 | with open(to, "wb") as f: 176 | f.write(gif_bytes) 177 | 178 | def q(self): 179 | """ 180 | Placeholder method. 181 | """ 182 | pass 183 | 184 | if __name__ == "__main__": 185 | stacker = fire.Fire(Stacker) 186 | -------------------------------------------------------------------------------- /reference/stac/sentinel.json: -------------------------------------------------------------------------------- 1 | { 2 | "stac_version": "1.0.0-beta.2", 3 | "stac_extensions": [ 4 | "view", 5 | "projection" 6 | ], 7 | "type": "Feature", 8 | "id": "S2A_OPER_MSI_L2A_TL_SGS__20180524T190423_A015250_T26SKD_N02.08", 9 | "collection": "sentinel-s2-l2a", 10 | "links": [ 11 | { 12 | "rel": "self", 13 | "href": "s3://sentinel-s2-l2a-catalog/tiles/35/V/MK/2018/6/5/0/sentinel2-sample.json" 14 | }, 15 | { 16 | "rel": "root", 17 | "href": "s3://sentinel-s2-l2a-catalog/catalog.json" 18 | }, 19 | { 20 | "rel": "collection", 21 | "href": "s3://sentinel-s2-l2a-catalog/catalog.json" 22 | } 23 | ], 24 | "bbox": [ 25 | 25.0815883093, 26 | 62.1306897126, 27 | 27.1935425597, 28 | 63.1293872370 29 | ], 30 | "geometry": { 31 | "type": "Polygon", 32 | "coordinates": [ 33 | [ 34 | [ 35 | -105.160846396, 36 | 39.1656009422 37 | ], 38 | [ 39 | -104.947574355, 40 | 39.1750024943 41 | ], 42 | [ 43 | -104.949890373, 44 | 39.0512153242 45 | ], 46 | [ 47 | -105.161151214, 48 | 39.0436821016 49 | ], 50 | [ 51 | -105.160846396, 52 | 39.1656009422 53 | ] 54 | ] 55 | ] 56 | }, 57 | "properties": { 58 | "datetime": "2018-06-05T10:00:27Z", 59 | "platform": "sentinel-2", 60 | "gsd": 10, 61 | "proj:epsg": 32635, 62 | "eo:cloud_cover": 88.459539, 63 | "view:sun_azimuth" : 176.091667178268 64 | }, 65 | "collection": "s2-l2a", 66 | "assets": { 67 | "metadata": { 68 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/metadata.xml", 69 | "title": "Tile metadata", 70 | "type": "application/xml", 71 | "roles": [ "metadata" ] 72 | }, 73 | "tileInfo": { 74 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/tileInfo.json", 75 | "title": "Tile info", 76 | "type": "application/json" 77 | }, 78 | "productInfo": { 79 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/productInfo.json", 80 | "title": "Product info", 81 | "type": "application/json" 82 | }, 83 | "thumbnail": { 84 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/qi/L2A_PVI.jp2", 85 | "title": "True color thumbnail", 86 | "type": "image/jp2", 87 | "roles": [ "thumbnail" ] 88 | }, 89 | "B02_10m": { 90 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R10m/B02.jp2", 91 | "title": "Band 2 - Blue 0.490 (10m)", 92 | "type": "image/jp2" 93 | }, 94 | "B03_10m": { 95 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R10m/B03.jp2", 96 | "title": "Band 3 - Green 0.560 (10m)", 97 | "type": "image/jp2" 98 | }, 99 | "B04_10m": { 100 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R10m/B04.jp2", 101 | "title": "Band 4 - Red 0.665 (10m)", 102 | "type": "image/jp2" 103 | }, 104 | "B08_10m": { 105 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R10m/B08.jp2", 106 | "title": "Band 8 - NIR 0.842 (10m)", 107 | "type": "image/jp2" 108 | }, 109 | "AOT_10m": { 110 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R10m/AOT.jp2", 111 | "title": "Aerosol Optical Thickness (10m)", 112 | "type": "image/jp2" 113 | }, 114 | "TCI_10m": { 115 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R10m/TCI.jp2", 116 | "title": "True Color Image (10m)", 117 | "type": "image/jp2" 118 | }, 119 | "WVP_10m": { 120 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R10m/WVP.jp2", 121 | "title": "Water Vapor (10m)", 122 | "type": "image/jp2" 123 | }, 124 | "B02_20m": { 125 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/B02.jp2", 126 | "title": "Band 2 - Blue 0.490 (20m)", 127 | 128 | "type": "image/jp2" 129 | }, 130 | "B03_20m": { 131 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/B03.jp2", 132 | "title": "Band 3 - Green 0.560 (20m)", 133 | "type": "image/jp2" 134 | }, 135 | "B04_20m": { 136 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/B04.jp2", 137 | "title": "Band 4 - Red 0.665 (20m)", 138 | "type": "image/jp2" 139 | }, 140 | "B05_20m": { 141 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/B05.jp2", 142 | "title" : "Band 5 - Vegetation Red Edge 0.705 (20m)", 143 | "type": "image/jp2" 144 | }, 145 | "B06_20m": { 146 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/B06.jp2", 147 | "title": "Band 6 - Vegetation Red Edge 0.740 (20m)", 148 | "type": "image/jp2" 149 | }, 150 | "B07_20m": { 151 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/B07.jp2", 152 | "title": "Band 7 - Vegetation Red Edge 0.783 (20m)", 153 | "type": "image/jp2" 154 | }, 155 | "B8A_20m": { 156 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/B8A.jp2", 157 | "title": "Band 8A - Narrow NIR 0.865 (20m)", 158 | "type": "image/jp2" 159 | }, 160 | "B11_20m": { 161 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/B11.jp2", 162 | "title": "Band 11 - SWIR 1.610 (20m)", 163 | "type": "image/jp2" 164 | }, 165 | "B12_20m": { 166 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/B12.jp2", 167 | "title": "Band 12 - SWIR 2.190 (20m)", 168 | "type": "image/jp2" 169 | }, 170 | "AOT_20m": { 171 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/AOT.jp2", 172 | "title": "Aerosol Optical Thickness (20m)", 173 | "type": "image/jp2" 174 | }, 175 | "SCL_20m": { 176 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/SCL.jp2", 177 | "title": "Scene Classification (20m)", 178 | "type": "image/jp2" 179 | }, 180 | "TCI_20m": { 181 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/TCI.jp2", 182 | "title": "True Color Image (20m)", 183 | "type": "image/jp2" 184 | }, 185 | "WVP_20m": { 186 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/R20m/WVP.jp2", 187 | "title": "Water Vapor (20m)", 188 | "type": "image/jp2" 189 | }, 190 | "CLD_20m": { 191 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/qi/CLD_20m.jp2", 192 | "title": "Cloud (20m)", 193 | "type": "image/jp2" 194 | }, 195 | "SNW_20m": { 196 | "href": "s3://sentinel-s2-l2a/tiles/35/V/MK/2018/6/5/0/qi/SNW_20m.jp2", 197 | "title": "Snow (20m)", 198 | "type": "image/jp2" 199 | } 200 | } 201 | } -------------------------------------------------------------------------------- /reference/stac/landsat.json: -------------------------------------------------------------------------------- 1 | { 2 | "stac_version": "1.0.0-beta.2", 3 | "stac_extensions": [ 4 | "eo", 5 | "view", 6 | "https://example.com/stac/landsat-extension/1.0/schema.json" 7 | ], 8 | "id": "LC81530252014153LGN00", 9 | "type": "Feature", 10 | "bbox": [ 11 | 49.16354, 12 | 72.27502, 13 | 51.36812, 14 | 75.67662 15 | ], 16 | "geometry": { 17 | "type": "Polygon", 18 | "coordinates": [ 19 | [ 20 | [ 21 | 51.33855, 22 | 72.27502 23 | ], 24 | [ 25 | 51.36812, 26 | 75.70821 27 | ], 28 | [ 29 | 49.19092, 30 | 75.67662 31 | ], 32 | [ 33 | 49.16354, 34 | 72.3964 35 | ], 36 | [ 37 | 51.33855, 38 | 72.27502 39 | ] 40 | ] 41 | ] 42 | }, 43 | "collection": "landsat-8-l1", 44 | "properties": { 45 | "datetime": "2014-06-02T09:22:02Z", 46 | "gsd": 30, 47 | "platform": "landsat-8", 48 | "instruments": [ 49 | "oli", 50 | "tirs" 51 | ], 52 | "eo:cloud_cover": 78, 53 | "view:off_nadir": 0, 54 | "view:azimuth": 0, 55 | "view:sun_azimuth": 149.01607154, 56 | "view:sun_elevation": 59.214247, 57 | "landsat:path": 107, 58 | "landsat:row": 18, 59 | "landsat:earth_sun_distance": 1.014156, 60 | "landsat:ground_control_points_verify": 114, 61 | "landsat:geometric_rmse_model": 7.562, 62 | "landsat:image_quality_tirs": 9, 63 | "landsat:ground_control_points_model": 313, 64 | "landsat:geometric_rmse_model_x": 5.96, 65 | "landsat:geometric_rmse_model_y": 4.654, 66 | "landsat:geometric_rmse_verify": 5.364, 67 | "landsat:image_quality_oli": 9 68 | }, 69 | "links": [ 70 | { 71 | "rel": "self", 72 | "href": "https://landsat-stac.s3.amazonaws.com/landsat-8-l1/107/018/2018-10-01/LC81530252014153LGN00.json" 73 | }, 74 | { 75 | "rel": "collection", 76 | "href": "https://landsat-stac.s3.amazonaws.com/landsat-8-l1/catalog.json" 77 | }, 78 | { 79 | "rel": "parent", 80 | "href": "https://landsat-stac.s3.amazonaws.com/landsat-8-l1/107/018/catalog.json" 81 | }, 82 | { 83 | "rel": "root", 84 | "href": "https://landsat-stac.s3.amazonaws.com/catalog.json" 85 | } 86 | ], 87 | "assets": { 88 | "ANG": { 89 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_ANG.txt", 90 | "title": "Angle coefficients file", 91 | "type": "text/plain" 92 | }, 93 | "B1": { 94 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_B1.TIF", 95 | "type": "image/tiff; application=geotiff", 96 | "eo:bands": [ 97 | { 98 | "name": "B1", 99 | "common_name": "coastal", 100 | "center_wavelength": 0.44, 101 | "full_width_half_max": 0.02 102 | } 103 | ], 104 | "title": "Band 1 (coastal)" 105 | }, 106 | "B2": { 107 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_B2.TIF", 108 | "type": "image/tiff; application=geotiff", 109 | "eo:bands": [ 110 | { 111 | "name": "B2", 112 | "common_name": "blue", 113 | "center_wavelength": 0.48, 114 | "full_width_half_max": 0.06 115 | } 116 | ], 117 | "title": "Band 2 (blue)" 118 | }, 119 | "B3": { 120 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_B3.TIF", 121 | "type": "image/tiff; application=geotiff", 122 | "eo:bands": [ 123 | { 124 | "name": "B3", 125 | "common_name": "green", 126 | "center_wavelength": 0.56, 127 | "full_width_half_max": 0.06 128 | } 129 | ], 130 | "title": "Band 3 (green)" 131 | }, 132 | "B4": { 133 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_B4.TIF", 134 | "type": "image/tiff; application=geotiff", 135 | "eo:bands": [ 136 | { 137 | "name": "B4", 138 | "common_name": "red", 139 | "center_wavelength": 0.65, 140 | "full_width_half_max": 0.04 141 | } 142 | ], 143 | "title": "Band 4 (red)" 144 | }, 145 | "B5": { 146 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_B5.TIF", 147 | "type": "image/tiff; application=geotiff", 148 | "eo:bands": [ 149 | { 150 | "name": "B5", 151 | "common_name": "nir", 152 | "center_wavelength": 0.86, 153 | "full_width_half_max": 0.03 154 | } 155 | ], 156 | "title": "Band 5 (nir)" 157 | }, 158 | "B6": { 159 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_B6.TIF", 160 | "type": "image/tiff; application=geotiff", 161 | "eo:bands": [ 162 | { 163 | "name": "B6", 164 | "common_name": "swir16", 165 | "center_wavelength": 1.6, 166 | "full_width_half_max": 0.08 167 | } 168 | ], 169 | "title": "Band 6 (swir16)" 170 | }, 171 | "B7": { 172 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_B7.TIF", 173 | "type": "image/tiff; application=geotiff", 174 | "eo:bands": [ 175 | { 176 | "name": "B7", 177 | "common_name": "swir22", 178 | "center_wavelength": 2.2, 179 | "full_width_half_max": 0.2 180 | } 181 | ], 182 | "title": "Band 7 (swir22)" 183 | }, 184 | "B8": { 185 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_B8.TIF", 186 | "type": "image/tiff; application=geotiff", 187 | "eo:bands": [ 188 | { 189 | "name": "B8", 190 | "common_name": "pan", 191 | "center_wavelength": 0.59, 192 | "full_width_half_max": 0.18 193 | } 194 | ], 195 | "title": "Band 8 (pan)" 196 | }, 197 | "B9": { 198 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_B9.TIF", 199 | "type": "image/tiff; application=geotiff", 200 | "eo:bands": [ 201 | { 202 | "name": "B9", 203 | "common_name": "cirrus", 204 | "center_wavelength": 1.37, 205 | "full_width_half_max": 0.02 206 | } 207 | ], 208 | "title": "Band 9 (cirrus)" 209 | }, 210 | "B10": { 211 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_B10.TIF", 212 | "type": "image/tiff; application=geotiff", 213 | "eo:bands": [ 214 | { 215 | "name": "B10", 216 | "common_name": "lwir11", 217 | "center_wavelength": 10.9, 218 | "full_width_half_max": 0.8 219 | } 220 | ], 221 | "title": "Band 10 (lwir)" 222 | }, 223 | "B11": { 224 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_B11.TIF", 225 | "type": "image/tiff; application=geotiff", 226 | "eo:bands": [ 227 | { 228 | "name": "B11", 229 | "common_name": "lwir12", 230 | "center_wavelength": 12, 231 | "full_width_half_max": 1 232 | } 233 | ], 234 | "title": "Band 11 (lwir)" 235 | }, 236 | "BQA": { 237 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_BQA.TIF", 238 | "title": "Band quality data", 239 | "type": "image/tiff; application=geotiff" 240 | }, 241 | "MTL": { 242 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_MTL.txt", 243 | "title": "original metadata file", 244 | "type": "text/plain" 245 | }, 246 | "thumbnail": { 247 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/LC81530252014153LGN00_thumb_large.jpg", 248 | "title": "Thumbnail image", 249 | "type": "image/jpeg" 250 | }, 251 | "index": { 252 | "href": "https://landsat-pds.s3.amazonaws.com/c1/L8/107/018/LC81530252014153LGN00/index.html", 253 | "type": "text/html", 254 | "title": "HTML index page" 255 | } 256 | } 257 | } --------------------------------------------------------------------------------