Skip to content

hp-8/bubblesheet-ai

Repository files navigation

OMR Grader — YOLOv8 Answer-Sheet Scanner

Automated grading of bubble-sheet (OMR) exams with a real computer-vision pipeline. Upload scanned answer sheets, a YOLOv8 model detects each filled bubble, the answers are compared against a key, and you get per-student scores as CSV — from the command line or a small Flask web app.


The problem

Grading multiple-choice exams by hand is slow, error-prone, and doesn't scale. Classic OMR scanners need expensive dedicated hardware and rigidly pre-printed sheets. This project replaces that with a trained object detector that reads ordinary scanned sheets (PDF or image) and grades them automatically.

The approach

The core is a YOLOv8n detector fine-tuned to recognise marked bubbles. Each bubble is classified into one of six classes:

a · b · c · d · e · none

For every page the model emits one detection per question; the detected option is matched against the answer key to compute correctness and a final score.

PDF / image ──► page split ──► YOLOv8 bubble detection ──► compare vs key ──► CSV
   (pdf2image)                  (ultralytics)              (utils/ans.py)

Architecture

Component File Role
Web server app.py Flask upload UI + /upload, /download_csv routes
JSON API api.py FastAPI service returning structured results + OpenAPI docs
Live demo app_gradio.py Gradio app for Hugging Face Spaces
Standalone CLI grade.py Grade sheets without Flask
Grading core utils/ans.py Detect → compare → score
PDF splitter utils/pdf_splitter.py Multi-page PDF → page images
Inference helpers models/yolo_model.py Raw box-level detections
Weight loader models/weights.py Auto-downloads best.pt from Releases
Training / eval train.py, val.py, test.py Reproduce or extend the model

The 6 MB trained model is published as a GitHub Release asset (v1.0-weights) and downloaded automatically on first run — it is intentionally not committed to git.

Accuracy & metrics

Trained for 80 epochs (YOLOv8n, 640px, batch 16) on a custom answer-sheet dataset. Validation results:

Metric Value
mAP@50 0.536
mAP@50-95 0.283
Precision 0.47
Recall 0.54

Confusion matrix Precision-Recall curve

F1 curve Training curves

These are honest first-pass numbers from a small dataset. The none class and blank bubbles dominate errors — see Limitations.

Quickstart

git clone https://github.com/hp-8/bubblesheet-ai.git
cd bubblesheet-ai
pip install -r requirements.txt          # also needs poppler for pdf2image

Command line (model auto-downloads on first run):

python grade.py --sheets exam.pdf --key answer_keys/ans.txt --out scores.csv

Multiple sheets or a folder of images work too:

python grade.py --sheets a.pdf b.pdf scans/ --key answer_keys/ans.txt

Web app:

python app.py        # then open http://127.0.0.1:5000

Upload your answer-sheet PDFs and a key file (one lowercase answer per line), then download the results CSV.

JSON API (typed, OpenAPI docs at /docs):

uvicorn api:app --reload
curl -F "answer_key=@answer_keys/ans.txt" -F "files=@exam.pdf" \
     http://127.0.0.1:8000/grade

Live demo (Gradio — runs locally or on Hugging Face Spaces):

python app_gradio.py

See docs/HUGGINGFACE.md for one-push Spaces deployment.

Reproduce the model

python train.py      # trains YOLOv8n on dataset.yaml
python val.py        # evaluates and writes predictions.csv

Point dataset.yaml at your own labelled data (classes: a,b,c,d,e,none).

Limitations

Kept deliberately honest:

  • Student-ID OCR (models/id_detection.py, Tesseract) reads the printed ID from the top strip of each sheet. It needs the Tesseract binary installed (brew install tesseract); without it, grading falls back to a placeholder id so output stays well-formed.
  • Metrics reflect a small training set; more labelled data would lift mAP substantially.

License

MIT

About

YOLOv8 OMR / answer-sheet grader: detects bubbles + scores scanned exams to CSV via CLI or Flask

Topics

Resources

License

Stars

0 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors