Skip to content

Instantly share code, notes, and snippets.

@davidbernat
Last active January 26, 2019 04:59
Show Gist options
  • Save davidbernat/a393cf6f6f35709b52c8452147b533bc to your computer and use it in GitHub Desktop.
Save davidbernat/a393cf6f6f35709b52c8452147b533bc to your computer and use it in GitHub Desktop.
Starlight Aether SDK application example: Visualizing the Profound Fury of Wildfires in Satellite Imagery
###############################################
#
# First things first.
#
# Please go to: network.runsonaether.com
#
# You will be prompted to log in with a
# gmail or email address.
#
# After log-in, you will see all the good
# stuff.
# 1) our Aether SDK documentation
# 2) our examples
# 3) your applications and UUID.
#
# Company url: www.runsonaether.com
# www.starlight.ai
#
# Demos, Pictures, & Videos:
# Posted to Twitter: https://twitter.com/astrorobotic
#
# Medium: https://medium.com/starlightteam
#
# Thank you,
# David Bernat
# @astrorobotic
#
###############################################
import aether as ae
import os
import logging
logger = logging.getLogger(__name__)
###############################################
#
#
# Visualizing the Profound Fury of Wildfires
# in Satellite Imagery
#
# An example of the Starlight Aether SDK
# Starlight: starlight.ai
# Aether SDK docs: docs.runsonaether.com
# Get a UUID in one-click: apply.runsonaether.com
#
# Author: David Bernat
# Twitter: @astrorobotic
#
# It will help us if you follow us on Twitter
#
# Report Issues to:
# https://github.com/TeamStarlight/aether-alpha-program
#
###############################################
# To install Aether SDK, simply pip install aether
# For documentation: docs.runsonaether.com
# Get a UUID in one-click: Log in to apply.runsonaether.com
uuid = "YOUR_UUID"
ae.GlobalConfig.set_user(uuid)
job_name = "paradise"
out_dir = "enhancedFire"
# The Paradise / Camp Fire started in Pulga, CA. So we use that as our center.
#
# There are several tunable parameters in the EnhancedFire function before.
# To reproduce the images in the Medium article, you simple need to change one
# line. Find that line by searching for [STARLIGHT NOTE].
# Medium Article: Visualizing the Profound Fury of Wildfires in Satellite Imagery
# center = [39.754985, -121.609025] # paradise; November 10, 2018
center = [39.802015, -121.448666] # pulga, center of fire
w = 0.15 # degrees
####################################
# DEMO START
####################################
coordinates = [[center[0] - 1.2*w, center[1] - 1.2*w],
[center[0] - 1.2*w, center[1] + 0.6*w],
[center[0] + 0.8*w, center[1] + 0.6*w],
[center[0] + 0.8*w, center[1] - 1.2*w],
[center[0] - 1.2*w, center[1] - 1.2*w]]
polygon = ae.AEPolygon(coordinates)
resource_name = "landsat"
query_parameters = dict(
bands=["BLUE", "GREEN", "RED", "NIR", "NIR", "SWIR1", "SWIR2"],
date_acquired=["2018-11-08", "2018-11-08"],
spacecraft_id=["LANDSAT_4", "LANDSAT_5", "LANDSAT_8"],
cloud_cover=[0.0, 100.0],
)
def EnhancedFire(s):
# FIRE NATURAL COLOR ENHANCED
# Pierre Markuse (@pierre_markuse)
def stretch(val, min, max):
return (val-min) / (max-min)
BITDEPTH = 16
B02 = s.bands(0) / (2.0 ** BITDEPTH)
B03 = s.bands(1) / (2.0 ** BITDEPTH)
B04 = s.bands(2) / (2.0 ** BITDEPTH)
B05 = s.bands(3) / (2.0 ** BITDEPTH)
B08 = s.bands(4) / (2.0 ** BITDEPTH)
B11 = s.bands(5) / (2.0 ** BITDEPTH)
B12 = s.bands(6) / (2.0 ** BITDEPTH)
NaturalColors = [stretch(3.1*B04, 0.05, 0.9),
stretch(3.0*B03, 0.05, 0.9),
stretch(3.0*B02, 0.05, 0.9)]
EnhancedNaturalColors = [stretch(3.1*B04 + 0.10*B05, 0.05, 0.9),
stretch(3.0*B03 + 0.15*B08, 0.05, 0.9),
stretch(3.0*B02, 0.05, 0.9)]
NIRSSWIRColors = [stretch(2.6*B12, 0.05, 0.9),
stretch(1.9*B08, 0.05, 0.9),
stretch(2.7*B02, 0.05, 0.9)]
NaturalNIRSWIRMix = [stretch(2.1*B04 + 0.5*B12, 0.01, 0.99),
stretch(2.2*B03 + 0.5*B08, 0.01, 0.99),
stretch(3.2*B02, 0.01, 0.99)]
PanBand = [stretch(B08, 0.01, 0.99),
stretch(B08, 0.01, 0.99),
stretch(B08, 0.01, 0.99)]
PanTintedGreen = [B08 * 0.2, B08, B08 * 0.2]
Fire1OVL = [stretch(2.1*B04 + 0.5*B12, 0.01, 0.99) + 1.1,
stretch(2.2*B03 + 0.5*B08, 0.01, 0.99),
stretch(2.1*B02, 0.01, 0.99)]
Fire2OVL = [stretch(2.1*B04 + 0.5*B12, 0.01, 0.99) + 1.1,
stretch(2.2*B03 + 0.5*B08, 0.01, 0.99) + 0.5,
stretch(2.1*B02, 0.01, 0.99)]
FIRE1 = Fire1OVL
FIRE2 = Fire2OVL
# [STARLIGHT NOTE]
# TO CREATE NATURAL PHOTO OF SMOKE PLUME, USE NOFIRE = EnhancedNaturalColors
# TO CREATE BURN SCAR + FIRE OUTLINE, USE NOFIRE = NaturalNIRSWIRMix
NOFIRE = NaturalNIRSWIRMix
NOFIRE = EnhancedNaturalColors
SENSITIVITY = 0.5
# Bookkeeping
import numpy as np
shape = B02.shape
FIRE1 = np.reshape(np.concatenate(FIRE1, axis=3), newshape=(shape[0], shape[1]*shape[2], 3))
FIRE2 = np.reshape(np.concatenate(FIRE2, axis=3), newshape=(shape[0], shape[1]*shape[2], 3))
NOFIRE = np.reshape(np.concatenate(NOFIRE, axis=3), newshape=(shape[0], shape[1]*shape[2], 3))
B11 = np.reshape(B11, newshape=(shape[0], shape[1]*shape[2], 1))
B12 = np.reshape(B12, newshape=(shape[0], shape[1]*shape[2], 1))
IMAGE = NOFIRE
w1 = np.squeeze((B12+B11) > (1.0/SENSITIVITY), axis=2)
w2 = np.squeeze((B12+B11) > (2.0/SENSITIVITY), axis=2)
for ts_i in range(shape[0]):
IMAGE[ts_i, w1[ts_i]&w2[ts_i],:] = FIRE2[0,w1[ts_i]&w2[ts_i]]
IMAGE[ts_i, w1[ts_i]&~w2[ts_i],:] = FIRE1[0,w1[ts_i]&~w2[ts_i]]
IMAGE = np.reshape(IMAGE, newshape=(shape[0], shape[1], shape[2], 3))
return s.update(IMAGE)
###########
# App Start
###########
out_full_path = "{}/{}/".format(out_dir, job_name)
# Write the essential data to file:
if not os.path.exists(out_full_path):
os.makedirs(out_full_path)
with ae.SkySession() as sky:
sb = sky.Resource(resource_name).search(polygon, query_parameters)
sb = sky.crop(sb)
spacetime = sky.download(sb, run=[EnhancedFire])
spacetime.generate_image([0], [0,1,2], show_now=True, save_to="{}/{}.png".format(out_full_path, job_name))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment