From cdf228fe56081ad2fbf3856283ac45ed9466e714 Mon Sep 17 00:00:00 2001 From: zimoyin <2556608754@qq.com> Date: Sat, 10 Jan 2026 18:03:18 +0800 Subject: [PATCH] =?UTF-8?q?feat(app):=20=E9=9B=86=E6=88=90loguru=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E7=B3=BB=E7=BB=9F=E5=B9=B6=E4=BC=98=E5=8C=96=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在app.py中引入loguru并配置日志轮转、异步输出等功能 - 添加全局日志初始化函数和程序启动/退出日志记录 - 将所有print语句替换为logger.info/error/debug/warning方法 - 在data_source.py中添加模型加载和视频打开的日志记录 - 在各个处理器中集成日志记录器实例并记录处理状态 - 修改处理器模块导入路径以符合相对导入规范 - 在requirements.txt中添加loguru依赖包 - 统一异常处理的日志记录方式,便于调试和监控 --- app.py | 26 ++++++++++++++++++---- pipeline/base_processor.py | 4 ++++ pipeline/data_source.py | 7 +++++- pipeline/handler/DrawDirectionProcessor.py | 6 ++--- pipeline/handler/DrawGraffitiProcessor.py | 4 ++-- pipeline/handler/DrawObjectBoxProcessor.py | 4 ++-- pipeline/handler/GraffitiProcessor.py | 4 ++-- pipeline/handler/ResultLogger.py | 4 ++-- pipeline/handler/RetrogradeProcessor.py | 6 ++--- pipeline/handler/graffiti_visualizer.py | 4 ++-- pipeline/pipeline.py | 18 +++++++++------ requirements.txt | 3 ++- 12 files changed, 61 insertions(+), 29 deletions(-) diff --git a/app.py b/app.py index c8df3d1..364c60c 100644 --- a/app.py +++ b/app.py @@ -1,4 +1,5 @@ import asyncio +from loguru import logger from yolo_gs.pipeline.handler.DrawDirectionProcessor import DrawDirectionProcessor from yolo_gs.pipeline.handler.DrawGraffitiProcessor import DrawGraffitiProcessor @@ -12,8 +13,23 @@ import cv2 from yolo_gs.pipeline.data_source import video_yolo_iterator from yolo_gs.pipeline.pipeline import Pipeline + +def init_logger(): + logger.add( + "logs/yolo_gs.log", + rotation="100 MB", # 原有配置:日志文件达100MB轮转 + level="DEBUG", # 原有配置:记录DEBUG及以上级别 + enqueue=True, # 开启异步输出(关键参数) + backtrace=True, # 记录完整异常堆栈(包括第三方库) + diagnose=True, # 显示异常时的变量值(便于调试,生产环境可设为False) + ) + + # ===================== 测试运行 ===================== if __name__ == "__main__": + init_logger() + logger.info("开始运行YOLO涂鸦车道检测系统") + # 1. 创建管道 pipeline = Pipeline() @@ -25,12 +41,12 @@ if __name__ == "__main__": pipeline.add_processor(DrawObjectBoxProcessor()) pipeline.add_processor(ResultLogger(name="结果日志器")) - # 4. 构建视频+YOLO跟踪迭代器(替换为你的视频路径,或0使用摄像头) video_path = "123.mp4" # 或 0 (摄像头) try: + logger.info(f"开始处理视频: {video_path}") # 使用跟踪迭代器,可以获取对象ID - data_iter = video_yolo_iterator(video_path, model_path="yolo11s.pt",tracker="botsort.yaml", device="0") + data_iter = video_yolo_iterator(video_path, model_path="yolo11s.pt", tracker="botsort.yaml", device="0") # 5. 运行管道,迭代处理数据 for processed_data in pipeline.run(data_iter): @@ -40,8 +56,10 @@ if __name__ == "__main__": # 直接显示经过管道处理后的帧,其中已经包含了绘制处理器的效果 cv2.imshow("YOLO Tracking Pipeline", frame) if cv2.waitKey(1) & 0xFF == ord('q'): + logger.info("用户请求退出程序") break except Exception as e: - print(f"运行出错: {e}") + logger.error(f"运行出错: {e}") finally: - cv2.destroyAllWindows() \ No newline at end of file + cv2.destroyAllWindows() + logger.info("程序结束运行") diff --git a/pipeline/base_processor.py b/pipeline/base_processor.py index 5581f50..f6a0773 100644 --- a/pipeline/base_processor.py +++ b/pipeline/base_processor.py @@ -1,3 +1,4 @@ +from loguru import logger from abc import ABC, abstractmethod import asyncio from .pipeline_data import PipelineData @@ -7,6 +8,9 @@ class BaseProcessor(ABC): """所有处理器的抽象基类,定义统一的处理接口""" def __init__(self, name: str): self.name = name # 处理器名称(便于日志/调试) + # 初始化日志记录器 + self.logger = logger + self.logger.debug(f"处理器 {self.name} 已初始化") @abstractmethod def process(self, data: PipelineData) -> PipelineData: diff --git a/pipeline/data_source.py b/pipeline/data_source.py index 11327a7..1a3e0e8 100644 --- a/pipeline/data_source.py +++ b/pipeline/data_source.py @@ -1,3 +1,4 @@ +from loguru import logger from typing import Iterator import cv2 from ultralytics import YOLO @@ -16,15 +17,18 @@ def video_yolo_iterator(video_path: str, model_path: str = "yolov8n.pt", tracker """ # 加载YOLO模型 model = YOLO(model_path) + logger.info(f"已加载YOLO模型: {model_path}") # 打开视频 cap = cv2.VideoCapture(video_path) if not cap.isOpened(): + logger.error(f"无法打开视频: {video_path}") raise ValueError(f"无法打开视频: {video_path}") frame_idx = 0 try: # 使用 model.track 替代 model 进行跟踪检测 results_stream = model.track(source=video_path, tracker=tracker, device=device, stream=True) + logger.info(f"已开始跟踪视频: {video_path}") last_data = PipelineData() for r in results_stream: # 迭代跟踪结果 @@ -67,6 +71,7 @@ def video_yolo_detect_iterator(video_path: str, model_path: str = "yolov8n.pt", # 打开视频 cap = cv2.VideoCapture(video_path) if not cap.isOpened(): + logger.error(f"无法打开视频: {video_path}") raise ValueError(f"无法打开视频: {video_path}") frame_idx = 0 @@ -94,4 +99,4 @@ def video_yolo_detect_iterator(video_path: str, model_path: str = "yolov8n.pt", frame_idx += 1 finally: # 确保视频流关闭 - cap.release() + cap.release() \ No newline at end of file diff --git a/pipeline/handler/DrawDirectionProcessor.py b/pipeline/handler/DrawDirectionProcessor.py index 898067f..98db489 100644 --- a/pipeline/handler/DrawDirectionProcessor.py +++ b/pipeline/handler/DrawDirectionProcessor.py @@ -2,8 +2,8 @@ import cv2 import numpy as np import math from collections import deque -from yolo_gs.pipeline.base_processor import BaseProcessor -from yolo_gs.pipeline.pipeline_data import PipelineData +from ..base_processor import BaseProcessor +from ..pipeline_data import PipelineData class DrawDirectionProcessor(BaseProcessor): @@ -96,7 +96,7 @@ class DrawDirectionProcessor(BaseProcessor): self._draw_track_info(vis, track_id, (center_x, center_y)) except Exception as e: - print(f"Error processing box: {e}") + self.logger.error(f"Error processing box: {e}") continue # 清理长时间未出现的track diff --git a/pipeline/handler/DrawGraffitiProcessor.py b/pipeline/handler/DrawGraffitiProcessor.py index c8845b0..97736ef 100644 --- a/pipeline/handler/DrawGraffitiProcessor.py +++ b/pipeline/handler/DrawGraffitiProcessor.py @@ -1,8 +1,8 @@ import cv2 import numpy as np import math -from yolo_gs.pipeline.base_processor import BaseProcessor -from yolo_gs.pipeline.pipeline_data import PipelineData +from ..base_processor import BaseProcessor +from ..pipeline_data import PipelineData class DrawGraffitiProcessor(BaseProcessor): diff --git a/pipeline/handler/DrawObjectBoxProcessor.py b/pipeline/handler/DrawObjectBoxProcessor.py index 220e3e2..a98ab43 100644 --- a/pipeline/handler/DrawObjectBoxProcessor.py +++ b/pipeline/handler/DrawObjectBoxProcessor.py @@ -2,8 +2,8 @@ import cv2 import numpy as np from dataclasses import dataclass, field from typing import List, Optional, Set -from yolo_gs.pipeline.base_processor import BaseProcessor -from yolo_gs.pipeline.pipeline_data import PipelineData +from ..base_processor import BaseProcessor +from ..pipeline_data import PipelineData @dataclass diff --git a/pipeline/handler/GraffitiProcessor.py b/pipeline/handler/GraffitiProcessor.py index 1226e6d..edd981d 100644 --- a/pipeline/handler/GraffitiProcessor.py +++ b/pipeline/handler/GraffitiProcessor.py @@ -2,8 +2,8 @@ import numpy as np import cv2 import math from collections import deque, defaultdict -from yolo_gs.pipeline.base_processor import BaseProcessor -from yolo_gs.pipeline.pipeline_data import PipelineData +from ..base_processor import BaseProcessor +from ..pipeline_data import PipelineData class GraffitiProcessor(BaseProcessor): diff --git a/pipeline/handler/ResultLogger.py b/pipeline/handler/ResultLogger.py index cbda1e3..96c10b2 100644 --- a/pipeline/handler/ResultLogger.py +++ b/pipeline/handler/ResultLogger.py @@ -5,6 +5,6 @@ import numpy as np class ResultLogger(BaseProcessor): """示例处理器:打印检测结果日志""" def process(self, data: PipelineData) -> PipelineData: - print(f"\n【{self.name}】帧{data.frame_idx} - 检测到目标数: {len(data.current_result.boxes)}") - print(f"缓存帧数: {len(data.result_cache)}") + self.logger.info(f"【{self.name}】帧{data.frame_idx} - 检测到目标数: {len(data.current_result.boxes)}") + self.logger.info(f"缓存帧数: {len(data.result_cache)}") return data \ No newline at end of file diff --git a/pipeline/handler/RetrogradeProcessor.py b/pipeline/handler/RetrogradeProcessor.py index d2a8dd9..6f09f6e 100644 --- a/pipeline/handler/RetrogradeProcessor.py +++ b/pipeline/handler/RetrogradeProcessor.py @@ -1,7 +1,7 @@ import cv2 import numpy as np -from yolo_gs.pipeline.base_processor import BaseProcessor -from yolo_gs.pipeline.pipeline_data import PipelineData +from ..base_processor import BaseProcessor +from ..pipeline_data import PipelineData import math @@ -115,7 +115,7 @@ class RetrogradeProcessor(BaseProcessor): # 输出逆行信息 for track_id, event in events_all0.items(): - print(f"【逆行检测器】帧{self.frame_idx} - 检测到事件:{event} - 轨迹ID: {track_id}") + self.logger.info(f"【逆行检测器】帧{self.frame_idx} - 检测到事件:{event} - 轨迹ID: {track_id}") # 更新事件历史 for track_id, event in frame_events.items(): diff --git a/pipeline/handler/graffiti_visualizer.py b/pipeline/handler/graffiti_visualizer.py index 24f9ea9..43a5025 100644 --- a/pipeline/handler/graffiti_visualizer.py +++ b/pipeline/handler/graffiti_visualizer.py @@ -1,8 +1,8 @@ import numpy as np import cv2 import math -from yolo_gs.pipeline.base_processor import BaseProcessor -from yolo_gs.pipeline.pipeline_data import PipelineData +from ..base_processor import BaseProcessor +from ..pipeline_data import PipelineData class GraffitiVisualizer(BaseProcessor): diff --git a/pipeline/pipeline.py b/pipeline/pipeline.py index c4243df..b87189d 100644 --- a/pipeline/pipeline.py +++ b/pipeline/pipeline.py @@ -1,3 +1,4 @@ +from loguru import logger from typing import List, Iterator import asyncio from .base_processor import BaseProcessor @@ -10,16 +11,19 @@ class Pipeline: def __init__(self): self.processors: List[BaseProcessor] = [] # 同步处理器列表 self.async_processors: List[BaseProcessor] = [] # 异步处理器列表 + # 初始化日志记录器 + self.logger = logger + self.logger.debug("管道已初始化") def add_processor(self, processor: BaseProcessor) -> None: """向管道添加同步处理器(按添加顺序执行)""" self.processors.append(processor) - print(f"管道已添加同步处理器: {processor}") + self.logger.info(f"管道已添加同步处理器: {processor}") def add_processor_async(self, processor: BaseProcessor) -> None: """向管道添加异步处理器(异步执行,不阻塞数据流)""" self.async_processors.append(processor) - print(f"管道已添加异步处理器: {processor}") + self.logger.info(f"管道已添加异步处理器: {processor}") def remove_processor(self, processor_name: str) -> bool: """移除指定名称的处理器""" @@ -27,15 +31,15 @@ class Pipeline: for idx, p in enumerate(self.processors): if p.name == processor_name: self.processors.pop(idx) - print(f"管道已移除同步处理器: {p}") + self.logger.info(f"管道已移除同步处理器: {p}") return True # 检查异步处理器列表 for idx, p in enumerate(self.async_processors): if p.name == processor_name: self.async_processors.pop(idx) - print(f"管道已移除异步处理器: {p}") + self.logger.info(f"管道已移除异步处理器: {p}") return True - print(f"未找到处理器: {processor_name}") + self.logger.warning(f"未找到处理器: {processor_name}") return False def run(self, data_iterator: Iterator[PipelineData]) -> Iterator[PipelineData]: @@ -61,7 +65,7 @@ class Pipeline: data = processor.process(data) yield data except Exception as e: - print(f"同步处理器 {processor.name} 执行出错: {e}") + self.logger.error(f"同步处理器 {processor.name} 执行出错: {e}") # 异步执行异步处理器,不阻塞数据流 if self.async_processors: @@ -87,4 +91,4 @@ class Pipeline: # 如果处理器不支持异步处理,则同步处理 processor.process(data) except Exception as e: - print(f"异步处理器 {processor.name} 执行出错: {e}") + self.logger.error(f"异步处理器 {processor.name} 执行出错: {e}") diff --git a/requirements.txt b/requirements.txt index 69571f0..0c1aa58 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -ultralytics>=8.3.249 \ No newline at end of file +ultralytics>=8.3.249 +loguru>=0.7.3 \ No newline at end of file