Last Seen: I taught an eleven-year-old drone to find a person from one photo, and to ask before it follows anyone
Last Seen gives a 2015 DJI Phantom 3 one photo and a search area. OpenCV 5 finds and compares every person, Claude decides where to look next, and a human answers "Is this them?" before the drone follows anyone. Flown live in a park: found on the first scan at 0.85, followed for 90 seconds, 49 pins on the coordinator's map.

One photo and an old drone
Picture a search coordinator at a park at dusk. A man with dementia walked away from his care home an hour ago. She has one photo from this morning and one volunteer with an old consumer drone. She is a composite; the job is real. The aircraft is real too: a DJI Phantom 3 Standard from 2015, with no obstacle sensing and a 720p video link, driven by a Kotlin bridge app on the phone that carries video out and stick commands in. The person the drone finds in the video is me, with consent.
OpenCV sees, every frame
Three loops are kept apart on purpose. The first is OpenCV 5 on every frame. cv2.dnn, the new graph engine, runs YOLO11n for people at about 41 to 50 ms a frame on a laptop CPU. Each person is then compared with the photo two ways: the OpenCV Model Zoo person re-identification network and HSV clothing histograms by body band, fused into one score. A camera model turns the feet of each box into a point on the ground, which is what lands on the coordinator's map.


Claude decides where to look, never who someone is
The second loop is Claude, every few seconds. It has six strict tools: scan_here, fly_to, look_closer, ask_coordinator, follow_confirmed and end_mission. It sees the candidate table and the crops and chooses what to do next. While it thinks, the runtime keeps the aircraft holding and perceiving, and every decision is written to trace.jsonl. The third loop is a person, once. ask_coordinator puts "Is this them?" on the coordinator's phone with the photo beside what the drone sees. The page is a Lambda function URL, and the answer is a DynamoDB conditional write, so a second answer to the same question is refused.

Three missions in a park
On 25 October 2026 I flew three missions in a public park, playing the missing person. Run 1 used a photo taken at eye level. From the air I never scored above 0.24, so it looked closer twice, searched two corners, never asked anyone, and I called it back. That is the right behaviour for a weak match, and it is the hard case. Run 2 used an aerial photo: it looked closer at 0.76, asked, was confirmed, and followed for 90 seconds with 49 pins. In its own summary, the agent wrote that the lock held only 47% of the time and that it lost me seven times. Run 3 found me on the first scan at 0.85, asked, was confirmed, and followed until the battery reached its 18% floor after 64 seconds, when the envelope aborted and the aircraft landed itself.


The camera's own check
I printed ArUco markers at 190 mm and checked them with a ruler. The full calibration was not flown, but the markers were caught in the onboard video, so the camera check ran on the footage afterwards. OpenCV's solvePnP on a single marker puts the camera 5.9 m above it where the barometer said 8.0 m. The gap is a steady 2 m, which points at the spec-sheet lens model rather than noise, and the report says so.

Safety that a prompt cannot promise
follow_confirmed raises NotConfirmed for anyone the coordinator did not confirm. That is code, not a prompt, and it is tested. The envelope (geofence, ceiling, speed, battery floor and a stale-link abort) runs on every control tick in pilot.py, and the agent cannot widen it. The coordinator can recall the aircraft from the page, and the pilot's mode switch overrides everything: flip it back and the sticks are mine. Safety never depends on the cloud round trip.

What is not claimed
Every number in this post comes from my own three flights, with me as the only subject, so none of it is graded by anyone else; what the repository does guarantee is that the write-up matches the run files, because a script fails the build when they disagree. Pin error against the subject's phone GPS and the gimbal-angle check against the printed markers were planned and not measured. Identification is clothing and build, not a face: a photo in different clothes will not match, two people dressed alike are both put to the coordinator, and a photo taken at eye level does not match the same person seen from above, which is the next problem. One person was sometimes split into two tracks, and the agent reported it rather than hiding it. Autonomous takeoff failed on every attempt on 30 September and worked on 25 October. There is no obstacle sensing: the aircraft is kept over open ground by the geofence and the ceiling. The Phantom is registered with Transport Canada and was flown under a Basic pilot certificate, in visual line of sight, away from bystanders.
Last Seen: an eleven-year-old drone finds a person from one photo with OpenCV 5, asks a human "Is this them?", and only then follows
View the project