A fully offline Android app that points your camera at the world and tells you one thing: HOTDOG or NOT HOTDOG. Inspired by Silicon Valley's "SeeFood".
It runs an on-device YOLOv8n TFLite model (COCO class 52 = hot dog) — no network,
no server, all inference on the phone.
And yes, this is from the Silicon Valley TV show.
- Kotlin + CameraX (preview + image analysis)
- TensorFlow Lite 2.14 (GPU delegate with CPU fallback)
- Min SDK 26 (Android 8.0), compile/target SDK 36
- AGP 8.9.1, Kotlin 2.0.21, Gradle 8.13
app/src/main/
├── assets/yolov8n.tflite ← exported model (NHWC float32, [1,84,8400])
├── java/com/seefood/hotdog/
│ ├── MainActivity.kt ← CameraX + UI
│ ├── HotdogDetector.kt ← TFLite inference wrapper
│ └── ImageUtils.kt ← ImageProxy → upright Bitmap
└── res/
├── layout/activity_main.xml
└── values/{colors,strings,themes}.xml
- CameraX
ImageAnalysis(RGBA_8888, KEEP_ONLY_LATEST) hands each frame to a background thread. - The frame is rotated upright and scaled to 640×640, normalized to
[0,1]RGB in NHWC order. - The interpreter runs YOLOv8n; output is
[1, 84, 8400]— 4 box coords + 80 class scores × 8400 candidate boxes. - We take the max score across all boxes for channel 56 (
4 + 52, the "hot dog" class). - If that score
> 0.5, it's a HOTDOG.
HotdogDetector reads the model's actual input/output tensor shapes at load time, so it stays
correct even if you re-export with a different layout.
# JBR from Android Studio works as the JDK:
export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
./gradlew :app:assembleDebug
# APK -> app/build/outputs/apk/debug/app-debug.apkInstall on a connected device:
adb install -r app/build/outputs/apk/debug/app-debug.apkOr just open the folder in Android Studio and hit Run. A device with a real camera is the meaningful test (emulator cameras show a synthetic scene with no hot dogs).
The model was produced with Ultralytics (export_model.py). The export toolchain
(onnx2tf, TensorFlow) requires Python 3.10–3.12 — 3.13/3.14 are not yet supported, and
this machine's pyenv 3.13.0 was also built without _lzma.
~/.pyenv/versions/3.12.8/bin/python -m venv .venv-export
. .venv-export/bin/activate
pip install ultralytics onnx onnxslim onnx2tf sng4onnx onnx_graphsurgeon tensorflow tf_keras onnxruntime ai-edge-litert
python export_model.py
cp yolov8n_saved_model/yolov8n_float32.tflite app/src/main/assets/yolov8n.tfliteFor a smaller/faster model, export with int8=True (or use the float16 variant the export
also produces) — but note an int8 model changes the input dtype, which HotdogDetector would
need to handle.
- Confidence threshold lives in
HotdogDetector.CONFIDENCE_THRESHOLD(default0.5). The on-screen confidence read-out helps you calibrate. - Validated offline: a hot dog photo scores ~0.88; banana / pizza / people score 0.00.
- Input is NHWC
[1,640,640,3]— the TFLite export is channels-last, not NCHW. - The "hot dog" score is at output channel 56 (
4 + 52), not52 - 4. - The
.venv-export/andyolov8n_saved_model/directories are local export scratch space (git-ignored); delete them to reclaim disk once you're happy withapp/src/main/assets/yolov8n.tflite.