OMR Pro is a desktop-first, hybrid application built to handle the end-to-end lifecycle of Optical Mark Recognition (OMR) testing. It consists of two core systems:
- The Desktop Wrapper & React GUI: A cross-platform UI environment utilizing Electron and React to design templates, manage student records, visualize grading matrices, and run real-time dashboards.
- The High-Performance Processing Daemon (
main.py): An asynchronous Python backend spawned via Node subprocess IPC. It utilizes OpenCV and NumPy for heavy multi-core image alignment, perspective rectification, and contrast-based bubble scanning.
🎥 Click Here to Watch the OMR Pro Demo on YouTube
The entire pipeline, from designing sheets to executing scans and grading, operates in a unified workflow:
graph TD
%% App Shell Wrapper
subgraph AppShell [Desktop Application Shell]
React[React SPA UI] <-->|IPC Invoker / Preload| Electron[Electron Main Process]
end
%% Python processing daemon
subgraph PythonDaemon [Python Processing Daemon]
Electron <-->|child_process spawn| CLI[main.py CLI Subprocess]
%% Design Flow
CLI -->|generate-template / render| SchemaGen[renderer/schema_generator.py]
SchemaGen -->|1. A4 Coordinate Packing| SchemaJSON[(Template JSON)]
SchemaJSON -->|2. Draw Vector PDF| PDFRender[renderer/pdf_renderer.py*]
PDFRender -->|Output Document| OMRPDF[(Printable PDF Sheet)]
%% Scanning Flow
CLI -->|scan / scan-image| Scanner[scanner/omr_scanner.py]
subgraph ScanPipeline [Warp & Align Pipeline]
Scanner -->|1. Load & Preprocess| Pre[scanner/image_preprocessor.py]
Pre -->|Adaptive Thresholding| Corners{4 Corners Detected?}
Corners -->|Yes| Warp[AlignmentDetector: 4-Point Warp]
Corners -->|No| Boundary[Page Boundary Fallback]
Warp & Boundary --> Straightened[Straightened A4 Image]
end
Straightened -->|2. Local Contrast Analysis| Bubble[BubbleDetector: Run contrast check]
Bubble -->|3. Set Code Verification| Evaluator[evaluator/evaluator.py*]
Evaluator -->|4. Score output JSON| Exporter[exports/export_results.py]
Exporter -->|5. Tabular reports| Output[(Excel / CSV / Charts)]
end
classDef default fill:#111827,stroke:#374151,color:#f3f4f6;
classDef highlight fill:#1e1b4b,stroke:#4f46e5,color:#f3f4f6;
class PDFRender,Evaluator highlight;
*Note: Source code files for pdf_renderer.py and evaluator.py exist in the repository as compiled __pycache__ binaries. If source edits are required, these modules can be written to match the specified backend CLI inputs.
OMR Pro uses a hybrid physical-to-digital coordinate mapping model:
- Millimeter Schema Packing: During template generation in schema_generator.py, bubble locations, candidate writing boxes, and alignment markers are calculated in physical millimeters (mm) relative to A4 page dimensions (210mm x 297mm).
-
DPI-Safe Pixel Conversion: During scanning, target mm coordinates are dynamically mapped to absolute pixel boundaries matching the scanned image's actual resolution:
$$\text{Pixel Coordinate} = \text{Coordinate (mm)} \times \frac{\text{DPI}}{25.4}$$ This makes the system resolution-independent, supporting images scanned from 72 DPI up to 600+ DPI without modifying the schema coordinates.
To resolve tilt, rotation, and camera angle distortion during hand-held smartphone scans:
-
Convex Hull Filtering: The alignment_detector.py searches the processed image for four solid square markers near the corners. It checks candidate contours for solidity (
$>0.8$ ) and area consistency ($0.005%$ to$0.5%$ of image). -
4-Point Perspective Warp: Once the 4 centers are detected, OpenCV's
getPerspectiveTransformandwarpPerspectiveproject the quadrilateral back into a perfectly flat, straightened, A4 ratio image of$1654 \times 2339$ pixels. - Smart Boundary Fallback: If the markers are smudged, image_preprocessor.py falls back to detecting the largest outer boundary of the paper itself, ensuring scanning still succeeds.
Simple pixel thresholding fails when shadows cover half the sheet. OMR Pro features a local grayscale contrast engine in bubble_detector.py:
- The detector crops a small Region of Interest (ROI) around each bubble.
- It measures the average pixel value of the inner circle ($\text{ROI}{\text{inner}}$, 80% radius) and compares it directly to the average value of the concentric outer ring representing the blank paper surrounding the bubble ($\text{ROI}{\text{outer}}$, 130% radius).
- Contrast Score Formula: $$\text{Score} = \frac{\text{Mean}(\text{ROI}{\text{outer}}) - \text{Mean}(\text{ROI}{\text{inner}})}{\text{Mean}(\text{ROI}_{\text{outer}})}$$
- A bubble is only flagged as marked if the inner region is
$>20%$ darker than the surrounding paper. This eliminates failures caused by local brightness, shadows, and scanner lighting gradients.
Evaluating folders of hundreds of images is computationally intensive:
- The core CLI in main.py leverages Python's
ProcessPoolExecutorto map images across all available CPU threads concurrently. - Results are compiled, converted to DataFrames, and exported by export_results.py into detailed Excel files containing global rank summaries, option distributions, and item difficulty calculations.
The project maintains a clean split between the UI client wrapper and the Python daemon:
electron-ui/: The React and Electron wrapper.python-backend/: The OpenCV and ReportLab core logic.docs/: GitHub Pages distribution folder hosting the static landing page.
These are explicitly excluded via .gitignore to prevent repository bloat:
**/node_modules/: Package dependencies.**/__pycache__/&*.pyc: Compiled Python binaries.python-backend/venv/: Local python virtual environments.generated_omrs/&results/: Local user outputs from scans.- Development files like
prompt.txt,ANTIGRAVITY.md, and scratch scripts.
Navigate to the backend directory and configure the environment:
cd python-backend
python -m venv venv
# Activate Virtual Environment (Windows)
.\venv\Scripts\activate
# Install Dependencies
pip install -r requirements.txtNavigate to the UI directory, install Node packages, and launch:
cd ../electron-ui
npm install
npm run dev- Design OMR Sheet: Launch the app, navigate to Studio, design candidate blocks/questions, and click Generate. This renders the schema and creates a vector PDF in
generated_omrs/. - Setup Answer Keys: Go to Scanner, configure your question marks, create your sets, and check the correct bubbles.
- Execute Batch Scan: Select the folder containing scanned image files, select your template schema, and click Scan Folder.
To run OMR Pro as a standalone app, download the setup file directly: