Using the Sentinel L1C satellite to monitor deforestation
This blog seeks to take you through all the steps to using images obtained from the Sentinel satellite to monitor deforestation
In 2010, Ghana had 7.00Mha of natural forest, extending over 30% of its land area. In 2021, it lost 101kha of natural forest, equivalent to 62.9Mt of CO₂ emissions. This has led to the drying up of headwaters of water bodies which supply water to major cities in the country. As a result of logging activities in our forest, Ghana has had a higher percentage of deforestation since the 1990s.
Sentinel-2 (an Earth observation mission from the Copernicus Programme that systematically acquires optical imagery at high spatial resolution (10 m to 60 m) over land and coastal waters.) using the bands from 1, 2, 3, 4, 5, 6, 7, 8, 8a, 9, 10, 11, and 12, we will compare images from Mole National Park in the Savannah region of Ghana and Ankasa Game Reserve in the Western Region of Ghana
Steps used to build it
1. Import Necessary Libraries
First, we import the essential Python libraries for data extraction, processing, and visualization.
2. Define Coordinates for Study Areas
Using the bboxfinder
tool, we obtain the bounding box coordinates for Mole National Park and Ankasa Game Reserves by specifying the xMin, yMin, xMax, and yMax values.
3. Determine the time interval.
We utilize the search_time_interval
function to specify the time period for our data extraction.
4. Extract Tile Information
For the specified time period, we use the wfs_iterator
to retrieve unique tile information for each tile within the defined bounding boxes.
5. Convert Tile IDs to Tile Names
Each tile_id
obtained is converted into a tile_name
which can be accessed from the S3 bucket.
6. Select Tiles with Least Cloud Cover
To ensure clear imagery, we select the tile with the least cloud cover.
7. Choose Relevant Bands
We choose specific bands that are relevant for our analysis: 'B01', 'B02', 'B03', 'B04', 'B07', 'B08', 'B8A', 'B10', 'B11', 'B12'.
8. Specify Download Folders
We set up download folders for storing the data:
- Mole National Park data in
Mole_Data
- Ankasa Game Reserves data in
Ankasa_Data
9. Request and Download Data
We use the request.save_data
function to request and save the data. The download is triggered, specifying the bands we want to download.
10. Plot the Images
After downloading the images, we plotted them using matplotlib
for visualization.
11. Analyze Vegetation with GeoTIFF
To highlight the areas affected most, we import rasterio
and utilize its GeoTIFF features to check the vegetation of the selected areas.
12. Use Bands for Vegetation Analysis
We use Band 4 and Band 8 specifically to check the vegetation view.
13. Plot the Final Image
Finally, we plot the processed image to visualize the vegetation in the study areas.
The video below takes you through all the steps used
Steps explained in Details
Stage One: Install and Import required libraries
In this step, we will install all the Python libraries that will be needed. The first will be to install the Pandas python library followed by NumPy, Geopandas, Matplotlib and the list goes on. After installing our libraries, we can then import previously installed libraries
%pip install pandas
%pip install numpy
%pip install geopandas
%pip install shapely
%pip install matplotlib
%pip install plotly_express
%pip install sentinelhub
%pip install rasterio
%pip install earthpyname: geo-data
%pip install utils
!pip install sentinelhub==3.4.1
import pandas as pd
import numpy as np
import geopandas as gpd
from shapely.geometry import Point
import matplotlib
import matplotlib.pyplot as plt
import folium
import plotly_express as px
import os
import warnings
import datetime
warnings.filterwarnings('ignore')
After all libraries have been successfully installed, we will also import some libraries from the Sentinel Hub
from sentinelhub import (
MimeType,
CRS,
BBox,
SentinelHubRequest,
SentinelHubDownloadClient,
DataCollection,
bbox_to_dimensions,
DownloadRequest
)
The next most important thing to do is configure your AWS Secret Key and Sentinel Instance ID
To do this, we will head over to AWS IAM console, set up our secret keys and save
Head over Sentinel Hub, sign up and go to the configuration utility to access your keys
#Input instance id and client id from the sentinel hub
#input aws iAM keys for access to my aws account
from sentinelhub import SHConfig
config = SHConfig()
config.instance_id = '' #instance id
config.sh_client_id = '' #sentinel hub client id
config.sh_client_secret = '' #sentinel hub secret
config.aws_access_key_id = '' #aws access key
config.aws_secret_access_key = '' #aws secret key
Save your configuration
#Save configuration
config.save()
Finally, we import WFS to allow us perform some data manipulations
#Input WFS to allow us to perform some data manipulation on different geographical locations
from sentinelhub import WebFeatureService, BBox, CRS, DataCollection, SHConfig
if config.instance_id == '':
print("Warning! To use WFS functionality, please configure the `instance_id`.")
Stage Two: Using Bbox finder to specify your longitude and latitude
A bounding box (abbreviated bbox) is an area defined by two longitudes and two latitudes in which:
Latitude is a decimal number ranging from -90.0 to 90.0.
Longitude is a decimal number ranging from -180.0 to 180.0.
Log on to bboxfinder.com Bbox, and locate the area you would like to obtain the images from the satelitte.
In the code below I specified Mole National Park as our primary location
#Use Bbox to specify the geographical location of Mole National Park https://molenationalpark.org/
search_bbox = BBox(bbox=[-1.851196,9.264779,-1.788025,9.700935], crs=CRS.WGS84)
search_time_interval = ("2021-01-10T00:00:00", "2022-12-10T23:59:59")
wfs_iterator = WebFeatureService(
search_bbox, search_time_interval, data_collection=DataCollection.SENTINEL2_L1C, maxcc=1.0, config=config
)
for tile_info in wfs_iterator:
print(tile_info)
The first line search_bbox, allows us to specify our Longitude and Latitute, the proceeding line search_time_interval, allows us to specify the date and time period we want to retrieve the images.
Finally we can print our tiles
A tile obtained can be in the format below
{'type': 'Feature', 'geometry': {'type': 'MultiPolygon', 'crs': {'type': 'name', 'properties': {'name': 'urn:ogc:def:crs:EPSG::4326'}}, 'coordinates': [[[[-1.9246049674382728, 9.949669984838678], [-2.0897179274737763, 9.200678565551982], [-2.090331938754135, 8.957173405588467], [-1.0918256072464385, 8.953372194561377], [-1.0863496013234732, 9.94592425838906], [-1.9246049674382728, 9.949669984838678]]]]}, 'properties': {'id': 'S2B_OPER_MSI_L1C_TL_VGS2_20210111T123100_A020111_T30PXR_N02.09', 'date': '2021-01-11', 'time': '10:38:30', 'path': 's3://sentinel-s2-l1c/tiles/30/P/XR/2021/1/11/0', 'crs': 'EPSG:32630', 'mbr': '600000,990240 709800,1100040', 'cloudCoverPercentage': 5.34}}
Stage 3: Convert each tile_id obtained into a tile_name which was accessed from the s3 bucket
from sentinelhub import AwsTile
tile_id = 'S2A_OPER_MSI_L1C_TL_SGS__20200112T120158_A023800_T30NXN_N02.08'
tile_name, time, aws_index = AwsTile.tile_id_to_tile(tile_id)
tile_name, time, aws_index
tile_id2 = 'S2B_OPER_MSI_L1C_TL_SGS__20200117T121509_A014963_T30NXN_N02.08'
tile_name2, time2, aws_index2 = AwsTile.tile_id_to_tile(tile_id2)
tile_name2, time2, aws_index2
from sentinelhub import CRS, BBox, DataCollection, SHConfig, WebFeatureService
config = SHConfig()
if config.instance_id == "":
print("Warning! To use WFS functionality, please configure the `instance_id`.")
Stage 4: Select the appropraite bands needed
The Sentinel-2 satellites each carry a single multi-spectral instrument (MSI) with 13 spectral channels in the visible/near infrared (VNIR) and short wave infrared spectral range (SWIR). Within the 13 bands, the 10 meter spatial resolution allows for continued collaboration with the SPOT-5 and Landsat-8 missions, with the core focus being land classification
In this stage I will select the bands needed, B01,B02,B03,B04,B07,B08,B8A, B10,B11,B12
B01 | Band 1 |
B02 | Band 2 |
B03 | Band 3 |
B04 | Band 4 |
B07 | Band 7 |
B08 | Band 8 |
B08A | Band 8A |
B10 | Band 10 |
B11 | Band 11 |
B12 | Band 12 |
#Import the type of bands needed and specify our folder Data to store the data
warnings.simplefilter("ignore", UserWarning)
from sentinelhub import AwsTileRequest
bands = ['B01','B02','B03','B04','B07','B08','B8A', 'B10','B11','B12']
metafiles = ['tileInfo', 'preview', 'qi/MSK_CLOUDS_B00']
data_folder = './Mole_Data'
In the code above we imported AwsTileRequest and specified the bands we needed to collect images from
The meta files specifies what info we want to retrieve along side our data, in the third line we will create a folder named Mole_Data
Stage 4: Trigger our download
After successfully creating our folder Mole_Data we will then trigger our download
#Trigger the download to create the folder Data
request = AwsTileRequest(
tile=tile_name,
time=time,
aws_index=aws_index,
bands=bands,
metafiles=metafiles,
data_folder=data_folder,
data_collection=DataCollection.SENTINEL2_L1C
)
request.save_data()
request2 = AwsTileRequest(
tile=tile_name2,
time=time2,
aws_index=aws_index2,
bands=bands,
metafiles=metafiles,
data_folder=data_folder,
data_collection=DataCollection.SENTINEL2_L1C
)
request2.save_data()
We can then go ahead to download our data
#Download data one
data_list = request.get_data(redownload=True)
p_b01,p_b02,p_b03,p_b04,p_b07,p_b08,p_b8a,p_b10,p_b11,p_b12,p_tile_info, p_preview, p_cloud_mask = data_list
#Download data two
data_list2 = request2.get_data(redownload=True)
p_b01_2,p_b02_2,p_b03_2,p_b04_2,p_b07_2,p_b08_2,p_b8a_2,p_b10_2,p_b11_2,p_b12_2,p_tile_info_2, p_preview_2, p_cloud_mask_2 = data_list2
After all images have been successfully downloaded, we will go ahead to plot our images using Matplotlib
What's Your Reaction?