Text Type Classifier (Handwritten vs. Printed) β€” ResNet-18

A lightweight binary image classifier that distinguishes handwritten from printed text on cropped text-line images. Built as a preprocessing step for an HTR (Handwritten Text Recognition) pipeline, where scans mix typewritten/printed content with handwriting, and each type needs to be routed to a different recognition model.

Trained on text-line crops in modern Russian, pre-reform (old orthography) Russian, Belarusian, English, Polish, German, and other European languages.

Developed as part of the Zhnivo initiative β€” a project building genealogical databases from Belarusian archival records.

Training Data

~73,000 text-line crops from scanned archival documents:

Split Handwritten Printed Total
Train 25,665 36,277 61,942
Validation 4,544 6,506 11,050

Model Details

  • Architecture: ResNet-18 (torchvision), final fully-connected layer replaced with a 2-class head
  • Task: Binary image classification
  • Classes: 0 β†’ handwritten, 1 β†’ printed
  • Input: RGB text-line crop, resized to 128Γ—512 (HΓ—W), normalized with ImageNet mean/std
  • Framework: PyTorch / torchvision
  • File: resnet18_text_classifier_final.pth (state dict)

Intended Use

  • Dataset preparation for OCR/HTR training β€” automatically splitting large collections of text-line crops into handwritten and printed subsets when building training datasets for TrOCR, Tesseract, PaddleOCR, and similar recognition systems. This removes the need for manual sorting and keeps each recognizer's training data clean of the other text type.
  • Inference-time routing β€” sorting text-line crops (e.g., produced by a text-detection stage) into handwritten and printed streams so each can be sent to a specialized recognizer.
  • Corpus analysis β€” estimating the share of handwritten vs. printed content in scanned document collections.

Trained on line-level crops from scanned archival documents; works best on horizontal text-line images rather than full pages or isolated characters.

Usage

import torch
import torch.nn as nn
from torchvision import models, transforms
from PIL import Image

CLASS_MAP = {0: "handwritten", 1: "printed"}

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

model = models.resnet18(weights=None)
model.fc = nn.Linear(model.fc.in_features, 2)
model.load_state_dict(torch.load("resnet18_text_classifier_final.pth", map_location=device))
model.to(device).eval()

transform = transforms.Compose([
    transforms.Resize((128, 512)),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
])

img = Image.open("line_crop.jpg").convert("RGB")
with torch.no_grad():
    logits = model(transform(img).unsqueeze(0).to(device))
    pred = logits.argmax(1).item()

print(CLASS_MAP[pred])

Limitations

  • Trained on European languages in Cyrillic and Latin scripts; accuracy may drop on other scripts (e.g., CJK, Arabic) or low-quality photos.
  • Expects text-line crops; full-page images or non-text regions are out of scope.
  • Binary output only β€” mixed lines (printed form with handwritten fill-in within one crop) are assigned to a single class.

Files

File Description
resnet18_text_classifier_final.pth Final model weights (state dict)
best_model.pth Best checkpoint by validation loss
class_indices.json Class-to-index mapping
loss_history.png Training loss curves

License

MIT β€” free to use, modify, and redistribute, including commercially. The ResNet-18 architecture and torchvision implementation are BSD-3-Clause licensed (PyTorch/torchvision), which is compatible with this release.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support