1 前言
?? 優(yōu)質(zhì)競賽項目系列,今天要分享的是
?? Yolov安全帽佩戴檢測 危險區(qū)域進(jìn)入檢測
??學(xué)長這里給一個題目綜合評分(每項滿分5分)
- 難度系數(shù):3分
- 工作量:3分
- 創(chuàng)新點(diǎn):4分
該項目較為新穎,適合作為競賽課題方向,學(xué)長非常推薦!
?? 更多資料, 項目分享:文章來源:http://www.zghlxwxcb.cn/news/detail-826100.html
https://gitee.com/dancheng-senior/postgraduate文章來源地址http://www.zghlxwxcb.cn/news/detail-826100.html
1 課題背景
建筑工人頭部傷害是造成建筑傷亡事故的重要原因。佩戴安全帽是防止建筑工人發(fā)生腦部外傷事故的有效措施,而在實(shí)際工作中工人未佩戴安全帽的不安全行為時有發(fā)生。因此,對施工現(xiàn)場建筑工人佩戴安全帽自動實(shí)時檢測進(jìn)行探究,將為深入認(rèn)知和主動預(yù)防安全事故提供新的視角。然而,傳統(tǒng)的施工現(xiàn)場具有安全管理水平低下、管理范圍小、主要依靠安全管理人員的主觀監(jiān)測并且時效性差、不能全程監(jiān)控等一系列問題。
本項目基于yolov5實(shí)現(xiàn)了安全帽和危險區(qū)域檢測。
2 效果演示
3 Yolov5框架
我們選擇當(dāng)下YOLO最新的卷積神經(jīng)網(wǎng)絡(luò)YOLOv5來進(jìn)行火焰識別檢測。6月9日,Ultralytics公司開源了YOLOv5,離上一次YOLOv4發(fā)布不到50天。而且這一次的YOLOv5是完全基于PyTorch實(shí)現(xiàn)的!在我們還對YOLOv4的各種高端操作、豐富的實(shí)驗(yàn)對比驚嘆不已時,YOLOv5又帶來了更強(qiáng)實(shí)時目標(biāo)檢測技術(shù)。按照官方給出的數(shù)目,現(xiàn)版本的YOLOv5每個圖像的推理時間最快0.007秒,即每秒140幀(FPS),但YOLOv5的權(quán)重文件大小只有YOLOv4的1/9。
目標(biāo)檢測架構(gòu)分為兩種,一種是two-stage,一種是one-stage,區(qū)別就在于 two-stage 有region
proposal過程,類似于一種海選過程,網(wǎng)絡(luò)會根據(jù)候選區(qū)域生成位置和類別,而one-stage直接從圖片生成位置和類別。今天提到的 YOLO就是一種
one-stage方法。YOLO是You Only Look Once的縮寫,意思是神經(jīng)網(wǎng)絡(luò)只需要看一次圖片,就能輸出結(jié)果。YOLO
一共發(fā)布了五個版本,其中 YOLOv1 奠定了整個系列的基礎(chǔ),后面的系列就是在第一版基礎(chǔ)上的改進(jìn),為的是提升性能。
YOLOv5有4個版本性能如圖所示:
網(wǎng)絡(luò)架構(gòu)圖
YOLOv5是一種單階段目標(biāo)檢測算法,該算法在YOLOv4的基礎(chǔ)上添加了一些新的改進(jìn)思路,使其速度與精度都得到了極大的性能提升。主要的改進(jìn)思路如下所示:
輸入端
在模型訓(xùn)練階段,提出了一些改進(jìn)思路,主要包括Mosaic數(shù)據(jù)增強(qiáng)、自適應(yīng)錨框計算、自適應(yīng)圖片縮放;
Mosaic數(shù)據(jù)增強(qiáng)
:Mosaic數(shù)據(jù)增強(qiáng)的作者也是來自YOLOv5團(tuán)隊的成員,通過隨機(jī)縮放、隨機(jī)裁剪、隨機(jī)排布的方式進(jìn)行拼接,對小目標(biāo)的檢測效果很不錯
基準(zhǔn)網(wǎng)絡(luò)
融合其它檢測算法中的一些新思路,主要包括:Focus結(jié)構(gòu)與CSP結(jié)構(gòu);
Neck網(wǎng)絡(luò)
在目標(biāo)檢測領(lǐng)域,為了更好的提取融合特征,通常在Backbone和輸出層,會插入一些層,這個部分稱為Neck。Yolov5中添加了FPN+PAN結(jié)構(gòu),相當(dāng)于目標(biāo)檢測網(wǎng)絡(luò)的頸部,也是非常關(guān)鍵的。
FPN+PAN的結(jié)構(gòu)
這樣結(jié)合操作,F(xiàn)PN層自頂向下傳達(dá)強(qiáng)語義特征(High-Level特征),而特征金字塔則自底向上傳達(dá)強(qiáng)定位特征(Low-
Level特征),兩兩聯(lián)手,從不同的主干層對不同的檢測層進(jìn)行特征聚合。
FPN+PAN借鑒的是18年CVPR的PANet,當(dāng)時主要應(yīng)用于圖像分割領(lǐng)域,但Alexey將其拆分應(yīng)用到Y(jié)olov4中,進(jìn)一步提高特征提取的能力。
Head輸出層
輸出層的錨框機(jī)制與YOLOv4相同,主要改進(jìn)的是訓(xùn)練時的損失函數(shù)GIOU_Loss,以及預(yù)測框篩選的DIOU_nms。
對于Head部分,可以看到三個紫色箭頭處的特征圖是40×40、20×20、10×10。以及最后Prediction中用于預(yù)測的3個特征圖:
?
①==>40×40×255
②==>20×20×255
③==>10×10×255
?
-
相關(guān)代碼
class Detect(nn.Module): stride = None # strides computed during build onnx_dynamic = False # ONNX export parameter def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer super().__init__() self.nc = nc # number of classes self.no = nc + 5 # number of outputs per anchor self.nl = len(anchors) # number of detection layers self.na = len(anchors[0]) // 2 # number of anchors self.grid = [torch.zeros(1)] * self.nl # init grid self.anchor_grid = [torch.zeros(1)] * self.nl # init anchor grid self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2) self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv self.inplace = inplace # use in-place ops (e.g. slice assignment) def forward(self, x): z = [] # inference output for i in range(self.nl): x[i] = self.m[i](x[i]) # conv bs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85) x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous() if not self.training: # inference if self.onnx_dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]: self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i) y = x[i].sigmoid() if self.inplace: y[..., 0:2] = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh else: # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953 xy = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh y = torch.cat((xy, wh, y[..., 4:]), -1) z.append(y.view(bs, -1, self.no)) return x if self.training else (torch.cat(z, 1), x) def _make_grid(self, nx=20, ny=20, i=0): d = self.anchors[i].device if check_version(torch.__version__, '1.10.0'): # torch>=1.10.0 meshgrid workaround for torch>=0.7 compatibility yv, xv = torch.meshgrid([torch.arange(ny).to(d), torch.arange(nx).to(d)], indexing='ij') else: yv, xv = torch.meshgrid([torch.arange(ny).to(d), torch.arange(nx).to(d)]) grid = torch.stack((xv, yv), 2).expand((1, self.na, ny, nx, 2)).float() anchor_grid = (self.anchors[i].clone() * self.stride[i]) \ .view((1, self.na, 1, 1, 2)).expand((1, self.na, ny, nx, 2)).float() return grid, anchor_grid
4 數(shù)據(jù)處理和訓(xùn)練
4.1 安全帽檢測
這里只是判斷 【人沒有帶安全帽】、【人有帶安全帽】、【人體】 3個類別 ,基于 data/coco128.yaml 文件,創(chuàng)建自己的數(shù)據(jù)集配置文件
custom_data.yaml。
創(chuàng)建自己的數(shù)據(jù)集配置文件
?
# 訓(xùn)練集和驗(yàn)證集的 labels 和 image 文件的位置
? train: ./score/images/train
? val: ./score/images/val
?
# number of classes
nc: 3
# class names
names: ['person', 'head', 'helmet']
創(chuàng)建每個圖片對應(yīng)的標(biāo)簽文件
使用 data/gen_data/gen_head_helmet.py 來將 VOC 的數(shù)據(jù)集轉(zhuǎn)換成 YOLOv5 訓(xùn)練需要用到的格式。
使用標(biāo)注工具類似于 Labelbox 、CVAT 、精靈標(biāo)注助手 標(biāo)注之后,需要生成每個圖片對應(yīng)的 .txt 文件,其規(guī)范如下:
- 每一行都是一個目標(biāo)
- 類別序號是零索引開始的(從0開始)
- 每一行的坐標(biāo) class x_center y_center width height 格式
- 框坐標(biāo)必須采用歸一化的 xywh格式(從0到1)。如果您的框以像素為單位,則將x_center和width除以圖像寬度,將y_center和height除以圖像高度。
代碼如下:
? import numpy as np
? def convert(size, box):
? """
? 將標(biāo)注的 xml 文件生成的【左上角x,左上角y,右下角x,右下角y】標(biāo)注轉(zhuǎn)換為yolov5訓(xùn)練的坐標(biāo)
? :param size: 圖片的尺寸: [w,h]
? :param box: anchor box 的坐標(biāo) [左上角x,左上角y,右下角x,右下角y,]
? :return: 轉(zhuǎn)換后的 [x,y,w,h]
? """
?
x1 = int(box[0])
y1 = int(box[1])
x2 = int(box[2])
y2 = int(box[3])
dw = np.float32(1. / int(size[0]))
dh = np.float32(1. / int(size[1]))
w = x2 - x1
h = y2 - y1
x = x1 + (w / 2)
y = y1 + (h / 2)
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return [x, y, w, h]
生成的 .txt 例子:
?
? 1 0.1830000086920336 0.1396396430209279 0.13400000636465847 0.15915916301310062
? 1 0.5240000248886645 0.29129129834473133 0.0800000037997961 0.16816817224025726
? 1 0.6060000287834555 0.29579580295830965 0.08400000398978591 0.1771771814674139
? 1 0.6760000321082771 0.25375375989824533 0.10000000474974513 0.21321321837604046
? 0 0.39300001866649836 0.2552552614361048 0.17800000845454633 0.2822822891175747
? 0 0.7200000341981649 0.5570570705458522 0.25200001196935773 0.4294294398277998
? 0 0.7720000366680324 0.2567567629739642 0.1520000072196126 0.23123123683035374
選擇模型
在文件夾 ./models 下選擇一個你需要的模型然后復(fù)制一份出來,將文件開頭的 nc = 修改為數(shù)據(jù)集的分類數(shù),下面是借鑒
./models/yolov5s.yaml來修改的
? # parameters
? nc: 3 # number of classes <============ 修改這里為數(shù)據(jù)集的分類數(shù)
? depth_multiple: 0.33 # model depth multiple
? width_multiple: 0.50 # layer channel multiple
?
# anchors
anchors:
- [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16
- [116,90, 156,198, 373,326] # P5/32
# YOLOv5 backbone
backbone:
# [from, number, module, args]
[[-1, 1, Focus, [64, 3]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, BottleneckCSP, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 9, BottleneckCSP, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, BottleneckCSP, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 1, SPP, [1024, [5, 9, 13]]],
[-1, 3, BottleneckCSP, [1024, False]], # 9
]
# YOLOv5 head
head:
[[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 6], 1, Concat, [1]], # cat backbone P4
[-1, 3, BottleneckCSP, [512, False]], # 13
[-1, 1, Conv, [256, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 4], 1, Concat, [1]], # cat backbone P3
[-1, 3, BottleneckCSP, [256, False]], # 17
[-1, 1, Conv, [256, 3, 2]],
[[-1, 14], 1, Concat, [1]], # cat head P4
[-1, 3, BottleneckCSP, [512, False]], # 20
[-1, 1, Conv, [512, 3, 2]],
[[-1, 10], 1, Concat, [1]], # cat head P5
[-1, 3, BottleneckCSP, [1024, False]], # 23
[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
]
?
開始訓(xùn)練
這里選擇了 yolov5s 模型進(jìn)行訓(xùn)練,權(quán)重也是基于 yolov5s.pt 來訓(xùn)練
python train.py --img 640 \
--batch 16 --epochs 10 --data ./data/custom_data.yaml \
--cfg ./models/custom_yolov5.yaml --weights ./weights/yolov5s.pt
4.2 檢測危險區(qū)域內(nèi)是否有人
危險區(qū)域標(biāo)注方式
使用的是 精靈標(biāo)注助手 標(biāo)注,生成了對應(yīng)圖片的 json 文件
執(zhí)行偵測
?
python area_detect.py --source ./area_dangerous --weights ./weights/helmet_head_person_s.pt
效果
危險區(qū)域會使用 紅色框 標(biāo)出來,同時,危險區(qū)域里面的人體也會被框出來,危險區(qū)域外的人體不會被框選出來。
5 最后
?? 更多資料, 項目分享:
https://gitee.com/dancheng-senior/postgraduate
到了這里,關(guān)于挑戰(zhàn)杯 Yolov安全帽佩戴檢測 危險區(qū)域進(jìn)入檢測 - 深度學(xué)習(xí) opencv的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!