← Back to Blog

My Master's Thesis: Satellite-Based Detection of Pesticide Overuse

For our master's thesis in Software Engineering at the University of Southern Denmark, Anton Christensen and I worked on a case from the Danish Environmental Protection Agency (Miljøstyrelsen): could satellite imagery help the agency decide which potato fields to inspect for overuse of pre-harvest desiccants?

The problem

Before harvest, seed potato farmers spray a desiccant that kills the plant above ground, so the potatoes stop growing and the skin hardens. The chemicals can leach into groundwater and harm nearby wildlife, so the agency regulates how much and how often they may be applied. Compliance is checked with soil samples, but there are fewer than a thousand inspections a year (746 in 2019), and the sites are picked at random.

The agency's idea was to use the vegetation index NDVI, which can be calculated from Sentinel-2 satellite data. A desiccant makes a field's NDVI drop, and a field whose NDVI drops faster than normal might have been sprayed too heavily. A list of suspicious fields would be a better basis for choosing inspections than chance.

What we built

A Python system that collects satellite data for every field of a given crop type in Denmark and turns it into vegetation index time series:

  • A database populator reads the agency's public GIS shapefile of all Danish fields, filters it by crop type, and stores each field's ID, crop type and polygon in MySQL
  • Download workers ask the Sentinel Hub Catalog API which dates have imagery for a field, including cloud cover, and download the raw spectral bands as GeoTIFFs from the Process API
  • Processing workers read the GeoTIFFs with Rasterio, check the data mask for invalid pixels, calculate NDVI, NDRE, GNDVI and EVI per pixel, and store the results or render heatmaps and KDE plots
  • RabbitMQ distributes the work. A work order (for example "download field data for August") is split into tasks of at most ten days, which are spread across the running workers

Engineering decisions

Raw bands instead of ready-made statistics. Sentinel Hub can compute an index or an average for a field on its own servers, which is cheaper. We downloaded the raw reflectance bands instead, because that let us check the data per pixel, draw heatmaps, and calculate new indices later without downloading everything again. We chose Sentinel Hub over openEO because it is a plain REST API and doesn't tie the project to Python.

A relational database. The agency suggested a time series database. We chose MySQL because the data is relational (fields and their readings per date), and because during exploration we kept updating data and changing the schema, which time series databases handle poorly.

Parallel workers. The workload is I/O-bound: most of the time goes to waiting for the API and the database. Python's Global Interpreter Lock rules out simple multithreading, so we ran several worker processes fed by RabbitMQ. In a test with ten fields and 30 days of data, one worker took 119 seconds and four workers took 32 seconds. The time per day of data stayed at about 4.3 seconds, so adding workers did not slow each one down.

Long-running tasks in RabbitMQ. A download task could run for over an hour, but RabbitMQ drops a consumer that runs too long, and our worker blocked the heartbeat while waiting for a task to finish. We moved task execution to a separate thread with a callback, raised the timeout to two hours, and capped each task at ten days of data to stay within it.

Bounding boxes or individual fields. Instead of one request per field, the system can download large bounding boxes and cut the fields out afterwards. On Funen this was about 29 times faster (163 seconds for 40 boxes against 4,824 seconds for 1,993 fields), but the per-field downloads followed the field borders more closely and gave more accurate readings. We kept both modes, so speed can be traded for accuracy.

Results

The data told a clear story. On a typical seed potato field, NDVI starts rising in mid-May, holds just below 0.8 through June and July, falls to about 0.6 between 7 and 15 August, which matches the timing of a desiccant, and drops to near zero at harvest in October.

Line chart of minimum, maximum, average and median NDVI for field 2443 through 2020. NDVI is low until May, peaks around 0.8 in June and July, falls steeply in August, and reaches near zero in mid-October.
NDVI through 2020 for one certified seed potato field (field 2443), from days with at most 25% cloud cover.

The heatmaps show the same drop across the whole field, pixel by pixel:

NDVI heatmap of field 2443 on 7 August 2020, almost entirely green at around 0.8. NDVI heatmap of field 2443 on 15 August 2020, pale green and yellow at around 0.6. NDVI heatmap of field 2443 on 30 August 2020, orange and red at around 0.2.
Field 2443 on 7, 15 and 30 August 2020.

Seed potatoes could also be told apart from starch potatoes, sugar beets and apple orchards by their NDVI curves alone. Starch potatoes are usually left to wilt naturally, so their NDVI falls later and more gradually.

Average NDVI from August to October 2020 for ten seed potato fields. Several fall from around 0.8 to below 0.4 by mid-August, and the rest are already low in early August. Average NDVI from August to October 2020 for ten starch potato fields. All stay above 0.6 through mid-August, then decline gradually through September and October.
Average NDVI from August to October 2020 for ten seed potato fields (left) and ten starch potato fields (right).

We developed three methods for scoring possible overuse: comparing the decline of NDVI with that of NDRE (which measures deeper into the plant than the leaf canopy), finding each field's steepest NDVI drop, and comparing the NDVI and NDRE gradients. Each method produces a ranked list of fields.

Line chart of average NDVI and average NDRE for field 2443 through 2020. Both follow the same shape, with NDRE lower than NDVI, and NDVI falling more steeply in August.
Average NDVI and NDRE for field 2443. NDVI falls more steeply than NDRE after the desiccant is applied.

What didn't work

To validate the scores, we needed ground truth: fields where the agency knew whether desiccants had been used correctly or overused. The agency could not share this data because of GDPR, and the farmers we contacted declined. Our contact at the agency also left partway through the project, so the requirements were never validated with the stakeholder.

Clouds were the other problem. Readings with more than 25% cloud cover were too noisy to use, so some fields had gaps of weeks, often around the desiccation date. The scoring methods ranked the same fields very differently, and without ground truth we could not tell which one was right. The steepest-drop NDVI ranking was the most reliable of the three, and we argued it is still a better starting point for inspections than random selection. But the question of whether overuse can be detected remains open.

Next steps

  • Get ground truth, either from the agency's internal data or from test data from desiccant manufacturers
  • Compare NDVI and NDRE over the whole desiccation period instead of only the steepest drop
  • With enough ground truth, train a machine learning model that also includes weather and cloud cover data

Related project

Satellite-Based Detection of Pesticide Overuse

Analyzed Sentinel-2 satellite imagery to flag likely overuse of pre-harvest desiccant on Danish potato fields, for a case brought by the Danish Environmental Protection Agency.