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

Jan 9, 2023 - 15:18
Jan 12, 2023 - 13:17
 0  101
Using the Sentinel L1C 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 lead to the drying up of headwaters of water bodies which supplies 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 90's.

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,12 we will compare images from Mole National Park in the Savannah region of Ghana and Ankasa Game Reserve in the Western Region of Ghan

Steps used to build it

  1. Download and Import all python libraries
  2. We used "" to obtain the co-ordinates of Mole National Park and Ankasa Game Forest by passing it's xMin, yMin, xMax and yMax through bboxfinder's search_bbox function.
  3. We used the search_time_interval python function to determine the time interval.
  4. To obtain the tile_info for the specified period of time, we used wfs_iterator to extract a unique tile info for each tile.
  5. Next, we converted each tile_id obtained into a tile_name which was accessed from the s3 bucket.
  6. For clearer results, we chose the tile_id with the least cloud cover.
  7. Next, we selected bands 'B01','B02','B03','B04','B07','B08','B8A', 'B10','B11','B12'
  8. We specified our download folders for both Mole National Park(Mole_Data) and Ankasa Game Reserves(Ankasa_Data).
  9. We then requested for the data using the request.save_data function.
  10. Next, we triggered the download and specified the bands we want to download.
  11. After downloading the images to our folder, we plotted our image using matplotlib.
  12. To highlight on the area affected most we imported rasterio and used the GeoTIFF feature to check the vegetation of the selected area.
  13. Band 4 and Band 8 was used because we were checking for the vegetation view.
  14. Finally, we plotted our obtained image.

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 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

After all libraries have been successfully installed, we will also import some libraries from the Sentinel Hub

from sentinelhub import (

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

Finally we import WFS to allows 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 Longitute 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 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
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:

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(


request2 = AwsTileRequest(


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?