How we watch the lakes
A fitness tracker, but for lakes
We point satellites at Bengaluru's lakes and turn the pixels into numbers: how much water is left, and how green it is getting. This page explains exactly how that works, where the data comes from, and what it can and cannot tell you.
Every 5 days, the European Space Agency's Sentinel-2 satellites photograph the city at 10-meter resolution. We turn those pixels into numbers that tell you which lakes are thriving and which ones need help.
Think of it as a fitness tracker, but for lakes. Except the “wearable” is a satellite orbiting 786 km above your head, and instead of counting steps it's measuring how much water is left and whether it's turning green.
How it works
Water detection (NDWI)
We use the Normalized Difference Water Index to figure out where the water is. The formula is simple:
NDWI = (B03 - B08) / (B03 + B08)B03 = Green band (560nm). B08 = Near-Infrared band (842nm). Both at 10m resolution.
Water reflects green light and absorbs near-infrared (NIR), so water pixels get a positive NDWI value (closer to +1). Land does the opposite (closer to -1). We use Otsu's method, an adaptive thresholding technique, to find the water/not-water boundary for each image automatically. Otsu looks at the histogram of all NDWI values across the lake and finds the value that best separates the two peaks (water and land). If the histogram is weird (fully cloudy, no clear pixels), we fall back to a fixed threshold of 0.3.
Once we know which pixels are water, we count them and multiply by the pixel area (100 m² each at 10m resolution) to get the total water surface area in square meters. That's the Water Areanumber you see on each lake's page.
Cloud masking
Before computing anything, we strip out clouds using the SCL (Scene Classification Layer) band that comes with every Sentinel-2 image. We only keep pixels classified as vegetation, bare soil, or water (SCL values 4, 5, 6). Everything else gets masked out: clouds, cloud shadows, saturated pixels, snow. If more than 30% of the lake area is cloudy, we throw out the entire image. No point measuring clouds.
Algae detection
NDVI = (B08 - B04) / (B08 + B04)B08 = Near-Infrared (842nm). B04 = Red (665nm). Only computed on water pixels.
We run NDVI (the vegetation index) on pixels we've already classified as water. Healthy water has low NDVI. But when algae blooms on the surface, it reflects NIR light just like plants on land, pushing NDVI up. We flag any water pixel with NDVI > 0.15 as showing algae. The Algae Level percentage you see is the fraction of the lake's water surface where this is happening.
High algae means eutrophication, usually from sewage or fertilizer runoff feeding the lake nutrients it can't handle. Bellandur Lake famously froths and catches fire partly because of this.
Health score (0-100)
Each lake gets a composite health score, weighted like this:
- 40% Area stability: is the lake shrinking?
- 30% Algae levels: is it getting greener?
- 20% Water presence: is there actually water?
- 10% Trend: is it getting better or worse over time?
The score needs at least 10 monthly observations to compute (roughly a year of data). Lakes with fewer observations show a placeholder instead of a score. The trend component uses linear regression on the water area time series, so a lake that's been steadily shrinking gets penalized even if it's still relatively large.
Time intervals
We offer three ways to view the data: raw (every usable satellite pass), monthly (best observation per month), and yearly (annual averages). Any image with more than 30% cloud cover over the lake area gets rejected, because there is no point in measuring clouds.
The data pipeline
Here's what happens every time we process a lake, step by step:
- Query Google Earth Engine for Sentinel-2 images covering the lake polygon. We pick the least cloudy image per month.
- Mask clouds using the SCL band. Reject the image entirely if >30% of the lake is obscured.
- Compute NDWIon clear pixels. Classify water vs land using Otsu's threshold.
- Measure water area by counting water pixels and multiplying by 100 m² per pixel.
- Detect algae by running NDVI on water pixels. Flag anything above 0.15.
- Store the observation: date, water area, mean NDWI, algae fraction, cloud percentage.
- Compute health score from the full history of observations (needs 10+ months of data).
All the heavy computation (steps 1 to 5) happens on Google's servers via Earth Engine. We only download the final numbers, not the raw satellite images. This means we can process a decade of data for a lake in about a minute.
Data sources
Satellite imagery
Copernicus Sentinel-2 L2A data, provided free of charge by the European Space Agency (ESA) via Google Earth Engine. This is the surface reflectance product with atmospheric correction already applied, so we're working with clean, calibrated data from 2015 to present.
Lake boundaries
Lake boundary polygons from CSEI-ATREE's Mapping Bangalore's Lakes project. Supplementary boundary data from OpenCity.in.
Contains modified Copernicus Sentinel data [2015-present]
Lake boundary data: CSEI-ATREE via OpenCity.in
EMPRI inventory: EMPRI/KLCDA via OpenCity.in
Water quality reports: KSPCB via OpenCity.in
Storm drain network: BBMP SWD Maps via OpenCity.in
Limitations & caveats
This is satellite data, not magic. Here's what you should know:
- Resolution. Sentinel-2 has 10-meter resolution. Each pixel covers 100m². Lakes smaller than ~0.5 hectares are unreliable, because there just aren't enough pixels to work with.
- Cloud cover. Monsoon season (June to September) means sparse usable images. Bangalore gets clouds. We can't change the weather.
- Proxy measurements. NDWI and NDVI are satellite-derived estimates, not ground truth water quality measurements. We're looking at reflectance patterns, not testing the water in a lab.
- Not encroachment detection. This project tracks lake health: water area and algae levels. We do not attempt to identify encroachment. That's a different (and politically sensitive) question.
- Update frequency. New satellite images every 5 days, weather permitting. This is not real-time monitoring.
Ground-truth data
Satellites are powerful, but they're not the whole story. We cross-reference our satellite observations with field data from two government sources:
EMPRI Pollution Inventory (2018)
The Environmental Management & Policy Research Institute conducted a field survey of Bangalore's lakes in 2018, visiting each lake to document pollution sources, sewage inflow, biota (what's growing in the water), encroachment status, and which government agency is responsible. This is the “what people on the ground actually saw” dataset. When the satellite says a lake has high algae and EMPRI says “untreated sewage inflow observed”, the data tells a consistent story.
KSPCB Water Quality (2019-2025)
The Karnataka State Pollution Control Board runs quarterly lab tests on lake water: BOD (Biochemical Oxygen Demand), COD (Chemical Oxygen Demand), dissolved oxygen, pH, and total coliform bacteria. Each lake gets a classification from A (drinking water) to E (below irrigation quality). High BOD means lots of organic waste decomposing, which means the lake is struggling. Low dissolved oxygen means fish can't breathe. When our satellite data shows high algae and KSPCB shows Class E with high BOD, you know it's not a false alarm.
Stream network (rajakaluves)
Bangalore's lakes are connected by a network of storm drains called rajakaluves. When one lake is polluted, its overflow carries downstream, so Bellandur's mess flows into Varthur. We map these connections so you can see which lakes feed into which, and understand why pollution cascades through the city.
Contains modified Copernicus Sentinel data [2015-present]
Lake boundary data: Centre for Social and Environmental Innovation, ATREE (CSEI-ATREE)
EMPRI field survey data: Environmental Management & Policy Research Institute, Govt. of Karnataka (2018)
KSPCB lab data: Karnataka State Pollution Control Board quarterly monitoring reports (2019-2025)
Supplementary boundary and enrichment data: OpenCity.in
Credits & acknowledgments
This project would not be possible without the open data and open science ecosystems that make civic technology viable:
- European Space Agency (ESA) for making Sentinel-2 imagery freely available to anyone through the Copernicus programme. This is what happens when a space agency decides that Earth observation data should be a public good.
- Google Earth Engine for providing the compute infrastructure to process petabytes of satellite imagery without downloading a single file. The free tier for non-commercial use is genuinely transformative.
- CSEI-ATREE, the Centre for Social and Environmental Innovation at the Ashoka Trust for Research in Ecology and the Environment. Their meticulous mapping of Bangalore's lake boundaries is the foundation of everything here.
- EMPRI, the Environmental Management & Policy Research Institute, for their 2018 field survey documenting the ground truth at each lake.
- KSPCB, the Karnataka State Pollution Control Board, for publishing water quality lab data that lets us cross-validate satellite observations.
- OpenCity.in for aggregating and making Bangalore's civic data accessible and machine-readable.
Built with
Sentinel-2
Satellite imagery
Google Earth Engine
Geospatial compute
Python
Pipeline & analysis
PostgreSQL + PostGIS
Spatial database
FastAPI
REST API
Next.js
Frontend framework
Mapbox GL
Map rendering
Recharts
Time-series charts
Tailwind CSS
Styling
The entire codebase is open source. The satellite data is free. The ground-truth data is public. If you want to build something similar for another city, everything you need is here.
Have questions, spotted a bug, or want to help? Check out the repo on GitHub.
Namma Lakes is an independent civic project. It is not affiliated with or endorsed by any government agency. All data is derived from publicly available sources.
Sentinel-2 data: © ESA, Copernicus Sentinel data. Lake boundaries: © CSEI-ATREE, CC BY-SA 4.0. EMPRI data: © EMPRI, Govt. of Karnataka. KSPCB data: © KSPCB, Govt. of Karnataka.