Uploaded by dev_hashi

GISC606 Lab1.ipynb

advertisement
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": [],
"authorship_tag": "ABX9TyMengzOvSvUK3zBUlhx+XFx",
"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/github/alex-pakalniskis/gisc606-spring2023/blob/main/lab1/GISC606_Lab1.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"source": [
"# GISC 606 Lab 1: Normalized Burn Ratio (NBR)\n",
"\n",
"## Overview\n",
"* Part 1: Assess burn scars with satellite imagery and open-source GIS tools\n",
"* Part 2: Assigned readings and literature search\n",
"* Your Deliverable\n",
"\n",
"## Part 1\n",
"Assess burn scars with satellite imagery\n",
"> Note: This tutorial was originally developed by Esri's Learn Team. You can find the official maintained version at [this location](https://learn.arcgis.com/en/projects/assess-burn-scars-with-satellite-imagery/). Additionally you can find other tutorials in the [tutorial gallery](https://learn.arcgis.com/en/gallery/).\n",
"\n",
"\n",
"You'll use Linux command line tools and Python to display multispectral imagery data and calculate a Normalized Burn Ratio spectral index. No prior Linux and minimal prior Python experience is required (I've provided all the code).\n"
],
"metadata": {
"id": "JwuvPnjcKmQi"
}
},
{
"cell_type": "code",
"source": [
"# Install dtrx, an extraction utility that simplifies user experience. \n",
"# In a more real-life scenario you wouldn't necessarily do this step every time but only once. \n",
"# In Google Colab, we get a fresh computer each time so need to reinstall each time. \n",
"# https://pypi.org/project/dtrx/ \n",
"!pip install dtrx"
],
"metadata": {
"id": "9C7bEH9BeBRh"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Download the lab data from Esri\n",
"# We're only using the provided imagery, so will throw away the ArcGIS Pro project and other related files.\n",
"# https://man7.org/linux/man-pages/man1/wget.1.html\n",
"!wget -c https://www.arcgis.com/sharing/rest/content/items/1bc2bc1305b447fa939b937a8867114f/data -O MontanaFires"
],
"metadata": {
"id": "t2iu16W7f7VX"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Extract the compressed MontanaFires file into an uncompressed folder\n",
"!dtrx MontanaFires"
],
"metadata": {
"id": "B6L6xKo0eBT-"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Move a nested subdirectory in the extracted MontanaFires.1 directory to a new location \n",
"# https://man7.org/linux/man-pages/man1/mv.1.html\n",
"!mv MontanaFires.1/commondata/raster_data raster_data"
],
"metadata": {
"id": "aqztpMJ8eBWs"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Clean up your workspace by removing unnecessary folders and files\n",
"# https://man7.org/linux/man-pages/man1/rm.1.html\n",
"!rm MontanaFires\n",
"!rm -rf MontanaFires.1"
],
"metadata": {
"id": "7cDw8AsifhN9"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Display the contents of `raster_data` directory\n",
"# https://man7.org/linux/man-pages/man1/ls.1.html\n",
"!ls raster_data/"
],
"metadata": {
"id": "sdcHGpvDfhQj"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Install dependencies for rasterio then install rasterio\n",
"!sudo apt-get install python-numpy gdal-bin libgdal-dev\n",
"!pip install rasterio"
],
"metadata": {
"id": "rcTwMbtffhSv"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Check the version of rasterio installed via command line\n",
"!rio --version"
],
"metadata": {
"id": "45JynjQGfhVF"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Use rasterio command line tool to display image metadata for 2014 pre-fire imagery\n",
"!rio info raster_data/G_2014.tif --indent 2 --verbose"
],
"metadata": {
"id": "N7mUnZtEfhXO"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Do the same thing for the 2015 post-fire imagery but save to a JSON file\n",
"!rio info raster_data/G_2015.tif --indent 2 --verbose > G_2015.json"
],
"metadata": {
"id": "jQpwerZCfhZ0"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Let's switch to Python now\n",
"# Notice how we stop using ! since we're no longer trying to invoke Linux command line tools\n",
"# We're importing the `json` library and opening the JSON file we just created with rio\n",
"import json\n",
"\n",
"with open(\"G_2015.json\") as f:\n",
" info_2015 = json.load(f)"
],
"metadata": {
"id": "1HX6glnPXaF0"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Let's display the JSON \"dictionary keys\"\n",
"info_2015.keys()"
],
"metadata": {
"id": "RCiqzunSXix0"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# And we can display a specific key value\n",
"info_2015[\"descriptions\"]"
],
"metadata": {
"id": "RFlNi7E4Xi0c"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Determine the CRS of 2015 imagery data here\n"
],
"metadata": {
"id": "Dr-oMQLwXi3C"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Question 1 (double-click this cell and write your answer below the question)\n",
"### Part A\n",
"What are the band names for the 2015 imagery data?\n",
"* aka `info_2015[\"descriptions\"]`\n",
"\n",
"### Part B\n",
"Using the blank code cell above, determine the CRS of the 2015 imagery data. You can copy+paste the preceeding code cell, but make sure to replace \"description\" with \"crs\"."
],
"metadata": {
"id": "mWX06_n7W_vF"
}
},
{
"cell_type": "code",
"source": [
"# Import `rasterio` and some support libraries for performing array computation (multispectral images are big arrays) and visualizing data\n",
"import rasterio\n",
"from matplotlib import pyplot as plt\n",
"from rasterio.plot import show, show_hist\n",
"import numpy as np"
],
"metadata": {
"id": "BK6gJRd2f7dz"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Load the data set into rasterio\n",
"data_14 = rasterio.open(\"raster_data/G_2014.tif\")\n",
"data_15 = rasterio.open(\"raster_data/G_2015.tif\")"
],
"metadata": {
"id": "nWg8F9taifcB"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Plot one of the bands\n",
"plt.imshow(data_15.read(3), cmap=\"pink\")\n",
"plt.show()"
],
"metadata": {
"id": "mYhk647aife5"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Apply super basic contrast stretching\n",
"img=data_15.read(3)\n",
"vmin, vmax = np.nanpercentile(img, (5,95)) # 5-95% stretch\n",
"img_plt = plt.imshow(img, cmap='pink', vmin=vmin, vmax=vmax)\n",
"plt.show()"
],
"metadata": {
"id": "kEu4joIPdMN4"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Convenience function to normalize data to 0-1 scale\n",
"def normalize(array):\n",
" \"\"\"Normalizes numpy arrays into scale 0.0 - 1.0\"\"\"\n",
" array_min, array_max = array.min(), array.max()\n",
" return ((array - array_min)/(array_max - array_min))"
],
"metadata": {
"id": "JMP_bS59js7H"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Load RGB data from 2015 into memory, normalize, then display\n",
"red = data_15.read(3)\n",
"green = data_15.read(2)\n",
"blue = data_15.read(1)\n",
"\n",
"redn = normalize(red)\n",
"greenn = normalize(green)\n",
"bluen = normalize(blue)\n",
"\n",
"rgb = np.dstack((redn, greenn, bluen))\n",
"plt.imshow(rgb)"
],
"metadata": {
"id": "v0lFA5rQelZS"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Calculate NBR for 2014 and display the result\n",
"band_5_14 = data_14.read(5)\n",
"band_7_14 = data_14.read(7)\n",
"\n",
"n5 = normalize(band_5_14)\n",
"n7 = normalize(band_7_14)\n",
"\n",
"nbr_14 = (n5 - n7) / (n5 + n7)\n",
"\n",
"plt.imshow(nbr_14, cmap=\"gray\")\n",
"plt.show()"
],
"metadata": {
"id": "4lvwgOXwjs-z"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Calculate NBR for 2015 and display the result\n",
"band_5_15 = data_15.read(5)\n",
"band_7_15 = data_15.read(7)\n",
"\n",
"n5 = normalize(band_5_15)\n",
"n7 = normalize(band_7_15)\n",
"\n",
"nbr_15 = (n5 - n7) / (n5 + n7)\n",
"\n",
"\n",
"\n",
"plt.imshow(nbr_15, cmap=\"gray\")\n",
"plt.show()"
],
"metadata": {
"id": "00hHWDOkjtCG"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Derive NBR difference then plot it\n",
"nbr_delta = nbr_15 - nbr_14\n",
"\n",
"plt.imshow(nbr_delta, cmap=\"RdYlGn\")\n",
"plt.show()"
],
"metadata": {
"id": "wBCljM3QjtFW"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Convenience function to apply standard deviation contrast stretch to an array\n",
"import math\n",
"# https://stackoverflow.com/questions/59813350/create-new-raster-tif-from-standard-deviation-stretched-bands-works-with-dst\n",
"def std_stretch_data(data, n=2):\n",
" \"\"\"Applies an n-standard deviation stretch to data.\"\"\"\n",
"\n",
" # Get the mean and n standard deviations.\n",
" mean, d = data.mean(), data.std() * n\n",
"\n",
" # Calculate new min and max as integers. Make sure the min isn't\n",
" # smaller than the real min value, and the max isn't larger than\n",
" # the real max value.\n",
" new_min = math.floor(max(mean - d, data.min()))\n",
" new_max = math.ceil(min(mean + d, data.max()))\n",
"\n",
" # Convert any values smaller than new_min to new_min, and any\n",
" # values larger than new_max to new_max.\n",
" data = np.clip(data, new_min, new_max)\n",
"\n",
" # Scale the data.\n",
" data = (data - data.min()) / (new_max - new_min)\n",
" return data\n"
],
"metadata": {
"id": "NCoNW_WLlvuw"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Apply standard deviation contrast stretching to enhance NBR difference raster then display\n",
"std_stretched = std_stretch_data(nbr_delta)\n",
"plt.imshow(std_stretched, cmap=\"RdBu\")\n",
"plt.show()"
],
"metadata": {
"id": "lXuyvu-Elvxm"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Display stretched data and a corresponding histogram\n",
"fig, (axrgb, axhist) = plt.subplots(1, 2, figsize=(14,7))\n",
"show(std_stretched, ax=axrgb, cmap=\"RdBu\")\n",
"show_hist(std_stretched, bins=50, histtype='stepfilled', lw=0.0, stacked=False, alpha=0.3, ax=axhist)\n",
"plt.show()"
],
"metadata": {
"id": "GPyfKIurjtIf"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Save NBR difference raster to file\n",
"with rasterio.open(\n",
" \"nbr_delta.tif\", \n",
" \"w\", \n",
" driver=\"GTiff\", \n",
" height=data_15.shape[0], \n",
" width=data_15.shape[1], \n",
" dtype=red.dtype, \n",
" count=1, \n",
" crs='+proj=latlong', \n",
" transform=data_15.transform\n",
" ) as dst:\n",
" dst.write(nbr_delta, 1)"
],
"metadata": {
"id": "mXzoNkvGlxMk"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Display directory contents\n",
"!ls"
],
"metadata": {
"id": "CWCn6bUTlSJ8"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Question 2:\n",
"Please use `rio` to display information about the `nbr_delta.tif` data set to your command line output. Use the empty code cell below this question."
],
"metadata": {
"id": "60q1G2OnUraF"
}
},
{
"cell_type": "code",
"source": [],
"metadata": {
"id": "mvkiOY2QUrrI"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"## Part 2\n",
"### Assigned readings\n",
"* [Mapping Burns and Natural Reforestation using Thematic Mapper Data by Lopez Garcia, M., and V. Caselles](https://www.researchgate.net/publication/246761915_Mapping_burns_and_natural_reforestation_using_Thematic_Mapper_data)\n",
"* [Landscape Assessment: Remote Sensing of Severity, the Normalized Burn Ratio; and Ground Measure of Severity, the Composite Burn Index by Key, C. and N. Benson, N](https://www.researchgate.net/publication/241687027_Landscape_Assessment_Ground_measure_of_severity_the_Composite_Burn_Index_and_Remote_sensing_of_severity_the_Normalized_Burn_Ratio)\n",
"\n",
"## Your Deliverable\n",
"### Part 1\n",
"Save a copy of your Notebook in the GitHub repository you created during Lab 0. \n",
"* Click File > Download > Download .ipynb\n",
"* Navigate to your GitHub repo (created during Lab 0) and make sure that you're logged into GitHub\n",
"* Click Add file > Upload files\n",
"* Select the .ipynb file you saved\n",
"* Paste the link to your uploaded file in the GitHub issue you opened last week in this repo: https://github.com/alex-pakalniskis/gisc606-spring2023\n",
"\n",
"\n",
"\n",
"### Part 2\n",
"Please write a 2-4 sentence summary (paraphrase in your own words) about each article then compile your results into JSON format. Follow the steps below to submit your JSON data.\n",
"> Note: The steps may contain links with additional explanations to provide you with missing context.\n",
"\n",
"1. Login to your GitHub account if you aren't already logged in\n",
"1. Navigate to [https://github.com/alex-pakalniskis/gisc606-spring2023](https://github.com/alex-pakalniskis/gisc606-spring2023)\n",
"1. [Create a branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-and-deleting-branches-within-your-repository#creating-a-branch-using-the-branch-dropdown) of `alex-pakalniskis/gisc606-spring2023` from `main` branch using the branch dropdown\n",
" 1. Title your branch `lab 1: your csulb email without @csulb.edu`, i.e. mine would be `lab 1: alex.pakalniskis`\n",
"1. Create a file called `your-email-without-@csulb.edu.json`, i.e. mine would be `alex-pakalniskis.json` in the `gisc606-spring/lab1` subdirectory.\n",
"1. Copy the contents of Part 2's submission template (see below) into `your-email-without-@csulb.edu.json` then update with your information. \n",
"1. [Merge your changes](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request#creating-the-pull-request) into `main` branch by opening a pull request\n",
"1. [Request a review](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/requesting-a-pull-request-review) from @alex-pakalniskis\n",
"\n",
"#### Part 2 Submission Template\n",
"\n",
"``` json\n",
"{\n",
" \"your_name\": \"Alex Pakalniskis\",\n",
" \"your_csulb_email\": \"alex.pakalniskis@csulb.edu\",\n",
" \"articles\": [\n",
" {\n",
" \"title\": \"Mapping Burns and Natural Reforestation using Thematic Mapper Data\",\n",
" \"authors\": \"Lopez Garcia, M., and V. Caselles\",\n",
" \"link\": \"https://www.researchgate.net/publication/246761915_Mapping_burns_and_natural_reforestation_using_Thematic_Mapper_data\",\n",
" \"your_summary\": \"In two to four sentences, paraphrase the content of the article (your own words).\"\n",
" },\n",
" {\n",
" \"title\": \"Landscape Assessment: Remote Sensing of Severity, the Normalized Burn Ratio; and Ground Measure of Severity, the Composite Burn Index.\",\n",
" \"authors\": \"Key, C. and N. Benson, N\",\n",
" \"link\": \"https://www.researchgate.net/publication/241687027_Landscape_Assessment_Ground_measure_of_severity_the_Composite_Burn_Index_and_Remote_sensing_of_severity_the_Normalized_Burn_Ratio\",\n",
" \"your_summary\": \"In two to four sentences, paraphrase the content of the article (your own words).\"\n",
" }\n",
" ]\n",
"}\n",
"```\n",
"\n"
],
"metadata": {
"id": "gswRD-5DK7n1"
}
}
]
}
Download