#!/usr/bin/env python3 """KOCR v5 — OCR 识别模块(简化版:原图直出,无预处理)""" import cv2 from paddleocr import PaddleOCR _ocr = None def get_ocr_instance(config: dict): """懒加载 PaddleOCR 实例""" global _ocr if _ocr is None: _ocr = PaddleOCR( use_angle_cls=config.get('use_angle_cls', True), lang=config.get('lang', 'ch'), use_gpu=config.get('use_gpu', False), show_log=config.get('show_log', False), det_db_thresh=config.get('det_db_thresh', 0.3), det_db_box_thresh=config.get('det_db_box_thresh', 0.5), det_db_unclip_ratio=config.get('det_db_unclip_ratio', 2.2), det_limit_side_len=config.get('max_side_len', 1600), det_db_score_mode=config.get('det_db_score_mode', 'slow'), min_size=config.get('min_size', 8), rec_drop_score=config.get('rec_drop_score', 0.5), ) return _ocr def run_ocr(image, ocr_config: dict, photo_type: str = 'normal') -> list: """对图像执行 OCR,返回 [(text, confidence, cx, cy, box), ...] 输入: image: numpy array (cv2.imread) 或 图像文件路径 ocr_config: dict(PaddleOCR 参数) photo_type: str — 照片类型,用于动态调参 返回: 排序后的 lines: [(text, conf, cx, cy, box), ...] 按 (y, x) 排序 """ # 根据照片类型动态调整 OCR 参数 config_override = dict(ocr_config) if photo_type == 'flash': config_override['det_db_thresh'] = config_override.get('det_db_thresh_flash', 0.18) elif photo_type == 'dark': config_override['det_db_thresh'] = config_override.get('det_db_thresh_dark', 0.25) elif photo_type == 'blurry': config_override['det_db_thresh'] = config_override.get('det_db_thresh_blurry', 0.2) # normal 保持默认 ocr = get_ocr_instance(config_override) # 支持 numpy array 和 文件路径 result = ocr(image) # PaddleOCR v2.8 返回格式多变,兼容处理 lines_raw = [] if result is None: return [] # tuple of 3: (boxes, texts, elapsed) if isinstance(result, tuple) and len(result) >= 2: boxes = result[0] texts = result[1] if boxes and texts: for box, (text, conf) in zip(boxes, texts): if conf < 0.4: continue cx = float((box[0][0] + box[2][0]) / 2) cy = float((box[0][1] + box[2][1]) / 2) lines_raw.append((text, conf, cx, cy, box)) # 旧版格式: list of [[box], (text, conf), ...] elif isinstance(result, list): for item in result: if isinstance(item, (list, tuple)) and len(item) >= 2: box = item[0] if isinstance(box, (list, tuple)) and len(box) >= 1: text, conf = item[1] if conf < 0.4: continue cx = float((box[0][0] + box[2][0]) / 2) cy = float((box[0][1] + box[2][1]) / 2) lines_raw.append((text, conf, cx, cy, box)) # 按 y 排序(从上到下),同 y 按 x 排序(从左到右) lines_raw.sort(key=lambda l: (l[3], l[2])) return lines_raw