F071_vue+flask基于YOLOv8的实时目标检测与追踪系统

基于YOLOv8的实时目标检测与追踪系统实战

欢迎关注B站:麦麦大数据

https://space.bilibili.com/1583208775

编号:F071

一、项目概述

本系统是一个基于YOLOv8的实时目标检测与追踪平台,采用前后端分离架构设计。后端使用Flask构建RESTful API,前端使用Vue.js + Element UI构建用户界面。系统支持图片、视频的目标检测,并提供任务队列管理、实时系统监控、大模型对话等功能。

技术栈

层级 技术选型
后端框架 Flask
前端框架 Vue.js 2.x + Element UI
数据库 MySQL + SQLAlchemy ORM
任务队列 Redis + RQ (Redis Queue)
目标检测 Ultralytics YOLOv8
数据可视化 ECharts
大语言模型 SiliconFlow API / Ollama

系统功能模块

复制代码
┌─────────────────────────────────────────────────────────────┐
│                      系统功能模块                            │
├─────────────────────────────────────────────────────────────┤
│  用户管理    │  用户注册、登录、个人信息管理、头像上传       │
├─────────────────────────────────────────────────────────────┤
│  YOLO检测   │  图片检测、视频检测、实时流检测               │
├─────────────────────────────────────────────────────────────┤
│  任务管理    │  任务提交、状态查询、结果查看                │
├─────────────────────────────────────────────────────────────┤
│  智能对话    │  大模型对话(流式/非流式)                  │
├─────────────────────────────────────────────────────────────┤
│  数据统计    │  任务类型分布、状态统计、趋势分析            │
├─────────────────────────────────────────────────────────────┤
│  系统监控    │  CPU/内存/GPU监控、任务队列管理             │
└─────────────────────────────────────────────────────────────┘

二、系统架构设计

2.1 整体架构图

复制代码
┌─────────────────────────────────────────────────────────────────────┐
│                          Vue.js Frontend (Port 8081)                │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────┐        │
│  │  Login   │  │  YOLO    │  │  Charts  │  │    Chat      │        │
│  │  Register│  │  Demo    │  │  01/02   │  │   (LLM)      │        │
│  └──────────┘  └──────────┘  └──────────┘  └──────────────┘        │
└────────────────────────────────┬────────────────────────────────────┘
                                 │ HTTP / SSE / WebSocket
┌────────────────────────────────┴────────────────────────────────────┐
│                          Flask API (Port 8080)                      │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────┐         │
│  │  /user   │  │  /yolo   │  │  /chart  │  │    /chat     │         │
│  │ Routes   │  │ Routes   │  │ Routes   │  │   Routes     │         │
│  └──────────┘  └──────────┘  └──────────┘  └──────────────┘         │
└────────────────────────────────┬────────────────────────────────────┘
                                 │
        ┌────────────────────────┼────────────────────────┐
        │                        │                        │
        ▼                        ▼                        ▼
┌───────────────┐      ┌───────────────┐       ┌───────────────┐
│    MySQL      │      │    Redis      │       │   YOLO        │
│   (Port 3306) │      │  (Queue)     │       │   Worker      │
└───────────────┘      └───────────────┘       └───────────────┘

三、核心功能实现

3.1 用户管理模块

3.1.1 用户注册

接口路径: POST /api/user/register

python 复制代码
# app/routes/user_route.py
@user_bp.route('/register', methods=['POST'])
def register():
    data = request.json
    username = data.get('username')
    password = data.get('password')
    
    # 检查用户名是否已存在
    if User.query.filter_by(username=username).first():
        return make_response(code=1, message='username exists')
    
    # 密码哈希存储
    hashed_password = generate_password_hash(password)
    new_user = User(username=username, password=hashed_password, 
                   deleted=0, roles='normal')
    
    db.session.add(new_user)
    db.session.commit()
    
    return make_response(code=0, message='register success', 
                       data=user_schema.dump(new_user))
3.1.2 用户登录

接口路径: POST /api/user/login

python 复制代码
@user_bp.route('/login', methods=['POST'])
def login():
    data = request.json
    username = data.get('username')
    password = data.get('password')
    
    user = User.query.filter_by(username=username).first()
    if not user or not check_password_hash(user.password, password):
        return make_response(code=1, message='用户或密码错误')
    
    return make_response(code=0, message='登录成功', 
                       data=user_schema.dump(user))

3.2 YOLO目标检测模块

3.2.1 图片检测

接口路径: POST /api/yolo/detect_image

功能说明:

  1. 接收前端上传的图片文件
  2. 使用YOLOv8模型进行目标检测
  3. 在图片上绘制边界框和类别标签
  4. 返回检测结果和带框图片

后端实现代码:

python 复制代码
# app/routes/yolo_route.py
@yolo_bp.route('/detect_image', methods=['POST'])
def detect_image():
    # 1. 获取用户ID
    user_id = request.form.get('user_id')
    
    # 2. 文件校验
    if 'file' not in request.files:
        return make_response(code=1, message='No file part')
    
    file = request.files['file']
    ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'bmp'}
    
    # 3. 保存原始图片
    original_filename = f"{uuid.uuid4().hex}.{ext}"
    original_path = os.path.join(UPLOAD_FOLDER, original_filename)
    file.save(original_path)
    
    # 4. 创建Task记录
    new_task = Task(
        task_type='image',
        source_url=original_path,
        user_id=user_id,
        status='completed'
    )
    db.session.add(new_task)
    db.session.flush()
    
    # 5. 加载模型并检测
    model = get_yolo_model()
    img = cv2.imread(original_path)
    results = model(img)
    annotated_img = results[0].plot()
    
    # 6. 保存结果图
    result_filename = f"result_{new_task.id}.jpg"
    result_path = os.path.join(UPLOAD_FOLDER, result_filename)
    cv2.imwrite(result_path, annotated_img)
    
    # 7. 写入Detection表
    boxes = results[0].boxes
    detections = []
    for box in boxes:
        x1, y1, x2, y2 = map(int, box.xyxy[0].tolist())
        cls_id = int(box.cls.item())
        conf = float(box.conf.item())
        class_name = results[0].names[cls_id]
        
        detection = Detection(
            task_id=new_task.id,
            frame_index=0,
            object_class=class_name,
            confidence=conf,
            bbox_x1=x1, bbox_y1=y1, bbox_x2=x2, bbox_y2=y2
        )
        db.session.add(detection)
        detections.append({
            "object_class": class_name,
            "confidence": round(conf, 4),
            "bbox": [x1, y1, x2, y2]
        })
    
    new_task.result_url = result_filename
    db.session.commit()
    
    return make_response(code=0, data={
        "task_id": new_task.id,
        "image_url": f"/api/user/upload/{result_filename}",
        "detections": detections
    })


3.2.2 视频流检测(实时预览)

接口路径: GET /api/yolo/stream_detection/<task_id>

功能说明: 使用MJPEG流式传输,每3帧处理一次,实时返回检测结果

python 复制代码
# app/routes/yolo_route.py
@yolo_bp.route('/stream_detection/<task_id>', methods=['GET'])
def stream_detection(task_id):
    filepath = os.path.join(UPLOAD_FOLDER, task_id)
    
    def generate_frames():
        cap = cv2.VideoCapture(filepath)
        model = get_yolo_model()
        frame_count = 0
        
        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break
            
            # 每3帧处理一次
            if frame_count % 3 == 0:
                results = model(frame, verbose=False)
                annotated_frame = results[0].plot()
                
                # 编码为JPEG
                _, buffer = cv2.imencode('.jpg', annotated_frame, 
                                        [cv2.IMWRITE_JPEG_QUALITY, 70])
                img_bytes = buffer.tobytes()
                yield (b'--frame\r\n'
                       b'Content-Type: image/jpeg\r\n\r\n' + img_bytes + b'\r\n')
            
            frame_count += 1
        
        cap.release()
    
    return Response(
        generate_frames(),
        mimetype='multipart/x-mixed-replace; boundary=frame'
    )
3.2.3 异步视频任务处理

使用RQ任务队列实现异步处理:

python 复制代码
# app/worker.py
def process_task(task_id):
    """异步处理视频检测任务"""
    app = create_app()
    with app.app_context():
        task = Task.query.get(task_id)
        task.status = 'processing'
        task.started_at = db.func.now()
        db.session.commit()
        
        model = get_yolo_model()
        cap = cv2.VideoCapture(task.source_url)
        
        # 创建输出视频
        output_filename = f"output_{task_id}.mp4"
        output_path = os.path.join(app.config['UPLOAD_FOLDER'], output_filename)
        out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
        
        frame_idx = 0
        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break
            
            # 每10帧处理一次
            if frame_idx % 10 == 0:
                results = model(frame)
                annotated_frame = results[0].plot()
                
                # 保存检测结果到数据库
                boxes = results[0].boxes
                for box in boxes:
                    detection = Detection(
                        task_id=task_id,
                        frame_index=frame_idx,
                        object_class=class_name,
                        confidence=conf,
                        bbox_x1=x1, bbox_y1=y1, bbox_x2=x2, bbox_y2=y2
                    )
                    db.session.add(detection)
                db.session.commit()
            else:
                annotated_frame = frame
            
            out.write(annotated_frame)
            frame_idx += 1
        
        cap.release()
        out.release()
        
        task.status = 'completed'
        task.result_url = output_filename
        task.finished_at = db.func.now()
        db.session.commit()


3.2.4 前端实时检测页面
vue 复制代码
<!-- yolo-vue/src/views/YoloDemo.vue -->
<template>
  <div class="yolo-demo-container">
    <el-card class="yolo-card">
      <div slot="header" class="header-section">
        <span class="header-title">YOLO 实时检测</span>
      </div>
      
      <div class="demo-content">
        <!-- 上传区域 -->
        <div class="upload-section">
          <el-upload
              ref="uploadRef"
              :auto-upload="false"
              :show-file-list="false"
              :on-change="handleFileChange"
              accept="video/mp4,video/avi,video/mov,video/mkv"
              drag
          >
            <i class="el-icon-upload"></i>
            <div class="el-upload__text">将视频拖到此处或点击上传</div>
          </el-upload>
          
          <div class="action-buttons">
            <el-button type="primary" @click="startDetection" 
                       :disabled="!selectedFile || isStreaming">
              开始检测
            </el-button>
            <el-button @click="togglePause" :disabled="!isStreaming">
              {{ isPaused ? '继续' : '暂停' }}
            </el-button>
            <el-button @click="stopStream" :disabled="!isStreaming">
              停止
            </el-button>
          </div>
        </div>
        
        <!-- 结果显示区域 -->
        <div class="result-section">
          <div v-if="!streamUrl && !pausedFrame" class="video-placeholder">
            <i class="el-icon-video-camera"></i>
            <p>检测结果将在此显示</p>
          </div>
          <div v-else-if="isPaused && pausedFrame" class="paused-container">
            <img :src="pausedFrame" class="detection-stream"/>
            <div class="paused-overlay">已暂停</div>
          </div>
          <img v-else ref="streamImage" :src="streamUrl" 
               class="detection-stream" @load="captureFrame"/>
        </div>
      </div>
    </el-card>
  </div>
</template>

<script>
import { upload_video, getStreamUrl } from '@/api/yolo'

export default {
  data() {
    return {
      selectedFile: null,
      streamUrl: '',
      isStreaming: false,
      isPaused: false,
      pausedFrame: null
    }
  },
  methods: {
    async startDetection() {
      const formData = new FormData()
      formData.append('file', this.selectedFile)
      
      const res = await upload_video(formData)
      if (res.data.code === 0) {
        this.currentTaskId = res.data.data.task_id
        this.streamUrl = getStreamUrl(this.currentTaskId)
        this.isStreaming = true
      }
    },
    togglePause() {
      this.isPaused = !this.isPaused
      if (this.isPaused) {
        const imgEl = this.$refs.streamImage
        if (imgEl && imgEl.src) this.pausedFrame = imgEl.src
        this.streamUrl = ''
      } else {
        this.pausedFrame = null
        this.streamUrl = getStreamUrl(this.currentTaskId) + '&t=' + Date.now()
      }
    },
    stopStream() {
      this.streamUrl = ''
      this.isStreaming = false
      this.isPaused = false
      this.pausedFrame = null
    }
  }
}
</script>

3.3 任务管理模块

3.3.1 任务提交
python 复制代码
# app/routes/yolo_route.py
@yolo_bp.route('/submit_task', methods=['POST'])
def submit_task():
    task_type = request.form.get('task_type')
    user_id = request.form.get('user_id')
    file = request.files.get('file')
    
    # 保存文件
    filename = f"{uuid.uuid4().hex}.mp4"
    filepath = os.path.join(UPLOAD_FOLDER, filename)
    file.save(filepath)
    
    # 创建任务
    new_task = Task(
        task_type=task_type,
        source_url=filepath,
        user_id=user_id,
        status='pending'
    )
    db.session.add(new_task)
    db.session.commit()
    
    # 入队异步处理
    q.enqueue('app.worker.process_task', new_task.id, job_timeout='10m')
    
    return make_response(code=0, data={'task_id': new_task.id})

3.5 数据统计模块

3.5.1 任务类型统计(柱状图)
python 复制代码
# app/routes/chart_route.py
@chart_bp.route('/getC1', methods=['GET'])
def getC1():
    user_id = request.args.get('user_id', type=int)
    
    query = db.session.query(
        Task.task_type,
        func.count(Task.id).label('count')
    )
    
    if user_id is not None:
        query = query.filter(Task.user_id == user_id)
    
    result = query.group_by(Task.task_type).all()
    data = [{'name': item[0], 'value': item[1]} for item in result]
    
    return make_response(code=0, data=data)
3.5.2 任务状态统计(饼图)
python 复制代码
@chart_bp.route('/getC2', methods=['GET'])
def getC2():
    user_id = request.args.get('user_id', type=int)
    
    query = db.session.query(
        Task.status,
        func.count(Task.id).label('count')
    )
    
    if user_id is not None:
        query = query.filter(Task.user_id == user_id)
    
    result = query.group_by(Task.status).all()
    total = sum(item[1] for item in result)
    
    data = []
    for status, count in result:
        pct = round((count / total) * 100, 2) if total > 0 else 0
        data.append({
            'name': status,
            'value': count,
            'percentage': pct
        })
    
    return make_response(code=0, data=data)

3.6 系统监控模块

3.6.1 后台系统负载记录
python 复制代码
# app/__init__.py
def record_system_load(app):
    with app.app_context():
        while True:
            from app.models import SystemLoad
            from app.tasks import q
            
            load = SystemLoad(
                cpu_percent=psutil.cpu_percent(),
                memory_percent=psutil.virtual_memory().percent,
                queue_length=len(q)
            )
            db.session.add(load)
            db.session.commit()
            
            time.sleep(360)  # 每6分钟记录一次

# 启动后台线程
Thread(target=record_system_load, args=(app, ), daemon=True).start()


四、关键技术亮点

4.1 异步任务处理

使用Redis Queue (RQ)实现任务队列,将耗时的视频检测任务异步处理,提升用户体验。

4.2 流式响应

使用SSE (Server-Sent Events)实现大模型流式输出,实时显示AI生成内容。

4.3 MJPEG视频流

使用multipart/x-mixed-replace实现实时视频流推送,无需WebSocket。

4.4 模型缓存

在Worker启动时全局加载YOLOv8模型,避免重复加载,提升处理效率。

4.5 暗色主题UI

统一的暗色主题设计,配合霓虹绿配色,符合科技感视觉风格。

五、部署说明

5.1 环境要求

  • Python 3.8+
  • Node.js 16+
  • MySQL 8.0+
  • Redis 6.0+

5.2 后端部署

bash 复制代码
# 1. 进入后端目录
cd yolo-flask

# 2. 安装依赖
pip install -r requirements.txt

# 3. 配置环境变量
cp .env.example .env
# 编辑 .env 填入数据库、Redis等配置

# 4. 启动Redis
redis-server

# 5. 启动RQ Worker
rq worker

# 6. 启动Flask服务
python run.py

5.3 前端部署

bash 复制代码
# 1. 进入前端目录
cd yolo-vue

# 2. 安装依赖
npm install

# 3. 启动开发服务器
npm run serve

# 或构建生产版本
npm run build

5.4 端口说明

服务 端口
Flask API 8080
Vue.js 8081
MySQL 3306
Redis 6379

六、总结

本文详细介绍了基于YOLOv8的实时目标检测与追踪系统的完整实现,涵盖了用户管理、YOLO目标检测、任务队列管理、大模型对话、数据统计和系统监控等核心功能。系统采用前后端分离架构,结合Redis队列实现异步任务处理,通过MJPEG流和SSE实现实时视频流和流式响应,为用户提供了一个功能完善、性能优异的AI检测平台。


源码获取 :联系麦麦大数据获取

欢迎关注B站:麦麦大数据

https://space.bilibili.com/1583208775

相关推荐
带你看月亮3 小时前
Vue3解析学习 - handlers 模块
vue.js·学习
暴力袋鼠哥3 小时前
SpringBoot+Vue实战:多模态疾病初筛与护理建议系统(含泳道图+时序图+完整后端代码)
vue.js·spring boot·后端
滕青山3 小时前
JSON转TypeScript接口核心JS实现
前端·javascript·vue.js
Katecat996633 小时前
野生动物多类别目标检测-改进YOLO11结合AKConv提升兔子野兔猞猁狼识别效果
人工智能·目标检测·计算机视觉
ShoreKiten4 小时前
ctfshowweb入门 SSTI模板注入专题保姆级教程(一)
web安全·flask·ssti·ctfshow
Xin_z_4 小时前
Vue3 + Element Plus el-tree 节点点击选中问题修复总结
前端·javascript·vue.js
Katecat996634 小时前
基于YOLOv10的混凝土蜂窝缺陷检测系统深度学习模型
人工智能·深度学习·yolo
麦麦大数据13 小时前
M003_中药可视化系统开发实践:知识图谱与AI智能问答的完美结合
人工智能·flask·llm·vue3·知识图谱·neo4j·ner
思通数科人工智能大模型16 小时前
电力巡检无人机和工程车“空地一体”AI全域巡检方案
人工智能·目标检测·计算机视觉·数据挖掘·无人机·知识图谱·零售