File size: 2,922 Bytes
88acb4e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5de5b2e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
---
language:
  - uk
license: mit
tags:
  - ocr
  - object-detection
  - image-classification
  - passport
  - ukraine
  - crnn
  - yolo
  - dot-matrix
pipeline_tag: image-to-text
---

# Ukrainian Passport Series/Number OCR

Automatic recognition of the series and number from Ukrainian internal passports (старого зразка).

The system reads the dot-matrix perforated 8-character string — **2 Cyrillic letters + 6 digits** — from a full passport photo.

```
НР 430098
^^─────── series  (one of: А В Е К М Н О Р С Т И Ю)
   ^^^^^^ number  (6 digits)
```

---

## Pipeline

```
passport image


 YOLO detector          ← finds the dotted strip (class: "Dotted")


  preprocessing         ← grayscale → denoise → Otsu binarisation


  CRNN recognizer       ← CNN + biGRU + 8 position heads → "НР430098"


{"series": "НР", "number": "430098", "confidence": 0.97}
```

---

## Quick start

```bash
pip install -r requirements.txt

python pipeline.py passport.jpg
python pipeline.py passport.jpg --show
```

Output:
```
Result:     НР430098
Series:     НР
Number:     430098
Confidence: 97.3%  [OK]
```

---

## Python API

```python
from pipeline import PassportOCR

ocr    = PassportOCR()
result = ocr("passport.jpg")

print(result["full"])        # "НР430098"
print(result["series"])      # "НР"
print(result["number"])      # "430098"
print(result["confidence"])  # 0.9734
print(result["readable"])    # True
```

---

## Models

| Model | Architecture | Purpose |
|-------|-------------|---------|
| `models/detector.pt` | YOLOv8n fine-tuned | Locates the dotted strip on the passport page |
| `models/recognizer.pth` | CNN + biGRU | Reads the 8-character string from the strip |

The recognizer is trained on **80 000 synthetic images** generated with a custom dot-matrix Cyrillic font, with heavy augmentation (rotation ±20°, perspective, noise, donut dots, shadow stripes, inversion).

Val character accuracy: **96.1%** | Full-string accuracy on real passports: **~95%**

---

## Training

```bash
# Generate synthetic training data
cd train
python generate_sequences.py --n-samples 80000

# Train the recognizer
python train_sequence.py --epochs 35 --batch-size 64
```

To retrain the YOLO detector, annotate passport images with the "Dotted" class and run standard YOLOv8 training.

---

## Series letters

Valid Ukrainian passport series letters: `А В Е К М Н О Р С Т И Ю`

The model enforces positional constraints: positions 0–1 accept only series letters, positions 2–7 accept only digits.

---

## Limitations

- Works on Ukrainian **internal** passports (старого зразка, до 2016 року)
- Requires the dot-matrix strip to be visible and not heavily physically damaged
- Very low contrast or extreme blur may result in `readable: False`