import torch import numpy as np from typing import Dict, Tuple import cv2 import utils import model_loader from config import settings def predict_character(char_tensor: torch.Tensor, models: Dict[str, torch.nn.Module]) -> str: """Predicts a single character using the Triage and Expert system.""" triage_model = models['triage'] with torch.no_grad(): triage_output = triage_model(char_tensor) _, predicted_class_idx = torch.max(triage_output, 1) expert_name = settings.TRIAGE_OUTPUT_MAP[predicted_class_idx.item()] expert_model = models[expert_name] expert_output = expert_model(char_tensor) _, predicted_char_idx = torch.max(expert_output, 1) offset = settings.EXPERT_LABEL_OFFSETS[expert_name] global_idx = predicted_char_idx.item() + offset return chr(global_idx) def process_image_data(image_data: np.ndarray, models: Dict[str, torch.nn.Module]) -> str: """Performs end-to-end OCR, now with intelligent word spacing.""" gray_image = cv2.cvtColor(image_data, cv2.COLOR_BGR2GRAY) _, binary_image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) bounding_boxes = utils.segment_characters(binary_image) if not bounding_boxes: return "" print(f"Found {len(bounding_boxes)} characters to recognize.") recognized_elements = [] previous_box = bounding_boxes[0] for i, box in enumerate(bounding_boxes): if i > 0: previous_x, previous_y, previous_w, previous_h = previous_box current_x, current_y, _, _ = box if current_y > (previous_y + previous_h * settings.NEWLINE_THRESHOLD_FACTOR): recognized_elements.append('\n') elif current_x > (previous_x + previous_w + (previous_w * settings.SPACE_THRESHOLD_FACTOR)): recognized_elements.append(' ') x, y, w, h = box char_crop = binary_image[y:y + h, x:x + w] char_tensor = utils.prepare_char_for_model(char_crop) predicted_char = predict_character(char_tensor, models) recognized_elements.append(predicted_char) previous_box = box return "".join(recognized_elements)