# -*- coding: utf-8 -*- """ 配置管理模块 集中管理所有可配置参数,便于维护和扩展 """ from dataclasses import dataclass, field from typing import Optional, Tuple, List from enum import Enum class InputMode(Enum): """输入模式枚举""" SINGLE = "single" # 单张图片 BATCH = "batch" # 多张图片列表 DIRECTORY = "directory" # 目录批量 @dataclass class InputConfig: """ 图片输入配置 Attributes: mode: 输入模式 image_path: 单张图片路径 image_paths: 多张图片路径列表 directory: 图片目录路径 pattern: 文件匹配模式(如 "*.jpg") recursive: 是否递归搜索子目录 """ mode: InputMode = InputMode.SINGLE image_path: Optional[str] = None image_paths: Optional[List[str]] = None directory: Optional[str] = None pattern: Optional[str] = None recursive: bool = False def __post_init__(self): """参数校验""" if self.mode == InputMode.SINGLE and not self.image_path: raise ValueError("单张图片模式下必须指定 image_path") if self.mode == InputMode.BATCH and not self.image_paths: raise ValueError("批量模式下必须指定 image_paths") if self.mode == InputMode.DIRECTORY and not self.directory: raise ValueError("目录模式下必须指定 directory") @dataclass class ROIConfig: """ 感兴趣区域(ROI)配置 使用归一化坐标 (0.0 ~ 1.0),便于适配不同分辨率 Attributes: enabled: 是否启用 ROI 裁剪 x_ratio: ROI 左上角 x 坐标比例 y_ratio: ROI 左上角 y 坐标比例 width_ratio: ROI 宽度比例 height_ratio: ROI 高度比例 """ enabled: bool = False x_ratio: float = 0.1 y_ratio: float = 0.1 width_ratio: float = 0.8 height_ratio: float = 0.8 def get_roi_rect(self, frame_width: int, frame_height: int) -> Tuple[int, int, int, int]: """ 根据帧尺寸计算实际 ROI 矩形 Args: frame_width: 帧宽度 frame_height: 帧高度 Returns: (x, y, width, height) 像素坐标 """ x = int(frame_width * self.x_ratio) y = int(frame_height * self.y_ratio) width = int(frame_width * self.width_ratio) height = int(frame_height * self.height_ratio) return x, y, width, height @dataclass class OCRConfig: """ OCR 引擎配置 (适配 PaddleOCR 2.x API) Attributes: lang: 识别语言,支持 "ch"(中文), "en"(英文) 等 use_angle_cls: 是否启用方向分类器 use_gpu: 是否使用 GPU 加速 det_db_thresh: 文本检测阈值 det_db_box_thresh: 检测框阈值 drop_score: 低于此置信度的结果将被过滤 show_log: 是否显示 PaddleOCR 日志 det_model_dir: 检测模型目录路径 rec_model_dir: 识别模型目录路径 cls_model_dir: 分类模型目录路径 """ lang: str = "ch" use_angle_cls: bool = True use_gpu: bool = False det_db_thresh: float = 0.3 det_db_box_thresh: float = 0.5 drop_score: float = 0.5 show_log: bool = False det_model_dir: Optional[str] = None rec_model_dir: Optional[str] = None cls_model_dir: Optional[str] = None @dataclass class PipelineConfig: """ OCR 处理管道配置 Attributes: roi: ROI 配置 """ roi: ROIConfig = field(default_factory=ROIConfig) @dataclass class VisualizeConfig: """ 可视化配置 Attributes: show_window: 是否显示可视化窗口 window_name: 窗口名称 box_color: 文本框颜色 (B, G, R) box_thickness: 文本框线宽 text_color: 文字颜色 (B, G, R) text_scale: 文字缩放比例 text_thickness: 文字线宽 show_confidence: 是否在文字旁显示置信度 font_path: 中文字体路径,None 则使用 OpenCV 默认字体 """ show_window: bool = False window_name: str = "OCR Result" box_color: Tuple[int, int, int] = (0, 255, 0) box_thickness: int = 2 text_color: Tuple[int, int, int] = (0, 0, 255) text_scale: float = 0.6 text_thickness: int = 1 show_confidence: bool = True font_path: Optional[str] = None @dataclass class OutputConfig: """ 输出配置 Attributes: output_dir: 输出目录路径 save_json: 是否保存 JSON 结果 save_image: 是否保存标注后的图片 json_filename: JSON 文件名模板 image_suffix: 标注图片后缀 """ output_dir: Optional[str] = None save_json: bool = True save_image: bool = False json_filename: str = "ocr_result.json" image_suffix: str = "_ocr" @dataclass class Config: """ 全局配置类,聚合所有配置模块 Attributes: input: 输入配置 ocr: OCR 引擎配置 pipeline: 处理管道配置 visualize: 可视化配置 output: 输出配置 """ input: Optional[InputConfig] = None ocr: OCRConfig = field(default_factory=OCRConfig) pipeline: PipelineConfig = field(default_factory=PipelineConfig) visualize: VisualizeConfig = field(default_factory=VisualizeConfig) output: OutputConfig = field(default_factory=OutputConfig) @classmethod def default(cls) -> "Config": """创建默认配置""" return cls() @classmethod def for_single_image(cls, image_path: str) -> "Config": """ 创建单张图片模式的配置 Args: image_path: 图片路径 """ config = cls() config.input = InputConfig( mode=InputMode.SINGLE, image_path=image_path ) return config @classmethod def for_directory(cls, directory: str, pattern: Optional[str] = None, recursive: bool = False) -> "Config": """ 创建目录批量模式的配置 Args: directory: 目录路径 pattern: 文件匹配模式 recursive: 是否递归搜索 """ config = cls() config.input = InputConfig( mode=InputMode.DIRECTORY, directory=directory, pattern=pattern, recursive=recursive ) return config @classmethod def for_batch(cls, image_paths: List[str]) -> "Config": """ 创建批量图片模式的配置 Args: image_paths: 图片路径列表 """ config = cls() config.input = InputConfig( mode=InputMode.BATCH, image_paths=image_paths ) return config