Inspiration

On 26 August 2026 a glacier-lake outburst flood tore down the Bhote Koshi–Trishuli valley in Nepal. In the hours after a flood like that, one question matters more than any other: which villages can we still reach? The data to answer it is free: Sentinel-1 radar, Sentinel-2 imagery, the Copernicus elevation model and OpenStreetMap. But a per-pixel change map is only a first draft. Monsoon cloud, seasonal green-up, wet soil and two images that don't quite line up all look like "change". A good analyst looks twice before trusting it. We built an agent that does that second look with OpenCV 5 and hands a person whatever it can't settle.

What it does

  1. Map the flood. Pick an area and a date. WaterGuard pulls Sentinel-1 radar (which sees through cloud), cloud-free Sentinel-2 composites, the Copernicus DEM and OpenStreetMap as it was the day before. Three to five minutes later the debris path is mapped on the valley floor.
  2. Who is cut off. It flags the buildings, roads, bridges and health posts on the impact map. A road-network analysis finds the settlements that lost every road link and estimates how many people are stranded.
  3. An inspector agent looks twice. Before a report goes out, the agent re-examines every 600 m cell that matters, most exposed first, in a perceive → decide → act loop:
    • perceive with OpenCV 5: four evidence lines (colour, vegetation, structure, radar), each measured as a contrast against nearby unflagged ground, plus how well the before and after images line up;
    • decide what to do next from those measurements, using rules or an LLM under guard rails enforced in code;
    • act with OpenCV tools: realign (SIFT + USAC MAGSAC++) when registration fails, zoom into 300 m quadrants when the evidence is mixed, look later at a fresh Sentinel-2 image from weeks after the event when clouds leave doubt;
    • confirm only what the evidence agrees on. Everything else goes to an analyst's review queue with an annotated before/after/colour-change chip and the full trace. The agent never removes anything; only a person can.
  4. Ask, print, trace. A bilingual (English/Nepali) copilot that can only quote numbers the maps back up, a one-page situation report, and a flood-path tracer for a second surge.
  5. Verifiable. Every report is fingerprinted with SHA-256 Merkle roots, and anyone can re-run the open pipeline and check the result.

Inspector agent: perceive, decide, act

How we built it

OpenCV 5 does the work (opencv-contrib-python-headless==5.0.0.93), in the detection pipeline and in every step of the agent:

Where OpenCV 5 Why
Radar change blur (box-filter multilooking) despeckle Sentinel-1 before per-pixel z-scores
Fusion morphologyEx open/close, connectedComponentsWithStats, distanceTransform clean the impact mask, keep patches that touch the river channel, grow along the riverbed
Co-registration findTransformECC on Sobel gradient magnitude, warpAffine sub-pixel alignment that ignores the flood's own brightness change
realign tool SIFT_create on CLAHE-equalised lightness, BFMatcher.knnMatch + Lowe ratio test, estimateAffine2D(method=USAC_MAGSAC) when ECC fails: keypoints on changed ground have no true match and drop out as outliers
Colour change cvtColor → CIELAB, ΔE grey debris replacing forest or fields
Structure / texture SSIM from GaussianBlur moments, Laplacian variance new surface pattern (boulders, scour)
Correspondence DISOpticalFlow both ways + remap ground that only shifted vs ground that was replaced; misalignment left over
Edge artefacts Canny + dilate "change" that sits on edges that already existed
Shape findContours, minAreaRect, convexHull elongated debris tongues vs speckle
zoom tool the same measures per 300 m quadrant a debris lobe isn't averaged away by unchanged ground
Analyst chip resize, CLAHE, applyColorMap, drawContours, putText, hconcat the before / after / ΔE image the human reviews

The visual evidence changes what the agent does next. Here is one real trace, from cell r840c660 in Bidur, a held-out area, with the after image shifted 3 px in our stress test:

  1. perceive: ECC finds no lock; 2.6 px of shift is left over unflagged ground; 2 of 4 evidence lines agree.
  2. decide → realign: "before and after do not line up".
  3. act: realign: SIFT finds 1,348 / 957 keypoints and 49 ratio-test matches. MAGSAC++ keeps 12; the other 37 sit on ground that changed. It recovers 3.59 px with a 0.27 px residual. Now 3 of 4 lines agree.
  4. decide → zoom: "colour missing: measure the four 300 m quadrants separately".
  5. act: zoom: in the NE and SE quadrants all 4 lines agree, covering 65 % of the flagged ground.
  6. decide → confirm. With registration alone, the same cell goes to a human.

Every step is kept in inspection.json and shown in the dashboard's Inspect tab, and every decision is also a CloudWatch metric. With --planner llm, a model (Amazon Bedrock, or any OpenAI-compatible endpoint) picks the next tool. The evidence bar, one use per tool and a 4-call budget are enforced in code, so the model can steer the inspection but not lower the bar.

On AWS. One Docker image (pinned requirements.txt) runs on EC2 behind CloudFront (HTTPS; the security group admits only CloudFront; IMDSv2 required). The boot script pulls the app and data from S3 and secrets from SSM Parameter Store, so no keys live in the image or the repo. The copilot and the LLM planner call Amazon Bedrock through the instance role. Logs go to CloudWatch, and the inspector writes one Embedded Metric Format line per decision, which becomes the WaterGuard/Inspector metrics: cells by verdict, tool calls, seconds per cell. The IAM role is least-privilege. Updates go out over SSM with a health check and automatic rollback.

Architecture: open data, OpenCV 5, the agent and AWS

Challenges we ran into

  • Registration fails exactly where it matters. Where a flood replaced a third of the ground, gradient-based ECC has nothing consistent to lock on to. Feature matching works only if the matches on changed ground are thrown out, and that is what MAGSAC++ does. OpenCV 5's estimateAffinePartial2D rejects USAC methods, so we fit a full affine with estimateAffine2D and reject any model that isn't a near-pure shift (scale, rotation and shear are all checked).
  • The false alarms are real change. The Tadi Khola control cells aren't noise. They are monsoon change in a tributary the flood never reached: vegetation loss, structure, sometimes radar, but never the colour change of fresh debris. No threshold separates them without also dropping real damage. The honest design is an agent that knows when to stop and ask.
  • Reproducibility. Our first published report was disputed by an independent re-run, because OpenStreetMap returned buildings in a different order. We fixed it with canonical ordering and a regression test. Now a laptop and an AWS server reproduce the settlement results byte for byte.

Accomplishments that we're proud of

All of these numbers are reproducible from the repo with python -m waterguard.validate, --inspection and --robustness.

  • Checked against the official Copernicus EMS damage maps (EMSR927). We tuned on 2 areas and held out 2. Held-out F1 is 0.92 and 0.88. False-alarm tests: a placebo date gives 0 ha and the untouched Langtang valley 0 ha.
  • Inspector agent, held-out areas (113 cells): 98.5 % of the cells it confirms are EMS-confirmed damage. It confirms 68.6 % of the real damage area with no human, using 31 later-look downloads, 12 realign calls and 43 zoom calls.
  • Stress test, misaligned imagery: at a 3 px shift, registration alone confirms 4.2 % of real damage; with realign + zoom it confirms 50.6 %. At 5 px it's 0.4 % vs 50.9 %. There were 0 false confirmations at every shift. Misregistration doesn't fool the agent; it blinds it, and realign locked on in 84 of 113 cells at 3 px.
  • Failure cases, published. One held-out cell in Bidur (1.5 ha) that EMS didn't map was confirmed. All 8 Tadi Khola cells go to a person. In Phosretar, 30 of 51 scored cells still need a human.
  • Live and usable: the agent's traces and chips are viewable on the public demo.

What we learned

  • Contrast beats thresholds. Measuring every cell against nearby unflagged ground cancels out season, haze and sensor drift, which is why misregistration made the agent cautious rather than wrong.
  • An agent's most valuable action is often ask a human. The design goal isn't to confirm everything, but to never confirm something false and to spend the analyst's time where it matters.
  • Robust estimation is a feature, not a detail. Without MAGSAC++ the realign tool locks on to the debris and makes things worse.

What's next for WaterGuard

  • Pilot with a district disaster office for the 2027 monsoon.
  • Add a higher-resolution optical sensor through the same realign tool.
  • Use analysts' Keep/Remove decisions to re-tune the evidence lines on more flood types.
  • Put the inspector's OpenCV tools behind MCP, so any agent framework can call them.

Responsible use

WaterGuard is decision support, not a decision. Outputs are labelled satellite-derived and unverified on the ground, and people counts are labelled as estimates. Humans decide removals, and published reports say how many cells were left unreviewed. Inputs are public 10 m imagery and public OpenStreetMap, with no personal data, and EMS maps are used only for scoring. Known limits are in the technical report: no early warning (satellite revisit), radar blind spots on steep slopes, building damage inferred at 10 m and not seen, OSM completeness, and tuning on one event.

Technical report: docs/REPORT.pdf · Team: Adil Mahajan (solo)

Built With

Share this project:

Updates

Submission history