File size: 6,314 Bytes
ef9f248
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
993b508
 
 
 
 
ef9f248
 
 
993b508
 
 
 
 
ef9f248
 
 
 
 
 
 
 
 
 
993b508
ef9f248
993b508
ef9f248
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
993b508
 
ef9f248
993b508
ef9f248
993b508
 
 
 
 
 
ef9f248
993b508
 
ef9f248
 
 
 
993b508
 
ef9f248
993b508
ef9f248
 
 
 
993b508
 
ef9f248
 
 
 
 
 
993b508
ef9f248
 
 
993b508
ef9f248
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
---
license: cc-by-nc-sa-4.0
language:
- tr
library_name: keras
pipeline_tag: image-to-text
tags:
- ocr
- text-recognition
- turkish
- tinyml
- tflite
- int8
- ctc
- microcontroller
---

# InviolusOCR: tiny Turkish line OCR for microcontrollers

A compact convolutional CTC recognizer for **one cropped line of printed
Turkish text**: 560,954 parameters and a **598 KB full-int8 TensorFlow Lite**
file that keeps almost all of the float model's accuracy. A half-width **tiny**
variant is **171 KB**.

*Keywords: Turkish OCR, Türkçe OCR, tiny OCR, text recognition, TFLite, int8,
TinyML, ESP32, microcontroller.*

> **Türkçe özet:** Mikrodenetleyiciler için tek satır Türkçe metin okuyan,
> 561 bin parametreli, int8 TFLite dosyası 598 KB olan küçük bir OCR modeli.
> int8 hâli, ayrılmış test satırlarının %77,3'ünü, gerçek sahne metni
> (TS-TR) kırpıntılarının %56,2'sini ve basılı belge satırlarının (donut)
> %46,5'ini harfi harfine doğru okuyor. 171 KB'lık küçük sürüm daha düşük
> doğrulukta çalışıyor (%64,4 / %32,6 / %20,1). Ticari olmayan kullanım içindir
> (CC BY-NC-SA 4.0).

This replaces [inviolus/erdem-ocr-tr-tinyml](https://huggingface.co/inviolus/erdem-ocr-tr-tinyml)
(2026-10-09), whose int8 file lost most of its accuracy.

## Files

| File | What it is |
|---|---|
| `inviolusocr.keras` | Float model, input `(batch, 32, 160, 1)`, output `(batch, 40, 90)` softmax |
| `inviolusocr_int8.tflite` | Full-int8 export, input `[1, 32, 160, 1]` int8 (scale 0.007843, zero point -1), output `[1, 40, 90]` int8 (scale 0.00390625, zero point -128) |
| `inviolusocr_tiny.keras`, `inviolusocr_tiny_int8.tflite` | Half-width variant, 144,330 parameters, same input, output and alphabet |
| `alphabet.json` | Character set used to decode the output |
| `benchmark.json`, `benchmark_T.json` | Scores for this model and the earlier versions; scores for tiny |

## Model

- **Input:** one horizontal text line, grayscale, resized to 160×32, scaled
  to `[-1, 1]` (`pixel / 127.5 - 1`).
- **Architecture:** 4 conv + batch-norm + pool blocks, a dense projection,
  then four residual dilated 1-D convolutions (dilation 1, 2, 4, 1) instead of
  an LSTM, and a dense softmax. Only ops that quantize cleanly to int8.
- **Output:** 40 timesteps × 90 classes. Class `0` is padding, `1..88` are the
  characters of `alphabet.json` in order, `89` is the CTC blank.
- **Character set:** digits, ASCII letters, `ç ğ ı İ ö ş ü Ç Ğ Ö Ş Ü`, space
  and `.,:;!?-_/()'%`. Up to 24 characters per line.
- **Not included:** text detection. The line must already be cropped.

## Usage

```python
import json
import numpy as np
import tensorflow as tf

alphabet = json.load(open("alphabet.json", encoding="utf-8"))["alphabet"]
BLANK = len(alphabet) + 1

def preprocess(path):
    image = tf.io.decode_image(tf.io.read_file(path), channels=1, expand_animations=False)
    image = tf.image.resize(image, [32, 160])
    return (tf.cast(image, tf.float32) / 127.5 - 1.0).numpy()

def decode(ids):
    text, previous = [], None
    for i in ids:
        if i != previous and 0 < i < BLANK:
            text.append(alphabet[i - 1])
        previous = i
    return "".join(text)

# int8 TFLite (the file meant for devices)
interpreter = tf.lite.Interpreter(model_path="inviolusocr_int8.tflite")
interpreter.allocate_tensors()
inp, out = interpreter.get_input_details()[0], interpreter.get_output_details()[0]
scale, zero = inp["quantization"]
x = np.clip(np.round(preprocess("line.png") / scale + zero), -128, 127).astype(np.int8)
interpreter.set_tensor(inp["index"], x[np.newaxis])
interpreter.invoke()
print(decode(interpreter.get_tensor(out["index"])[0].argmax(-1)))
```

## Results

Exact-line accuracy (the whole line correct), all models scored on the same
rows: 12,093 held-out lines (synthetic, Zenodo, TS-TR, esengul3, STS-TR) and
the 2,078-crop official TS-TR test split (real scene text, never trained on),
plus 2,563 printed-document rows from the donut 200k test list.

![Exact-line accuracy of the int8 files of the main and tiny models](benchmark-1102-size-light.svg)

| Model, int8 file | Params | Size | Held-out | TS-TR | Donut test |
|---|---:|---:|---:|---:|---:|
| erdem-ocr 2026-10-09 (LSTM) | 631,226 | 665 KB | 32.9% | 33.5% | not measured |
| InviolusOCR 2026-10-31 (previous version here) | 560,954 | 598 KB | 78.4% | 58.2% | 9.3% |
| **InviolusOCR 2026-11-01 (main)** | **560,954** | **598 KB** | **77.3%** | **56.2%** | **46.5%** |
| **InviolusOCR tiny 2026-11-02** | **144,330** | **171 KB** | 64.4% | 32.6% | 20.1% |

Character error rate of the int8 files: main 10.0% held-out, 18.8% TS-TR, 12.6%
donut; tiny 14.1%, 31.3%, 24.1%.

## Limitations

- Printed text only; no handwriting, curved text or full pages.
- Real scene text is still the weak spot (56% exact).
- **Licence plates are not read** (2% exact on 250 plate crops in a first,
  unchecked test).
- Not yet measured on a microcontroller (speed, memory).
- Text detection and line cropping must be done before this model runs.

## Training data

About 106,000 training crops. The main model was continued from earlier
weights; tiny was trained from scratch for 260 minutes on CPU.

- Synthetic Turkish lines rendered from a 50k-word Turkish word list.
- [Turkish OCR Text Image Dataset](https://zenodo.org/records/21923181), Zenodo, CC BY 4.0.
- [Turkish Scene Text Recognition (TS-TR)](https://www.kaggle.com/datasets/serdaryildiz/turkish-scene-text-recognition-dataset), Serdar Yıldız, CC BY-NC 4.0.
- [Synthetic Turkish Scene Text (STS-TR)](https://www.kaggle.com/datasets/serdaryildiz/synthetic-turkish-scene-text-recognition-dataset), Serdar Yıldız, CC BY-NC 4.0.
- [Turkish Word OCR](https://huggingface.co/datasets/esengul3/turkish-word-ocr), esengul3, CC BY-SA 4.0.
- Turkish recognition 200k v4 (donut), turgutguvercin, CC BY-SA 4.0.

## License

Because of the non-commercial (TS-TR, STS-TR) and share-alike (esengul3, donut)
terms of the training data, this model is released under
**[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/)**:
non-commercial use only, credit this model and the datasets above, and share
adaptations under the same license.

Training code (MIT): [ErdemWilkinson/InviolusOCR](https://github.com/ErdemWilkinson/InviolusOCR).