要搭建一个基于Flask和YOLOv5的实时视频检测Web应用,首先需要准备好开发环境。我推荐使用Python 3.8或更高版本,这个版本在兼容性和性能方面都有不错的表现。在实际项目中,我发现Python 3.8与PyTorch的配合最为稳定。
安装基础依赖包时,建议创建一个虚拟环境。这样可以避免与其他项目的依赖冲突。我通常使用conda来管理环境,但venv也是个不错的选择:
bash复制python -m venv yolov5_flask_env
source yolov5_flask_env/bin/activate # Linux/Mac
yolov5_flask_env\Scripts\activate # Windows
接下来安装核心依赖项。这里有个小技巧:先安装PyTorch,再安装其他依赖,可以减少版本冲突的可能性:
bash复制pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113
pip install flask flask-cors opencv-python numpy
对于YOLOv5的获取,直接从官方仓库克隆是最稳妥的做法。我在多个项目中发现,使用pip安装的版本有时会缺少必要的工具函数:
bash复制git clone https://github.com/ultralytics/yolov5
cd yolov5
pip install -r requirements.txt
一个良好的项目结构能让后续开发事半功倍。经过多次项目实践,我总结出了这样一个目录结构:
code复制yolov5_flask/
├── app.py # Flask主应用
├── static/ # 静态资源
│ ├── js/
│ └── css/
├── templates/ # HTML模板
│ └── index.html
├── utils/ # 工具函数
│ └── video_processor.py
└── yolov5/ # YOLOv5模型代码
在app.py中,我们需要初始化Flask应用并配置基本路由。这里有个细节需要注意:静态文件夹和模板文件夹的路径设置。我遇到过因为路径问题导致模板无法加载的情况,所以建议使用绝对路径:
python复制import os
from flask import Flask
app = Flask(__name__,
static_folder=os.path.abspath('static'),
template_folder=os.path.abspath('templates'))
将YOLOv5集成到Flask应用中需要特别注意模型加载和推理的性能优化。我封装了一个VideoProcessor类来处理这些逻辑:
python复制import torch
import cv2
import numpy as np
from yolov5.models.experimental import attempt_load
from yolov5.utils.general import non_max_suppression, scale_coords
class VideoProcessor:
def __init__(self, weights_path='yolov5s.pt'):
self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
self.model = attempt_load(weights_path, device=self.device)
self.model.eval()
self.names = self.model.module.names if hasattr(self.model, 'module') else self.model.names
self.colors = [[np.random.randint(0, 255) for _ in range(3)] for _ in self.names]
def process_frame(self, frame):
# 预处理
img = self._preprocess(frame)
# 推理
with torch.no_grad():
pred = self.model(img, augment=False)[0]
# 后处理
pred = non_max_suppression(pred, conf_thres=0.25, iou_thres=0.45)
# 绘制检测框
return self._draw_boxes(frame, pred[0]) if pred[0] is not None else frame
def _preprocess(self, img):
# 实现图像预处理逻辑
pass
def _draw_boxes(self, img, detections):
# 实现检测框绘制逻辑
pass
在实际使用中,我发现将模型加载放在类初始化阶段可以显著提高处理速度,因为避免了重复加载模型的开销。
实现实时视频检测的核心是正确处理视频流。我采用了multipart/x-mixed-replace这种流式传输方式,它特别适合实时视频场景。下面是Flask路由的实现:
python复制from flask import Response
@app.route('/video_feed')
def video_feed():
return Response(generate_frames(),
mimetype='multipart/x-mixed-replace; boundary=frame')
def generate_frames():
cap = cv2.VideoCapture(0) # 使用摄像头
processor = VideoProcessor()
while True:
success, frame = cap.read()
if not success:
break
processed_frame = processor.process_frame(frame)
ret, buffer = cv2.imencode('.jpg', processed_frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
这里有几个关键点需要注意:
在前端,我们只需要一个简单的img标签就能显示视频流:
html复制<img src="{{ url_for('video_feed') }}" alt="实时视频流">
为了让用户能够上传自己的视频文件进行检测,我们需要实现文件上传功能。在Flask中处理文件上传时,有几个安全注意事项:
python复制from flask import request
import os
UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'mp4', 'avi', 'mov'}
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return 'No file part', 400
file = request.files['file']
if file.filename == '':
return 'No selected file', 400
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(filepath)
# 处理视频文件
process_video(filepath)
return 'File uploaded successfully', 200
在实际部署中,我还建议:
在开发过程中,我发现了几种有效的性能优化方法:
python复制model.half() # 转换为半精度
python复制# 将多帧组合成一个batch
batch = torch.stack([preprocess(frame) for frame in frames])
pred = model(batch)
python复制from functools import lru_cache
@lru_cache(maxsize=100)
def cached_detect(frame_hash):
return model.detect(frame)
在项目开发过程中,我遇到过不少坑,这里分享几个典型问题的解决方法:
问题1:CUDA内存不足
解决方法:
问题2:视频流延迟高
解决方法:
问题3:前端视频显示卡顿
解决方法:
问题4:跨域问题
解决方法:
虽然核心功能在后端,但好的前端体验同样重要。我推荐使用Bootstrap快速搭建界面:
html复制<!DOCTYPE html>
<html>
<head>
<title>实时视频检测</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
#video-container {
position: relative;
}
#detection-canvas {
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<div class="container mt-4">
<h1 class="text-center">实时视频检测系统</h1>
<div class="row mt-4">
<div class="col-md-6">
<div class="card">
<div class="card-header">摄像头检测</div>
<div class="card-body">
<img src="{{ url_for('video_feed') }}" class="img-fluid">
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">上传视频检测</div>
<div class="card-body">
<form id="upload-form" enctype="multipart/form-data">
<div class="mb-3">
<input class="form-control" type="file" id="video-file" accept="video/*">
</div>
<button type="submit" class="btn btn-primary">开始检测</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
// 这里添加JavaScript交互逻辑
</script>
</body>
</html>
对于更高级的需求,可以考虑使用Video.js或类似的库来增强视频播放功能。
将应用部署到生产环境时,我推荐使用Gunicorn+Nginx的组合:
bash复制pip install gunicorn
python复制from app import app
if __name__ == "__main__":
app.run()
bash复制gunicorn --bind 0.0.0.0:8000 -w 4 wsgi:app
对于Nginx配置,这里是我的常用配置模板:
nginx复制server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /static/ {
alias /path/to/your/static/files;
}
}
在部署YOLOv5模型时,记得检查CUDA和cuDNN版本是否匹配。我遇到过因为版本不匹配导致性能下降50%的情况。
基础功能实现后,可以考虑添加这些增强功能:
实现多模型切换的示例代码:
python复制@app.route('/switch_model', methods=['POST'])
def switch_model():
model_type = request.json.get('model_type', 'yolov5s')
global video_processor
video_processor = VideoProcessor(f'yolov5/{model_type}.pt')
return jsonify({'status': 'success'})
在实际项目中,我发现这种架构可以支持每秒20-30帧的实时检测(使用yolov5s模型和RTX 3060显卡)。对于更高要求的场景,可以考虑使用TensorRT加速或部署到边缘计算设备上。