wormocr 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wormocr-1.0.0/LICENSE +21 -0
- wormocr-1.0.0/PKG-INFO +377 -0
- wormocr-1.0.0/README.md +338 -0
- wormocr-1.0.0/pyproject.toml +58 -0
- wormocr-1.0.0/setup.cfg +4 -0
- wormocr-1.0.0/src/wormocr/__init__.py +18 -0
- wormocr-1.0.0/src/wormocr/__main__.py +4 -0
- wormocr-1.0.0/src/wormocr/api.py +229 -0
- wormocr-1.0.0/src/wormocr/benchmark/__init__.py +5 -0
- wormocr-1.0.0/src/wormocr/benchmark/report.py +403 -0
- wormocr-1.0.0/src/wormocr/checkpoints.py +55 -0
- wormocr-1.0.0/src/wormocr/cli.py +308 -0
- wormocr-1.0.0/src/wormocr/config.py +220 -0
- wormocr-1.0.0/src/wormocr/data/__init__.py +5 -0
- wormocr-1.0.0/src/wormocr/data/dataset.py +110 -0
- wormocr-1.0.0/src/wormocr/data/fonts.py +173 -0
- wormocr-1.0.0/src/wormocr/data/handwriting.py +304 -0
- wormocr-1.0.0/src/wormocr/data/lexicon.py +105 -0
- wormocr-1.0.0/src/wormocr/data/lexicon_medical.py +48 -0
- wormocr-1.0.0/src/wormocr/data/mixed.py +211 -0
- wormocr-1.0.0/src/wormocr/data/synthetic.py +445 -0
- wormocr-1.0.0/src/wormocr/detection/__init__.py +5 -0
- wormocr-1.0.0/src/wormocr/detection/lines.py +382 -0
- wormocr-1.0.0/src/wormocr/evaluation/__init__.py +5 -0
- wormocr-1.0.0/src/wormocr/evaluation/errors.py +145 -0
- wormocr-1.0.0/src/wormocr/evaluation/metrics.py +105 -0
- wormocr-1.0.0/src/wormocr/evaluation/robustness.py +43 -0
- wormocr-1.0.0/src/wormocr/exceptions.py +25 -0
- wormocr-1.0.0/src/wormocr/export/__init__.py +5 -0
- wormocr-1.0.0/src/wormocr/export/onnx_export.py +75 -0
- wormocr-1.0.0/src/wormocr/hub.py +157 -0
- wormocr-1.0.0/src/wormocr/inference/__init__.py +5 -0
- wormocr-1.0.0/src/wormocr/inference/decode.py +113 -0
- wormocr-1.0.0/src/wormocr/inference/engine.py +122 -0
- wormocr-1.0.0/src/wormocr/models/__init__.py +5 -0
- wormocr-1.0.0/src/wormocr/models/crnn.py +236 -0
- wormocr-1.0.0/src/wormocr/preprocessing.py +135 -0
- wormocr-1.0.0/src/wormocr/py.typed +0 -0
- wormocr-1.0.0/src/wormocr/runtime.py +56 -0
- wormocr-1.0.0/src/wormocr/training/__init__.py +5 -0
- wormocr-1.0.0/src/wormocr/training/loop.py +645 -0
- wormocr-1.0.0/src/wormocr/vocabulary.py +69 -0
- wormocr-1.0.0/src/wormocr/web/__init__.py +5 -0
- wormocr-1.0.0/src/wormocr/web/server.py +505 -0
- wormocr-1.0.0/src/wormocr/web/static/app.js +514 -0
- wormocr-1.0.0/src/wormocr/web/static/index.html +141 -0
- wormocr-1.0.0/src/wormocr/web/static/style.css +379 -0
- wormocr-1.0.0/src/wormocr.egg-info/PKG-INFO +377 -0
- wormocr-1.0.0/src/wormocr.egg-info/SOURCES.txt +65 -0
- wormocr-1.0.0/src/wormocr.egg-info/dependency_links.txt +1 -0
- wormocr-1.0.0/src/wormocr.egg-info/entry_points.txt +2 -0
- wormocr-1.0.0/src/wormocr.egg-info/requires.txt +15 -0
- wormocr-1.0.0/src/wormocr.egg-info/top_level.txt +1 -0
- wormocr-1.0.0/tests/test_api.py +81 -0
- wormocr-1.0.0/tests/test_cli.py +55 -0
- wormocr-1.0.0/tests/test_decoder.py +48 -0
- wormocr-1.0.0/tests/test_detection.py +81 -0
- wormocr-1.0.0/tests/test_hub.py +66 -0
- wormocr-1.0.0/tests/test_metrics.py +25 -0
- wormocr-1.0.0/tests/test_mixed.py +88 -0
- wormocr-1.0.0/tests/test_model.py +55 -0
- wormocr-1.0.0/tests/test_onnx.py +49 -0
- wormocr-1.0.0/tests/test_preprocess.py +48 -0
- wormocr-1.0.0/tests/test_synthetic.py +30 -0
- wormocr-1.0.0/tests/test_train.py +184 -0
- wormocr-1.0.0/tests/test_vocabulary.py +29 -0
- wormocr-1.0.0/tests/test_web.py +101 -0
wormocr-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 arjun shukla
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
wormocr-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wormocr
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Local OCR for printed and handwritten English text. Small CRNN models, CPU-friendly, no cloud.
|
|
5
|
+
Author: arjun shukla
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/arjun988/wormOCR
|
|
8
|
+
Project-URL: Repository, https://github.com/arjun988/wormOCR
|
|
9
|
+
Project-URL: Issues, https://github.com/arjun988/wormOCR/issues
|
|
10
|
+
Project-URL: Release-notes, https://github.com/arjun988/wormOCR/releases
|
|
11
|
+
Keywords: ocr,ctc,crnn,pytorch,onnx,handwriting,document
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: numpy>=1.26
|
|
27
|
+
Requires-Dist: pillow>=10
|
|
28
|
+
Requires-Dist: pyyaml>=6
|
|
29
|
+
Requires-Dist: safetensors>=0.4
|
|
30
|
+
Requires-Dist: torch>=2.2
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
33
|
+
Provides-Extra: export
|
|
34
|
+
Requires-Dist: onnx>=1.16; extra == "export"
|
|
35
|
+
Requires-Dist: onnxruntime>=1.18; extra == "export"
|
|
36
|
+
Provides-Extra: pdf
|
|
37
|
+
Requires-Dist: pypdfium2>=4; extra == "pdf"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
# wormOCR
|
|
41
|
+
|
|
42
|
+
**Local OCR for printed and handwritten English text.**
|
|
43
|
+
|
|
44
|
+
[](https://pypi.org/project/wormocr/)
|
|
45
|
+
[](LICENSE)
|
|
46
|
+
[](pyproject.toml)
|
|
47
|
+
[](https://pytorch.org)
|
|
48
|
+
|
|
49
|
+
Install the package, download the weights once, and read text on your machine. No cloud API. No silent downloads on import.
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install wormocr
|
|
55
|
+
wormocr download
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from wormocr import OCR
|
|
60
|
+
|
|
61
|
+
ocr = OCR()
|
|
62
|
+
print(ocr.predict("invoice_line.png").text)
|
|
63
|
+
# Invoice #1042 Total: $18.50
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
That uses **wormocr-2M** (2.17M parameters, 8.7 MB). For the larger model:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
wormocr download wormocr-9M
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
ocr = OCR(model="wormocr-9M")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
> **v1.0.0.** Clean printed lines and receipts are strong. Messy notes and historical handwriting are usable and still short of a careful human reading. See [Limitations](#limitations).
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Contents
|
|
81
|
+
|
|
82
|
+
- [Highlights](#highlights)
|
|
83
|
+
- [Models](#models)
|
|
84
|
+
- [Results](#results)
|
|
85
|
+
- [Installation](#installation)
|
|
86
|
+
- [Usage](#usage)
|
|
87
|
+
- [Training](#training)
|
|
88
|
+
- [Evaluation, export, and benchmarks](#evaluation-export-and-benchmarks)
|
|
89
|
+
- [How it works](#how-it-works)
|
|
90
|
+
- [Project layout](#project-layout)
|
|
91
|
+
- [Limitations](#limitations)
|
|
92
|
+
- [Contributing](#contributing)
|
|
93
|
+
- [Citation](#citation)
|
|
94
|
+
- [License](#license)
|
|
95
|
+
|
|
96
|
+
## Highlights
|
|
97
|
+
|
|
98
|
+
- **Small enough to ship.** wormocr-2M is 8.7 MB. wormocr-9M is 33.5 MB. Both are ordinary CRNN + CTC models.
|
|
99
|
+
- **Fast on CPU.** About 14 ms per line end to end with wormocr-2M on a laptop CPU. No GPU required for inference.
|
|
100
|
+
- **Fully local.** Importing the package never touches the network. Weights come from a pinned GitHub release only when you run `wormocr download`, and every file is checked against a SHA-256 hash.
|
|
101
|
+
- **Print and handwriting.** One recognizer family for invoices, receipts, handwritten names, notes, and historical lines. No third-party OCR weights.
|
|
102
|
+
- **Full toolkit.** Train, resume, evaluate (CER / WER / exact match), export ONNX, benchmark, page layout, PDFs, and a local browser demo.
|
|
103
|
+
|
|
104
|
+
## Models
|
|
105
|
+
|
|
106
|
+
| | wormocr-2M | wormocr-9M |
|
|
107
|
+
| --- | --- | --- |
|
|
108
|
+
| Parameters | 2,174,880 | 8,776,416 |
|
|
109
|
+
| Weights (`.safetensors`, FP32) | 8.7 MB | 33.5 MB |
|
|
110
|
+
| ONNX (FP32) | 8.7 MB | 33.5 MB |
|
|
111
|
+
| Architecture | Separable CNN + 2-layer BiGRU (256) + CTC | Same family, BiGRU 512 |
|
|
112
|
+
| Input height | 32 px | 48 px |
|
|
113
|
+
| Output stride | 4 | 4 |
|
|
114
|
+
| Character set | 95 printable ASCII + CTC blank | Same |
|
|
115
|
+
| Training data | Synthetic print & handwriting, GNHK, names, Bentham, CORD. FUNSD / IAM / RxHand evaluation only | Same mix |
|
|
116
|
+
| Best checkpoint | step 58,000 of 60,000 | step 19,000 (early-stopped at 30,000) |
|
|
117
|
+
| Default for `OCR()` | Yes | Pass `model="wormocr-9M"` |
|
|
118
|
+
|
|
119
|
+
## Results
|
|
120
|
+
|
|
121
|
+
Character error rate (CER), greedy decode, NVIDIA RTX 5060 Laptop GPU. wormocr-2M measured 23 October 2026. wormocr-9M measured 6 November 2026 on the same frozen test lines. Lower is better. Older printed-only scores live in [docs/BENCHMARKS.md](docs/BENCHMARKS.md).
|
|
122
|
+
|
|
123
|
+
| Test set | Lines | wormocr-2M | wormocr-9M |
|
|
124
|
+
| --- | ---: | ---: | ---: |
|
|
125
|
+
| Synthetic printed lines | 1,000 | 3.1% | 3.7% |
|
|
126
|
+
| [FUNSD](https://guillaumejaume.github.io/FUNSD/) form words (eval only) | 8,526 | 11.5% | **10.2%** |
|
|
127
|
+
| CORD receipts | 795 | 3.7% | **3.1%** |
|
|
128
|
+
| Synthetic handwriting | 1,000 | 9.2% | **7.1%** |
|
|
129
|
+
| Handwritten form names | 26,170 | **5.3%** | 5.3% |
|
|
130
|
+
| GNHK handwritten notes | 2,410 | 23.3% | **19.2%** |
|
|
131
|
+
| IAM lines (eval only) | 2,915 | 22.4% | **18.3%** |
|
|
132
|
+
| Bentham historical lines | 1,135 | 15.1% | **8.8%** |
|
|
133
|
+
| RxHand words, case-insensitive (eval only) | 1,107 | 37.9% | **35.2%** |
|
|
134
|
+
|
|
135
|
+
FUNSD, IAM, and RxHand were never used for training.
|
|
136
|
+
|
|
137
|
+
### Speed (CPU, wormocr-2M)
|
|
138
|
+
|
|
139
|
+
Intel Core i9-14900HX, PyTorch 2.14.1, FP32. Medians after warmup (22 October 2026).
|
|
140
|
+
|
|
141
|
+
| Path | Batch | Median | Throughput |
|
|
142
|
+
| --- | ---: | ---: | ---: |
|
|
143
|
+
| Model only, 256 px wide | 1 | 26.0 ms | 38 lines/s |
|
|
144
|
+
| Model only, 256 px wide | 8 | 51.0 ms | 157 lines/s |
|
|
145
|
+
| Preprocess + model + decode | 1 | 14.4 ms | 69 lines/s |
|
|
146
|
+
| Preprocess + model + decode | 8 | 42.2 ms | 189 lines/s |
|
|
147
|
+
|
|
148
|
+
wormocr-9M is larger and slower. Use it when the handwriting gains matter more than size.
|
|
149
|
+
|
|
150
|
+
### Training cost
|
|
151
|
+
|
|
152
|
+
| Run | Hardware | Steps | Effective batch | Wall time |
|
|
153
|
+
| --- | --- | ---: | ---: | ---: |
|
|
154
|
+
| wormocr-2M | RTX 5060 Laptop, mixed precision | 60,000 | 64 | 125 min |
|
|
155
|
+
| wormocr-9M | RTX 5060 Laptop, mixed precision | 30,000 (best at 19,000) | 64 (16 × 4 accum) | about 150 min |
|
|
156
|
+
|
|
157
|
+
## Installation
|
|
158
|
+
|
|
159
|
+
Requires Python 3.10+.
|
|
160
|
+
|
|
161
|
+
### From PyPI (recommended)
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
pip install wormocr
|
|
165
|
+
wormocr download # wormocr-2M
|
|
166
|
+
# wormocr download wormocr-9M
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Optional extras:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
pip install "wormocr[pdf]" # PDF input
|
|
173
|
+
pip install "wormocr[export]" # ONNX export
|
|
174
|
+
pip install "wormocr[dev]" # pytest
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
A CPU build of PyTorch is enough for inference. For GPU training, install a CUDA build from [pytorch.org](https://pytorch.org/get-started/locally/) first, then install wormOCR.
|
|
178
|
+
|
|
179
|
+
### From source
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
git clone https://github.com/arjun988/wormOCR.git
|
|
183
|
+
cd wormOCR
|
|
184
|
+
python -m venv .venv
|
|
185
|
+
.venv\Scripts\activate # Windows
|
|
186
|
+
# source .venv/bin/activate # macOS / Linux
|
|
187
|
+
pip install -e ".[dev,export,pdf]"
|
|
188
|
+
wormocr download
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
wormocr info
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Weights
|
|
196
|
+
|
|
197
|
+
Weights are **not** on PyPI and **not** in git. They are GitHub release assets, verified by SHA-256 hashes baked into the package:
|
|
198
|
+
|
|
199
|
+
| Release | Size |
|
|
200
|
+
| --- | ---: |
|
|
201
|
+
| [`wormocr-2M`](https://github.com/arjun988/wormOCR/releases/tag/wormocr-2M) | 8.7 MB |
|
|
202
|
+
| [`wormocr-9M`](https://github.com/arjun988/wormOCR/releases/tag/wormocr-9M) | 33.5 MB |
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
wormocr download
|
|
206
|
+
wormocr download wormocr-9M
|
|
207
|
+
wormocr download wormocr-2M --force
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Files land in `~/.cache/wormocr/<name>/` (override with `WORMOCR_HOME` or `--dir`). If weights are missing, `OCR()` tells you to run the download command. You can also pass a local file:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
OCR(checkpoint="path/to/wormocr-2M.safetensors")
|
|
214
|
+
OCR(model="wormocr-9M")
|
|
215
|
+
OCR(checkpoint="artifacts/checkpoints/tiny/best.pt")
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Training checkpoints (`.pt`) are PyTorch pickles. Load only files you trust ([SECURITY.md](SECURITY.md)).
|
|
219
|
+
|
|
220
|
+
## Usage
|
|
221
|
+
|
|
222
|
+
### Python
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
from wormocr import OCR
|
|
226
|
+
|
|
227
|
+
ocr = OCR()
|
|
228
|
+
print(ocr.predict("line.png", mode="line").text)
|
|
229
|
+
|
|
230
|
+
page = ocr.predict("page.png") # mode="auto" by default
|
|
231
|
+
for item in page.lines:
|
|
232
|
+
print(item.order, item.text, item.confidence, item.bbox)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`predict` accepts a path, a PIL image, or a PDF (with the `pdf` extra). Pass `device="cuda"` or `beam_width=8` if you need them.
|
|
236
|
+
|
|
237
|
+
| Mode | Behavior |
|
|
238
|
+
| --- | --- |
|
|
239
|
+
| `line` | Whole image is one text line |
|
|
240
|
+
| `page` | Line detection, deskew, reading order |
|
|
241
|
+
| `auto` | `line` for short wide images, else `page` |
|
|
242
|
+
|
|
243
|
+
### Command line
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
wormocr download
|
|
247
|
+
wormocr predict --image line.png
|
|
248
|
+
wormocr predict --image page.png --json
|
|
249
|
+
wormocr predict --image document.pdf --model wormocr-9M
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Commands: `info`, `download`, `predict`, `train`, `evaluate`, `analyze`, `export`, `benchmark`, `generate`, `serve`.
|
|
253
|
+
|
|
254
|
+
### Web UI
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
wormocr serve # http://127.0.0.1:8000
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Drop in an image or PDF, paste with <kbd>Ctrl</kbd>+<kbd>V</kbd>, or try the sample invoice. Recognition streams while the model works. The server listens on localhost by default; files stay on your machine.
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
wormocr serve --model wormocr-9M --device cuda --port 8000
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Training
|
|
267
|
+
|
|
268
|
+
Clone the repository for configs and scripts. Synthetic lines are rendered from fonts on your machine. The released weights come from `configs/unified.yaml` (wormocr-2M) and `configs/wormocr-9M.yaml` (wormocr-9M).
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
wormocr train --config configs/unified.yaml --mode baseline
|
|
272
|
+
wormocr train --config configs/wormocr-9M.yaml --mode baseline
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Override any field with `--set section.key=value`. Training writes `best.pt`, `last.pt`, `best_weights.pt`, and `train_log.jsonl`.
|
|
276
|
+
|
|
277
|
+
| Mode | Purpose |
|
|
278
|
+
| --- | --- |
|
|
279
|
+
| `smoke` | Short check that data, loss, validation, and checkpoints run |
|
|
280
|
+
| `debug` | Tiny network experiment |
|
|
281
|
+
| `baseline` | Full run as written in the config |
|
|
282
|
+
| `resume` | Continue from `last.pt` |
|
|
283
|
+
|
|
284
|
+
Own labels: `relative/path.png<TAB>exact text`. See [docs/DATASETS.md](docs/DATASETS.md).
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
wormocr train --config configs/tiny.yaml --mode baseline \
|
|
288
|
+
--set data.labels=data/train.tsv --set data.image_root=data/images \
|
|
289
|
+
--set data.val_labels=data/val.tsv --set data.val_image_root=data/images
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Evaluation, export, and benchmarks
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
wormocr evaluate --model artifacts/checkpoints/tiny/best.pt --synthetic-samples 800
|
|
296
|
+
wormocr evaluate --model artifacts/checkpoints/tiny/best.pt --labels data/val.tsv --image-root data/images --errors errors.md
|
|
297
|
+
|
|
298
|
+
python scripts/prepare_funsd.py artifacts/datasets/funsd/dataset/testing_data artifacts/datasets/funsd_test
|
|
299
|
+
wormocr evaluate --model artifacts/checkpoints/unified/best.pt --labels artifacts/datasets/funsd_test/labels.tsv
|
|
300
|
+
|
|
301
|
+
wormocr export --model artifacts/checkpoints/tiny/best.pt --format onnx --output artifacts/export/tiny.onnx
|
|
302
|
+
wormocr benchmark --model artifacts/checkpoints/tiny/best.pt --output artifacts/benchmarks/report.md
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
CER counts every character, including spaces. INT8 ONNX exists (`--format onnx-int8`) but is not recommended: it barely shrinks the file and drifts from FP32.
|
|
306
|
+
|
|
307
|
+
## How it works
|
|
308
|
+
|
|
309
|
+
1. **Preprocessing.** Grayscale, resize to model height (32 or 48), normalize to `[-1, 1]`, pad with the line's background.
|
|
310
|
+
2. **Encoder.** Four-stage depthwise-separable CNN. Height pools to 2; width by 4.
|
|
311
|
+
3. **Sequence model.** Linear projection into a 2-layer bidirectional GRU (256 or 512).
|
|
312
|
+
4. **Decoder.** CTC over 96 classes, greedy by default; beam search optional.
|
|
313
|
+
5. **Page layout.** Deskew, Otsu, projection profiles, gutters, reading order.
|
|
314
|
+
|
|
315
|
+
Training uses CTC + AdamW, warmup then cosine decay, EMA 0.999, AMP on CUDA, and scan-style augmentation. Details: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md), [docs/DATASETS.md](docs/DATASETS.md).
|
|
316
|
+
|
|
317
|
+
## Project layout
|
|
318
|
+
|
|
319
|
+
```text
|
|
320
|
+
wormOCR/
|
|
321
|
+
├── configs/ unified.yaml → wormocr-2M; wormocr-9M.yaml → wormocr-9M
|
|
322
|
+
├── docs/ Architecture, datasets, benchmarks, roadmap
|
|
323
|
+
├── scripts/ Dataset prep and helpers
|
|
324
|
+
├── src/wormocr/
|
|
325
|
+
│ ├── api.py OCR class
|
|
326
|
+
│ ├── cli.py wormocr command
|
|
327
|
+
│ ├── hub.py Releases, download, SHA-256 checks
|
|
328
|
+
│ ├── models/ CRNN
|
|
329
|
+
│ ├── training/ Loop and EMA
|
|
330
|
+
│ ├── inference/ Engine and CTC decode
|
|
331
|
+
│ ├── detection/ Line finding and reading order
|
|
332
|
+
│ ├── evaluation/ CER / WER
|
|
333
|
+
│ ├── export/ ONNX
|
|
334
|
+
│ └── web/ Local serve UI
|
|
335
|
+
└── tests/
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Limitations
|
|
339
|
+
|
|
340
|
+
- **English printable ASCII only.** Accented letters and other scripts are rejected, not silently dropped.
|
|
341
|
+
- **Messy handwriting is still hard.** On wormocr-9M: GNHK 19.2%, IAM 18.3%, Bentham 8.8%, RxHand 35.2% case-insensitive (eval only).
|
|
342
|
+
- **Real scans beat clean synth.** FUNSD form words are about 10–11.5% CER. Tiny one-character crops remain weak.
|
|
343
|
+
- **Simple page layout.** Projection profiles, not a learned detector. Tables and heavy clutter can fail.
|
|
344
|
+
- **No language-model correction.** Output is exactly what the decoder emits.
|
|
345
|
+
- **No third-party OCR baseline yet.** Tesseract / PaddleOCR were not measured on this machine.
|
|
346
|
+
|
|
347
|
+
See [docs/ROADMAP.md](docs/ROADMAP.md).
|
|
348
|
+
|
|
349
|
+
## Contributing
|
|
350
|
+
|
|
351
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
python -m pytest
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
When you report accuracy, include the dataset, line count, exact command, and a set the model was not trained on.
|
|
358
|
+
|
|
359
|
+
## Citation
|
|
360
|
+
|
|
361
|
+
```bibtex
|
|
362
|
+
@software{shukla2026wormocr,
|
|
363
|
+
author = {Shukla, Arjun},
|
|
364
|
+
title = {wormOCR: a small local OCR engine for printed and handwritten English text},
|
|
365
|
+
year = {2026},
|
|
366
|
+
version = {1.0.0},
|
|
367
|
+
url = {https://github.com/arjun988/wormOCR}
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Also [CITATION.cff](CITATION.cff).
|
|
372
|
+
|
|
373
|
+
## License
|
|
374
|
+
|
|
375
|
+
[MIT License](LICENSE). Copyright (c) 2026 arjun shukla.
|
|
376
|
+
|
|
377
|
+
wormOCR ships no third-party OCR weights and redistributes no fonts. FUNSD is evaluation-only and is not included in this repository.
|