Satellite imagery access and analysis in Python & Jupyter notebooks | by Abdishakur | Towards Data Science

The vast amount of satellite imagery collected every day across the globe is huge. Frequent Global coverage of the Earth and high-resolution data with readily available data to the public makes it helpful in monitoring the earth and its environment.
In this tutorial, we will learn how to access satellite images, analyze and visualize them right in Jupyter notebooks environment with python. Satellite images are pixel wised data just like any other types of images you have used. In Geography and Remote sensing terminology, this is called Rasters. Raster images mainly consist of satellite images, Lidar data as well as Georeferenced maps. As we will see, rasters consist of a matrix of cells and rows and each cell/row holds information about the location, such as elevation, temperature and vegetation.
We will cover the following in this tutorial:
Querry, retrieve and download satellite images directly with Python in Jupyter notebook.Read and Write Raster images in Python.Create RGB and NDVI images from Sentinel 2 Bands
Querry, retrieve and download satellite images directly with Python in Jupyter notebook.
Read and Write Raster images in Python.
Create RGB and NDVI images from Sentinel 2 Bands
In this tutorial, we will use Sentinel 2 data. There are many options to access Sentinel 2 images and most of them will require you to access through website interaction whether directly via a downloading service utility or via the cloud. However, since we are using Jupyter notebook, we will access them right here using, sentinelsat a python library which makes searching, retrieving and downloading Sentinel satellite images easy. So let us start installing sentinelsat through pip.
pip install sentinelsat
Before we are able to use sentinelsat, we need to register a username in Copernicus Open Access Hub and note down your username and password and paste them here inside the code.
You are all set to use sentinelsat and download Sentinel Satellite images. In this tutorial, we will use boundary data from Roma city, Italy. In the southern part of Roma, there is a natural reserve called Castel Porziano which we will use as a boundary to clip from the whole satellite image tile.
I have the boundary of the natural reserve as Shapefile and we will read it with Geopandas and visualize it with Folium python library (Note that I have covered Geopandas and Vector data analysis in 3 part series of articles available here: Part 1, Part 2, and Part 3)
With the above code, we have read natural reserve shapefile in Geopandas and called it nReserve, then later created an empty base map in Folium centred around coordinates in the area, we call this m. Finally, we can add the Geopandas data to the base map we have created to visualize the Natural Reserve boundary we are interested in. Below you can see the map.
One last step before we can search and download sentinel 2 images is to create a footprint from the nReservegeometry. Here we will use Shapely Python library since our data is in Shapefiles and have read it already as Geopandas GeodataFrame. (Note that if you have Geojson data, sentinelsatprovides a handy way to convert your data into a proper format in the query).
Now we can run a query on the apiwe have created above. There are different ways you can construct your query here depending on your use case. In this example, we will create a query for Sentinel 2 images Level 2A with cloud coverage between 0 and 10 that fall or intersect with the footprint (Area of study). For the time period, we are interested only in Sentinel Level 2A satellite images taken between ‘20190601’ and ‘20190626’ (For reference on valid search queries please refer to scihub).
We get a dictionary of all products available in this period with the query specification. In this case, we receive only 6 images taken but you can tweak the query for your use case example expanding the time period or increasing the cloud coverage percentage.
From here we can create a GeodataFrame or Dataframe from the product dictionary and sort them according to cloud coverage percentage. I prefer GeodataFrame instead of plain dataframe as the first holds the geometry of each satellite image tile. Once we create the GeodataFrame and sort it. As we do not have many products here we call directly products_gdf_sorted table to see the attributes off all 6 rows.
The table below only shows the first columns of the products_gdf_sorted table. In the index, you have tiles which you can use to download the particular image. Additional columns also include a title which has the full name of the tile and some other useful columns like cloud coverage percentage.
Let us say we are interested in the first satellite image since this has the least cloud coverage of all available images. we can simply call download and provide the product name (Note that you can download all images at once with api.download_all() function).
This will take a while (Sentinel 2 Satellite image tiles are about 1 GB). Once the download is finished, we can simply unzip it. In the next section, we will use the downloaded satellite images to process, analyze and visualize them.
Once we unzip the downloaded folder, we get many subfolders and it is sometimes hard to navigate through these folders. Here is a tree of the folders.
Sentinel-2 data is multispectral with 13 bands in the visible, near infrared and shortwave infrared spectrum. These bands come in a different spatial resolution ranging from 10 m to 60 m, thus images can be categorized as high-medium resolution. While there are other higher resolution satellites available(1m to 0.5 cm), Sentinel-2 data is free and has a high revisit time (5 days) which makes it an excellent option to study environmental challenges. Here is a useful table for sentinel 2 bands colours.
The true colour of satellite images is often displayed in a combination of the red, green and blue bands. Let us first read the data with Rasterio and create an RGB image from Bands 4, 3, and 2.
First, we open an empty RGB.tiff in Rasterio with the same parameters — i.e. width, height, CRS, etc.. — of Band 4 ( You can choose any of the three bands). Then we need to write those bands to the empty RGB image.
One important preprocessing task to clip or mask an area of study. Since this RGB image is large and huge you save both computing power and time to clip and use only the area of interest. We will clip the Natural reserve area from the RGB image.
Here, we first reproject our Natural reserve with the same projection as the original image. Next, we open the RGB image, get the metadata and mask with the projected boundary.
The result is only the masked/clipped area of interest as shown in the above image.
Calculating Normalized Difference Vegetation Index (NDVI) is an important indicator to assess the presence/absence of green vegetation from the satellite images. To calculate the NDVI, you need Red band and Near-Infrared Band (NIR). Different satellite images assign different numbers for these bands. Sentinel Images have red in 4th band and NIR in the 8th band. The formula for NDVI calculation is:
nir - red /(nir + red)
To carry out this in Rasterio we need first to read the 4th and 8th bands as arrays. We also need to make sure that the arrays are floats.
The output is an NDVI image which shows vegetation level of areas in the satellite image as shown below. For example, water has low vegetation (shown red in the image).
Accessing Sentinel 2 images with Python is made easy with sentinelsat. In this tutorial, we have covered how to construct a query and retrieve on information from available images as well as how to download Sentinel 2 images within Jupyter notebooks. We have also seen how to preprocess, create RGB and NDVI images and visualize raster images with Rasterio. The code for this tutorial is available in this Github repository with Google Colab Notebooks that you can run directly. Feel free to experiment and let me know if you have comments or questions.