numpy, opencv-python, and Pillow. A single OmrEngine covers the whole workflow — Generate() turns a template, built code-first from a TemplateConfig tree of elements like ChoiceBoxConfig, CheckBoxConfig, GridConfig, and AnswerSheetConfig, or written in a compact text-markup DSL, into a page image plus a .omr descriptor; GetTemplateProcessor() loads that descriptor back to recognize new scans with Recognize() or RecognizeFolder(), returning results exportable to CSV, JSON, or XML. The library is MIT licensed and installs with a single pip command (see below); it is an early release (v0.1.0, Development Status: Alpha) covering the foundation, generation, and recognition layers of the full Aspose.OMR surface — rendering in this release is LTR/Western only, with RTL writing systems and full overflow handling tracked on the upstream roadmap but not yet implemented. For the enterprise product family, see Aspose.OMR — Enterprise Product Family.TemplateConfig, PageConfig, and element configs (ChoiceBoxConfig, CheckBoxConfig, GridConfig, CompositeGridConfig, AnswerSheetConfig) describe every field on the page.?choicebox=... / &choicebox) builds the same structures without constructing objects by hand.Arabic, Hebrew, Persian, Urdu, Bengali, and Western are present for API fidelity with the Aspose.OMR surface; this release’s renderer is LTR/Western only — RTL rendering is not yet implemented.LongWordHandling and the OverflowAction subclasses (Clip, NoClip, Wrap) parse and validate correctly, but this release’s renderer does not yet honor them — actual overflow behavior is not yet configurable.CheckBoxConfig and ChoiceBoxConfig support multi-select; FormValidationLogic, set once per TemplateProcessor, can raise if a question with Multiselect disabled receives more than one mark.AnswerSheetConfig for large-scale response collection.GridConfig and CompositeGridConfig capture numeric or custom-symbol entries as one merged value.Save() writes a ready-to-print PNG page alongside the .omr descriptor used for later recognition.RecognizeFolder() processes a whole folder of scans in one call.OmrEngine.Generate() produces a GenerationResult (page image + .omr template JSON); GetTemplateProcessor() loads that template to recognize new scans.RecognitionResult exports to CSV, JSON, or XML, each with a matching stream variant.MemoryGenerationResult exposes generated images as in-memory streams via GetImages()/GetOmr() — no disk I/O required.Recalculate() re-applies a different threshold without re-scanning.ImageCollection lets markup reference in-memory image bytes by name, avoiding filesystem round-trips.Aspose.OMR FOSS for Python installs with a single pip command (see the Quick Start example below). The API centers on three objects — OmrEngine, a TemplateConfig tree (or the markup DSL), and TemplateProcessor — that cover the whole generate → scan → recognize → export workflow.
The library depends only on numpy, opencv-python, and Pillow — no native OMR binaries to compile. It is MIT licensed, hosted on GitHub, and currently at an early v0.1.0 release covering the foundation, generation, and recognition layers of the full Aspose.OMR surface.
Build (or load) a template, save the generated page image and .omr descriptor, then recognize a scanned copy and export the results as CSV.
git clone https://github.com/aspose-omr-foss/Aspose.OMR-FOSS-for-Python.git
cd Aspose.OMR-FOSS-for-Python
pip install -e .from omr.api import OmrEngine, FormValidationLogic
engine = OmrEngine()
gen = engine.Generate("final-exam.txt") # or a code-first TemplateConfig
gen.Save("out", "final-exam") # -> out/final-exam.png + out/final-exam.omr
processor = engine.GetTemplateProcessor("out/final-exam.omr", FormValidationLogic.Ignore)
result = processor.Recognize("scan.png") # -100 = auto-calibrated threshold
print(result.GetCsv()) # also GetJson() / GetXml()
The text-markup DSL builds the same element tree as the code-first API. Here ?choicebox=... opens a choice-box question, the next line lists its options, and &choicebox closes it — Generate() returns a .Template JSON descriptor you can inspect directly.
import json
from omr.api import OmrEngine
markup = [
"?choicebox=Rate it",
"(1) Poor (2) Fair (3) Good",
"&choicebox",
]
engine = OmrEngine()
result = engine.Generate(markup)
desc = json.loads(result.Template)
cb = desc["Pages"][0]["Elements"][0]
print([b["Value"] for b in cb["Fields"][0]["Bubbles"]]) # ['Poor', 'Fair', 'Good']
It is distributed under the MIT License — free to use, modify, and distribute, including in commercial products, subject to including the original copyright notice.
Python 3.10 or later, with three dependencies installed automatically by pip — numpy, opencv-python, and Pillow. No native OMR hardware or external services are required.
Not in this release. GenerationResult.SaveAsPdf() and MemoryGenerationResult.GetPDF() both raise NotImplementedError. Use the PNG output from Save() or GetImages() instead.
RecognitionResult exports to CSV, JSON, or XML via GetCsv(), GetJson(), and GetXml(), each with a matching in-memory stream variant.
Not yet for rendering. The template layer defines Arabic, Hebrew, Persian, Urdu, and Bengali writing systems for fidelity with the Aspose.OMR surface, but this release’s render engine is LTR/Western only – RTL rendering and native-digit typesetting are on the upstream roadmap, not yet implemented.
Yes, for questions configured with Multiselect disabled. Pass FormValidationLogic.Exception to GetTemplateProcessor() to raise when such a question receives more than one mark; the default, Ignore, accepts it silently. GlobalPageSettings.Multiselect defaults to enabled.