{ "cells": [ { "cell_type": "markdown", "id": "5ef72609-b294-4cce-a917-6629581c2ac6", "metadata": {}, "source": [ "# Monitoring Deforestation with SageMaker Geospatial Capabilities\n" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "This notebook's CI test result for us-west-2 is as follows. CI test results in other regions can be found at the end of the notebook. \n", "\n", "![This us-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-2/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "---" ] }, { "cell_type": "markdown", "id": "5ef72609-b294-4cce-a917-6629581c2ac6", "metadata": {}, "source": [ "\n", "\n", "This notebook runs with Kernel Geospatial 1.0. Note that the following policies need to be attached to the execution role that you used to run this notebook:\n", "\n", "- AmazonSageMakerFullAccess\n", "- AmazonSageMakerGeospatialFullAccess\n", "\n", "You can see the policies attached to the role in the IAM console under the permissions tab. If required, add the roles using the 'Add Permissions' button. \n", "\n", "In addition to these policies, ensure that the execution role's trust policy allows the SageMaker-GeoSpatial service to assume the role. This can be done by adding the following trust policy using the 'Trust relationships' tab:\n", "```\n", "{\n", " \"Version\": \"2012-10-17\",\n", " \"Statement\": [\n", " {\n", " \"Effect\": \"Allow\",\n", " \"Principal\": {\n", " \"Service\": [\n", " \"sagemaker.amazonaws.com\",\n", " \"sagemaker-geospatial.amazonaws.com\"\n", " ]\n", " },\n", " \"Action\": \"sts:AssumeRole\"\n", " }\n", " ]\n", "}\n", "```" ] }, { "cell_type": "markdown", "id": "04a08fa7-a784-40e8-a36d-cfa84830b66b", "metadata": {}, "source": [ "**Contents**\n", "\n", "* [Setup SageMaker geospatial capabilities](#1)\n", "* [Query and access Data](#2)\n", "* [Start an Earth Observation Job (EOJ) to calculate the NVDI](#3)\n", "* [Visualize EOJ inputs and outputs in FourSquare Studio](#4)\n", "* [Extract the NDVI results](#5)\n", "* [Measure the dense forest area](#6)\n", "\n" ] }, { "cell_type": "markdown", "id": "62e59d15-3a3e-4eae-8100-50b646425a12", "metadata": {}, "source": [ "\n", "\n", "## Setup SageMaker geospatial capabilities" ] }, { "cell_type": "code", "execution_count": null, "id": "0dc40c18-a7c6-4afa-a9f5-e76bcce62bc0", "metadata": {}, "outputs": [], "source": [ "import datetime as dt\n", "import os\n", "import time\n", "from glob import glob\n", "from urllib import request\n", "from urllib.parse import urlparse\n", "\n", "import boto3\n", "import cv2\n", "import imageio.v2 as imageio\n", "import matplotlib.dates as mdates\n", "import matplotlib.pyplot as plt\n", "import matplotlib.colors\n", "import numpy as np\n", "import sagemaker\n", "import sagemaker_geospatial_map\n", "import tifffile\n", "from botocore import UNSIGNED\n", "from botocore.config import Config\n", "from IPython.display import HTML" ] }, { "cell_type": "code", "execution_count": null, "id": "fb593738-f41e-4bbe-bab3-12e4e5beab26", "metadata": {}, "outputs": [], "source": [ "session = boto3.Session()\n", "execution_role = sagemaker.get_execution_role()\n", "sg_client = session.client(service_name=\"sagemaker-geospatial\")" ] }, { "cell_type": "markdown", "id": "767b519b-4b00-4702-9e99-34d91ba0c720", "metadata": {}, "source": [ "\n", "\n", "## Query and access data" ] }, { "cell_type": "markdown", "id": "665d5b78-06fb-4c36-a5eb-5ec080f8e794", "metadata": {}, "source": [ "Query the geospatial data with area of interest (AOI), time range and cloud cover filter. In this example we will monitor a location near Novo Progresso, Brazil. We enter the coordinates for this location, the time that we are interested, and the maximium cloud coverage. " ] }, { "cell_type": "code", "execution_count": null, "id": "63f1c759-83b3-4f61-8060-92b3b6e6e6c2", "metadata": {}, "outputs": [], "source": [ "coords = [[-55.9, -7.5], [-55.2, -7.5], [-55.2, -7.8], [-55.9, -7.8], [-55.9, -7.5]]\n", "timestart = \"2020-01-01T00:00:00Z\"\n", "timeend = \"2022-09-01T00:00:00Z\"\n", "maxclouds = 1 #" ] }, { "cell_type": "code", "execution_count": null, "id": "8a9749b1-4622-46da-9172-1491c9cb816f", "metadata": {}, "outputs": [], "source": [ "dc = sg_client.list_raster_data_collections()\n", "for k in dc[\"RasterDataCollectionSummaries\"]:\n", " print()\n", " print(f\"Dataset: {k['Name']}\\nDescription: {k['Description']}\\nArn: {k['Arn']}\")" ] }, { "cell_type": "code", "execution_count": null, "id": "bde07cea-8d83-4027-b20e-921e7f36f298", "metadata": {}, "outputs": [], "source": [ "search_rdc_args = {\n", " \"Arn\": \"arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8\", # sentinel-2 L2A COG\n", " \"RasterDataCollectionQuery\": {\n", " \"AreaOfInterest\": {\n", " \"AreaOfInterestGeometry\": {\"PolygonGeometry\": {\"Coordinates\": [coords]}}\n", " },\n", " \"TimeRangeFilter\": {\n", " \"StartTime\": timestart,\n", " \"EndTime\": timeend,\n", " },\n", " \"PropertyFilters\": {\n", " \"Properties\": [\n", " {\"Property\": {\"EoCloudCover\": {\"LowerBound\": 0, \"UpperBound\": maxclouds}}}\n", " ],\n", " \"LogicalOperator\": \"AND\",\n", " },\n", " \"BandFilter\": [\"visual\"],\n", " },\n", "}\n", "\n", "tci_urls = []\n", "data_manifests = []\n", "while search_rdc_args.get(\"NextToken\", True):\n", " search_result = sg_client.search_raster_data_collection(**search_rdc_args)\n", " if search_result.get(\"NextToken\"):\n", " data_manifests.append(search_result)\n", " for item in search_result[\"Items\"]:\n", " tci_url = item[\"Assets\"][\"visual\"][\"Href\"]\n", " print(tci_url)\n", " tci_urls.append(tci_url)\n", "\n", " search_rdc_args[\"NextToken\"] = search_result.get(\"NextToken\")" ] }, { "cell_type": "markdown", "id": "4cae74ac-9ec4-429f-a154-c37d0916293d", "metadata": {}, "source": [ "Great! We have images that match our area of interest, time range, and cloud filter. Note that the total number of images found will depend on the data query. " ] }, { "cell_type": "code", "execution_count": null, "id": "fd275826-b340-4e1f-9a30-9c5ec6c96fcd", "metadata": {}, "outputs": [], "source": [ "print(f\"total number of results found that match the filter criteria: {len(tci_urls)}\")" ] }, { "cell_type": "markdown", "id": "5c8063b1-7a84-4447-b3b2-35106b948369", "metadata": {}, "source": [ "Now, let's download one of the results and plot it in the notebook. This is used as a sanity check to ensure the image covers the area of interest, time range, and cloud coverage. " ] }, { "cell_type": "code", "execution_count": null, "id": "733e7ae7-4b22-47d8-967a-97b2c1a5b12c", "metadata": {}, "outputs": [], "source": [ "# Check one example.\n", "image_dir = \"./images/data\"\n", "os.makedirs(image_dir, exist_ok=True)\n", "\n", "tci_url = tci_urls[1]\n", "img_id = tci_url.split(\"/\")[-2]\n", "tci_path = image_dir + \"/\" + img_id + \"_TCI.tif\"\n", "response = request.urlretrieve(tci_url, tci_path)\n", "print(\"Downloaded image: \" + img_id)\n", "\n", "tci = tifffile.imread(tci_path)\n", "fig, ax = plt.subplots(figsize=(5, 5))\n", "plt.title(img_id)\n", "plt.imshow(tci)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "23788ee9-bf5f-48b8-80f9-e0432048f679", "metadata": {}, "source": [ "\n", "## Start an Earth Observation Job (EOJ) to calculate the Normalized Difference Vegetation Index (NDVI)" ] }, { "cell_type": "markdown", "id": "9594d2f8-11d7-45e8-9999-7e8d8e8494e5", "metadata": {}, "source": [ "First, let's check to see what spectral bands are available in the dataset" ] }, { "cell_type": "code", "execution_count": null, "id": "2670ea5c-0698-4978-b1a2-5756fa71e954", "metadata": {}, "outputs": [], "source": [ "sg_client.get_raster_data_collection(\n", " Arn=\"arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8\"\n", ")[\"ImageSourceBands\"]" ] }, { "cell_type": "markdown", "id": "0273455a-de1b-4b9d-bfaf-fe7d171db0cb", "metadata": {}, "source": [ "We can get more information on the bands by visiting the [sentinel website](https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-2-msi/resolutions/spatial). Here we will be using band 8 - nir and band 4 - red. Both of these bands have a 10 m spatial resolution. The bands will be used to calculate the Normalized Difference Vegetation Index (NDVI). The index is a ratio between -1 to +1, where values near -1 have low vegetation reflectance and values near +1 have high vegetation reflectance. Healthy vegetation (chlorophyll) will reflect more near infrared and green light while absorbling more red and blue light. We will impliment the NDVI calculation using BandMath EOJ job and specify the equation in the EOJ config. " ] }, { "cell_type": "code", "execution_count": null, "id": "4a7f45ab-06fc-41cc-b7c2-9c169ea5b787", "metadata": {}, "outputs": [], "source": [ "# Perform land cover segmentation on images returned from the sentinel dataset.\n", "#\n", "# This Earth Observation Job will take ~20 minutes to complete\n", "\n", "eoj_input_config = {\n", " \"RasterDataCollectionQuery\": {\n", " \"RasterDataCollectionArn\": \"arn:aws:sagemaker-geospatial:us-west-2:378778860802:raster-data-collection/public/nmqj48dcu3g7ayw8\",\n", " \"AreaOfInterest\": {\n", " \"AreaOfInterestGeometry\": {\"PolygonGeometry\": {\"Coordinates\": [coords]}}\n", " },\n", " \"TimeRangeFilter\": {\n", " \"StartTime\": timestart,\n", " \"EndTime\": timeend,\n", " },\n", " \"PropertyFilters\": {\n", " \"Properties\": [\n", " {\"Property\": {\"EoCloudCover\": {\"LowerBound\": 0, \"UpperBound\": maxclouds}}}\n", " ],\n", " \"LogicalOperator\": \"AND\",\n", " },\n", " }\n", "}\n", "\n", "\n", "eoj_config = {\n", " \"BandMathConfig\": {\n", " \"CustomIndices\": {\n", " \"Operations\": [{\"Name\": \"veggie\", \"Equation\": \"(nir - red) / (nir + red)\"}]\n", " }\n", " }\n", "}\n", "\n", "response = sg_client.start_earth_observation_job(\n", " Name=\"brazil-deforestation\",\n", " InputConfig=eoj_input_config,\n", " JobConfig=eoj_config,\n", " ExecutionRoleArn=execution_role,\n", ")" ] }, { "cell_type": "markdown", "id": "47e00573-a20b-4264-8fb7-f80a1c92f4e3", "metadata": {}, "source": [ "### Monitor the EOJ status." ] }, { "cell_type": "code", "execution_count": null, "id": "309b74ca-883e-4b64-b597-0f0e154a23dc", "metadata": {}, "outputs": [], "source": [ "eoj_arn = response[\"Arn\"]\n", "job_details = sg_client.get_earth_observation_job(Arn=eoj_arn)\n", "{k: v for k, v in job_details.items() if k in [\"Arn\", \"Status\", \"DurationInSeconds\"]}" ] }, { "cell_type": "markdown", "id": "c205a536-fd97-4500-a108-08bc988cd086", "metadata": {}, "source": [ "We can also impliment a loop to check on the EOJ status" ] }, { "cell_type": "code", "execution_count": null, "id": "b728c906-74cf-4ff5-a892-e86addc75db2", "metadata": {}, "outputs": [], "source": [ "def EOJwaiter(arn, max_check=1000, max_sleep=60):\n", " status = None\n", " print(f\"##### Checking Status on EOJ: {arn} #####\")\n", " tic = time.time()\n", "\n", " for i in range(max_check):\n", " _ = sg_client.get_earth_observation_job(Arn=arn)[\"Status\"]\n", "\n", " if status != _:\n", " if status is not None:\n", " print(f\"Step Duration: {time.time()-tic:.2f} seconds\")\n", " tic = time.time()\n", "\n", " status = _\n", " print(status)\n", "\n", " if status == \"COMPLETED\":\n", " break\n", " else:\n", " print(\".\", end=\"\", flush=True)\n", " time.sleep(max_sleep)" ] }, { "cell_type": "code", "execution_count": null, "id": "73e20adf-dce6-4474-8389-a38c5bff9407", "metadata": {}, "outputs": [], "source": [ "EOJwaiter(eoj_arn)" ] }, { "cell_type": "markdown", "id": "6ec7662d-7528-4cb8-99e4-dedc4025edca", "metadata": {}, "source": [ "\n", "\n", "## Visualize EOJ inputs and outputs using the geospatial client" ] }, { "cell_type": "code", "execution_count": null, "id": "2dbbfd3b-2726-42ae-9c00-487b1244d590", "metadata": {}, "outputs": [], "source": [ "# Creates an instance of the map to add EOJ input/ouput layer\n", "map = sagemaker_geospatial_map.create_map({\"is_raster\": True})\n", "map.set_sagemaker_geospatial_client(sg_client)" ] }, { "cell_type": "code", "execution_count": null, "id": "770cea38-8376-4d25-89ad-1784ee83726c", "metadata": {}, "outputs": [], "source": [ "# Render the map\n", "map.render()" ] }, { "cell_type": "code", "execution_count": null, "id": "7eca43da-4bdc-4133-bea2-45bbf4fcc269", "metadata": {}, "outputs": [], "source": [ "# Visualize AOI\n", "config = {\"label\": \"Novo Progresso AOI\"}\n", "aoi_layer = map.visualize_eoj_aoi(Arn=eoj_arn, config=config)\n", "time.sleep(20)" ] }, { "cell_type": "code", "execution_count": null, "id": "f82107b8-eefe-424e-8389-d11d31acc772", "metadata": {}, "outputs": [], "source": [ "# Visualize input.\n", "time_range_filter = {\n", " \"start_date\": timestart,\n", " \"end_date\": timeend,\n", "}\n", "config = {\"label\": \"Input\"}\n", "\n", "input_layer = map.visualize_eoj_input(\n", " Arn=eoj_arn, config=config, time_range_filter=time_range_filter\n", ")\n", "time.sleep(20)" ] }, { "cell_type": "code", "execution_count": null, "id": "ebf1b5d7-6e15-4c7f-9dcd-e98e02d42b34", "metadata": {}, "outputs": [], "source": [ "# Visualize output, EOJ needs to be in completed status.\n", "time_range_filter = {\n", " \"start_date\": timestart,\n", " \"end_date\": timeend,\n", "}\n", "config = {\"preset\": \"singleBand\", \"band_name\": \"veggie\"}\n", "output_layer = map.visualize_eoj_output(\n", " Arn=eoj_arn, config=config, time_range_filter=time_range_filter\n", ")\n", "time.sleep(20)" ] }, { "cell_type": "markdown", "id": "321c260b-49fd-4973-9dd6-0f00f629fab6", "metadata": {}, "source": [ "\n", "## Extract the NDVI band math results" ] }, { "cell_type": "markdown", "id": "5c55936b-6077-433c-972b-fa5c1592a898", "metadata": {}, "source": [ "To get the output from the EOJ job we need to export it to s3. Here we provide an export location and start the export job. Note that the export job will take ~5 minutes to complete." ] }, { "cell_type": "code", "execution_count": null, "id": "d68d8237-c580-4164-b69c-6098eb76fd00", "metadata": {}, "outputs": [], "source": [ "sagemaker_session = sagemaker.Session()\n", "s3_bucket_name = sagemaker_session.default_bucket() # Replace with your own bucket if needed\n", "s3_bucket = session.resource(\"s3\").Bucket(s3_bucket_name)\n", "prefix = \"eoj_deforestation_ndvi\" # Replace with the S3 prefix desired\n", "export_bucket_and_key = f\"s3://{s3_bucket_name}/{prefix}/\"\n", "\n", "eoj_output_config = {\"S3Data\": {\"S3Uri\": export_bucket_and_key}}\n", "export_response = sg_client.export_earth_observation_job(\n", " Arn=eoj_arn,\n", " ExecutionRoleArn=execution_role,\n", " OutputConfig=eoj_output_config,\n", " ExportSourceImages=False,\n", ") #" ] }, { "cell_type": "code", "execution_count": null, "id": "34cef2da-7704-4ce8-b461-08a198ab62b3", "metadata": {}, "outputs": [], "source": [ "print(f\"Data will be exported to: {export_bucket_and_key}\")" ] }, { "cell_type": "code", "execution_count": null, "id": "36eea163-528c-4471-9a4e-2cc71b55af70", "metadata": {}, "outputs": [], "source": [ "# Monitor the export job status\n", "export_job_details = sg_client.get_earth_observation_job(Arn=export_response[\"Arn\"])" ] }, { "cell_type": "markdown", "id": "851e8ce5-8360-466a-aabb-de377f2820c9", "metadata": {}, "source": [ "Again we can impliment a loop to monitor the status of the export" ] }, { "cell_type": "code", "execution_count": null, "id": "ac7d2342-c396-46f1-8574-2cbd022d18fc", "metadata": {}, "outputs": [], "source": [ "def EOJexportwaiter(arn, max_check=1000, max_sleep=60):\n", " status = None\n", " print(f\"##### Checking Export Status on EOJ: {arn} #####\")\n", " tic = time.time()\n", "\n", " for i in range(max_check):\n", " _ = sg_client.get_earth_observation_job(Arn=arn)[\"ExportStatus\"]\n", "\n", " if status != _:\n", " if status is not None:\n", " print(f\"Step Duration: {time.time()-tic:.2f} seconds\")\n", " tic = time.time()\n", "\n", " status = _\n", " print(status)\n", "\n", " if status == \"SUCCEEDED\":\n", " break\n", " else:\n", " print(\".\", end=\"\", flush=True)\n", " time.sleep(max_sleep)" ] }, { "cell_type": "code", "execution_count": null, "id": "ae5e761a-4372-48f0-a06e-f6a456919549", "metadata": {}, "outputs": [], "source": [ "EOJexportwaiter(eoj_arn)" ] }, { "cell_type": "markdown", "id": "a667db5f-ac1c-4218-9e28-48208d35d54a", "metadata": {}, "source": [ "\n", "## Measure Vegetation Index\n", "\n", "Now with our data exported to s3, let's download the tif masks to the notebook elastic file system (EFS). Once we download the image we can then calculate the vegetation. We need to download the images to the file system to be able to read them into memory and to calculate the total area of vegetation. " ] }, { "cell_type": "code", "execution_count": null, "id": "6ef9344c-9f0b-42a8-a1e9-7c77c57487c0", "metadata": {}, "outputs": [], "source": [ "# Download band math masks\n", "mask_dir = \"./masks/deforestation\"\n", "os.makedirs(mask_dir, exist_ok=True)\n", "image_paths = []\n", "for s3_object in s3_bucket.objects.filter(Prefix=prefix).all():\n", " path, filename = os.path.split(s3_object.key)\n", " if \"output\" in path:\n", " mask_name = mask_dir + \"/\" + filename\n", " s3_bucket.download_file(s3_object.key, mask_name)\n", " print(\"Downloaded mask: \" + mask_name)\n", "\n", "# Download source images for visualization\n", "for tci_url in tci_urls:\n", " url_parts = urlparse(tci_url)\n", " img_id = url_parts.path.split(\"/\")[-2]\n", " tci_download_path = image_dir + \"/\" + img_id + \"_TCI.tif\"\n", " cogs_bucket = session.resource(\n", " \"s3\", config=Config(signature_version=UNSIGNED, region_name=\"us-west-2\")\n", " ).Bucket(url_parts.hostname.split(\".\")[0])\n", " cogs_bucket.download_file(url_parts.path[1:], tci_download_path)\n", " print(\"Downloaded image: \" + img_id)\n", "\n", "print(\"Downloads complete.\") #" ] }, { "cell_type": "markdown", "id": "cd1e76bc-6204-44b7-9ee4-4d618cfb2943", "metadata": {}, "source": [ "### Extract area of vegetation." ] }, { "cell_type": "code", "execution_count": null, "id": "23111adf-e639-45eb-baa1-6f9c20ae47c7", "metadata": {}, "outputs": [], "source": [ "image_files = glob(\"./images/data/*.tif\")\n", "mask_files = glob(\"./masks/deforestation/*.tif\")\n", "image_files.sort(key=lambda x: x.split(\"MXM_\")[1])\n", "mask_files.sort(key=lambda x: x.split(\"MXM_\")[1])" ] }, { "cell_type": "code", "execution_count": null, "id": "9bd68e7f-4dee-4f94-b699-f8ce91c1c76e", "metadata": {}, "outputs": [], "source": [ "overlay_dir = \"./masks/veg-index-overlay\"\n", "os.makedirs(overlay_dir, exist_ok=True)\n", "\n", "veg_areas = []\n", "mask_dates = []\n", "thresh = 0.4 # https://www.usgs.gov/special-topics/remote-sensing-phenology/science/ndvi-foundation-remote-sensing-phenology\n", "\n", "for image_file, mask_file in zip(image_files, mask_files):\n", " image_id = image_file.split(\"/\")[-1].split(\"_TCI\")[0]\n", " mask_id = mask_file.split(\"/\")[-1].split(\"_veggie.tif\")[0]\n", " mask_date = mask_id.split(\"_\")[2]\n", " if image_id == mask_id:\n", " print(image_id)\n", " mask_dates.append(mask_date)\n", " image = tifffile.imread(image_file) # (10980 x 10980 x 3)\n", " image_ds = cv2.resize(\n", " image, (2000, 2000), interpolation=cv2.INTER_LINEAR\n", " ) # (2000 x 2000 x 3)\n", " mask = tifffile.imread(mask_file) # 10980 x 10980 (10 m per pixel)\n", " veg_mask = (mask > thresh).astype(np.uint8)\n", " veg_mask = veg_mask[\n", " 2000:, :\n", " ] # sample image to remove missing path in the north west corner\n", " veg_area = (\n", " veg_mask.sum() * 10 * 10 / (1000 * 1000)\n", " ) # calculate the surface area, 10m per pixel\n", " veg_areas.append(veg_area)\n", "\n", " cmap = matplotlib.colors.ListedColormap([\"red\", \"green\"])\n", " f, axarr = plt.subplots(1, 2, figsize=(12, 5))\n", " axarr[0].imshow(image[2000:, :])\n", " axarr[0].axis(\"off\")\n", " axarr[1].imshow(veg_mask, cmap=cmap)\n", " axarr[1].axis(\"off\")\n", "\n", " f.suptitle(\n", " f\"{image_id}\\nTotal Area = {veg_area:.1f} sq km\\nDate = {mask_date[0:4]}-{mask_date[4:6]}-{mask_date[6:8]} \"\n", " )\n", " overlay_file = overlay_dir + \"/\" + mask_date + \".png\"\n", " f.savefig(overlay_file, dpi=80, bbox_inches=\"tight\")\n", " plt.close()" ] }, { "cell_type": "markdown", "id": "96a7be77-2de8-4899-aad8-4c6ce3cd0e5d", "metadata": {}, "source": [ "We have produced output plots using the satellite image overlayed with the vegetation index at a transparency of 40%. Let's take a look at a single image" ] }, { "cell_type": "code", "execution_count": null, "id": "5cbf1a7b-778b-4c4e-9c9f-2270bfa7f811", "metadata": {}, "outputs": [], "source": [ "HTML('')" ] }, { "cell_type": "markdown", "id": "fa05069c-22dd-40bd-94cc-c729f9f8e4b2", "metadata": {}, "source": [ "Now let's split the data by year so we can compare 2020, 2021, and 2022. " ] }, { "cell_type": "code", "execution_count": null, "id": "f781b3ce-e389-40a2-8dff-1b05dfbb3cdb", "metadata": {}, "outputs": [], "source": [ "a = []\n", "t = []\n", "years = [\"2020\", \"2021\", \"2022\"]\n", "for y in years:\n", " a_ = []\n", " t_ = []\n", " for i, m in enumerate(mask_dates):\n", " if m[0:4] == y:\n", " t_.append(dt.datetime.strptime(\"1900\" + m[4:], \"%Y%m%d\").date())\n", " a_.append(veg_areas[i])\n", "\n", " a.append(a_)\n", " t.append(t_)" ] }, { "cell_type": "code", "execution_count": null, "id": "18fdc809-02bf-49fc-90b2-5d4bb1269983", "metadata": {}, "outputs": [], "source": [ "plt.figure(figsize=(15, 5))\n", "plt.title(\"Novo Progresso, Brazil - Vegetation Index Total Area Per Year\", fontsize=20)\n", "plt.xticks(rotation=45)\n", "plt.ylabel(\"Vegetation area [sq km]\", fontsize=14)\n", "plt.plot(t[0], a[0], marker=\"o\", label=\"2020\")\n", "plt.plot(t[1], a[1], marker=\"o\", label=\"2021\")\n", "plt.plot(t[2], a[2], marker=\"o\", label=\"2022\")\n", "# Make ticks on occurrences of each month:\n", "plt.gca().xaxis.set_major_locator(mdates.MonthLocator())\n", "# Get only the month to show in the x-axis:\n", "plt.gca().xaxis.set_major_formatter(mdates.DateFormatter(\"%b\"))\n", "plt.grid(\"on\")\n", "plt.legend(loc=\"best\", fontsize=14)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "3edfbfa5-00d0-41e3-a440-20586428c5e0", "metadata": {}, "source": [ "The plot above was produced using geospatial images alone. We can monitor how the total area of the vegetation index is changing over time and compare this to previous years. In this plot we show how year 2020, 2021, and 2022 are slightly different. There is a clear seasonal trend where the spring vegetation decreases as we approach fall / winter. As deforestation continues we see the yearly curves move down (less area) each year. Note that the same number of images for each year are different. This is due to the cloud filter where some of the images acquired during the time range of interest did not meet the cloud coverage constraints." ] }, { "cell_type": "markdown", "id": "e0ef0d0b-e2c7-453f-9f84-31ff380afef3", "metadata": {}, "source": [ "If we take a closer look at the images that were collected in 2020, 2021, and 2022 we can see the change in the vegetation. Here the 3 image gif shows the visual image with the vegetation index. We can see that the vegetation area decreases as we progress from 2020 to 2022" ] }, { "cell_type": "code", "execution_count": null, "id": "650d64f2-7b73-46ea-bcce-dd5af8c261cd", "metadata": {}, "outputs": [], "source": [ "frames = []\n", "filenames = glob(\"./masks/veg-index-overlay/*0705.png\")\n", "filenames.sort()\n", "\n", "for filename in filenames:\n", " frames.append(imageio.imread(filename))\n", "imageio.mimsave(\"deforestation.gif\", frames, duration=1)" ] }, { "cell_type": "code", "execution_count": null, "id": "0c497269-479b-4172-b522-4253353a8408", "metadata": {}, "outputs": [], "source": [ "HTML('')" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Notebook CI Test Results\n", "\n", "This notebook was tested in multiple regions. The test results are as follows, except for us-west-2 which is shown at the top of the notebook.\n", "\n", "![This us-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-1/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This us-east-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-east-2/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This us-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/us-west-1/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This ca-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ca-central-1/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This sa-east-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/sa-east-1/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This eu-west-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-1/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This eu-west-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-2/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This eu-west-3 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-west-3/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This eu-central-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-central-1/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This eu-north-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/eu-north-1/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This ap-southeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-1/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This ap-southeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-southeast-2/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This ap-northeast-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-1/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This ap-northeast-2 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-northeast-2/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n", "\n", "![This ap-south-1 badge failed to load. Check your device's internet connectivity, otherwise the service is currently unavailable](https://h75twx4l60.execute-api.us-west-2.amazonaws.com/sagemaker-nb/ap-south-1/sagemaker-geospatial|brazil-deforestation-monitoring|deforestation-monitoring.ipynb)\n" ] } ], "metadata": { "instance_type": "ml.m5.4xlarge", "kernelspec": { "display_name": "Python 3 (Geospatial 1.0)", "language": "python", "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-west-2:081189585635:image/sagemaker-geospatial-v1-0" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3" }, "toc-autonumbering": true, "toc-showtags": false }, "nbformat": 4, "nbformat_minor": 5 }