FIG. 0 · FINSALBEKKEN, NORWAYFive seconds of a river camera, 150 frames registered and averaged with OpenCV. The silk is moving water; the stones held still.

Every river camera,a gauging station.

Thalweg reads discharge from the video a river camera already records. OpenCV 5 measures the surface three ways, a policy-gated agent decides whether the number can go out, and a flood warning waits for a hydrologist's signature.

Open the live station

Most rivers that flood have a camera somewhere near them, and no gauge. Thalweg turns that camera into one, checks itself three ways, and says plainly when it can't.

Chapter one · how it measures

From a shaky clip to cubic metres per second.

Four steps, each with its evidence. Every figure in this chapter comes from one development run on video 8 of the Video Globe Challenge, a Norwegian brook: 300 frames, ten seconds.

Hold the banks still.

ALIKED keypoints are matched with LightGlue on the banks only, never on the water, and each keyframe is registered to the reference view, so camera shake can't become velocity. On this clip the frozen build rejected the feature model and treated the camera as static. It was hand-held and drifts. That miss is the clearest open issue in our report.

keyframes
13
residual p95
1.20 px
min inlier ratio
0.51
verdict
static (frozen build)
FIG. 1Frame 0 of the clip. Only the hatched banks are allowed to vote on how the camera moved.

Flatten the surface at today's water level.

Surveyed ground reference points fix the camera model. Each pixel is projected onto the water plane at the measured stage, so a distance on the image becomes a distance on the river. When the river rises, the plane rises with it.

model
planar, 4 GRPs
level
0.00 m
resolution
8 mm per pixel
FIG. 2The camera's view and the same frame laid flat on the water, half-metre grid, north up. The dashed outline is where velocity was measured.

Measure it three ways that fail differently.

Window correlation, streak angles in space-time images, and dense optical flow. A visible riverbed fools correlation but not streaks; glare fools both in different ways. The agent compares them before it trusts any of them.

LSPIV

0.968m/s p50

914 of 1146 vectors

STIV

0.972m/s p50

55 of 60 lines

DIS optical flow

0.959m/s p50

997 of 1109 vectors

FIG. 3Three independent readings of the same ten seconds. Their median surface speeds sit within 1.4 % of each other.

Integrate across the surveyed section.

Surface velocity, times a coefficient for the slower water below, across the surveyed bed at the measured level. The uncertainty is carried with the number, never dropped.

wetted area
1.017 m²
width
3.41 m
α
0.85
95 % budget
α 5.9 · level 3.4 · velocity 1.2 %
FIG. 4The section at X = 2.20 m: bed from 16 survey points, LSPIV velocity along it (line) and one STIV reading per line (circles).
0.776m³/s

published · 95 % [0.711, 0.840] · mean of agreeing LSPIV and STIV
reference 0.636 m³/s, so +22 %. Two methods agreeing on a drifting frame is still wrong; see step i.

Chapter two · the agent refuses

It would rather say nothing than say it wrong.

The agent picks methods and parameters, but it can't publish on its own say-so. Every action passes a policy gate written in code. A gauging goes out only when the evidence in the run supports the basis the agent claims.

Publish
methods_agree
LSPIV 0.724 · STIV 0.828 m³/s · spread 13.5 % of a 15 % tolerance

Two independent methods agree, so the mean of the agreeing pair is published with its uncertainty.

Hold
image_quality: no_moving_tracers, glare
glare_frac 1.00 · recapture requested

The surface can't be seen. The station asks for another clip instead of guessing.

Escalate
camera_moved
shift p95 33.5 px from the surveyed reference · 394 inliers

The view no longer matches the survey. GRP pixels must be re-confirmed by a person before any gauging.

Escalate
perception_failed:orthorectify:planar_grp_level_mismatch
reported level 1.50 m · plane surveyed at 0.00 m

The water level is off the surveyed plane, so the projection would be fiction.

Hold
fail_closed:timeout
Step Functions FailClosed

Any error or timeout before a decision is saved ends in HOLD. Never a guessed number.

The gate's other words for no: methods_disagree · basis_false:bed_not_visible · basis_false:surface_not_seeded · coverage_low · valid_vectors_low · confidence_low · geometry_unverified · stabilization_residual_high · frozen_frames · bad_args:missing:reason

A warning needs a signature.

After each published gauging the station refits its rating curve and runs a stage nowcast. If the chance of crossing the flood threshold within three hours is at least one half, it drafts a warning and the workflow stops on a task token. Only a reviewer with the passcode can issue it; the agent has no tool for it. Unsigned drafts expire after six hours.

DRAFTSIGNEDREJECTEDEXPIRED
River Dart at Austins Bridge · 12 Oct 2018, 12:00DRAFT · NOT ISSUED
River Dart at Austins Bridge: river level 5000.12 m and rising 30 cm/h. Flow is forecast to reach the warning threshold of 231 m³/s (stage 5000.23 m) in about 0.4 h. Threshold source: NRFA 46003 Dart at Austins Bridge, QMED 231.2 m³/s (median annual maximum flood).
p(cross)
ETA
threshold
expires
0.963
12:25
231.2 m³/s
18:00
Signedreviewer passcode
required

Specimen: Thalweg's nowcast and warning code replayed on the published Storm Callum stage series at noon. Live drafts wait in the review queue.

Chapter three · benchmark

Blind, against the hydrologists.

The eight videos of the Video Globe Challenge 2020, from a 0.6 m³/s Norwegian brook to a 960 m³/s Australian river. Each was gauged by 15 to 23 hydrologists with their own tools. We developed on videos 1 and 8, froze the agent, then scored videos 2 to 7 once per brain. Every answer, plotted.

Drone frame of the West Normanby river

West Normanby

no. 2

Australia, drone
reference 108 m³/s · 17 hydrologists

autopilot+17.9 %12/18LLM+25.7 %14/18
Bank camera frame of Le Séran

Le Séran

no. 3

France, 3D bank camera
reference 55.2 m³/s · 18 hydrologists

autopilot−7.0 %5/19LLM−1.6 %1/19
Drone frame of the Russell River

Russell River

no. 4

Australia, drone
reference 139 m³/s · 22 hydrologists

escalated by both brains: the methods disagreed and nothing justified picking one
Hand-held frame of Storåne

Storåne

no. 5

Norway, hand-held
reference 19.7 m³/s · 23 hydrologists

autopilot+23.1 %22/24LLM+27.8 %24/24
Bank camera frame of Le Groin

Le Groin

no. 6

France, 3D bank camera
reference 53.7 m³/s · 17 hydrologists

autopilot+3.2 %5/18LLM+3.2 %5/18
Drone frame of the Herbert River

Herbert River

no. 7

Australia, drone
reference 963 m³/s · 15 hydrologists

autopilot−14.3 %13/16LLM−3.0 %9/16
Ground camera frame of La Vence

La Vence

no. 1

France, ground camera
reference 1.26 m³/s · 15 hydrologists

development video, not scored blind

Hand-held frame of Finsalbekken

Finsalbekken

no. 8

Norway, hand-held
reference 0.636 m³/s · 23 hydrologists

development video, not scored blind

Signed error of the published discharge, and rank among the hydrologists plus our answer (1 is best). Frozen build, scored once.

13.1 %mean absolute error of the frozen autopilot, 5 of 6 held-out videos published
3 of 6held-out videos where the autopilot beat the median hydrologist
1st of 19the LLM agent on video 3, at −1.6 %
0wrong publications in the refusal suite, in every run
COOL

On Graviton4, COOL's OpenCV build was no faster than the stock OpenCV 5 wheel for our workload: 38.9 s against 37.7 s per clip. Graviton4 itself is the saving: with the stock wheel, about 15 % per gauging against x86. The measurements.

median of 5s / clip$ / 1000
c8g · COOL38.90.97
c8g · pip OpenCV 537.70.84
c7i x86 · pip39.70.98