import os from dataclasses import dataclass def _get_str(name: str, default: str) -> str: return os.getenv(name, default) def _get_int(name: str, default: int) -> int: value = os.getenv(name) if value is None or value == "": return default return int(value) def _get_float(name: str, default: float) -> float: value = os.getenv(name) if value is None or value == "": return default return float(value) def _get_bool(name: str, default: bool) -> bool: value = os.getenv(name) if value is None or value == "": return default return value.lower() in ["1", "true", "yes", "y"] def _get_int_list(name: str, default: str) -> list[int]: value = os.getenv(name, default) if value is None or value.strip() == "": return [] return [int(x.strip()) for x in value.split(",") if x.strip() != ""] @dataclass(frozen=True) class Settings: # Docker 内默认模型路径 det_model_path: str = _get_str( "DET_MODEL_PATH", "/app/models/YNDC_20251010_yolov5_optimize.onnx", ) cls_model_path: str = _get_str( "CLS_MODEL_PATH", "/app/models/HHK_20260525_mmcls_optimize.onnx", ) det_classes_path: str = _get_str( "DET_CLASSES_PATH", "/app/models/YNDC_20251010_yolov5_optimize.txt", ) cls_classes_path: str = _get_str( "CLS_CLASSES_PATH", "/app/models/HHK_20260525_mmcls_optimize.txt", ) # 输入尺寸 det_img_size: int = _get_int("DET_IMG_SIZE", 640) cls_img_size: int = _get_int("CLS_IMG_SIZE", 224) # YOLO 检测阈值 det_conf_thres: float = _get_float("DET_CONF_THRES", 0.25) det_iou_thres: float = _get_float("DET_IOU_THRES", 0.45) # 目标裁剪外扩比例 crop_padding_ratio: float = _get_float("CROP_PADDING_RATIO", 0.08) # 最多保留目标数量 max_detections: int = _get_int("MAX_DETECTIONS", 50) # 当前环境没有 onnxruntime-gpu 时,建议用 cpu device: str = _get_str("DEVICE", "cpu") # 输出目录 output_dir: str = _get_str("OUTPUT_DIR", "/app/runs") image_output_subdir: str = _get_str("IMAGE_OUTPUT_SUBDIR", "images") video_output_subdir: str = _get_str("VIDEO_OUTPUT_SUBDIR", "video") # 视频抽帧间隔 video_sample_interval: int = _get_int("VIDEO_SAMPLE_INTERVAL", 2) # 是否保存画框后视频 save_annotated_video: bool = _get_bool("SAVE_ANNOTATED_VIDEO", True) # 只保留 YOLO 类别 0,也就是“鸟” target_det_class_ids: list[int] = None # 视频平滑参数 smooth_video_boxes: bool = _get_bool("SMOOTH_VIDEO_BOXES", True) # 未处理帧或短暂漏检时,最多复用多少帧上一结果 smooth_hold_frames: int = _get_int("SMOOTH_HOLD_FRAMES", 3) # 框坐标平滑系数,越大越稳定,但响应越慢 box_smooth_alpha: float = _get_float("BOX_SMOOTH_ALPHA", 0.25) def __post_init__(self): object.__setattr__( self, "target_det_class_ids", _get_int_list("TARGET_DET_CLASS_IDS", "0"), ) settings = Settings()