erdem-ocr: Turkish line OCR for microcontrollers

Newer version: inviolus/InviolusOCR (2026-10-31) is smaller and its int8 file reads 78% of held-out lines exactly instead of 33%.

A compact CNN + BiLSTM + CTC recognizer for one cropped line of printed Turkish text, built to eventually run on a microcontroller-class device. It ships as a float Keras model and a full-int8 TensorFlow Lite model (~650 KB).

Türkçe özet: Mikrodenetleyiciler için tasarlanmış, tek satır basılı Türkçe metni okuyan küçük bir OCR modeli (yaklaşık 631 bin parametre, int8 TFLite dosyası yaklaşık 650 KB). Ticari olmayan kullanım içindir (CC BY-NC 4.0).

Files

File What it is
erdem_ocr.keras Float recognition model, input (batch, 32, 160, 1), output (batch, 40, 90) softmax
erdem_ocr_int8.tflite Full-int8 export, static batch 1, input [1, 32, 160, 1] int8, output [1, 40, 90] int8
alphabet.json Character set and blank index used to decode the output

Model

  • Input: one horizontal text line, grayscale, resized to 160×32 (width×height), scaled to [-1, 1] (pixel / 127.5 - 1).
  • Architecture: 4 conv + batch-norm + pool blocks, 2 × bidirectional LSTM (96 units), dense softmax. 631,226 parameters.
  • Output: 40 timesteps × 90 classes. Class 0 is padding (never predicted), classes 1..88 are the characters of alphabet.json in order, class 89 is the CTC blank.
  • Character set: digits, ASCII letters, ç ğ ı İ ö ş ü Ç Ğ Ö Ş Ü, space and .,:;!?-_/()'%. Up to 24 characters per line.
  • Decoding: greedy CTC (argmax per step, collapse repeats, drop blanks).
  • int8 quantization: input scale 0.00784, zero point -1; output scale 0.00390625, zero point -128.
  • Not included: text detection. The model expects a line that has already been cropped.

Usage

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)

model = tf.keras.models.load_model("erdem_ocr.keras", compile=False)
probabilities = model.predict(preprocess("line.png")[np.newaxis])
print(decode(probabilities[0].argmax(-1)))

Results

Exact-line accuracy (whole line correct) and character error rate (CER) of the float model, on data it was not trained on:

Test set Samples Exact line CER
TS-TR official test split (real scene text) 2,078 45.33% 24.17%
Held-out synthetic + real + Zenodo lines 3,234 58.23% 12.61%
of which Zenodo (clean printed lines) 200 91.00% 1.61%
Small real-photo test set 66 19.70% 50.21%

int8 TFLite model: on the 3,993-row held-out split it reads 10.5% of lines exactly (CER 21.7%), against 55.7% for the float model. The quantization loss is large and unresolved, so treat the .tflite file as an experimental export.

Limitations

  • Printed text only; no handwriting, curved text or full pages.
  • Works best on clean, high-contrast lines; real scene text is still weak.
  • The int8 model loses most of the float model's accuracy (see above).
  • Text detection and line cropping must be done before this model runs.

Training data

Training/validation splits are group-disjoint (no font, background or source group appears in both).

License

Because the training data includes TS-TR (CC BY-NC 4.0), this model is released under Creative Commons Attribution-NonCommercial 4.0:

  • You may use, share and adapt the model for non-commercial purposes.
  • You must credit this model and the datasets listed above.
  • Commercial use is not permitted.

The training code is MIT-licensed: ErdemWilkinson/InviolusOCR.

Version

Trained 2026-10-09. Later versions of this model score higher (65% exact on TS-TR) but were trained with a dataset whose license is not stated, so they are not published here.

Downloads last month
40
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support