基于YOLOV5+Flask安全帽RTSP视频流实时目标检测
1、背景
在现代工业和建筑行业中,安全始终是首要考虑的因素之一。特别是在施工现场,工人佩戴安全帽是确保人身安全的基本要求。然而,人工监督难免会有疏漏,尤其是在大型工地或复杂环境中,确保每个人都佩戴安全帽变得非常具有挑战性。
为了解决这一问题,计算机视觉技术提供了一个有效的解决方案。通过使用深度学习模型(如YOLOv5)进行实时目标检测,我们可以自动识别视频流中的工人是否佩戴了安全帽。结合Flask框架,我们可以将这一功能封装为一个Web服务,方便在任何地方通过浏览器或其他设备进行访问。
项目目标:
- 使用YOLOv5模型实现对RTSP视频流的工人是否佩戴安全帽实时目标检测。
- 将检测功能集成到Flask Web应用中,以便通过简单的HTTP请求访问检测结果。
- 提供一个用户友好的前端界面,实时展示检测结果。
技术栈:
- YOLOv5:一个高效的实时目标检测模型,适用于多种场景的物体检测。
- Flask:一个轻量级的Python Web框架,用于构建RESTful API和Web应用。
- OpenCV:一个强大的计算机视觉库,用于处理视频流和图像。
- RTSP:实时流传输协议,用于从摄像头获取视频流。
接下来,我将详细介绍如何构建这样一个系统,从环境准备到最终的部署。
2、环境准备
pip install Flask
pip install opencv-python
# 安装YOLOv5依赖:
pip install -r requirements.txt
#下载预训练权重:
wget https://github.com/ultralytics/yolov5/releases/download/v4.0/yolov5s.pt
3、模型训练
数据集为各类场景下的安全帽图片,并使用Labelimg标注工具对每张图片中的目标边框(Bounding Box)及类别进行标注。一共包含22789张图片,其中训练集包含15887张图片,验证集包含4641张图片,测试包含2261张图片。
-
数据集目录结构:
yolov5/ ├── datasets/ │ ├── train/ │ │ ├── images/ │ │ └── labels/ │ ├── val/ │ │ ├── images/ │ │ └── labels/ │ └── test/ │ ├── images/ │ └── labels/
-
创建数据配置文件:
在 datasets 文件夹下创建一个 data.yaml 文件,内容如下:
train: E:\yolo\mydata\train\images val: E:\yolo\mydata\val\images test: E:\yolo\mydata\test\images # number of classes nc: 2 # class names names: ['head', 'helmet']
-
在YOLOv5项目目录下,运行以下命令开始训练模型:
python train.py --img 640 --batch 16 --epochs 50 --data datasets/data.yaml --cfg models/yolov5s.yaml --weights yolov5s.pt --project runs/train --name safety_helmet
4、训练结果评估
在深度学习中,我们通常用损失函数下降的曲线来观察模型训练的情况。YOLOv5在训练时主要包含三个方面的损失:定位损失(box_loss)、分类损失(cls_loss)和动态特征损失(dfl_loss),在训练结束后,可以在runs/目录下找到训练过程及结果文件,如下所示:
本文训练结果如下:
PR曲线:
5、实现RTSP视频流处理
使用OpenCV可以方便地处理RTSP视频流逻辑集成到Flask Web服务中,以便通过HTTP请求访问目标检测结果。在这个获取视频流过程中利用海康或者大华摄像头。
from flask import Flask, render_template, Response
import cv2
from models.experimental import attempt_load
from utils.general import set_logging, check_img_size
from utils.torch_utils import select_device
app = Flask(__name__)
from camera_ready import detect
class VideoCamera(object):
def __init__(self):
# 通过opencv获取实时视频流(海康摄像头)
self.count = 0
self.video = cv2.VideoCapture("rtsp://admin:Tc246800@ya.tenchan.cn:61554/Streaming/Channels/102")
# 大华摄像头
# self.video = cv2.VideoCapture("rtsp://%s:%s@%s/cam/realmonitor?channel=%d&subtype=0" % (user, pwd, ip, channel))
self.weights, imgsz = 'best.pt', 640
set_logging()
self.device = select_device('')
self.half = self.device.type != 'cpu' # half precision only supported on CUDA
self.model = attempt_load(self.weights, map_location=self.device) # load FP32 model
self.stride = int(self.model.stride.max()) # model stride
self.imgsz = check_img_size(imgsz, s=self.stride) # check img_size
if self.half:
self.model.half() # to FP16
def __del__(self):
self.video.release()
def get_frame(self):
for i in range(1):
success, image = self.video.read()
image = detect(source=image, half=self.half, model=self.model, device=self.device, imgsz=self.imgsz,
stride=self.stride)
ret, jpeg = cv2.imencode('.jpg', image)
return jpeg.tobytes()
@app.route('/xyhaw')
def xyhaw():
return render_template('index.html')
def gen(camera):
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/video_feed')
def video_feed():
return Response(gen(VideoCamera()),
mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
前端简单页面:index.html
<!DOCTYPE html>
<html>
<head>
<title>安全帽检测</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
margin: 0;
padding: 0;
}
.header {
background-color: #4CAF50;
color: white;
padding: 15px;
}
.video-container {
margin-top: 20px;
}
img {
border: 1px solid #ddd;
border-radius: 4px;
padding: 5px;
}
</style>
</head>
<body>
<div class="header">
<h1>安全帽RTSP视频流实时目标检测</h1>
</div>
<div class="video-container">
<img src="{{ url_for('video_feed') }}" width="640" height="480">
</div>
</body>
</html>