0 前言
?? 優(yōu)質(zhì)競賽項目系列,今天要分享的是
?? **基于深度學(xué)習(xí)疫情社交安全距離檢測算法 **
該項目較為新穎,適合作為競賽課題方向,學(xué)長非常推薦!
??學(xué)長這里給一個題目綜合評分(每項滿分5分)
- 難度系數(shù):3分
- 工作量:3分
- 創(chuàng)新點(diǎn):5分
?? 更多資料, 項目分享:文章來源:http://www.zghlxwxcb.cn/news/detail-735667.html
https://gitee.com/dancheng-senior/postgraduate文章來源地址http://www.zghlxwxcb.cn/news/detail-735667.html
1 課題背景
安全的社交距離是公共預(yù)防傳染病毒的途徑之一。所以,在人群密集的區(qū)域進(jìn)行社交距離的安全評估是十分重要的。社交距離的測量旨在保持個體之間的物理距離和減少相互接觸的人群來減緩或阻止病毒傳播,在抗擊病毒和預(yù)防大流感中發(fā)揮重要作用。但時刻保持安全距離具有一定的難度,特別是在校園,工廠等場所,在這種情況下,開發(fā)智能攝像頭等技術(shù)尤為關(guān)鍵。將人工智能,深度學(xué)習(xí)集成至安全攝像頭對行人進(jìn)行社交距離評估?,F(xiàn)階段針對疫情防范的要求,主要采用人工干預(yù)和計算機(jī)處理技術(shù)。人工干預(yù)存在人力資源要求高,風(fēng)險大,時間成本高等等缺點(diǎn)。計算機(jī)處理等人工智能技術(shù)的發(fā)展,對社交安全距離的安全評估具有良好的效果。
2 實現(xiàn)效果
通過距離分類人群的高危險和低危險距離。
相關(guān)代碼
?
import argparse
from utils.datasets import *
from utils.utils import *
def detect(save_img=False):
out, source, weights, view_img, save_txt, imgsz = \
opt.output, opt.source, opt.weights, opt.view_img, opt.save_txt, opt.img_size
webcam = source == '0' or source.startswith('rtsp') or source.startswith('http') or source.endswith('.txt')
# Initialize
device = torch_utils.select_device(opt.device)
if os.path.exists(out):
shutil.rmtree(out) # delete output folder
os.makedirs(out) # make new output folder
half = device.type != 'cpu' # half precision only supported on CUDA
# Load model
google_utils.attempt_download(weights)
model = torch.load(weights, map_location=device)['model'].float() # load to FP32
# torch.save(torch.load(weights, map_location=device), weights) # update model if SourceChangeWarning
# model.fuse()
model.to(device).eval()
if half:
model.half() # to FP16
# Second-stage classifier
classify = False
if classify:
modelc = torch_utils.load_classifier(name='resnet101', n=2) # initialize
modelc.load_state_dict(torch.load('weights/resnet101.pt', map_location=device)['model']) # load weights
modelc.to(device).eval()
# Set Dataloader
vid_path, vid_writer = None, None
if webcam:
view_img = True
torch.backends.cudnn.benchmark = True # set True to speed up constant image size inference
dataset = LoadStreams(source, img_size=imgsz)
else:
save_img = True
dataset = LoadImages(source, img_size=imgsz)
# Get names and colors
names = model.names if hasattr(model, 'names') else model.modules.names
colors = [[random.randint(0, 255) for _ in range(3)] for _ in range(len(names))]
# Run inference
t0 = time.time()
img = torch.zeros((1, 3, imgsz, imgsz), device=device) # init img
_ = model(img.half() if half else img) if device.type != 'cpu' else None # run once
for path, img, im0s, vid_cap in dataset:
img = torch.from_numpy(img).to(device)
img = img.half() if half else img.float() # uint8 to fp16/32
img /= 255.0 # 0 - 255 to 0.0 - 1.0
if img.ndimension() == 3:
img = img.unsqueeze(0)
# Inference
t1 = torch_utils.time_synchronized()
pred = model(img, augment=opt.augment)[0]
# Apply NMS
pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres,
fast=True, classes=opt.classes, agnostic=opt.agnostic_nms)
t2 = torch_utils.time_synchronized()
# Apply Classifier
if classify:
pred = apply_classifier(pred, modelc, img, im0s)
# List to store bounding coordinates of people
people_coords = []
# Process detections
for i, det in enumerate(pred): # detections per image
if webcam: # batch_size >= 1
p, s, im0 = path[i], '%g: ' % i, im0s[i].copy()
else:
p, s, im0 = path, '', im0s
save_path = str(Path(out) / Path(p).name)
s += '%gx%g ' % img.shape[2:] # print string
gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh
if det is not None and len(det):
# Rescale boxes from img_size to im0 size
det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()
# Print results
for c in det[:, -1].unique():
n = (det[:, -1] == c).sum() # detections per class
s += '%g %ss, ' % (n, names[int(c)]) # add to string
# Write results
for *xyxy, conf, cls in det:
if save_txt: # Write to file
xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh
with open(save_path[:save_path.rfind('.')] + '.txt', 'a') as file:
file.write(('%g ' * 5 + '\n') % (cls, *xywh)) # label format
if save_img or view_img: # Add bbox to image
label = '%s %.2f' % (names[int(cls)], conf)
if label is not None:
if (label.split())[0] == 'person':
people_coords.append(xyxy)
# plot_one_box(xyxy, im0, line_thickness=3)
plot_dots_on_people(xyxy, im0)
# Plot lines connecting people
distancing(people_coords, im0, dist_thres_lim=(200,250))
# Print time (inference + NMS)
print('%sDone. (%.3fs)' % (s, t2 - t1))
# Stream results
if view_img:
cv2.imshow(p, im0)
if cv2.waitKey(1) == ord('q'): # q to quit
raise StopIteration
# Save results (image with detections)
if save_img:
if dataset.mode == 'images':
cv2.imwrite(save_path, im0)
else:
if vid_path != save_path: # new video
vid_path = save_path
if isinstance(vid_writer, cv2.VideoWriter):
vid_writer.release() # release previous video writer
fps = vid_cap.get(cv2.CAP_PROP_FPS)
w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*opt.fourcc), fps, (w, h))
vid_writer.write(im0)
if save_txt or save_img:
print('Results saved to %s' % os.getcwd() + os.sep + out)
if platform == 'darwin': # MacOS
os.system('open ' + save_path)
print('Done. (%.3fs)' % (time.time() - t0))
?
3 相關(guān)技術(shù)
3.1 YOLOV4
YOLOv4使用卷積網(wǎng)絡(luò) CSPDarknet-53 特征提取,網(wǎng)絡(luò)結(jié)構(gòu)模型如圖 2 所示。在每個 Darknet-53的殘塊行加上 CSP(Cross
Stage Partial)結(jié)構(gòu)13,將基礎(chǔ)層劃分為兩部分,再通過跨層次結(jié)構(gòu)的特征融合進(jìn)行合并。并采用 FPN( feature pyramid
networks)結(jié)構(gòu)加強(qiáng)特征金字塔,最后用不同層的特征的高分辨率來提取不同尺度特征圖進(jìn)行對象檢測。最終網(wǎng)絡(luò)輸出 3
個不同尺度的特征圖,在三個不同尺度特征圖上分別使用 3 個不同的先驗框(anchors)進(jìn)行預(yù)測識別,使得遠(yuǎn)近大小目標(biāo)均能得到較好的檢測。
YOLOv4 的先驗框尺寸是經(jīng)PASCALL_VOC,COCO
數(shù)據(jù)集包含的種類復(fù)雜而生成的,并不一定完全適合行人。本研究旨在研究行人之間的社交距離,針對行人目標(biāo)檢測,利用聚類算法對 YOLOv4
的先驗框微調(diào),首先將行人數(shù)據(jù)集 F 依據(jù)相似性分為i個對象,即,其中每個對象都具有 m
個維度的屬性。聚類算法的目的是 i 個對象依據(jù)相似性聚集到指定的 j 個類簇,每個對象屬于且僅屬于一個其到類簇中心距離最小的類簇中心。初始化 j 個 聚 類
中 心,計算每一個對象到每一個聚類中心的歐式距離,見公式
之后,依次比較每個對象到每個聚類中心的距離,將對象分配至距離最近的簇類中心的類簇中,
得到 個類簇
,聚類算法中定義了類簇的原型,類簇中心就是類簇內(nèi)所有對象在各個維度的均值,其公式見
相關(guān)代碼
?
def check_anchors(dataset, model, thr=4.0, imgsz=640):
# Check anchor fit to data, recompute if necessary
print('\nAnalyzing anchors... ', end='')
m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect()
shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True)
wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes, dataset.labels)])).float() # wh
def metric(k): # compute metric
r = wh[:, None] / k[None]
x = torch.min(r, 1. / r).min(2)[0] # ratio metric
best = x.max(1)[0] # best_x
return (best > 1. / thr).float().mean() # best possible recall
bpr = metric(m.anchor_grid.clone().cpu().view(-1, 2))
print('Best Possible Recall (BPR) = %.4f' % bpr, end='')
if bpr < 0.99: # threshold to recompute
print('. Attempting to generate improved anchors, please wait...' % bpr)
na = m.anchor_grid.numel() // 2 # number of anchors
new_anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False)
new_bpr = metric(new_anchors.reshape(-1, 2))
if new_bpr > bpr: # replace anchors
new_anchors = torch.tensor(new_anchors, device=m.anchors.device).type_as(m.anchors)
m.anchor_grid[:] = new_anchors.clone().view_as(m.anchor_grid) # for inference
m.anchors[:] = new_anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss
print('New anchors saved to model. Update model *.yaml to use these anchors in the future.')
else:
print('Original anchors better than new anchors. Proceeding with original anchors.')
print('') # newline
3.2 基于 DeepSort 算法的行人跟蹤
YOLOv4中完成行人目標(biāo)檢測后生成邊界框(Bounding box,Bbox),Bbox 含有包含最小化行人邊框矩形的坐標(biāo)信息,本研究引入
DeepSort 算法[18]完成對行人的質(zhì)點(diǎn)進(jìn)行跟蹤,目的是為了在運(yùn)動矢量分析時算行人安全社交距離中。首先,對行人進(jìn)行質(zhì)點(diǎn)化計算。其質(zhì)點(diǎn)計算公式如
確定行人質(zhì)點(diǎn)后,利用 DeepSort 算法實現(xiàn)對多個目標(biāo)的精確定位與跟蹤,其核心算法流程如圖所示:
相關(guān)代碼
?
class TrackState:
'''
單個軌跡的三種狀態(tài)
'''
Tentative = 1 #不確定態(tài)
Confirmed = 2 #確定態(tài)
Deleted = 3 #刪除態(tài)
class Track:
def __init__(self, mean, covariance, track_id, class_id, conf, n_init, max_age,
feature=None):
'''
mean:位置、速度狀態(tài)分布均值向量,維度(8×1)
convariance:位置、速度狀態(tài)分布方差矩陣,維度(8×8)
track_id:軌跡ID
class_id:軌跡所屬類別
hits:軌跡更新次數(shù)(初始化為1),即軌跡與目標(biāo)連續(xù)匹配成功次數(shù)
age:軌跡連續(xù)存在的幀數(shù)(初始化為1),即軌跡出現(xiàn)到被刪除的連續(xù)總幀數(shù)
time_since_update:軌跡距離上次更新后的連續(xù)幀數(shù)(初始化為0),即軌跡與目標(biāo)連續(xù)匹配失敗次數(shù)
state:軌跡狀態(tài)
features:軌跡所屬目標(biāo)的外觀語義特征,軌跡匹配成功時添加當(dāng)前幀的新外觀語義特征
conf:軌跡所屬目標(biāo)的置信度得分
_n_init:軌跡狀態(tài)由不確定態(tài)到確定態(tài)所需連續(xù)匹配成功的次數(shù)
_max_age:軌跡狀態(tài)由不確定態(tài)到刪除態(tài)所需連續(xù)匹配失敗的次數(shù)
'''
self.mean = mean
self.covariance = covariance
self.track_id = track_id
self.class_id = int(class_id)
self.hits = 1
self.age = 1
self.time_since_update = 0
self.state = TrackState.Tentative
self.features = []
if feature is not None:
self.features.append(feature) #若不為None,初始化外觀語義特征
self.conf = conf
self._n_init = n_init
self._max_age = max_age
def increment_age(self):
'''
預(yù)測下一幀軌跡時調(diào)用
'''
self.age += 1 #軌跡連續(xù)存在幀數(shù)+1
self.time_since_update += 1 #軌跡連續(xù)匹配失敗次數(shù)+1
def predict(self, kf):
'''
預(yù)測下一幀軌跡信息
'''
self.mean, self.covariance = kf.predict(self.mean, self.covariance) #卡爾曼濾波預(yù)測下一幀軌跡的狀態(tài)均值和方差
self.increment_age() #調(diào)用函數(shù),age+1,time_since_update+1
def update(self, kf, detection, class_id, conf):
'''
更新匹配成功的軌跡信息
'''
self.conf = conf #更新置信度得分
self.mean, self.covariance = kf.update(
self.mean, self.covariance, detection.to_xyah()) #卡爾曼濾波更新軌跡的狀態(tài)均值和方差
self.features.append(detection.feature) #添加軌跡對應(yīng)目標(biāo)框的外觀語義特征
self.class_id = class_id.int() #更新軌跡所屬類別
self.hits += 1 #軌跡匹配成功次數(shù)+1
self.time_since_update = 0 #匹配成功時,軌跡連續(xù)匹配失敗次數(shù)歸0
if self.state == TrackState.Tentative and self.hits >= self._n_init:
self.state = TrackState.Confirmed #當(dāng)連續(xù)匹配成功次數(shù)達(dá)標(biāo)時軌跡由不確定態(tài)轉(zhuǎn)為確定態(tài)
def mark_missed(self):
'''
將軌跡狀態(tài)轉(zhuǎn)為刪除態(tài)
'''
if self.state == TrackState.Tentative:
self.state = TrackState.Deleted #當(dāng)級聯(lián)匹配和IOU匹配后仍為不確定態(tài)
elif self.time_since_update > self._max_age:
self.state = TrackState.Deleted #當(dāng)連續(xù)匹配失敗次數(shù)超標(biāo)
'''
該部分還存在一些軌跡坐標(biāo)轉(zhuǎn)化及狀態(tài)判定函數(shù),具體可參考代碼來源
'''
?
4 最后
?? 更多資料, 項目分享:
https://gitee.com/dancheng-senior/postgraduate
到了這里,關(guān)于計算機(jī)競賽 深度學(xué)習(xí)疫情社交安全距離檢測算法 - python opencv cnn的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!