Last active
March 23, 2023 17:59
-
-
Save jdbcode/f3ebf33bfdf74a257b734a1ff61bc83b to your computer and use it in GitHub Desktop.
Create image chips that have consistent dimensions despite varying aspect ratios of input image region using Earth Engine and PIL
This file contains 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": [], | |
"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/f3ebf33bfdf74a257b734a1ff61bc83b/ee_image_chips.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"id": "cwxd0NG5Nk_7" | |
}, | |
"outputs": [], | |
"source": [ | |
"import ee\n", | |
"ee.Authenticate()\n", | |
"ee.Initialize()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"FeatureCollection of cities" | |
], | |
"metadata": { | |
"id": "GOYgn3aSYS6E" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"cities_fc = ee.FeatureCollection(\n", | |
" [ee.Feature(\n", | |
" ee.Geometry.Polygon(\n", | |
" [[[-86.30931396484377, 40.08385948719423],\n", | |
" [-86.52080078125002, 39.87550140515563],\n", | |
" [-86.53453369140627, 39.72145688768831],\n", | |
" [-86.22966308593752, 39.44839825753037],\n", | |
" [-85.81767578125002, 39.63901776816407],\n", | |
" [-85.78197021484377, 39.88603977106767],\n", | |
" [-85.89732666015627, 40.111172435524274]]]),\n", | |
" {\n", | |
" \"city_name\": \"city_0\"\n", | |
" }),\n", | |
" ee.Feature(\n", | |
" ee.Geometry.Polygon(\n", | |
" [[[-86.99870605468752, 40.51119785354961],\n", | |
" [-87.00145263671877, 40.385790713738075],\n", | |
" [-86.86961669921877, 40.29367679615214],\n", | |
" [-86.66636962890627, 40.43598164994896]]]),\n", | |
" {\n", | |
" \"city_name\": \"city_1\"\n", | |
" }),\n", | |
" ee.Feature(\n", | |
" ee.Geometry.Polygon(\n", | |
" [[[-86.23515625000002, 40.52998873829066],\n", | |
" [-86.19670410156252, 40.392066627828704],\n", | |
" [-86.05113525390627, 40.35858832843792],\n", | |
" [-86.03740234375002, 40.477778831614565],\n", | |
" [-86.10881347656252, 40.55294822166985]]]),\n", | |
" {\n", | |
" \"city_name\": \"city_2\"\n", | |
" })]);" | |
], | |
"metadata": { | |
"id": "0EIiL4ipYB1v" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"An impervious surface image visualized as RGB" | |
], | |
"metadata": { | |
"id": "jBf6CD82YYtt" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"img = ee.Image('USGS/NLCD_RELEASES/2019_REL/NLCD/2019').select('impervious')\n", | |
"vis_img = img.visualize(min=0, max=100, palette=['white', 'yellow', 'brown', 'black'])" | |
], | |
"metadata": { | |
"id": "OK0lf8N4Ntok" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"Get bounds and add buffer to each city" | |
], | |
"metadata": { | |
"id": "iXN41HiRYfuz" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"city_names = cities_fc.aggregate_array('city_name').distinct()\n", | |
"\n", | |
"def city_box(city_name):\n", | |
" city_box = (cities_fc.filter(ee.Filter.eq('city_name', city_name))\n", | |
" .geometry().bounds().buffer(1000, 1)) # 1 km buffer\n", | |
" return ee.Feature(city_box).set('city_name', city_name)\n", | |
"\n", | |
"city_boxes_fc = ee.FeatureCollection(city_names.map(city_box))" | |
], | |
"metadata": { | |
"id": "1Uvu1ufNYe1a" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"Loop to download images" | |
], | |
"metadata": { | |
"id": "bal2V8KDaidh" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"import urllib.request\n", | |
"from PIL import Image, ImageOps\n", | |
"\n", | |
"city_names_client = city_names.getInfo()\n", | |
"\n", | |
"def overlay_boundary(city_name):\n", | |
" city_features = cities_fc.filter(ee.Filter.eq('city_name', city_name))\n", | |
" return vis_img.clipToCollection(city_features).unmask(0)\n", | |
"\n", | |
"def add_padding(img_file, target_size):\n", | |
" img = Image.open(img_file)\n", | |
" width, height = img.size\n", | |
"\n", | |
" delta_w = target_size - width\n", | |
" delta_h = target_size - height\n", | |
"\n", | |
" pad_left = delta_w // 2\n", | |
" pad_right = delta_w - pad_left\n", | |
" pad_top = delta_h // 2\n", | |
" pad_bottom = delta_h - pad_top\n", | |
"\n", | |
" padded_img = ImageOps.expand(img, (pad_left, pad_top, pad_right, pad_bottom), fill=(0, 0, 0))\n", | |
"\n", | |
" padded_img.save(f'{img_file[:-4]}_padded.png')\n", | |
"\n", | |
"for city_name in city_names_client:\n", | |
" print(f'Downloading: {city_name}')\n", | |
" image_to_download = overlay_boundary(city_name)\n", | |
" img_url = image_to_download.getThumbURL({\n", | |
" 'dimensions': 1280,\n", | |
" 'region': city_boxes_fc.filter(ee.Filter.eq('city_name', city_name)).geometry(),\n", | |
" 'crs': 'EPSG:4326'\n", | |
" })\n", | |
"\n", | |
" filename = f'{city_name}.png'\n", | |
" urllib.request.urlretrieve(img_url, filename)\n", | |
"\n", | |
" add_padding(filename, 1280)" | |
], | |
"metadata": { | |
"id": "XBQ2JYGCamCV" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment