'commit'
This commit is contained in:
113
Util/PaddleOCRKit.py
Normal file
113
Util/PaddleOCRKit.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# coding=utf-8
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import cv2
|
||||
import numpy as np
|
||||
from paddleocr import PaddleOCR
|
||||
from Util.OcrParser import OcrParser
|
||||
|
||||
# Initialize logger
|
||||
logger = logging.getLogger("PaddleOCRKit")
|
||||
|
||||
class PaddleOCRKit:
|
||||
_instance = None
|
||||
_ocr = None
|
||||
|
||||
def __new__(cls):
|
||||
if cls._instance is None:
|
||||
cls._instance = super(PaddleOCRKit, cls).__new__(cls)
|
||||
cls._instance._initialize_model()
|
||||
return cls._instance
|
||||
|
||||
def _initialize_model(self):
|
||||
"""
|
||||
Initialize the PaddleOCR model once.
|
||||
Using PP-OCRv4 mobile model for speed.
|
||||
"""
|
||||
try:
|
||||
logger.info("Initializing PaddleOCR (PP-OCRv4 Mobile)...")
|
||||
# use_angle_cls is deprecated, using use_textline_orientation instead
|
||||
# ocr_version='PP-OCRv4' defaults to mobile model
|
||||
self._ocr = PaddleOCR(
|
||||
use_textline_orientation=True,
|
||||
lang="ch",
|
||||
ocr_version='PP-OCRv4'
|
||||
)
|
||||
logger.info("PaddleOCR initialized successfully.")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize PaddleOCR: {e}")
|
||||
self._ocr = None
|
||||
|
||||
def recognize(self, image_input):
|
||||
"""
|
||||
Recognize text from an image and parse it into structured data.
|
||||
|
||||
:param image_input: Image path (str) or OpenCV image object (numpy.ndarray)
|
||||
:return: Parsed structured data (dict) or None if failed
|
||||
"""
|
||||
if self._ocr is None:
|
||||
logger.error("PaddleOCR model is not initialized.")
|
||||
return None
|
||||
|
||||
try:
|
||||
# PaddleOCR handles both path and ndarray
|
||||
# predict() is recommended over ocr() in newer versions, but ocr() is the stable high-level API
|
||||
# We use ocr() as in the test script which worked well.
|
||||
# cls=True was causing issues in test, but use_textline_orientation=True in init handles it?
|
||||
# actually in test script: ocr = PaddleOCR(use_textline_orientation=True, ...)
|
||||
# result = ocr.ocr(image_path) -> this worked, but gave a warning about predict.
|
||||
# Let's stick to ocr() for now as it returns the structure we expect.
|
||||
|
||||
result = self._ocr.ocr(image_input)
|
||||
|
||||
ocr_text_lines = []
|
||||
|
||||
# Handle result structure
|
||||
if not result:
|
||||
logger.warning("OCR returned empty result.")
|
||||
else:
|
||||
res = result[0]
|
||||
if res is None:
|
||||
logger.warning("OCR result[0] is None.")
|
||||
elif isinstance(res, dict) and 'rec_texts' in res:
|
||||
# New PaddleOCR / Paddlex format
|
||||
ocr_text_lines = res['rec_texts']
|
||||
elif isinstance(res, list):
|
||||
# Legacy PaddleOCR format
|
||||
for line in res:
|
||||
# line structure: [[points], (text, confidence)]
|
||||
if len(line) >= 2 and isinstance(line[1], (tuple, list)):
|
||||
ocr_text_lines.append(line[1][0])
|
||||
|
||||
# --- 关键:打印原始识别内容 ---
|
||||
if ocr_text_lines:
|
||||
logger.info(f"🔍 OCR 原始识别文字 ({len(ocr_text_lines)} 行):")
|
||||
for i, line in enumerate(ocr_text_lines):
|
||||
logger.info(f" [{i+1}] {line}")
|
||||
else:
|
||||
logger.info("No text detected.")
|
||||
return {}
|
||||
|
||||
# Parse with Regex Parser
|
||||
parsed_data = OcrParser.parse(ocr_text_lines)
|
||||
|
||||
# --- 关键:打印解析后的结构化数据 ---
|
||||
if parsed_data:
|
||||
logger.info("📦 OCR 解析结果 (JSON):")
|
||||
logger.info(f" {parsed_data}")
|
||||
|
||||
return parsed_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error during OCR recognition: {e}")
|
||||
return None
|
||||
|
||||
# Global instance for easy access
|
||||
_kit_instance = None
|
||||
|
||||
def get_ocr_kit():
|
||||
global _kit_instance
|
||||
if _kit_instance is None:
|
||||
_kit_instance = PaddleOCRKit()
|
||||
return _kit_instance
|
||||
Reference in New Issue
Block a user