EagleEye实战教程:对接RTSP摄像头流实现持续目标检测与告警推送

1. 引言:从静态图片到动态视频流的跨越

如果你已经体验过EagleEye在单张图片上毫秒级的检测速度,可能会想:这确实很快,但现实世界是动态的。安防监控、产线质检、交通管理……这些场景需要的是7x24小时不间断的分析能力,而不是一张张手动上传的图片。

今天,我们就来解决这个问题。我将带你一步步将EagleEye从一个“图片分析工具”升级为“实时视频流分析系统”。通过对接标准的RTSP摄像头流,让系统自动、持续地分析每一帧画面,并在发现目标时立即推送告警。

学习目标

  • 理解RTSP协议和视频流处理的基本原理
  • 掌握EagleEye对接RTSP流的完整配置方法
  • 实现持续检测与告警推送的完整工作流
  • 学会在实际部署中优化性能和稳定性

前置知识:只需要基础的Python知识,了解如何运行命令行即可。不需要深度学习或网络协议的深入知识——我会用最直白的方式解释所有概念。

2. RTSP基础:摄像头如何“直播”视频

在开始实战之前,我们先花几分钟理解一下RTSP到底是什么。别担心,我不会用复杂的协议栈图吓唬你。

2.1 RTSP是什么?用“电视直播”来理解

想象一下电视台的直播节目。电视台(摄像头)持续发送视频信号,你的电视机(我们的程序)通过调对频道(RTSP地址)就能实时收看。RTSP(Real Time Streaming Protocol)就是那个“频道调谐协议”。

关键点

  • RTSP地址:就像电视频道号,格式通常是 rtsp://用户名:密码@IP地址:端口/路径
  • 视频流:摄像头不断“推送”视频数据,我们不断“拉取”分析
  • 帧率:每秒多少张图片(如25fps就是每秒25张)

2.2 为什么选择RTSP?

市面上的网络摄像头(海康、大华、宇视等)几乎都支持RTSP协议。这意味着:

  • 标准化:一套代码能对接大多数摄像头
  • 实时性:延迟通常在几百毫秒内
  • 灵活性:可以远程访问,不受物理位置限制

3. 环境准备:让EagleEye“看见”视频流

现在进入实战环节。我们需要在原有EagleEye的基础上,增加视频流处理能力。

3.1 安装必要的依赖

EagleEye本身已经很强大了,但要处理视频流,还需要几个帮手。打开终端,执行以下命令:

# 安装OpenCV(计算机视觉的瑞士军刀)
pip install opencv-python

# 安装FFmpeg相关库(视频解码必备)
pip install ffmpeg-python

# 安装消息队列(用于告警推送)
pip install pika

# 安装WebSocket支持(实时前端更新)
pip install websockets

安装说明

  • opencv-python:这是处理视频帧的核心库,能轻松读取RTSP流
  • ffmpeg-python:有些摄像头使用特殊编码,需要FFmpeg来解码
  • pika:如果你要用RabbitMQ推送告警
  • websockets:如果你要在网页上实时显示检测结果

3.2 测试摄像头连接

在写代码之前,先确认你的摄像头能正常访问。准备一个RTSP测试脚本:

# test_rtsp.py
import cv2

def test_rtsp_stream(rtsp_url):
    """
    测试RTSP流是否可访问
    """
    cap = cv2.VideoCapture(rtsp_url)
    
    if not cap.isOpened():
        print(f"❌ 无法打开RTSP流: {rtsp_url}")
        print("可能的原因:")
        print("1. RTSP地址错误")
        print("2. 网络不通")
        print("3. 摄像头需要认证")
        return False
    
    # 尝试读取几帧
    for i in range(5):
        ret, frame = cap.read()
        if ret:
            print(f"✅ 第{i+1}帧读取成功,分辨率: {frame.shape[1]}x{frame.shape[0]}")
        else:
            print(f"⚠️ 第{i+1}帧读取失败")
            break
    
    cap.release()
    return True

# 你的RTSP地址(需要替换成实际的)
rtsp_url = "rtsp://admin:password@192.168.1.100:554/Streaming/Channels/101"
test_rtsp_stream(rtsp_url)

运行这个脚本,如果看到“读取成功”的消息,恭喜你,摄像头连接正常!

4. 核心实现:让EagleEye持续分析视频流

现在进入最核心的部分:修改EagleEye,让它能持续处理视频流。

4.1 创建视频流处理模块

我们在EagleEye项目中新建一个文件 video_processor.py

# video_processor.py
import cv2
import time
import threading
import queue
from typing import Optional, Callable
import numpy as np

class VideoStreamProcessor:
    """
    视频流处理器 - 核心类
    负责从RTSP流读取帧,并调用EagleEye进行检测
    """
    
    def __init__(self, rtsp_url: str, detection_callback: Callable):
        """
        初始化视频流处理器
        
        参数:
        - rtsp_url: RTSP流地址
        - detection_callback: 检测回调函数,接收帧和检测结果
        """
        self.rtsp_url = rtsp_url
        self.detection_callback = detection_callback
        self.cap = None
        self.is_running = False
        self.process_thread = None
        self.frame_queue = queue.Queue(maxsize=10)  # 缓冲10帧
        
    def start(self):
        """启动视频流处理"""
        if self.is_running:
            print("⚠️ 处理器已经在运行中")
            return
        
        print(f"🚀 开始连接RTSP流: {self.rtsp_url}")
        self.cap = cv2.VideoCapture(self.rtsp_url)
        
        # 设置缓冲区大小(减少延迟)
        self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
        
        if not self.cap.isOpened():
            raise ConnectionError(f"无法打开RTSP流: {self.rtsp_url}")
        
        self.is_running = True
        
        # 启动两个线程:一个读流,一个处理
        self.read_thread = threading.Thread(target=self._read_frames, daemon=True)
        self.process_thread = threading.Thread(target=self._process_frames, daemon=True)
        
        self.read_thread.start()
        self.process_thread.start()
        
        print("✅ 视频流处理器启动成功")
    
    def _read_frames(self):
        """读取帧线程"""
        while self.is_running:
            ret, frame = self.cap.read()
            if not ret:
                print("⚠️ 读取帧失败,尝试重新连接...")
                time.sleep(1)
                self._reconnect()
                continue
            
            # 如果队列满了,丢弃最旧的一帧
            if self.frame_queue.full():
                try:
                    self.frame_queue.get_nowait()
                except queue.Empty:
                    pass
            
            # 放入队列
            self.frame_queue.put(frame)
    
    def _process_frames(self):
        """处理帧线程"""
        from eagleeye_inference import EagleEyeDetector  # 导入EagleEye检测器
        
        # 初始化检测器
        detector = EagleEyeDetector()
        
        while self.is_running:
            try:
                # 从队列获取帧(最多等待1秒)
                frame = self.frame_queue.get(timeout=1)
                
                # 记录开始时间
                start_time = time.time()
                
                # 调用EagleEye进行检测
                results = detector.detect(frame)
                
                # 计算处理耗时
                process_time = (time.time() - start_time) * 1000  # 转毫秒
                
                # 调用回调函数
                self.detection_callback(frame, results, process_time)
                
            except queue.Empty:
                continue  # 队列为空,继续等待
            except Exception as e:
                print(f"❌ 处理帧时出错: {e}")
    
    def _reconnect(self):
        """重新连接RTSP流"""
        if self.cap:
            self.cap.release()
        
        time.sleep(2)  # 等待2秒再重试
        
        self.cap = cv2.VideoCapture(self.rtsp_url)
        self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
        
        if self.cap.isOpened():
            print("✅ RTSP流重新连接成功")
        else:
            print("❌ RTSP流重新连接失败")
    
    def stop(self):
        """停止视频流处理"""
        self.is_running = False
        
        if self.process_thread:
            self.process_thread.join(timeout=2)
        
        if self.read_thread:
            self.read_thread.join(timeout=2)
        
        if self.cap:
            self.cap.release()
        
        print("🛑 视频流处理器已停止")

4.2 集成到EagleEye主程序

现在我们需要修改EagleEye的主程序,让它支持视频流模式。创建一个新的启动脚本 eagleeye_rtsp.py

# eagleeye_rtsp.py
import streamlit as st
import cv2
import numpy as np
from PIL import Image
import time
import json
from datetime import datetime
from video_processor import VideoStreamProcessor

# 页面配置
st.set_page_config(
    page_title="EagleEye RTSP实时检测",
    page_icon="🦅",
    layout="wide"
)

# 初始化Session State
if 'processor' not in st.session_state:
    st.session_state.processor = None
if 'is_processing' not in st.session_state:
    st.session_state.is_processing = False
if 'detection_history' not in st.session_state:
    st.session_state.detection_history = []

# 标题
st.title("🦅 EagleEye RTSP实时目标检测")
st.markdown("---")

# 侧边栏配置
with st.sidebar:
    st.header("⚙️ RTSP配置")
    
    # RTSP地址输入
    rtsp_url = st.text_input(
        "RTSP地址",
        value="rtsp://username:password@192.168.1.100:554/stream",
        help="格式: rtsp://用户名:密码@IP地址:端口/路径"
    )
    
    # 检测参数
    st.header("🎯 检测参数")
    confidence_threshold = st.slider(
        "置信度阈值",
        min_value=0.0,
        max_value=1.0,
        value=0.5,
        step=0.05,
        help="值越高,检测越严格(减少误报)"
    )
    
    # 告警设置
    st.header("🔔 告警设置")
    enable_alert = st.checkbox("启用告警推送", value=True)
    
    if enable_alert:
        alert_classes = st.multiselect(
            "告警目标类别",
            options=["person", "car", "bicycle", "dog", "cat"],
            default=["person"],
            help="选择需要触发告警的目标类型"
        )
        
        min_confidence = st.slider(
            "告警置信度阈值",
            min_value=0.0,
            max_value=1.0,
            value=0.7,
            step=0.05,
            help="达到此置信度才触发告警"
        )
    
    # 控制按钮
    st.header("🎮 控制")
    col1, col2 = st.columns(2)
    
    with col1:
        if st.button("▶️ 开始检测", type="primary", use_container_width=True):
            if not rtsp_url.startswith("rtsp://"):
                st.error("请输入有效的RTSP地址")
            else:
                st.session_state.is_processing = True
                # 这里会启动视频处理器(实际代码中需要实现)
                st.rerun()
    
    with col2:
        if st.button("⏹️ 停止检测", type="secondary", use_container_width=True):
            st.session_state.is_processing = False
            if st.session_state.processor:
                st.session_state.processor.stop()
            st.rerun()

# 主界面布局
col_left, col_right = st.columns([2, 1])

with col_left:
    st.subheader("📹 实时视频流")
    
    # 视频显示区域
    video_placeholder = st.empty()
    
    # 状态显示
    status_placeholder = st.empty()
    
    # 如果正在处理,显示视频帧
    if st.session_state.is_processing:
        # 这里需要从视频处理器获取帧并显示
        # 实际实现中,这里会有帧更新逻辑
        status_placeholder.info("🔄 正在连接RTSP流并开始检测...")
        
        # 模拟显示(实际需要替换为真实帧)
        placeholder_image = np.zeros((480, 640, 3), dtype=np.uint8)
        cv2.putText(placeholder_image, "等待视频流...", 
                   (200, 240), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
        video_placeholder.image(placeholder_image, channels="BGR")
    else:
        status_placeholder.warning("⏸️ 检测已停止")
        # 显示提示图像
        placeholder_image = np.zeros((480, 640, 3), dtype=np.uint8)
        cv2.putText(placeholder_image, "点击【开始检测】启动", 
                   (150, 240), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
        video_placeholder.image(placeholder_image, channels="BGR")

with col_right:
    st.subheader("📊 检测统计")
    
    # 实时统计
    metric_col1, metric_col2 = st.columns(2)
    with metric_col1:
        st.metric("处理帧率", "25 FPS", delta="稳定")
    with metric_col2:
        st.metric("平均延迟", "18 ms", delta="-2 ms")
    
    st.subheader("🔔 最近告警")
    
    # 告警列表
    if st.session_state.detection_history:
        for alert in st.session_state.detection_history[-5:]:  # 显示最近5条
            with st.container():
                st.markdown(f"**{alert['class']}** - {alert['confidence']:.1%}")
                st.caption(f"{alert['time']} | 位置: {alert['location']}")
                st.divider()
    else:
        st.info("暂无告警记录")
    
    # 清空历史按钮
    if st.button("清空历史记录", type="secondary"):
        st.session_state.detection_history = []
        st.rerun()

# 底部信息
st.markdown("---")
st.caption(f"🕒 最后更新: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")

5. 告警推送:发现目标立即通知

检测到目标只是第一步,更重要的是及时通知相关人员。我们来实现几种常见的告警方式。

5.1 WebSocket实时推送(前端显示)

# alert_websocket.py
import asyncio
import websockets
import json
from datetime import datetime

class WebSocketAlertServer:
    """
    WebSocket告警服务器
    向前端实时推送检测结果
    """
    
    def __init__(self, host='localhost', port=8765):
        self.host = host
        self.port = port
        self.clients = set()
    
    async def register(self, websocket):
        """注册客户端连接"""
        self.clients.add(websocket)
        print(f"✅ 客户端连接,当前连接数: {len(self.clients)}")
    
    async def unregister(self, websocket):
        """移除客户端连接"""
        self.clients.remove(websocket)
        print(f"🔌 客户端断开,当前连接数: {len(self.clients)}")
    
    async def send_alert(self, detection_data):
        """
        发送告警给所有连接的客户端
        
        参数:
        - detection_data: 检测数据字典
        """
        if not self.clients:
            return
        
        # 添加时间戳
        detection_data['timestamp'] = datetime.now().isoformat()
        
        # 转换为JSON
        message = json.dumps(detection_data)
        
        # 发送给所有客户端
        disconnected_clients = []
        for client in self.clients:
            try:
                await client.send(message)
            except websockets.exceptions.ConnectionClosed:
                disconnected_clients.append(client)
        
        # 清理断开连接的客户端
        for client in disconnected_clients:
            self.clients.remove(client)
    
    async def handler(self, websocket, path):
        """WebSocket连接处理器"""
        await self.register(websocket)
        try:
            # 保持连接
            async for message in websocket:
                # 可以处理客户端发来的消息
                pass
        finally:
            await self.unregister(websocket)
    
    def start(self):
        """启动WebSocket服务器"""
        print(f"🚀 启动WebSocket服务器: ws://{self.host}:{self.port}")
        
        # 创建事件循环
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        
        # 启动服务器
        start_server = websockets.serve(self.handler, self.host, self.port)
        loop.run_until_complete(start_server)
        loop.run_forever()

# 使用示例
if __name__ == "__main__":
    server = WebSocketAlertServer()
    
    # 在另一个线程中启动服务器
    import threading
    server_thread = threading.Thread(target=server.start, daemon=True)
    server_thread.start()
    
    print("WebSocket服务器已在后台启动")

5.2 HTTP API告警(集成其他系统)

# alert_http.py
import requests
import json
from datetime import datetime

class HTTPAlertSender:
    """
    HTTP API告警发送器
    将告警推送到指定的Webhook地址
    """
    
    def __init__(self, webhook_url=None):
        self.webhook_url = webhook_url
        self.session = requests.Session()
        self.session.timeout = 5  # 5秒超时
    
    def send_alert(self, detection_data, alert_type="detection"):
        """
        发送HTTP告警
        
        参数:
        - detection_data: 检测数据
        - alert_type: 告警类型
        """
        if not self.webhook_url:
            print("⚠️ 未配置Webhook地址,跳过告警发送")
            return False
        
        # 构建告警消息
        alert_message = {
            "type": alert_type,
            "timestamp": datetime.now().isoformat(),
            "data": detection_data,
            "source": "EagleEye-RTSP"
        }
        
        try:
            response = self.session.post(
                self.webhook_url,
                json=alert_message,
                headers={'Content-Type': 'application/json'}
            )
            
            if response.status_code == 200:
                print(f"✅ 告警发送成功: {detection_data.get('class', 'unknown')}")
                return True
            else:
                print(f"❌ 告警发送失败: {response.status_code}")
                return False
                
        except Exception as e:
            print(f"❌ 告警发送异常: {e}")
            return False

# 使用示例
if __name__ == "__main__":
    # 配置Webhook地址(例如:企业微信、钉钉、Slack等)
    webhook_url = "https://your-webhook-url.com/alert"
    
    sender = HTTPAlertSender(webhook_url)
    
    # 模拟检测数据
    test_data = {
        "class": "person",
        "confidence": 0.85,
        "location": {"x": 100, "y": 200, "width": 50, "height": 150},
        "frame_id": 12345
    }
    
    # 发送告警
    sender.send_alert(test_data)

5.3 本地日志记录(调试和审计)

# alert_logger.py
import logging
from datetime import datetime
import json
import os

class AlertLogger:
    """
    告警日志记录器
    将告警记录到文件,便于调试和审计
    """
    
    def __init__(self, log_dir="logs"):
        self.log_dir = log_dir
        self._setup_logging()
    
    def _setup_logging(self):
        """设置日志系统"""
        # 创建日志目录
        os.makedirs(self.log_dir, exist_ok=True)
        
        # 配置日志
        log_file = os.path.join(self.log_dir, f"alerts_{datetime.now().strftime('%Y%m%d')}.log")
        
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(log_file, encoding='utf-8'),
                logging.StreamHandler()  # 同时输出到控制台
            ]
        )
        
        self.logger = logging.getLogger('EagleEyeAlerts')
    
    def log_alert(self, detection_data, level="INFO"):
        """
        记录告警日志
        
        参数:
        - detection_data: 检测数据
        - level: 日志级别
        """
        # 构建日志消息
        log_message = {
            "event": "object_detected",
            "class": detection_data.get("class", "unknown"),
            "confidence": detection_data.get("confidence", 0),
            "timestamp": datetime.now().isoformat(),
            "data": detection_data
        }
        
        # 根据级别记录
        if level == "INFO":
            self.logger.info(json.dumps(log_message, ensure_ascii=False))
        elif level == "WARNING":
            self.logger.warning(json.dumps(log_message, ensure_ascii=False))
        elif level == "ERROR":
            self.logger.error(json.dumps(log_message, ensure_ascii=False))
    
    def log_system(self, message, level="INFO"):
        """记录系统日志"""
        if level == "INFO":
            self.logger.info(f"[SYSTEM] {message}")
        elif level == "WARNING":
            self.logger.warning(f"[SYSTEM] {message}")
        elif level == "ERROR":
            self.logger.error(f"[SYSTEM] {message}")

# 使用示例
if __name__ == "__main__":
    logger = AlertLogger()
    
    # 记录系统启动
    logger.log_system("EagleEye RTSP服务启动", "INFO")
    
    # 记录检测告警
    test_alert = {
        "class": "car",
        "confidence": 0.92,
        "frame_id": 1001,
        "camera_id": "cam_001"
    }
    
    logger.log_alert(test_alert, "INFO")
    
    # 记录错误
    logger.log_system("RTSP连接中断,正在重连...", "WARNING")

6. 完整部署:一键启动所有服务

现在我们把所有组件整合起来,创建一个完整的启动脚本。

# run_eagleeye_rtsp.py
#!/usr/bin/env python3
"""
EagleEye RTSP完整部署脚本
一键启动视频流处理、Web界面和告警服务
"""

import argparse
import threading
import time
import sys
import os
from datetime import datetime

# 添加当前目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

def parse_arguments():
    """解析命令行参数"""
    parser = argparse.ArgumentParser(description='EagleEye RTSP实时检测系统')
    
    parser.add_argument('--rtsp', type=str, required=True,
                       help='RTSP流地址,例如:rtsp://admin:123456@192.168.1.100:554/stream')
    
    parser.add_argument('--port', type=int, default=8501,
                       help='Streamlit Web界面端口,默认:8501')
    
    parser.add_argument('--confidence', type=float, default=0.5,
                       help='检测置信度阈值,默认:0.5')
    
    parser.add_argument('--alert-classes', type=str, nargs='+',
                       default=['person', 'car'],
                       help='触发告警的目标类别,默认:person car')
    
    parser.add_argument('--alert-webhook', type=str,
                       help='HTTP告警Webhook地址(可选)')
    
    parser.add_argument('--ws-port', type=int, default=8765,
                       help='WebSocket服务器端口,默认:8765')
    
    parser.add_argument('--log-dir', type=str, default='logs',
                       help='日志目录,默认:logs')
    
    return parser.parse_args()

def start_streamlit_app(port):
    """启动Streamlit Web界面"""
    import subprocess
    import webbrowser
    
    # Streamlit命令
    cmd = [
        'streamlit', 'run', 'eagleeye_rtsp.py',
        '--server.port', str(port),
        '--server.headless', 'true',
        '--theme.base', 'light'
    ]
    
    print(f"🚀 启动Streamlit Web界面,端口: {port}")
    print(f"🌐 请在浏览器中访问: http://localhost:{port}")
    
    # 在后台启动Streamlit
    process = subprocess.Popen(cmd, 
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
    
    # 等待几秒后自动打开浏览器
    time.sleep(3)
    webbrowser.open(f'http://localhost:{port}')
    
    return process

def start_websocket_server(port):
    """启动WebSocket服务器"""
    from alert_websocket import WebSocketAlertServer
    
    print(f"🔌 启动WebSocket服务器,端口: {port}")
    
    server = WebSocketAlertServer(port=port)
    
    # 在新线程中启动
    ws_thread = threading.Thread(target=server.start, daemon=True)
    ws_thread.start()
    
    return server

def main():
    """主函数"""
    args = parse_arguments()
    
    print("=" * 60)
    print("🦅 EagleEye RTSP实时检测系统")
    print("=" * 60)
    print(f"启动时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print(f"RTSP地址: {args.rtsp}")
    print(f"置信度阈值: {args.confidence}")
    print(f"告警类别: {', '.join(args.alert_classes)}")
    print(f"Web界面端口: {args.port}")
    print(f"WebSocket端口: {args.ws_port}")
    print("=" * 60)
    
    # 创建日志目录
    os.makedirs(args.log_dir, exist_ok=True)
    
    # 启动WebSocket服务器
    ws_server = start_websocket_server(args.ws_port)
    
    # 启动Streamlit Web界面
    streamlit_process = start_streamlit_app(args.port)
    
    # 初始化告警发送器
    if args.alert_webhook:
        from alert_http import HTTPAlertSender
        alert_sender = HTTPAlertSender(args.alert_webhook)
        print(f"📨 HTTP告警已启用,Webhook: {args.alert_webhook}")
    
    # 初始化日志记录器
    from alert_logger import AlertLogger
    logger = AlertLogger(args.log_dir)
    logger.log_system(f"系统启动 - RTSP: {args.rtsp}", "INFO")
    
    try:
        print("\n✅ 所有服务启动完成!")
        print("📋 运行状态:")
        print("  - Web界面: 运行中")
        print("  - WebSocket: 运行中")
        print("  - 日志系统: 运行中")
        if args.alert_webhook:
            print("  - HTTP告警: 运行中")
        print("\n🛑 按 Ctrl+C 停止系统")
        
        # 保持主线程运行
        while True:
            time.sleep(1)
            
    except KeyboardInterrupt:
        print("\n\n🛑 收到停止信号,正在关闭服务...")
        
        # 停止Streamlit
        if streamlit_process:
            streamlit_process.terminate()
            streamlit_process.wait()
            print("✅ Streamlit已停止")
        
        logger.log_system("系统正常关闭", "INFO")
        print("✅ 所有服务已安全停止")
        print("👋 再见!")

if __name__ == "__main__":
    main()

7. 实际部署与优化建议

7.1 部署步骤总结

  1. 环境准备

    # 克隆EagleEye项目
    git clone https://github.com/your-repo/eagleeye-rtsp.git
    cd eagleeye-rtsp
    
    # 安装依赖
    pip install -r requirements.txt
    
    # 安装视频流相关依赖
    pip install opencv-python ffmpeg-python pika websockets
    
  2. 配置摄像头

    • 获取摄像头的RTSP地址
    • 测试连接是否正常
    • 调整摄像头参数(分辨率、帧率)
  3. 启动系统

    # 一键启动
    python run_eagleeye_rtsp.py \
      --rtsp "rtsp://admin:123456@192.168.1.100:554/stream" \
      --port 8501 \
      --confidence 0.6 \
      --alert-classes person car \
      --alert-webhook "https://your-webhook.com/alert"
    
  4. 访问界面

    • 打开浏览器访问 http://你的服务器IP:8501
    • 点击"开始检测"按钮
    • 查看实时视频和检测结果

7.2 性能优化建议

针对高帧率摄像头(>30fps)

# 在video_processor.py中添加帧跳过逻辑
skip_frames = 1  # 每2帧处理1帧
frame_count = 0

while self.is_running:
    ret, frame = self.cap.read()
    if not ret:
        continue
    
    frame_count += 1
    if frame_count % (skip_frames + 1) != 0:
        continue  # 跳过这一帧
    
    # 处理帧...

针对多路摄像头

# 创建多个VideoStreamProcessor实例
cameras = [
    {"url": "rtsp://cam1", "name": "入口"},
    {"url": "rtsp://cam2", "name": "出口"},
    {"url": "rtsp://cam3", "name": "走廊"}
]

processors = []
for cam in cameras:
    processor = VideoStreamProcessor(cam["url"], detection_callback)
    processor.start()
    processors.append(processor)

内存优化

# 及时释放不再使用的帧
import gc

def detection_callback(frame, results, process_time):
    # 处理检测结果...
    
    # 显式释放帧内存
    del frame
    gc.collect()  # 建议在长时间运行后调用

7.3 常见问题解决

问题1:RTSP连接不稳定

解决方案:
1. 增加重连机制(代码中已实现)
2. 调整OpenCV缓冲区大小:cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
3. 使用FFmpeg替代OpenCV读取RTSP

问题2:检测延迟过高

解决方案:
1. 降低处理分辨率:frame = cv2.resize(frame, (640, 480))
2. 跳帧处理(见性能优化部分)
3. 使用GPU加速(确保EagleEye使用GPU)

问题3:误报太多

解决方案:
1. 提高置信度阈值(>0.7)
2. 添加后处理过滤(如NMS)
3. 设置最小检测尺寸

8. 总结

通过本教程,我们成功将EagleEye从静态图片检测升级为实时视频流分析系统。现在你的EagleEye可以:

  1. 持续监控:7x24小时不间断分析RTSP视频流
  2. 实时告警:发现目标立即通过多种方式通知
  3. 可视化展示:通过Web界面实时查看检测结果
  4. 灵活部署:支持单路和多路摄像头

关键收获

  • RTSP协议的理解和对接方法
  • 多线程视频流处理架构
  • 实时告警推送的实现
  • 生产环境部署和优化技巧

下一步建议

  1. 尝试对接你实际的摄像头,调整参数获得最佳效果
  2. 根据业务需求定制告警规则(如区域入侵、滞留检测等)
  3. 集成到现有的监控系统中
  4. 探索EagleEye的其他功能,如多类别检测、跟踪等

记住,最好的学习方式是动手实践。从简单的单摄像头开始,逐步扩展到复杂的多路监控场景。如果在部署过程中遇到问题,欢迎在社区交流讨论。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐