Views
No views yet
microsoft/trocr-base-handwritten on a custom dataset of 10,368 handwritten line images.1from transformers import TrOCRProcessor, VisionEncoderDecoderModel
2from PIL import Image
3import torch
4
5# Load model
6processor = TrOCRProcessor.from_pretrained("microsoft/trocr-base-handwritten")
7model = VisionEncoderDecoderModel.from_pretrained("abduazizovanozima7/uzbek-trocr-line-v1")
8
9device = "cuda" if torch.cuda.is_available() else "cpu"
10model.to(device)
11
12# Read image
13image = Image.open("line_image.png").convert("RGB")
14
15# OCR
16pixel_values = processor(image, return_tensors="pt").pixel_values.to(device)
17generated_ids = model.generate(pixel_values, max_new_tokens=128, num_beams=4)
18text = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
19
20print(text)1import cv2
2import numpy as np
3import torch
4from PIL import Image
5from transformers import TrOCRProcessor, VisionEncoderDecoderModel
6
7# Load model
8processor = TrOCRProcessor.from_pretrained("microsoft/trocr-base-handwritten")
9model = VisionEncoderDecoderModel.from_pretrained("abduazizovanozima7/uzbek-trocr-line-v1")
10device = "cuda" if torch.cuda.is_available() else "cpu"
11model.to(device)
12model.eval()
13
14def segment_lines(image_path):
15 """Split a full page image into individual text lines."""
16 img = cv2.imread(image_path)
17 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
18
19 # Binarize
20 binary = cv2.adaptiveThreshold(
21 gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
22 cv2.THRESH_BINARY_INV, 15, 10
23 )
24
25 # Horizontal projection profile
26 h_proj = np.sum(binary, axis=1) / 255
27 h, w = img.shape[:2]
28 threshold = w * 0.02
29
30 # Find text line regions
31 is_text = h_proj > threshold
32 lines = []
33 in_text = False
34 start = 0
35 for i in range(len(is_text)):
36 if is_text[i] and not in_text:
37 start = i
38 in_text = True
39 elif not is_text[i] and in_text:
40 if i - start >= 15:
41 lines.append((start, i))
42 in_text = False
43 if in_text and len(is_text) - start >= 15:
44 lines.append((start, len(is_text)))
45
46 # Crop each line with padding
47 cropped = []
48 for s, e in lines:
49 y1 = max(0, s - 10)
50 y2 = min(h, e + 10)
51 cropped.append(img[y1:y2, :])
52
53 return cropped
54
55def ocr_batch(line_images, batch_size=8):
56 """Run OCR on multiple line images in batches."""
57 results = []
58 for i in range(0, len(line_images), batch_size):
59 batch = line_images[i:i+batch_size]
60 pil_imgs = [Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) for img in batch]
61 pixel_values = processor(pil_imgs, return_tensors="pt").pixel_values.to(device)
62 with torch.no_grad():
63 ids = model.generate(pixel_values, max_new_tokens=128, num_beams=4)
64 texts = processor.batch_decode(ids, skip_special_tokens=True)
65 results.extend([t.strip() for t in texts])
66 return results
67
68def ocr_full_page(image_path):
69 """Full pipeline: image → lines → OCR → text."""
70 lines = segment_lines(image_path)
71 if not lines:
72 return ""
73 texts = ocr_batch(lines)
74 return "\n".join(texts)
75
76# Usage
77result = ocr_full_page("handwritten_page.jpg")
78print(result)| Parameter | Value |
|---|---|
| Base model | microsoft/trocr-base-handwritten |
| Dataset | 10,368 handwritten line images |
| Languages | Uzbek (Latin/Cyrillic), Russian |
| Epochs | 5 |
| Batch size | 16 |
| Learning rate | 5e-5 |
| GPU | NVIDIA P100 (Kaggle) |
| Final CER | 0.3395 |
| Final Loss | 1.6348 |
abduazizovanozima7/uzbek-line-handwriting-dataset1@misc{abduazizova2026uzbektrocr,
2 title={Uzbek Handwriting OCR with TrOCR},
3 author={Nozima Abduazizova},
4 year={2026},
5 publisher={Hugging Face},
6 url={https://huggingface.co/abduazizovanozima7/uzbek-trocr-line-v1}
7}