Documentation
User manual
Signing in
Open the demo and enter your PIN. There are two roles:
- User: browse every photo, upload a photo for a live reading, save a correction.
- Admin: everything a user can do, plus download the CSV of every reading and see saved corrections.
The demo shows the fields' real drone photos, so PINs are shared by the CarbonMint team rather than printed here. Five wrong PINs lock sign-in for 60 seconds. A session lasts 8 hours.
Gallery
Every pilot photo with the ring count from each method. Filter by field, or by whether v1 accepted the photo. Open a photo to see the rod with v1's first and last ring marked, and the four readings side by side:
- v0: the current detector, rebuilt from its description.
- Colour method: our colour-isolation and shot-transfer method.
- v1: this product.
- Hand count: the checked label.
Read a photo
Choose a drone JPEG of a gauge. v1 returns:
- the ring count, in centimetres
- the level against the guide, and the soil state
- its confidence
- whether the reading is accepted
On the hosted demo the photo is shrunk to 2048 px in your browser first, because the host accepts at most 4.5 MB per request. Exact readings drop from 81% to about 75% at that size. The on-premises lane reads full size.
Corrections and export
Type the right count and save. On-premises, corrections go to data/corrections.csv; the hosted demo does not keep them. Admins can download every reading as CSV.
A day in the life
- 07:30. The pilot flies the waypoint route and takes two shots at each gauge, following the capture guide: side-on, rod filling about a quarter of the frame, held still.
- 09:00. The photos are dropped into the reader, one folder per visit. Each photo gets a count, a confidence and a note.
- 09:05. Each visit with an accepted photo gets its level and soil state, for example "Drying". Visits where the two shots disagree, or nothing reached 0.7, wait for review.
- 09:15. A reviewer opens the flagged visits, looks at the marked rod and saves the right count where needed.
- 09:30. The CSV goes to the carbon-credit records.
Technical architecture
The reader, step by step
- Ring stacks. Pixels where red clearly beats green and blue, with straw and soil excluded, form blobs. Blobs stacked along a near-vertical line are joined into a stack; pieces split by a leaf are merged when they sit on the same axis. A plain blue-grey rod with no paint is the fallback, read as 0 rings.
- Straightening. A wide strip is sampled along the rod. A curve through the ring centre in each row follows lean and bend, and the core of the rod is resampled along it.
- Ring rhythm. The pitch comes from the autocorrelation of the redness down the rod. With only two to six rings, it is the median gap between them instead. Faint bands at either end, under 30% of a typical ring's redness, are sleeve rims or stains and are dropped.
- Count. (last ring − first ring) ÷ pitch + 1. Rings hidden by leaves in between count automatically.
- Confidence. A logistic model predicts P(count is exact) from the reader's signals and whether the visit's other shot agrees. The signals are pattern strength, the share of rings actually seen, sharpness, rod size and red coverage.
- Bad gauge. More rings than the scale holds (25), or a ring spacing that does not fit the rod's width, is never accepted and carries the note "bad gauge".
- Output. Centimetres (1 ring = 1 cm), level = count − 10, and soil state:
- Flooded above +2
- Saturated from −2 to +2
- Drying from −12 to below −2
- Irrigate now below −12
How v1 differs from v0
| v0 | v1 | |
|---|---|---|
| Finding the gauge | Pinkest upright column, a fixed 2% of the image width | Stack of separate ring blobs on one line; follows the rod's lean |
| Ring colour | Hue ≤20° or ≥330°, saturation ≥35%, value ≥50% | Red relative to green and blue; dark shaded rings count |
| Hidden rings | Gap ≥1.65× pitch adds round(gap÷pitch)−1; a gap over 4.5× ends the count | First-to-last span ÷ pitch; leaves up to 4 rings tall are bridged |
| No paint showing | No reading, confidence 0 | 0 rings (dry), a valid reading |
| Confidence | Spacing × holes × solidity × thickness | Trained probability of an exact count |
| Accepting a reading | Confidence ≥ 0.7; a visit takes the mean of its accepted photos (same rule) | |
What made the difference
Three details, each kept only because it raised the score on photos from a field the model had not seen:
- Ring gap. The gap is the shortest strong repeat, not the strongest. The strongest repeat can be 2–4 rings long, which made one rod read 4 instead of 24.
- Gap-by-gap count. Perspective stretches the gap along the rod, so each gap is compared with the gaps next to it rather than one average gap.
- Colour-method locator as a fallback. When our rod finder sees nothing, our colour method's locator is tried. On-premises only, because it needs OpenCV.
Tried and dropped, because they gained nothing or added errors: 2–3× upscaling of far rods, adding a ring at the sleeve, following a faint rhythm past the last ring, and the colour method's count or score as a confidence signal.
How accuracy is measured
The company's target: of the photos showing a correct gauge, 70–80% must be accepted (confidence 0.7 or more) and exact. A confident wrong count does not count.
| Method | Accepted & exact | Accepted | Right when accepted | Exact, all photos |
|---|---|---|---|---|
| v0: current detector (rebuilt) | 19/127 = 15.0% | 37.0% | 40.4% | 15.7% |
| Colour method | 51/127 = 40.2% | 81.1% | 49.5% | 51.2% |
| v1 | 97/127 = 76.4% | 89.0% | 85.8% | 82.7% |
How the numbers were made:
- Labels: ring counts for 127 photos were read by eye. A person checked two random samples of 15: round 1 matched 10 of 15, so the labels were fixed and moved to whole rings; round 2 matched 15 of 15.
- v1's confidence: the model is trained on six fields and scored on the seventh, for each field in turn.
- Caveat: the reader's rules were designed on these photos, so the next batch of field photos is the real test.
API reference
JSON over HTTPS. The session is an HttpOnly, signed cookie (cm_session) set by /api/login.
| Route | Role | What it does |
|---|---|---|
GET /api/me | public | {role, cloud, max_upload}; role is null when signed out |
POST /api/login | public | {pin} → sets the session; 401 wrong PIN, 429 while locked |
POST /api/logout | public | Clears the session |
GET /api/gallery | user | Every photo with the readings of v0, the colour method and v1, plus the hand count |
GET /api/photo/<id>.jpg | user | A 1200 px copy of a photo, metadata removed |
POST /api/read | user | Body: one JPEG (≤4.4 MB). Returns {cm, level, state, confidence, accepted, note, mark} |
POST /api/correct | user | {id, rings}; kept on-premises only |
GET /api/corrections | admin | Saved corrections |
GET /api/export.csv | admin | Every photo's readings as CSV |