A test Flutter app that uses the phone camera to detect cars in real time (on-device TensorFlow Lite) and estimate their speed. Built for Android first, structured so an iOS clone is a small step (see iOS port plan below).
WARNING - Accuracy honesty: Speed from a single phone camera is an estimate, not a radar reading. It depends on calibration, camera angle, and steady framing. Treat results as approximate.
- Live camera stream -> on-device object detection (SSD MobileNet v1, COCO).
- Filters to vehicles (car, truck, bus, motorcycle).
- Tracks each vehicle across frames (centroid tracker) and estimates km/h.
- Draws bounding boxes + speed labels over the preview.
- A calibration screen to set the pixel->meter scale.
lib/
main.dart app entry, camera enumeration
models/
recognition.dart a detected box + label + score + track id
calibration.dart meters-per-pixel scale
services/
detector.dart TFLite SSD MobileNet wrapper
image_utils.dart CameraImage (YUV/BGRA) -> RGB, resize, rotate
tracker.dart centroid tracker (assigns stable ids)
speed_estimator.dart pixel motion + calibration -> km/h (smoothed)
screens/
home_screen.dart menu + permissions
detection_screen.dart live camera + inference loop + overlay
calibration_screen.dart mark a known distance to set the scale
widgets/
box_painter.dart draws boxes + speed labels
assets/models/ put ssd_mobilenet.tflite here (+ labels.txt)
scripts/download_model.sh fetches the model
android/app/src/main/AndroidManifest.xml camera permission
You need the Flutter SDK (3.19+) and an Android device/emulator with a camera.
# 1. From the project root, generate the platform folders (android/ios/...).
# This fills in Gradle files, MainActivity, etc. that aren't checked in here.
flutter create .
# 2. Get the model (~4 MB).
bash scripts/download_model.sh
# 3. Install dependencies.
flutter pub get
# 4. Apply the two Gradle tweaks in android/app/build.gradle.notes
# (minSdkVersion 21 + noCompress 'tflite').
# 5. Run on a connected device (a real phone is best for the camera).
flutter runIf flutter create . overwrites AndroidManifest.xml, re-add the
<uses-permission android:name="android.permission.CAMERA" /> line.
The camera only sees pixels moving, not meters. To turn pixel motion into km/h:
- Calibrate - on the calibration screen you mark a real-world distance you know (a lane is ~3.7 m, a sedan is ~4.5 m long). The app converts the marker separation into model-input pixels and computes meters-per-pixel.
- Track - each vehicle gets a stable id and a short history of center positions with timestamps.
- Estimate - speed = (pixelDisplacement * metersPerPixel) / deltaTime, converted to km/h and exponentially smoothed.
This is a planar / single-scale model. Sources of error:
- Perspective: objects farther away move fewer pixels for the same real speed. One global meters-per-pixel is only right near the calibration line.
- Camera angle: shots not perpendicular to traffic distort distances.
- Square resize: frames are squashed to 300x300, mildly distorting motion.
- Frame rate: low fps widens the time step and adds noise.
To improve: use a homography (map 4 known ground points to a top-down plane) instead of a single scale, mount the phone steadily, shoot perpendicular to traffic, and raise camera resolution/fps. Reference-grade speed needs stereo depth or a calibrated fixed camera.
- Inference runs on the main isolate, throttled by a busy-flag (skips frames while one is processing). Simple and stable for a test app. For higher fps, move Detector.detect into a background Isolate and pass the interpreter address - listed in the roadmap.
- ResolutionPreset.medium balances detection quality and speed.
The app is already ~90% portable because the logic lives in Dart.
| Area | Android (now) | iOS (clone) |
|---|---|---|
| Camera | camera plugin, YUV420 | same plugin; frames arrive as BGRA8888 - already handled in image_utils.dart |
| Inference | tflite_flutter | same package; bundle the same .tflite |
| Permissions | manifest CAMERA | add NSCameraUsageDescription to ios/Runner/Info.plist |
| UI / tracking / speed | pure Dart | unchanged |
Steps to clone:
flutter create .already scaffolds ios/. Open it once.- Add to ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key> <string>Used to detect cars and estimate their speed.</string>
- Set the iOS deployment target to 12.0+ in Xcode (tflite_flutter needs it).
- iOS delivers bgra8888 frames, which ImageUtils.convertCameraImage already branches on.
flutter run -d <ios device>.
No Swift/Kotlin platform code is required for the core features.
- Move inference to a background isolate for higher fps.
- Replace single-scale calibration with a 4-point homography.
- Swap SSD MobileNet for YOLOv8n (update output decode + NMS).
- Record clips with overlaid speed for later review.
- Direction-aware speed (sign of motion, lane assignment).