teuchi's picture
Update ocr.py
3d898fb verified
Raw History Blame Contribute Delete
3.76 kB
import os
import torch
from PIL import Image
from model import get_model
from dataset import decode_prediction, get_val_transforms, ALPHABET
from word_detector import split_into_words
class OCR:
def __init__(
self,
checkpoint_path: str = "best_model.pth", # По умолчанию смотрим в корень для Hugging Face
device: str = None,
):
self.device = device or ("cuda" if torch.cuda.is_available() else "cpu")
# Если переданный путь не существует, но файл есть в корне — используем корень
if not os.path.exists(checkpoint_path) and os.path.exists("best_model.pth"):
checkpoint_path = "best_model.pth"
elif not os.path.exists(checkpoint_path) and os.path.exists("../models/best_model.pth"):
checkpoint_path = "../models/best_model.pth"
num_classes = len(ALPHABET) + 1
self.model = get_model(num_classes=num_classes, device=self.device)
print(f"[OCR] загружаем веса: {checkpoint_path}")
checkpoint = torch.load(checkpoint_path, map_location=self.device)
# Поддержка загрузки как чистого state_dict, так и сохраненного через чекпоинт словаря
if "model_state_dict" in checkpoint:
self.model.load_state_dict(checkpoint["model_state_dict"])
else:
self.model.load_state_dict(checkpoint)
self.model.eval()
print(f"[OCR] точность модели при обучении: {checkpoint.get('accuracy', 'неизвестно') if isinstance(checkpoint, dict) else 'неизвестно'}")
self.transform = get_val_transforms(img_height=32, img_width=128)
@torch.no_grad()
def _recognize_single_word(self, image: Image.Image) -> str:
image_tensor = self.transform(image.convert("RGB")).unsqueeze(0).to(self.device)
logits = self.model(image_tensor) # [T, B, C]
preds = logits.argmax(dim=2).permute(1, 0) # [B, T]
text = decode_prediction(preds[0].tolist())
return text
def recognize(self, image_path: str) -> str:
image = Image.open(image_path)
return self._recognize_single_word(image)
def recognize_line(self, image_path: str, **detector_kwargs) -> str:
image = Image.open(image_path)
word_images = split_into_words(image, **detector_kwargs)
if not word_images:
return self._recognize_single_word(image)
words = [self._recognize_single_word(w) for w in word_images]
return " ".join(words)
@torch.no_grad()
def recognize_batch(self, image_paths: list[str]) -> list[str]:
images = []
for path in image_paths:
image = Image.open(path).convert("RGB")
images.append(self.transform(image))
batch = torch.stack(images).to(self.device)
logits = self.model(batch)
preds = logits.argmax(dim=2).permute(1, 0)
results = [decode_prediction(seq.tolist()) for seq in preds]
return results
if __name__ == "__main__":
# Для локальных тестов проверяет обе папки
default_path = "best_model.pth" if os.path.exists("best_model.pth") else "../models/best_model.pth"
ocr = OCR(checkpoint_path=default_path)
test_image = "test_word.jpg"
try:
result = ocr.recognize_line(test_image)
print(f"\nРаспознанный текст: '{result}'")
except FileNotFoundError:
print(f"\nКартинка '{test_image}' не найдена.")
print("укажи нормальный путь.")