天天看點

手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)

導讀

本期将介紹使用OpenCV實作人臉口罩佩戴檢測的詳細步驟,手把手教你做一個效果還可以的口罩佩戴檢測系統。

口罩檢測思路與常用方法

在動手實作人臉口罩佩戴檢測系統之前,我們常常會思考如何檢測一個人是否佩戴口罩?方法很多,這裡列舉幾個比較典型的方法:

① 用深度學習目标檢測的方法,标注佩戴口罩與未佩戴口罩兩類,然後選擇合适的網絡去訓練檢測,比如YoloV5等;

手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)

② 先檢測人臉,然後将人臉ROI圖像做分類,分為佩戴口罩和未佩戴口罩兩類,結合人臉檢測和分類網絡實作;

手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)

③ 用OpenCV實作,先檢測人臉,然後判斷人臉ROI是否有佩戴口罩的特征;

④ 其他更好的方法。

本文使用第③種方法,選擇合适的人臉檢測方法與口罩佩戴判斷方法即可。

效果展示

示範從視訊中檢測人臉是否佩戴口罩,未佩戴口罩将語音提示,避免露臉,測試視訊素材來源于網絡,實測使用筆記本自帶攝像頭檢測效果更佳:

實作步驟與對應代碼

程式實作步驟:

(1) 使用OpenCV DNN網絡檢測人臉;

(2) 通過HSV門檻值提取膚色;

(3) 通過膚色輪廓面積與人臉ROI面積比值判斷是否佩戴口罩。

人臉檢測方法對比:

(1) 使用OpenCV Haar分類器檢測人臉,例如使用自帶的haarcascade_frontalface_alt.xml不能适應光線暗的情況和人臉遮擋情況,佩戴了口罩無法檢測到人臉,無法繼續進行後面步驟;

(2) 使用Dlib檢測人臉,例如使用自帶的shape_predictor_5_face_landmarks.dat不能适應人臉遮擋情況,佩戴了口罩無法檢測到人臉,無法繼續進行後面步驟;

(3) 使用OpenCV DNN網絡檢測人臉,使用自帶的opencv_face_detector_uint8.pb能适應部分人臉遮擋和側臉情況,能繼續進行後續檢測。

人臉檢測步驟與代碼:

(1) 下載下傳OpenCV DNN人臉檢測模型:

連結:https://pan.baidu.com/s/1AaLYDjyMn17ZTxOv5f-m5A

提取碼:9396

手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)

(2) 加載模型檢測人臉,執行個體代碼與效果如下;

手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)
手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)
import sys
import numpy as np
import cv2


modelFile = "opencv_face_detector_uint8.pb"
configFile = "opencv_face_detector.pbtxt"
net = cv2.dnn.readNetFromTensorflow(modelFile, configFile)
conf_threshold = 0.7


def detectFaceOpenCVDnn(net, frame):
    blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), [104, 117, 123], False, False)
    frameHeight = frame.shape[0]
    frameWidth = frame.shape[1]
    net.setInput(blob)
    detections = net.forward()
    bboxes = []
    ret = 0
    for i in range(detections.shape[2]):
        confidence = detections[0, 0, i, 2]
        if confidence > conf_threshold:
            x1 = int(detections[0, 0, i, 3] * frameWidth)
            y1 = int(detections[0, 0, i, 4] * frameHeight)
            x2 = int(detections[0, 0, i, 5] * frameWidth)
            y2 = int(detections[0, 0, i, 6] * frameHeight)




            ROI = frame[y1:y2,x1:x2].copy()
            
            cv2.rectangle(frame,(x1,y1),(x2,y2),(0,255,0),2)#框出人臉區域
            
    return ret, frame


if __name__ == '__main__':
  img = cv2.imread("./2.jpg")
  _, result = detectFaceOpenCVDnn(net,img)
  cv2.imshow("face_detection", result)
  cv2.waitKey()
  cv2.destroyAllWindows()      

(3) 通過HSV門檻值提取膚色輪廓:

手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)
手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)
手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)
ROI = frame[y1:y2,x1:x2].copy()
hsv_img=cv2.cvtColor(ROI,cv2.COLOR_BGR2HSV)
lower_hsv_1 = np.array([0,30,30])#顔色範圍低門檻值
upper_hsv_1 = np.array([40,255,255])#顔色範圍高門檻值
lower_hsv_2 = np.array([140,30,30])#顔色範圍低門檻值
upper_hsv_2 = np.array([180,255,255])#顔色範圍高門檻值
mask1 = cv2.inRange(hsv_img,lower_hsv_1,upper_hsv_1)
mask2 = cv2.inRange(hsv_img,lower_hsv_2,upper_hsv_2)
mask = mask1 + mask2
mask = cv2.blur(mask,(3,3))
    
mask_color = cv2.cvtColor(mask,cv2.COLOR_GRAY2BGR)
cv2.imshow("mask", mask)      

(4) 通過膚色輪廓面積與ROI面積比值判斷是否有佩戴口罩,這裡設定比值為0.65,上面三幅圖的比例分别如下:

手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)
手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)
手把手教你用OpenCV做人臉口罩佩戴檢測(附詳細步驟+代碼)
def cnt_area(cnt):
  area = cv2.contourArea(cnt)
  return area


def If_Have_Mask(img):
  hsv_img=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
  lower_hsv_1 = np.array([0,30,30])#顔色範圍低門檻值
  upper_hsv_1 = np.array([40,255,255])#顔色範圍高門檻值
  lower_hsv_2 = np.array([140,30,30])#顔色範圍低門檻值
  upper_hsv_2 = np.array([180,255,255])#顔色範圍高門檻值
  mask1 = cv2.inRange(hsv_img,lower_hsv_1,upper_hsv_1)
  mask2 = cv2.inRange(hsv_img,lower_hsv_2,upper_hsv_2)
  mask = mask1 + mask2
  mask = cv2.blur(mask,(3,3))
    
  mask_color = cv2.cvtColor(mask,cv2.COLOR_GRAY2BGR)
  cv2.imshow("mask", mask)


  contours,hierarchy = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
  if len(contours) < 1:
      return "No Mask" 
      
  contours.sort(key = cnt_area, reverse=True)  
  #print(cv2.contourArea(contours[0]))
  area = cv2.contourArea(contours[0])
  mask_rate = area / (img.shape[0]*img.shape[1])
  print(mask_rate)
  if mask_rate < 0.65:
    return "Have Mask"
  else:
    return "No Mask"      

結尾語:

文章實作的步驟并非最優,但基本檢測效果還OK,大家跟着上述步驟和代碼完全可以自己做出來。當然如果你懶得動手,那就加入知識星球擷取吧,那裡為你準備了完整源碼和測試素材。

更多實用文章請移步至--精華文章--專題文章分類。

繼續閱讀