基于paddlepaddle的社交距離檢測
- (一)訓練模型(paddleX)
- (二)使用模型進行目標檢測(YOLOv3-MobileNetV1)
- (三)結語
在新冠疫情危機中,減少人群的聚集是減少傳播的重要措施之一,減少親密接觸,從而減少傳染病的傳播,那么保持安全的社交距離則顯得尤為重要,
具體的實作步驟大致如下:
- 訓練目標檢測模型
- 用得到的模型檢測視頻流中的所有人
- 檢測人與人之間的距離
(一)訓練模型(paddleX)
模型的訓練,這里是使用百度飛槳(paddlepaddle),使用使用PaddleX提供的PPYOLO模型,在VOC2012資料集進行訓練;
什么是PaddleX:PaddleX是基于飛槳核心框架、開發套件和工具組件的深度學習全流程開發工具,具備 全流程打通 、融合產業實踐 、易用易集成 三大特點(非常好用,吹爆),具體怎么用,參考下面的鏈接
傳送門.
首先當然是搭建我們的環境,這里因為可以白嫖百度飛槳的算力資源(GPU:Tesla V100,Video Mem:16GB,CPU: 4 Croes,RAM:32GB,Disk:100GB),所以是在AIStudio上的notebook(類似于Jupyter Notebook)進行的模型訓練,這里使用的paddlex下的PPYOLO進行遷移學習訓練模型,所以我們就不用搞那么復雜了,就不需要自己一層層的搭建網路了
至于代碼,我就不一行行的解釋了,上面官方鏈接里寫的很清楚,這里僅附上我訓練的代碼
這是我在AIStudio訓練該模型的專案傳送門.
代碼如下:
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
import paddlex as pdx
from paddlex.det import transforms
# 定義訓練和驗證時的transforms
# API說明 https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html
train_transforms = transforms.Compose([
transforms.MixupImage(mixup_epoch=250), transforms.RandomDistort(),
transforms.RandomExpand(), transforms.RandomCrop(), transforms.Resize(
target_size=512, interp='RANDOM'), transforms.RandomHorizontalFlip(),
transforms.Normalize()
])
eval_transforms = transforms.Compose([
transforms.Resize(
target_size=512, interp='CUBIC'), transforms.Normalize()
])
# 定義訓練和驗證所用的資料集
# API說明:https://paddlex.readthedocs.io/zh_CN/develop/apis/datasets.html#paddlex-datasets-vocdetection
train_dataset = pdx.datasets.VOCDetection(
data_dir='work/voc2012',
file_list='work/voc2012/train_list.txt',
label_list='work/voc2012/labels_list.txt',
transforms=train_transforms,
shuffle=True)
eval_dataset = pdx.datasets.VOCDetection(
data_dir='work/voc2012',
file_list='work/voc2012/val_list.txt',
label_list='work/voc2012/labels_list.txt',
transforms=eval_transforms)
# 初始化模型,并進行訓練
# 可使用VisualDL查看訓練指標,參考https://paddlex.readthedocs.io/zh_CN/develop/train/visualdl.html
num_classes = len(train_dataset.labels)
# API說明: https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-yolov3
model = pdx.det.PPYOLO(num_classes=num_classes)
# API說明: https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#train
# 各引數介紹與調整說明:https://paddlex.readthedocs.io/zh_CN/develop/appendix/parameters.html
model.train(
num_epochs=20,
train_dataset=train_dataset,
train_batch_size=4,
eval_dataset=eval_dataset,
learning_rate=0.00025,
lr_decay_epochs=[10, 15],
save_interval_epochs=4,
log_interval_steps=100,
save_dir='output/ppyolo',
pretrain_weights='IMAGENET',
use_vdl=True)
剩下的就是等待了,我是早上(2021-01-13 10:21:33)開始訓練的,到下午(2021-01-13 14:46:20)就訓練好了,因為我這里Epoch設定的小了點,還有一些訓練引數設定的不夠好,導致訓練出的模型效果不是很好,時間有限,所以就沒有繼續優化了,所以下面使用的是飛槳已經訓練好的YOLOv3-MobileNetV1模型進行影像的目標檢測
PS:這里要說的是,其實在精度上,PPYOIO要比YOLOv3-MobileNetV1好,但因為我這里訓練引數沒有調好,所以訓練出來模型效果不是很好(也不是一塌糊涂,但相比于飛槳已經訓練好的YOLOv3-MobileNetV1),后面有時間的話,還會繼續調參繼續優化的,
(二)使用模型進行目標檢測(YOLOv3-MobileNetV1)
這是我在AIStudio進行行人社交距離檢測的專案鏈接傳送門.
有啥看不懂的,就看上面我附上的paddlex的說明檔案就明白了
import paddlex as pdx
model = pdx.load_model('yolov3_mobilenetv1_coco')
result = model.predict('3.jpg')
pdx.det.visualize('3.jpg', result, threshold=0.3, save_dir='./')
實作大致效果如下:

上面代碼中result回傳值是串列型別,串列中每個元素均為一個dict,key包括’bbox’, ‘category’, ‘category_id’, ‘score’,分別表示每個預測目標的框坐標資訊、類別、類別id、置信度,其中框坐標資訊為[xmin, ymin, w, h],即左上角x, y坐標和框的寬和高,
所以下面我們要做的就是對預測結果進行篩選,只提取和人相關的即可,然后就是,將每個矩形框的中心設定為每個人的中心,以每個人的中心為圓心,矩形框高度的一半為半徑,當兩個人中心之間的距離小于兩個人之間的半徑距離之和時,即認為兩個人之間的距離小于安全的社交距離,然后用紅色的矩形框將兩人框起來,并且用藍色的線條將兩人連接,如果某人與任何人的距離都大于安全的社交距離,則用綠色框將其框住,然后在影像下方顯示影像中的總人數和小于安全距離的總人數
代碼如下:
import paddlex as pdx
import cv2
from scipy.spatial import distance
test_jpg = '3.jpg'
model = pdx.load_model('yolov3_mobilenetv1_coco')
# predict介面并未過濾低置信度識別結果,用戶根據需求按score值進行過濾
result = model.predict(test_jpg)
def bounding_box(outs):#篩選目標為人和提取坐標的函式
boxes = []
for out in outs:
class_id=out['category_id']
if class_id == 0:
# 0 is ID of persons
confidence = out['score']
if confidence > 0.35:
x = int(out['bbox'][0])
y = int(out['bbox'][1])
w = int(out['bbox'][2])
h = int(out['bbox'][3])
boxes.append([x, y, w, h])
return boxes
boxes=bounding_box(result)
frame=cv2.imread('3.jpg')
circles = []
for i in range(len(boxes)):#生成圓心和半徑
x, y = int(boxes[i][0]), int(boxes[i][1])
w, h = int(boxes[i][2]), int(boxes[i][3])
frame = cv2.circle(frame, ( x + w // 2,y + h // 2), 5, (255, 20, 200), -1)
circles.append([x + w // 2, y + h // 2, h/2])#這里用人的高度做距離的檢測半徑
indexes = []
for i in range(len(circles)):#計算人與人之間的距離,并將距離小于安全距離的坐標索引進行保存
x1, y1, r1 = circles[i]
for j in range(i + 1, len(circles)):
x2, y2, r2 = circles[j]
if distance.euclidean((x1,y1),(x2,y2))<(r1+r2):
indexes.append(i)
indexes.append(j)
cv2.line(frame, (x1, y1), (x2, y2), (255, 0, 0), 2)
num=0
for (i, (x, y, w,h)) in enumerate(boxes):
if i in indexes:
num=num+1
color=(0,0,255)#安全距離之外的,為紅色
color=(0,255,0)#安全距離之外的,為綠色
cv2.rectangle(frame, (x, y), (x+w, y+h), color, 2)
cv2.rectangle(frame, (0, frame.shape[0] - 50), (frame.shape[1], frame.shape[0]), (0, 255, 0), -1)
cv2.putText(frame,"Total Persons : " + str(len(boxes)),(0, frame.shape[0]-10 ),
fontFace=cv2.QT_FONT_NORMAL,fontScale=1,color=(0, 0, 0))
cv2.putText(frame,"Alarm : " + str(num),(frame.shape[1]//2, frame.shape[0]-10),
fontFace=cv2.QT_FONT_NORMAL,fontScale=1,color=(0,0,255))
cv2.imwrite('frame.jpg',frame)
效果如下:

下面是對視頻流的處理
方法與圖片的類似,這里引入了moviepy庫,對影像進行處理,至于怎么使用,可自行baidu,這里就不解釋了,下面是一個寫的比較好的,小伙伴們,可以看看
傳送門.
視頻流處理的代碼:
import cv2
import paddlex as pdx
from scipy.spatial import distance
from moviepy.editor import VideoFileClip
model = pdx.load_model('work/yolov3_darknet53_coco')
# predict介面并未過濾低置信度識別結果,用戶根據需求按score值進行過濾
def bounding_box(outs):
boxes = []
for out in outs:
class_id = out['category_id']
if class_id == 0:
# 0 is ID of persons
confidence = out['score']
if confidence > 0.35:
w = int(out['bbox'][2])
h = int(out['bbox'][3])
x = int(out['bbox'][0])
y = int(out['bbox'][1])
boxes.append([x, y, w, h])
return boxes
def op(frame):
result = model.predict(frame)
boxes = bounding_box(result)
circles = []
for i in range(len(boxes)):
x, y = int(boxes[i][0]), int(boxes[i][1])
w, h = int(boxes[i][2]), int(boxes[i][3])
frame = cv2.circle(frame, (x + w // 2, y + h // 2), 5, (255, 201, 201), -1)
circles.append([x + w // 2, y + h // 2, h / 2]) # 這里用人的高度做距離的檢測半徑
indexes = []
for i in range(len(circles)):
x1, y1, r1 = circles[i]
for j in range(i + 1, len(circles)):
x2, y2, r2 = circles[j]
if distance.euclidean((x1, y1), (x2, y2)) < (r1 + r2):
indexes.append(i)
indexes.append(j)
cv2.line(frame, (x1, y1), (x2, y2), (0, 0, 255), 2)
num = 0
for (i, (x, y, w,h)) in enumerate(boxes):
if i in indexes:
num = num + 1
color = (255, 0, 0)
else:
color = (0, 255, 0)
cv2.rectangle(frame, (x, y), (x+w, y+h), color, 2)
cv2.rectangle(frame, (0, frame.shape[0] - 50), (frame.shape[1], frame.shape[0]), (0, 255, 0), -1)
cv2.putText(frame, "Total Persons : " + str(len(boxes)), (0, frame.shape[0] - 10),
fontFace=cv2.QT_FONT_NORMAL, fontScale=1, color=(0, 0, 0))
cv2.putText(frame, "Warning : " + str(num), (frame.shape[1] // 2, frame.shape[0] - 10),
fontFace=cv2.QT_FONT_NORMAL, fontScale=1, color=(0, 0, 255))
return frame
clip=VideoFileClip('1.mp4')
out_put=clip.fl_image(op)
out_put.write_videofile('out_put.mp4')
效果如下(有興趣的小伙伴可以看看,效果還不錯):
視頻傳送門.
提取碼:pmp7
用paddlex是不是很簡單,其簡明易懂的Python API,方便用戶根據實際生產需求進行直接呼叫或二次開發,為開發者提供飛槳全流程開發的最佳實踐,真的是太好用了,媽媽再也不用擔心我煉丹(Deep learning)了,總之就是非常好用,
(三)結語
木有了
如果有什么錯誤的地方,還請大家批評指正,最后,希望小伙伴們都能有所識訓,碼字不易,喜歡的話,關注一波在走吧

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/249063.html
標籤:其他
上一篇:非公平鎖比公平鎖高效的原因
