Last active
April 8, 2024 23:22
-
-
Save jdbcode/5650cf896ea84cf30b654536cfadbdfe to your computer and use it in GitHub Desktop.
ee_goes_16_eclipse_2024.ipynb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"nbformat": 4, | |
"nbformat_minor": 0, | |
"metadata": { | |
"colab": { | |
"provenance": [], | |
"authorship_tag": "ABX9TyNR0opLDesHFSHQmfUxryFa", | |
"include_colab_link": true | |
}, | |
"kernelspec": { | |
"name": "python3", | |
"display_name": "Python 3" | |
}, | |
"language_info": { | |
"name": "python" | |
} | |
}, | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "view-in-github", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"<a href=\"https://colab.research.google.com/gist/jdbcode/5650cf896ea84cf30b654536cfadbdfe/ee_goes_16_eclipse_2024.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"# Video of the 2024 solar eclipse as seen from the GOES-16 satellite\n", | |
"\n", | |
"This Colab notebook creates a time series animation of the 2024 solar eclipse from GOES-16 imagery using Google Earth Engine. A Google cloud project that is Earth Engine-enabled is required ([learn more](https://developers.google.com/earth-engine/cloud/earthengine_cloud_project_setup#get-access-to-earth-engine))." | |
], | |
"metadata": { | |
"id": "xdLIpggqRLXE" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@title Set these parameters\n", | |
"\n", | |
"ee_project = 'my-cloud-project' # @param {type:\"string\"}\n", | |
"goes_16_id = 'NOAA/GOES/16/MCMIPF' # @param {type:\"string\"}\n", | |
"start_time = '2024-04-08T16:00:00' # @param {type:\"string\"}\n", | |
"end_time = '2024-04-08T20:30:00' # @param {type:\"string\"}" | |
], | |
"metadata": { | |
"cellView": "form", | |
"id": "q8AqIfnWHAcw" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@title Import libraries and initialize Earth Engine\n", | |
"\n", | |
"!pip install -q retry\n", | |
"!apt-get -y install ffmpeg\n", | |
"\n", | |
"import ee\n", | |
"ee.Authenticate()\n", | |
"ee.Initialize(project=ee_project, opt_url='https://earthengine-highvolume.googleapis.com')\n", | |
"\n", | |
"import logging\n", | |
"import multiprocessing\n", | |
"import requests\n", | |
"import shutil\n", | |
"import glob\n", | |
"from PIL import Image as pil_image\n", | |
"from retry import retry\n", | |
"from IPython.display import Image\n", | |
"from IPython.display import Video" | |
], | |
"metadata": { | |
"cellView": "form", | |
"id": "OlzBeskqn04y" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@title Functions to prepare GOES imagery\n", | |
"\n", | |
"# Applies scaling factors.\n", | |
"def apply_scale_and_offset(img):\n", | |
" def get_factor_img(factor_names):\n", | |
" factor_list = img.toDictionary().select(factor_names).values()\n", | |
" return ee.Image.constant(factor_list)\n", | |
"\n", | |
" scale_img = get_factor_img(['CMI_C.._scale'])\n", | |
" offset_img = get_factor_img(['CMI_C.._offset'])\n", | |
" scaled = img.select('CMI_C..').multiply(scale_img).add(offset_img)\n", | |
" return img.addBands(srcImg=scaled, overwrite=True)\n", | |
"\n", | |
"\n", | |
"# Adds a synthetic green band.\n", | |
"def add_green_band(img):\n", | |
" green = img.expression(\n", | |
" expression='CMI_GREEN = 0.45 * red + 0.10 * nir + 0.45 * blue',\n", | |
" opt_map={\n", | |
" 'blue': img.select('CMI_C01'),\n", | |
" 'red': img.select('CMI_C02'),\n", | |
" 'nir': img.select('CMI_C03')\n", | |
" })\n", | |
" return img.addBands(green)\n", | |
"\n", | |
"\n", | |
"# Scales select bands for visualization.\n", | |
"def scale_for_vis(img):\n", | |
" return (img.select(['CMI_C01', 'CMI_GREEN', 'CMI_C02', 'CMI_C03', 'CMI_C05'])\n", | |
" .log10()\n", | |
" .interpolate([-1.6, 0.176], [0, 1], 'clamp')\n", | |
" .unmask(0)\n", | |
" .set('system:time_start', img.get('system:time_start')))\n", | |
"\n", | |
"# Wraps previous functions.\n", | |
"def process_for_vis(img):\n", | |
" return scale_for_vis(add_green_band(apply_scale_and_offset(img)))\n", | |
"\n", | |
"\n", | |
"# Paint GOES image onto EPSG:3857 for easier region definition.\n", | |
"def change_proj(img):\n", | |
" goes_16_proj = ee.Projection('PROJCS[\"unnamed\", ' +\n", | |
" 'GEOGCS[\"unknown\", ' +\n", | |
" ' DATUM[\"unknown\", ' +\n", | |
" ' SPHEROID[\"Spheroid\", 6378137.0, 298.2572221]], ' +\n", | |
" ' PRIMEM[\"Greenwich\", 0.0], ' +\n", | |
" ' UNIT[\"degree\", 0.017453292519943295], ' +\n", | |
" ' AXIS[\"Longitude\", EAST], ' +\n", | |
" ' AXIS[\"Latitude\", NORTH]], ' +\n", | |
" 'PROJECTION[\"GEOS\"], ' +\n", | |
" 'PARAMETER[\"central_meridian\", -89.5], ' +\n", | |
" 'PARAMETER[\"satellite_height\", 35786023.0], ' +\n", | |
" 'PARAMETER[\"false_easting\", 0.0], ' +\n", | |
" 'PARAMETER[\"false_northing\", 0.0], ' +\n", | |
" 'PARAMETER[\"sweep\", 0.0], ' +\n", | |
" 'UNIT[\"m\", 1.0], ' +\n", | |
" 'AXIS[\"x\", EAST], ' +\n", | |
" 'AXIS[\"y\", NORTH]]'\n", | |
" );\n", | |
"\n", | |
" return img.changeProj(goes_16_proj, 'EPSG:3857').set(\n", | |
" 'system:start_time', img.get('system:start_time'))" | |
], | |
"metadata": { | |
"cellView": "form", | |
"id": "88RxFq-voqM_" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@title Process GOES imagery\n", | |
"\n", | |
"IC = ee.ImageCollection(goes_16_id).filterDate(\n", | |
" start_time, end_time)\n", | |
"IC = IC.map(process_for_vis).map(change_proj)\n", | |
"timestamps = IC.aggregate_array('system:time_start').getInfo()\n", | |
"print('N images:', len(timestamps))" | |
], | |
"metadata": { | |
"cellView": "form", | |
"id": "9jtCLI2ep_Hy" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@title Test visualization and extent parameters\n", | |
"\n", | |
"geom = ee.Geometry.Polygon(\n", | |
" [[[-40.03174642343608, 45.57152286631389],\n", | |
" [-40.03174642343608, 0.15896988330457215],\n", | |
" [33.62059732656392, 0.15896988330457215],\n", | |
" [33.62059732656392, 45.57152286631389]]], None, False)\n", | |
"\n", | |
"THUMB_PARAMS = {\n", | |
" 'bands': ['CMI_C05', 'CMI_C03', 'CMI_GREEN'],\n", | |
" 'min': 0,\n", | |
" 'max': 0.8,\n", | |
" 'gamma': 0.8,\n", | |
" 'dimensions': 1000,\n", | |
" 'region': geom,\n", | |
" 'crs': 'EPSG:3857',\n", | |
" 'format': 'png'\n", | |
"};\n", | |
"\n", | |
"ee_image = IC.first()\n", | |
"Image(url = ee_image.getThumbURL(THUMB_PARAMS))" | |
], | |
"metadata": { | |
"cellView": "form", | |
"id": "zKz-PGIEqw61" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@title Download images\n", | |
"\n", | |
"@retry(tries=10, delay=1, backoff=2)\n", | |
"def get_result(index, timestamp):\n", | |
" img = IC.filter(ee.Filter.eq('system:time_start', timestamp)).first()\n", | |
"\n", | |
" url = img.getThumbURL(THUMB_PARAMS)\n", | |
"\n", | |
" r = requests.get(url, stream=True)\n", | |
" if r.status_code != 200:\n", | |
" raise r.raise_for_status()\n", | |
"\n", | |
" filename = 'img_%d.png' % timestamp\n", | |
" with open(filename, 'wb') as out_file:\n", | |
" shutil.copyfileobj(r.raw, out_file)\n", | |
" print(\"Done: \", timestamp)\n", | |
"\n", | |
"!rm *.png\n", | |
"pool = multiprocessing.Pool(4)\n", | |
"pool.starmap(get_result, enumerate(timestamps))\n", | |
"pool.close()\n", | |
"pool.join()" | |
], | |
"metadata": { | |
"cellView": "form", | |
"id": "QgR-pWWc1E3p" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@title Create an MP4 video\n", | |
"\n", | |
"image_list = sorted(glob.glob('/content/*.png'))\n", | |
"\n", | |
"image = pil_image.open(image_list[0])\n", | |
"width, height = image.size\n", | |
"if width % 2 != 0:\n", | |
" width -= 1\n", | |
"if height % 2 != 0:\n", | |
" height -= 1\n", | |
"scale = f\"scale={width}:{height}\"\n", | |
"\n", | |
"with open('image_list.txt', 'w') as f:\n", | |
" for file in image_list:\n", | |
" f.write(f\"file '{file}'\\n\")\n", | |
"\n", | |
"!rm -f out.mp4\n", | |
"!ffmpeg -f concat -safe 0 -r 6 -i image_list.txt -vf {scale} -c:v libx264 -pix_fmt yuv420p out.mp4" | |
], | |
"metadata": { | |
"cellView": "form", | |
"id": "LcU6pLL6KEd-" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@title Watch the video\n", | |
"\n", | |
"Video('out.mp4', embed=True)" | |
], | |
"metadata": { | |
"id": "esR1FD_u9d5L" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment