Skip to content
mariarodr1136Public

About

LeafMedic identifies plant diseases from a photo of a leaf and explains the symptoms, treatment, and prevention for what it finds. A fully integer-quantized MobileNet CNN classifies 16 conditions across 4 crops entirely on-device β€” no server, no uploads, no photo ever leaves your machine. 🌱

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

37 Commits

Folders and files

Repository files navigation

LeafMedic β€” On-Device Plant Disease Detection

CI Python TensorFlow Lite ONNX Runtime Web Edge AI License

Snap a photo of a leaf and get a diagnosis β€” symptoms, treatment, and prevention β€” for 16 conditions across 4 crops. A fully integer-quantized MobileNet runs entirely on-device: no server, no uploads, no photo ever leaves your machine.

One network, three runtimes, single source of truth: a browser app (ONNX Runtime Web β€” WebGPU with WASM fallback), a desktop app (Python + PyQt5), and a Raspberry Pi 4 with a camera module. Cross-runtime prediction parity is asserted in CI, and every performance claim below is reproducible with a command in this repo.

Live Demo: mariarodr1136.github.io/LeafMedic

Works in any modern browser β€” installable as an offline-capable PWA after the one-time 11 MB model download.

Gemini_Generated_Image_g02ewqg02ewqg02e Diagnosis with treatment guidance

Raspberry Pi with camera module

Table of Contents

Highlights

  • Edge AI deployment β€” an 11 MB uint8-quantized MobileNet converted from TFLite to ONNX, with byte-identical outputs verified by automated parity tests
  • Fast on CPU alone β€” 14 ms in-browser (WebGPU), 64 ms (multi-threaded WASM), ~145 ms on a Raspberry Pi 4
  • Knows when not to answer β€” predictive-entropy and vegetation heuristics downgrade non-leaf or ambiguous images to Uncertain instead of confidently misdiagnosing
  • Explainable predictions β€” an occlusion-sensitivity heatmap shows which leaf regions drove the diagnosis (gradient-free, so it works on the quantized black-box graph)
  • Capture-quality feedback β€” blur and exposure checks prompt a retake before a bad diagnosis
  • Multi-photo diagnosis β€” upload 2–5 photos of the same plant and the predictions are averaged (shots that fail the leaf check are left out); any diagnosis can be saved as a PDF report from the browser's print dialog
  • Plant timelines β€” tag a saved diagnosis with a plant name (e.g. "Backyard tomato #1") and repeat diagnoses of that plant line up in a chronological strip, so a recurring issue β€” or its recovery β€” is visible at a glance; all local, no account needed
  • Measured calibration β€” training/evaluate.py reports Expected Calibration Error with a reliability diagram and dry-runs the trust-guard thresholds, so "knows when not to answer" is a number, not a slogan
  • Private by design β€” zero third-party requests at runtime; runtime, fonts, and model are all self-hosted
  • Bilingual β€” full English/Spanish UI and care guidance, switchable at runtime
  • 167 tests in CI β€” golden predictions, cross-runtime parity, quality guards, data-contract validation, JS unit tests for the browser-only logic, plus a headless-browser end-to-end smoke test on every push
  • Retrainable β€” a complete pipeline (training/) for fine-tuning on PlantVillage, with int8 quantization, ONNX export, and parity verification built in

Tech Stack

Layer Technologies
Browser ONNX Runtime Web (WebGPU + WASM), vanilla JS (zero runtime dependencies), Canvas API, Service Worker PWA, GitHub Pages
Desktop / Pi Python, TensorFlow Lite / LiteRT, PyQt5, OpenCV, Picamera2
Model MobileNet, full-integer uint8 quantization, 11 MB, 300Γ—300 RGB input, TFLite β†’ ONNX via tf2onnx
Quality pytest (147 tests), node:test (20 tests), Playwright end-to-end, Lighthouse CI, ruff + mypy, five-job GitHub Actions CI

Quick Start

Browser β€” open the live demo. That's it.

Desktop:

git clone https://github.com/mariarodr1136/LeafMedic.git
cd LeafMedic
pip3 install -r requirements.txt
python3 main.py

The app auto-detects a Raspberry Pi camera module or any webcam, and can also analyze image files β€” test_images/ has real samples to try.

Raspberry Pi setup

Hardware: Pi 4 Model B (4 GB recommended) + camera module.

sudo raspi-config   # Interface Options β†’ Camera β†’ Enable
sudo apt update && sudo apt install python3-picamera2
pip3 install -r requirements-pi.txt --break-system-packages
python3 main.py

Full hardware list, camera connection steps, and troubleshooting: CONTRIBUTING.md.

How It Works

   Pi camera / webcam / browser upload
                  β”‚
                  β–Ό
   Preprocess β†’ 300Γ—300 RGB uint8
                  β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β–Ό                   β–Ό
   TFLite (desktop/Pi)   ONNX Runtime Web (browser)
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β–Ό
   Top-3 predictions + quality/OOD verdict
   Treatment guidance from knowledge base (44 diseases)
  1. Capture & preprocess β€” bilinear resize to 300Γ—300; the quantized graph bakes normalization into the model, so both runtimes feed raw uint8 pixels and their tensors match bit-for-bit.
  2. Inference β€” full-integer MobileNet; activations stay uint8 end to end, which is what makes ~145 ms CPU inference on a Pi 4 achievable.
  3. Trust checks β€” before showing a result, three guards run in the same pixel pass as preprocessing: vegetation coverage (is this a leaf?), normalized predictive entropy (is the model actually sure?), and blur/exposure (is the photo usable?). Any failure downgrades the verdict to Uncertain with reshoot guidance. Thresholds are mirrored between Python and JavaScript, and a test asserts they never drift apart.
  4. Explain β€” the "Why this diagnosis?" heatmap slides an occlusion patch across the image and measures confidence drop per region β€” the practical choice for a quantized graph that exposes no gradients.

Performance

Medians after warm-up; reproduce with python3 benchmark.py --onnx or the demo's ?bench mode.

Platform Runtime Inference
Laptop, browser ONNX Runtime Web (WebGPU) 14 ms
Laptop, desktop ONNX Runtime (Python) 24 ms
Laptop, desktop TFLite (LiteRT) 29 ms
Laptop, browser ONNX Runtime Web (WASM, 4 threads) 64 ms
Raspberry Pi 4B TFLite (LiteRT) ~145 ms

Notable engineering decisions

  • WebGPU adopted by measurement, not assumption β€” benchmarked at 4.5Γ— faster than multi-threaded WASM on this int8 model with a bit-identical output checksum, so the demo probes for a real GPU adapter and loads the matching runtime bundle.
  • Multi-threaded WASM on a host that can't set headers β€” GitHub Pages can't send the COOP/COEP headers ONNX Runtime's threading requires, so the service worker injects them by re-issuing same-origin responses.
  • Honest evaluation β€” the pretrained model's weak classes (healthy foliage, in particular) are documented and marked xfail in the test suite rather than hidden, and a known gap in the OOD guard is captured in a test that explains it.

Supported Crops

Crop Conditions
Tomato Healthy Β· Bacterial Spot Β· Septoria Leaf Spot Β· Late Blight Β· Leaf Mold Β· Spider Mites Β· Yellow Leaf Curl Virus
Corn (maize) Healthy Β· Common Rust Β· Gray Leaf Spot Β· Lethal Necrosis
Soybean Healthy Β· Frogeye Leaf Spot Β· Downy Mildew
Cabbage Healthy Β· Black Rot

The schema-validated knowledge base already covers 44 diseases (all 38 PlantVillage classes), ready for an expanded model from the training pipeline.


LeafMedic.mov

Screenshot 2026-07-18 at 2 02 42β€―PM

Project Structure

LeafMedic/
β”œβ”€β”€ main.py               # Desktop app entry point
β”œβ”€β”€ ml_module.py          # TFLite inference (mirrors docs/js/inference.js)
β”œβ”€β”€ image_quality.py      # Blur/exposure/vegetation/entropy guards (mirrors docs/js/quality.js)
β”œβ”€β”€ camera_module.py      # Picamera2 with OpenCV webcam fallback
β”œβ”€β”€ gui_module.py         # PyQt5 interface
β”œβ”€β”€ disease_database.py   # Treatment knowledge base (data/treatments.json)
β”œβ”€β”€ training/             # Fine-tune, quantize, export, evaluate
β”œβ”€β”€ tests/                # 147 pytest tests + 20 JS unit tests + Playwright browser smoke test
└── docs/                 # Browser demo (GitHub Pages, PWA)

The desktop and browser stacks are deliberate mirrors β€” every inference-path module has an exact counterpart on the other side, so a behavior change has one obvious twin to update.

Testing

Every push runs five CI jobs: lint + type checking (ruff, mypy), the Python suite, JS unit tests for the browser-only logic, a headless-browser end-to-end run, and Lighthouse CI (accessibility and SEO gated at 0.9, performance and best-practices tracked as a warning).

  • Golden predictions β€” each sample class must be top-1 by majority vote, catching silent model or preprocessing regressions
  • Cross-runtime parity β€” TFLite and ONNX outputs must be byte-identical on every sample image and on random tensors
  • Guard behavior β€” real leaves pass; synthetic sky, skin, concrete, and screenshots are rejected; diseased yellow/brown tissue still counts as vegetation
  • Data contracts β€” every model label has care guidance, translations cover the full label set, desktop and web copies stay identical
  • End-to-end β€” Playwright drives a real diagnosis, heatmap, OOD rejection, and language switch with zero console errors

Contributing

Contributions are welcome β€” see CONTRIBUTING.md for the development workflow, architecture internals (trust-guard heuristics, cross-runtime parity, browser runtime engineering), full Raspberry Pi setup, and troubleshooting.

License & Credits

MIT β€” see LICENSE. Built as an educational project; not a professional diagnostic tool β€” for real crop decisions, consult agricultural extension services.

Model: Kaggle AgriPredict Β· Dataset: PlantVillage (CC0) Β· Runtimes: TensorFlow Lite, ONNX Runtime

Contact

Questions or feedback? Reach out at mrodr.contact@gmail.com.

About

LeafMedic identifies plant diseases from a photo of a leaf and explains the symptoms, treatment, and prevention for what it finds. A fully integer-quantized MobileNet CNN classifies 16 conditions across 4 crops entirely on-device β€” no server, no uploads, no photo ever leaves your machine. 🌱

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages