目标检测:
目标检测是计算机视觉和数字图像处理的一个热门方向,广泛应用于无人驾驶、智能视频监控、工业检测、航空航天等诸多领域,通过计算机视觉减少对人力资本的消耗,具有重要的现实意义。 因此,目标检测也就成为了近年来理论和应用的研究热点,它是图像处理和计算机视觉学科的重要分支,也是智能监控系统的核心部分,同时目标检测也是泛身份识别领域的一个基础性的算法,对后续的人脸识别、步态识别、人群计数、实例分割等任务起着至关重要的作用。
YOLOv5简介:
YOLOV4出现之后不久,YOLOv5横空出世。YOLOv5在YOLOv4算法的基础上做了进一步的改进,检测性能得到进一步的提升。YOLOv5在COCO数据集上面的测试效果非常不错。工业界也往往更喜欢使用这些方法,而不是利用一个超级复杂的算法来获得较高的检测精度。
YOLOv5是一种单阶段目标检测算法,速度与精度都得到了极大的性能提升。主要的改进思路如下所示:
- 输入端:在模型训练阶段,提出了一些改进思路,主要包括Mosaic数据增强、自适应锚框计算、自适应图片缩放。
- 基准网络:融合其它检测算法中的一些新思路,主要包括:Focus结构与CSP结构。
- Neck网络:目标检测网络在BackBone与最后的Head输出层之间往往会插入一些层,Yolov5中添加了FPN+PAN结构。
- Head输出层:输出层的锚框机制与YOLOv4相同,主要改进的是训练时的损失函数GIOU_Loss,以及预测框筛选的DIOU_nms。
YOLOv5S模型的网络架构:
Yolov5s网络是Yolov5系列中深度最小,特征图的宽度最小的网络。Yolov5m、Yolov5l、Yolov5x 都是在此基础上不断加深,不断加宽。
YOLOV5目录结构:
下载源码后解压可以看到如下目录:
其中,train.py这个文件也是我们接下来训练yolo模型需要用到的启动文件。
requirement.txt 中有我们所需要的的全部依赖,采用pip安装。
pip install -r requirements.txt #安装完依赖后准备工作完成
每个文件作用:
YOLOv5
| detect.py #检测脚本
| hubconf.py # PyTorch Hub相关代码
| LICENSE # 版权文件
| README.md #README markdown 文件
| requirements.txt #项目所需的安装包列表
| sotabench.py #COCO 数据集测试脚本
| test.py #模型测试脚本
| train.py #模型训练脚本
| tutorial.ipynb #Jupyter Notebook演示代码
|-- data
| | coco.yaml #COCO 数据集配置文件
| | coco128.yaml #COCO128 数据集配置文件
| | hyp.finetune.yaml #超参数微调配置文件
| | hyp.scratch.yaml #超参数启始配置文件
| | voc.yaml #VOC数据集配置文件
| |---scripts
| get_coco.sh # 下载COCO数据集shell命令
| get_voc.sh # 下载VOC数据集shell命令
|-- inference
| | images #示例图片文件夹
| bus.jpg
| zidane.jpg
|-- models
| | common.py #模型组件定义代码
| | experimental.py #实验性质的代码
| | export.py #模型导出脚本
| | yolo.py # Detect 及 Model构建代码
| | yolo5l.yaml # yolov5l 网络模型配置文件
| | yolo5m.yaml # yolov5m 网络模型配置文件
| | yolo5s.yaml # yolov5s 网络模型配置文件
| | yolo5x.yaml # yolov5x 网络模型配置文件
| | __init__.py
| |---hub
| yolov3-spp.yaml
| yolov3-fpn.yaml
| yolov3-panet.yaml
|-- runs #训练结果
| |--exp0
| | | events.out.tfevents.
| | | hyp.yaml
| | | labels.png
| | | opt.yaml
| | | precision-recall_curve.png
| | | results.png
| | | results.txt
| | | test_batch0_gt.jpg
| | | test_batch0_pred.jpg
| | | test_batch0.jpg
| | | test_batch1.jpg
| | | test_batch2.jpg
| | |--weights
| | best.pt #所有训练轮次中最好权重
| | last.pt #最近一轮次训练权重
|-- utils
| | activations.py #激活函数定义代码
| | datasets.py #Dataset 及Dataloader定义代码
| | evolve.py #超参数进化命令
| | general.py #项目通用函数代码
| | google_utils.py # 谷歌云使用相关代码
| | torch_utils.py # torch工具辅助类代码
| | __init__.py # torch工具辅助类代码
| |---google_app_engine
| additional_requirements.txt
| app.yaml
| Dockerfile
|-- VOC #数据集目录
| |--images #数据集图片目录
| | |--train # 训练集图片文件夹
| | | 000005.jpg
| | | 000007.jpg
| | | 000009.jpg
| | | 0000012.jpg
| | | 0000016.jpg
| | | ...
| | |--val # 验证集图片文件夹
| | | 000001.jpg
| | | 000002.jpg
| | | 000003.jpg
| | | 000004.jpg
| | | 000006.jpg
| | | ...
| |--labels #数据集标签目录
| | train.cache
| | val.cache
| | |--train # 训练标签文件夹
| | | 000005.txt
| | | 000007.txt
| | | ...
| | |--val # 验证集图片文件夹
| | | 000001.txt
| | | 000002.txt
| | | ...
|-- weights
dwonload_weights.sh #下载权重文件命令
yolov5l.pt #yolov5l 权重文件
yolov5m.pt #yolov5m 权重文件
yolov5s.mlmodel #yolov5s 权重文件(Core M格式)
yolov5s.onnx #yolov5s 权重文件(onnx格式)
yolov5s.torchscript #yolov5s 权重文件(torchscript格式)
yolov5x.pt #yolov5x 权重文件
模型训练过程:
使用环境:Python3.8+torch1.8.1+cuda11.1+pycharm
(注:cuda的安装版本取决于显卡类型)
1.数据集的标注:
python打开labelimg这个软件进行标注。
python labelimg.py
数据格式建议选择VOC,后期再转换成 yolo格式。
( VOC生成 xml 文件,可以灵活转变为其他模型所需格式。)
本次训练标注两个标签,佩戴口罩为 mask,未佩戴口罩为 face。
在根目录下建立一个VOCData文件夹,再建立两个子文件,其中,jpg文件放置在VOCData/images下,xml放置在VOCData/Annotations中。(这一步根据个人随意,因为在训练时需要创建配置文件指定模型训练集的目录)
2.数据集的训练:
①、在项目根目录下文件夹下新建mask_data.yaml配置文件,添加如下内容:
(根据个人情况修改)
其中:
path:项目的根目录
train:训练集与path的相对路径
val:验证集与path的相对路径
nc:类别数量,2个
names:类别名字
(上一步中标注好的训练集,可以按照想要比例划分为训练和验证集,也可以不划分填同一路径。)
②、修改启动文件 train.py:
打开train.py,其相关参数如下:
其中:
weights:权重文件路径
cfg:存储模型结构的配置文件
data:存储训练、测试数据的文件(上一步中自己创建的那个.yaml)
epochs:训练过程中整个数据集的迭代次数
batch-size:训练后权重更新的图片数
img-size:输入图片宽高。
device:选择使用GPU还是CPU
workers:线程数,默认是8
#输入命令开始训练:
python train.py --weights data/yolov5s.pt --cfg models/yolov5s.yaml --data data/mask_data.yaml --epoch 100 --batch-size 8 --device 0
③、等待跑完
模型结果数据呈现:
1.数据集的分布:
mask的照片约有2000张,face的照片约有2500张。
2.损失函数和准确率:
可以看到随着训练的进行,以不同方式呈现的损失函数呈明显下降趋势,准确率呈上升趋势。
3.置信度与准确率:
置信度在0.6以上时,准确率接近80%。
GUI编程:
编写GUI界面,方便对权重文件进行一个替换,对图片和视频进行一个监测,以及调用摄像头进行实时监测。
呈现效果:
检测效果:
UI代码:
class MainWindow(QTabWidget):
def __init__(self):
# 初始化界面
super().__init__()
self.setWindowTitle('Qust-口罩识别')
self.resize(1200, 900)
# 图片读取进程
self.output_size = 500
self.img2predict = ""
self.device = '0'# todo 在这里设置使用 CPU还是GPU(0是GPU)
# # 初始化视频读取线程
self.vid_source = '0' # 初始设置为摄像头
self.stopEvent = threading.Event()
self.webcam = True
self.stopEvent.clear()
#best123.pt 训练好的口罩模型
self.model = self.model_load(weights="best2.pt",
device=self.device)
self.initUI()
self.reset_vid()
'''
***模型初始化***
'''
@torch.no_grad()
def model_load(self, weights="", # model.pt path(s)
device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu
half=False, # use FP16 half-precision inference
dnn=False, # use OpenCV DNN for ONNX inference
):
device = select_device(device)
half &= device.type != 'cpu' # half precision only supported on CUDA
device = select_device(device)
model = DetectMultiBackend(weights, device=device, dnn=dnn)
stride, names, pt, jit, onnx = model.stride, model.names, model.pt, model.jit, model.onnx
# Half
half &= pt and device.type != 'cpu' # half precision only supported by PyTorch on CUDA
if pt:
model.model.half() if half else model.model.float()
print("模型加载完成!")
return model
'''
***界面初始化***
'''
def initUI(self):
# 图片检测子界面
font_title = QFont('幼圆', 16)
font_main = QFont('幼圆', 20)
# 图片识别界面, 两个按钮,上传图片和显示结果
img_detection_widget = QWidget()
img_detection_layout = QVBoxLayout()
img_detection_title = QLabel("图片检测")
img_detection_title.setFont(font_title)
mid_img_widget = QWidget()
mid_img_layout = QHBoxLayout()
self.left_img = QLabel()
self.right_img = QLabel()
self.left_img.setPixmap(QPixmap("images/UI/up.png"))
self.right_img.setPixmap(QPixmap("images/UI/right.png"))
self.left_img.setAlignment(Qt.AlignCenter)
self.right_img.setAlignment(Qt.AlignCenter)
mid_img_layout.addWidget(self.left_img)
mid_img_layout.addStretch(0)
mid_img_layout.addWidget(self.right_img)
mid_img_widget.setLayout(mid_img_layout)
up_img_button = QPushButton("选择图片")
det_img_button = QPushButton("开始检测")
up_img_button.clicked.connect(self.upload_img)
det_img_button.clicked.connect(self.detect_img)
up_img_button.setFont(font_main)
det_img_button.setFont(font_main)
up_img_button.setStyleSheet("QPushButton{color:white}"
"QPushButton:hover{background-color: rgb(87,24,138);}"
"QPushButton{background-color:rgb(46,169,223)}"
"QPushButton{border:2px}"
"QPushButton{border-radius:5px}"
"QPushButton{padding:20px 20px}"
"QPushButton{margin:15px 150px}")
det_img_button.setStyleSheet("QPushButton{color:white}"
"QPushButton:hover{background-color: rgb(87,24,138);}"
"QPushButton{background-color:rgb(46,169,223)}"
"QPushButton{border:2px}"
"QPushButton{border-radius:5px}"
"QPushButton{padding:20px 20px}"
"QPushButton{margin:15px 150px}")
img_detection_layout.addWidget(img_detection_title, alignment=Qt.AlignCenter)
img_detection_layout.addWidget(mid_img_widget, alignment=Qt.AlignCenter)
img_detection_layout.addWidget(up_img_button)
img_detection_layout.addWidget(det_img_button)
img_detection_widget.setLayout(img_detection_layout)
# 视频识别子界面
vid_detection_widget = QWidget()
vid_detection_layout = QVBoxLayout()
vid_title = QLabel("视频检测")
vid_title.setFont(font_title)
self.vid_img = QLabel()
self.vid_img.setPixmap(QPixmap("images/UI/up.png"))
vid_title.setAlignment(Qt.AlignCenter)
self.vid_img.setAlignment(Qt.AlignCenter)
self.webcam_detection_btn = QPushButton("打开摄像头")
self.mp4_detection_btn = QPushButton("打开视频文件")
self.vid_stop_btn = QPushButton("停止检测")
self.webcam_detection_btn.setFont(font_main)
self.mp4_detection_btn.setFont(font_main)
self.vid_stop_btn.setFont(font_main)
self.webcam_detection_btn.setStyleSheet("QPushButton{color:white}"
"QPushButton:hover{background-color: rgb(87,24,138);}"
"QPushButton{background-color:rgb(46,169,223)}"
"QPushButton{border:2px}"
"QPushButton{border-radius:5px}"
"QPushButton{padding:15px 5px}"
"QPushButton{margin:5px 150px}")
self.mp4_detection_btn.setStyleSheet("QPushButton{color:white}"
"QPushButton:hover{background-color: rgb(87,24,138);}"
"QPushButton{background-color:rgb(46,169,223)}"
"QPushButton{border:2px}"
"QPushButton{border-radius:5px}"
"QPushButton{padding:15px 5px}"
"QPushButton{margin:5px 150px}")
self.vid_stop_btn.setStyleSheet("QPushButton{color:white}"
"QPushButton:hover{background-color: rgb(87,24,138);}"
"QPushButton{background-color:rgb(46,169,223)}"
"QPushButton{border:2px}"
"QPushButton{border-radius:5px}"
"QPushButton{padding:15px 5px}"
"QPushButton{margin:5px 150px}")
self.webcam_detection_btn.clicked.connect(self.open_cam)
self.mp4_detection_btn.clicked.connect(self.open_mp4)
self.vid_stop_btn.clicked.connect(self.close_vid)
vid_detection_layout.addWidget(vid_title)
vid_detection_layout.addWidget(self.vid_img)
vid_detection_layout.addWidget(self.webcam_detection_btn)
vid_detection_layout.addWidget(self.mp4_detection_btn)
vid_detection_layout.addWidget(self.vid_stop_btn)
vid_detection_widget.setLayout(vid_detection_layout)
# 选择权重文件子界面
about_widget = QWidget()
about_layout = QVBoxLayout()
self.about_title2 = QLabel('当前在使用GPU计算')
self.about_title = QLabel('当前的权重文件是:')
self.about_title.setFont(QFont('幼圆', 18))
self.about_title2.setFont(QFont('幼圆', 18))
path="best2.pt"
self.label_patch = QLabel()
self.label_patch.setText(path)
self.label_patch.setFont(QFont('黑体', 16))
self.label_patch.setWordWrap(1)
self.about_title.setAlignment(Qt.AlignCenter)
self.about_title2.setAlignment(Qt.AlignCenter)
self.label_patch.setAlignment(Qt.AlignCenter)
self.choose_button = QPushButton("选择权重文件")
self.choose_button.setFont(font_main)
self.choose_button.setStyleSheet("QPushButton{color:white}"
"QPushButton:hover{background-color: rgb(87,24,138);}"
"QPushButton{background-color:rgb(46,169,223)}"
"QPushButton{border:2px}"
"QPushButton{border-radius:5px}"
"QPushButton{padding:15px 5px}"
"QPushButton{margin:150px}"
"QPushButton{margin-top:25px}")
self.choose_button2 = QPushButton("点击切换CPU/GPU计算")
self.choose_button2.setFont(font_main)
self.choose_button2.setStyleSheet("QPushButton{color:white}"
"QPushButton:hover{background-color: rgb(87,24,138);}"
"QPushButton{background-color:rgb(46,169,223)}"
"QPushButton{border:2px}"
"QPushButton{border-radius:5px}"
"QPushButton{padding:15px 5px}"
"QPushButton{margin:150px}"
"QPushButton{margin-top:5px}")
about_layout.addWidget(self.about_title)
about_layout.addWidget(self.label_patch)
about_layout.addWidget(self.choose_button)
mid_img_layout.addStretch(0)
about_layout.addWidget(self.about_title2)
about_layout.addWidget(self.choose_button2)
about_widget.setLayout(about_layout)
self.choose_button.clicked.connect(self.chpath)
self.choose_button2.clicked.connect(self.chpath2)
#设置tab栏
self.left_img.setAlignment(Qt.AlignCenter)
self.addTab(img_detection_widget, '图片识别')
self.addTab(vid_detection_widget, '视频识别')
self.addTab(about_widget, '选择权重文件')