I built a land-use classification pipeline over Delhi-NCR that pairs Sentinel-2 tiles with ESA WorldCover labels and fine-tunes a ResNet18 to classify them.
Air-quality work across the Delhi airshed needs to know what is actually on the ground, built-up against cropland against vegetation, over thousands of square kilometres that nobody is going to label by hand.
02Implementation
Filtered the tile set to the Delhi-NCR boundary with GeoPandas, testing each tile's coordinates as a point against the region polygon.
Built labels from the ESA WorldCover 2021 raster: reprojected each tile's coordinates into the raster CRS with Rasterio, read a 128x128 window centred on that pixel, and took the modal class.
Mapped WorldCover codes into four working classes, built-up, cropland, water and vegetation, with everything else grouped as other.
Split 60/40 into train and test, then fine-tuned a torchvision ResNet18 with cross-entropy and Adam at lr 1e-3, batch size 32, for 5 epochs.
Evaluated with accuracy and weighted F1, and saved the confusion matrix, class distribution and grid overlay as figures.
03Models
ResNet18 (torchvision)
Fine-tuned to classify each tile into the four land-use classes.
ESA WorldCover 2021
Label source: the modal class inside each 128x128 raster window.
04Input data
Sentinel-2 RGB tiles named by latitude and longitude, filtered to the Delhi-NCR region and labelled against the ESA WorldCover 2021 raster.
05Results
Trains and evaluates end to end, with the confusion matrix, class distribution and grid overlay committed alongside the code.
Accuracy 81.13% on the 40% held-out split
Weighted F1 0.76
5 epochs, batch size 32, Adam at lr 1e-3
06Decisions
Labelled each tile by the modal WorldCover class across the whole 128x128 window rather than by its centre pixel, which is more stable on mixed-use tiles.