| import torch |
| import numpy as np |
| import cv2 |
| import os |
| import argparse |
| from pdf2image import convert_from_path |
|
|
| from config import settings |
| import utils |
| from model_loader import load_all_models |
|
|
|
|
| def predict_character(char_tensor, models): |
| """Predicts a single character using the Triage and Expert system with the CORRECTED mapping.""" |
| with torch.no_grad(): |
| triage_output = models['triage'](char_tensor) |
| _, triage_idx = torch.max(triage_output, 1) |
| triage_decision = settings.TRIAGE_OUTPUT_MAP[triage_idx.item()] |
|
|
| expert_model = models[triage_decision] |
| expert_output = expert_model(char_tensor) |
| _, expert_idx = torch.max(expert_output, 1) |
|
|
| character_map = settings.EXPERT_CHARACTER_MAPS[triage_decision] |
| final_prediction = character_map.get(expert_idx.item(), '?') |
|
|
| return final_prediction |
|
|
|
|
| def run_ocr_pipeline(image_data, models): |
| """Runs the full OCR pipeline with smarter sorting and word-gap detection.""" |
| 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 box in bounding_boxes: |
| prev_x, prev_y, prev_w, prev_h = previous_box |
| curr_x, curr_y, _, _ = box |
|
|
| if curr_y > (prev_y + prev_h * settings.NEWLINE_THRESHOLD_FACTOR): |
| recognized_elements.append('\n') |
| elif curr_x > (prev_x + prev_w + (prev_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) |
|
|
|
|
| def main(): |
| parser = argparse.ArgumentParser(description="Run the final, corrected OCR on an image or PDF.") |
| parser.add_argument("file_path", type=str, help="The path to the input image or PDF file.") |
| parser.add_argument("--page", type=int, default=12, help="Page number to process for a PDF.") |
| args = parser.parse_args() |
|
|
| try: |
| models = load_all_models() |
| except FileNotFoundError as e: |
| print(f"Error: {e}") |
| return |
|
|
| if not os.path.exists(args.file_path): |
| print(f"Error: Input file not found at '{args.file_path}'") |
| return |
|
|
| try: |
| if args.file_path.lower().endswith('.pdf'): |
| print(f"Processing PDF file, page {args.page}...") |
| poppler_path = os.path.join(settings.POPPLER_PATH, "bin") if settings.POPPLER_PATH else None |
| pil_image = \ |
| convert_from_path(args.file_path, first_page=args.page, last_page=args.page, poppler_path=poppler_path)[0] |
| image_data = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR) |
| else: |
| image_data = cv2.imread(args.file_path) |
|
|
| final_text = run_ocr_pipeline(image_data, models) |
|
|
| print("\n" + "=" * 50) |
| print(" FINAL RECOGNIZED TEXT") |
| print("=" * 50) |
| print(final_text) |
| print("=" * 50) |
|
|
| except Exception as e: |
| print(f"\nAn error occurred: {e}") |
|
|
|
|
| if __name__ == '__main__': |
| main() |