An Android app that performs fully on-device optical character recognition — no network calls for inference. Point it at an image and it detects text regions, recognizes the text in each region, draws the detected polygons over the image, and lets you tap regions to select and copy the recognized text.
- Pick an image from device storage.
- Run a two-stage OCR pipeline: text detection (find regions) → text recognition (read each region).
- Overlay detected polygons on the image; tap a region to select it.
- Copy selected text or copy all recognized text to the clipboard.
- Switch between a small bundled model and a larger, more accurate model.
The app uses PaddleOCR PP-OCRv6 models exported to ONNX and run with ONNX Runtime for Android. OCR is two models per variant:
- Detection — DBNet-style text detector. ONNX input is fully dynamic
[N, 3, H, W]. Preprocessing mirrors PaddleOCRDetResizeForTest(keep aspect ratio, longest side ≤ 960, each side rounded to a multiple of 32) with BGR + ImageNet normalization. Postprocessing is DBNet decode (thresh 0.3, box_thresh 0.6, unclip 1.5). - Recognition — CTC recognizer. ONNX input is
[N, 3, 48, W](fixed height 48, dynamic width). Preprocessing keeps aspect ratio and normalizespixel/127.5 - 1. The CTC vocabulary is["blank"] + dict + [" "], wheredictis read from the model's*_rec_inference.yml.
| Variant | Size | Where the models live | Accuracy |
|---|---|---|---|
| Tiny | ~6 MB total | Bundled in app/src/main/assets/models/ |
Lower |
| Medium | ~138 MB | Downloaded on demand, or bundled (see build variants) | Higher |
Medium models are pulled from the HuggingFace CDN on first use:
- Det:
https://huggingface.co/PaddlePaddle/PP-OCRv6_medium_det_onnx/resolve/main/inference.onnx - Rec:
https://huggingface.co/PaddlePaddle/PP-OCRv6_medium_rec_onnx/resolve/main/inference.onnx
OCR works best on photos/scans of printed or screen text. Stylized UI fonts and pixel/bitmap fonts are harder for the models.
- Kotlin + Jetpack Compose (Material 3)
- Hilt for dependency injection
- ONNX Runtime Android
1.22.0
core/inference/ OnnxSessionManager, ImagePreprocessor, TextDetector, DbNetDecoder,
TextRecognizer, CtcDecoder, CharacterDictionary
data/ OcrRepositoryImpl, ModelDownloader
di/ Hilt modules (AppModule, DataModule)
domain/ models, OcrRepository, RecognizeTextUseCase
presentation/ocr/ OcrViewModel, OcrScreen, ImageOverlayCanvas, ModelSelectionBar
The medium-model source is controlled by the LOAD_MODELS_FROM_ASSETS build flag:
| Build type | LOAD_MODELS_FROM_ASSETS |
Medium model source | Use for |
|---|---|---|---|
stage |
true |
Bundled in assets/ (no download) |
Testing medium models quickly |
debug |
false |
Downloaded on demand from HuggingFace | Normal development |
release |
false |
Downloaded on demand from HuggingFace | Shipping |
A helper script builds, installs, launches, and tails OCR logs:
./build_install.sh # stage variant — medium models load from assets, no download
./build_install.sh debug # debug variant — medium models download on demand- Tap to pick an image.
- Choose Tiny or Medium (Medium prompts to download on
debug/releasethe first time;stagehas them bundled). - Run OCR. Detected regions are outlined on the image.
- Tap regions to select them, then Copy Selected, or use Copy All.
- Detection currently uses axis-aligned bounding boxes; tilted text may include extra background. A rotated min-area-rect crop is a planned improvement.