How much green is Delhi as on 15 Oct 2017?

Introduction

The India State of Forests Report (ISFR) 2017, showed that the green cover of Delhi has increased from 20.08% in 2015 to 20.22% in 2017, as observed from satellite imageries of Delhi for the month of October and November [1]. This was a welcome news for the city struggling with severe pollution and rising population, which makes it necessary to monitor the city's green cover and keep the city liveable.

This sample shows the capabilities of spectral indices such as Normalized Difference Vegetation index (NDVI) for the calculation of green cover in Delhi, India on 15 October 2017 using Landsat 8 imagery.

Necessary Imports

Input
%matplotlib inline

import pandas as pd
from datetime import datetime
from IPython.display import Image
from IPython.display import HTML
import matplotlib.pyplot as plt

import arcgis
from arcgis.gis import GIS
from arcgis.raster.functions import apply, clip, remap, colormap
from arcgis.geocoding import geocode

Connect to your GIS

Input
gis = GIS('https://pythonapi.playground.esri.com/portal', 'arcgis_python', 'amazing_arcgis_123')

Get the data for analysis

Here we're getting the multispectral landsat imagery item in ArcGIS Online.

Input
landsat_item = gis.content.get('d9b466d6a9e647ce8d1dd5fe12eb434b')
landsat = landsat_item.layers[0]
landsat_item
Output
Multispectral Landsat
Landsat multispectral and multitemporal imagery with on-the-fly renderings and indices for visualization and analysis. The Landsat 8 imagery in this layer is updated daily and is directly sourced from the Landsat on AWS collection.Imagery Layer by esri_livingatlas
Last Modified: May 13, 2020
0 comments, 1 views

Search for India State Boundaries 2018 layer in ArcGIS Online. This layer has all the state boundaries for India. The boundary of Delhi can be filtered from the layer, as this notebook focuses on the city's green cover.

Input
boundaries = gis.content.get('c10550159eef410299ed373ca15a354b')
state_boundaries = boundaries.layers[1]

Extracting Landsat imagery for New Delhi Region

Input
area = geocode("New Delhi, India", out_sr=landsat.properties.spatialReference)[0]
landsat.extent = area['extent']

In State Boundary layer, OBJECTID for Delhi is 7 which is used below. Also, it is important to add extent to the geometry of selected boundary.

Input
delhi = state_boundaries.query(where='OBJECTID=7')
delhi_geom = delhi.features[0].geometry
delhi_geom['spatialReference'] = {'wkid':4326}
delhi.features[0].extent = area['extent']

Filter imageries based on cloud cover and Acquisition Date

In order to have good result, it is important to select cloud free imagery from the image collection for a specified time duration. In this example we have selected all the imageries captured between 1 October, 2017 to 31 December, 2017 with cloud cover less than or equal to 5% for Delhi.

Input
from datetime import datetime

selected = landsat.filter_by(where="(Category = 1) AND (cloudcover <=0.05)",
                             time=[datetime(2017, 10, 1), datetime(2017, 12, 31)],
                             geometry=arcgis.geometry.filters.intersects(delhi_geom))

df = selected.query(out_fields="AcquisitionDate, GroupName, CloudCover, DayOfYear", 
                    order_by_fields="AcquisitionDate").sdf
df['AcquisitionDate'] = pd.to_datetime(df['AcquisitionDate'], unit='ms')
df
Output
OBJECTID AcquisitionDate GroupName CloudCover DayOfYear Shape_Length Shape_Area SHAPE
0 2096408 2017-10-06 05:25:18 LC81470402017279LGN00_MTL 0.0000 279 852147.705738 4.534369e+10 {"rings": [[[8625624.2331, 3442812.7971], [857...
1 2095521 2017-10-15 05:19:09 LC81460402017288LGN00_MTL 0.0011 288 852002.482986 4.532785e+10 {"rings": [[[8796766.063900001, 3442853.641099...
2 2203649 2017-11-23 05:25:14 LC81470402017327LGN00_MTL 0.0333 327 852242.226027 4.535328e+10 {"rings": [[[8627133.4597, 3442780.260499999],...
3 2206118 2017-12-02 05:19:00 LC81460402017336LGN00_MTL 0.0015 336 851555.400431 4.528033e+10 {"rings": [[[8800038.6758, 3442628.6884000003]...
4 2211732 2017-12-09 05:25:11 LC81470402017343LGN00_MTL 0.0099 343 852179.154208 4.532813e+10 {"rings": [[[8626952.113400001, 3442914.852600...

Selecting imagery dated 15 October, 2017 from the collection using its OBJECTID.

Input
delhi_image = landsat.filter_by('OBJECTID=2095521') # 2017-10-15 

Applying Natural color to verify the quality of image

Input
apply(delhi_image, 'Natural Color with DRA')
Output

Creating NDVI composite for the filtered imagery

In the Landsat layer properties, pre defined "NDVI Raw" function is applied to get the NDVI composite.

Input
ndvi_colorized = apply(delhi_image, 'NDVI Raw')
ndvi_colorized
Output

Clipping the NDVI composite for Delhi and setting the extent of the generated raster.

Input
delhi_clip = clip(ndvi_colorized, delhi_geom)
delhi_clip.extent = area['extent']
delhi_clip
Output

Masking NDVI composite for green area calculation

"remap" function is used to define the NDVI range for agricultural land and forest. The NDVI values between 0.4 - 0.5 represents agricultural land whereas NDVI values between 0.5 - 1 shows forest/ tree cover [2].

Input
threshold_val = 0.5
masked = colormap(remap(delhi_clip, 
                        input_ranges=[0.4,threshold_val,     # agricultural land
                                     threshold_val, 1],      # forest area/ tree cover
                        output_values=[1, 2]),
                        colormap=[[1, 124, 252, 0], [2, 0, 102, 0]], astype='u8')

Image(masked.export_image(bbox=area['extent'], size=[1200,450], f='image'))
Output

Visualising results on map

Input
m = gis.map('New Delhi, India', 10)
m.add_layer(masked)
m.legend = True
m

Here, the pixels with light green color having a value of "1" represent agricultural land whereas the pixels with dark green color having a value of "2" represent forest area/ tree cover.

Area Derivation

Now we will calculate the total green cover of Delhi. It is important to note that pixels belonging to agricultural land as well as forest area/ tree cover are considered as green cover in the calculation.

Input
pixx = (delhi_clip.extent['xmax'] - delhi_clip.extent['xmin']) / 1200
pixy = (delhi_clip.extent['ymax'] - delhi_clip.extent['ymin']) / 450

res = masked.compute_histograms(delhi_clip.extent,
                               pixel_size={'x':pixx, 'y':pixy})
numpix = 0
histogram = res['histograms'][0]['counts'][0:]
for i in histogram[1:]:
    numpix += i
Input
sqmarea = numpix * pixx * pixy # in sq. m
acres = 0.00024711 * sqmarea   # in acres
HTML('<h3>Total Green cover in Delhi is ~ <i>{}%</i> of the total \
     geographical area of Delhi.</h3>'.format(int((acres/419004.17)*100)))
Output

Total Green cover in Delhi is ~ 19% of the total geographical area of Delhi.

Input
plt.title('Green Cover', y=-0.1)
plt.pie(histogram, labels=['Non green','Agricultural Land', 'Forest Cover']);
plt.axis('equal');

The pie chart clearly shows the distribution of agricultural land, forest cover and non green areas like urban areas, water, etc. Here, the non green areas contribute around 81% of Delhi's land and remaining 19% goes with forest cover and agricultural land.

Conclusion

In this study, green cover of Delhi is calculated using Landsat 8 imagery for 15 October, 2017. Normalised Difference Vegetation Index (NDVI) is used for the calculation of green areas, which is a well known and widely accepted spectral index for vegetation studies.

NDVI is used here compared to the other spectral indices because it is easy to compute and requires only two bands. Pixels with NDVI values greater than 0.4 and less than 0.5 are considered as agricultural land, parks, etc and the pixels with more than or equal to 0.5 NDVI values are considered as tree cover/ forest areas.

Finally, the area of the pixels of agricultural land and forest class is calculated to estimate overall green cover of Delhi.

The study shows how the green land cover of an area could be easily computed in few lines of code using Esri's predefined NDVI layer and Landsat 8 imagery from ArcGIS server.

References

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.