import cv2 import numpy as np import base64 import logging import json from typing import Optional from fastapi import APIRouter, UploadFile, File, Form, Query from models.schemas import ImageDetectionResult router = APIRouter() logger = logging.getLogger(__name__) @router.post("/detect/image", response_model=ImageDetectionResult) async def detect_image( file: UploadFile = File(...), model_id: str = Query("fire_detection"), confidence: float = Query(0.5), iou: float = Query(0.45), algorithm_config: Optional[str] = Query(None, description="算法配置JSON字符串") ): """ 图片检测接口 Args: algorithm_config: 算法配置JSON,例如: { "enable_stationary_detection": true, "enable_loitering_detection": false, "stationary_threshold": 10.0, "position_tolerance": 50, "loitering_threshold": 300.0, "movement_threshold": 5.0 } """ from main import model_service from services.detection_service import DetectionService detection_service = DetectionService(model_service) # 解析算法配置 algo_config = None if algorithm_config: try: algo_config = json.loads(algorithm_config) except json.JSONDecodeError as e: logger.warning(f"算法配置解析失败: {e}") try: contents = await file.read() nparr = np.frombuffer(contents, np.uint8) frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR) if frame is None: return ImageDetectionResult( success=False, message="无法读取图片", data={} ) result = await detection_service.detect_image( frame, model_id, confidence, iou, algorithm_config=algo_config ) if result['success']: annotated_frame = detection_service.draw_detections( frame, result['detections'], algorithm_config=algo_config ) # 将标注后的图片转换为 base64 _, buffer = cv2.imencode('.jpg', annotated_frame) img_base64 = base64.b64encode(buffer).decode('utf-8') return ImageDetectionResult( success=True, message="检测完成", data={ "detections": result['detections'], "image_base64": img_base64, "stats": result['stats'], "alerts": result.get('alerts', []), "behavior_stats": result.get('behavior_stats', {}) } ) else: return ImageDetectionResult( success=False, message=result['message'], data={} ) except Exception as e: logger.error(f"图片检测失败: {e}") return ImageDetectionResult( success=False, message=f"检测失败: {str(e)}", data={} ) @router.get("/algorithms/config") async def get_algorithm_config(): """获取算法配置选项""" return { "algorithms": [ { "id": "stationary_detection", "name": "静止检测", "description": "检测人员在同一位置静止停留", "params": [ { "name": "stationary_threshold", "label": "静止阈值", "type": "number", "default": 10.0, "min": 1.0, "max": 300.0, "unit": "秒", "description": "超过此时间视为静止" }, { "name": "position_tolerance", "label": "位置容差", "type": "number", "default": 50, "min": 10, "max": 200, "unit": "像素", "description": "位置匹配容差范围" } ] }, { "id": "loitering_detection", "name": "徘徊检测", "description": "检测人员长时间停留(需要跟踪ID)", "params": [ { "name": "loitering_threshold", "label": "徘徊阈值", "type": "number", "default": 300.0, "min": 60.0, "max": 1800.0, "unit": "秒", "description": "超过此时间视为徘徊" }, { "name": "movement_threshold", "label": "移动阈值", "type": "number", "default": 5.0, "min": 1.0, "max": 50.0, "unit": "像素", "description": "小于此移动视为静止" } ] } ] }