이미지/비디오에서 마스크 착용여부 감지

Updated:

  1. Mask detection
    • Info
    • Observations
    • 환경 및 실습

Info

  • Dependencies:
    • Python 3+
    • TensorFlow 2+
    • OpenCV
    • numpy
    • matplotlib
  • Reference

observations

코로나 바이러스로 생활 속 마스크 착용은 대부분(?)의 사람들에게 당연한 일상이 되었다. 대중교통 이용시 마스크 착용 의무화와 관련하여 마스크 착용감지를 하는 모델을 만들어보자.

모델파일 추가한 github(원본 말고 이것을 사용하세요)

ex_img1

모델 학습을 위해 다음 2가지 data가 필요함.

  1. 마스크를 착용한 사람의 이미지
  2. 마스크를 착용하지 않은 사람의 이미지

ex_img2

원본 제작자의 아이디어는 실제 마스크를 착용한 사람의 이미지를 사용하는 것이 아니라 <사람의 얼굴 사진 -> 얼굴 감지 -> 스노우 앱과 비슷한 기능으로 마스크 모양의 이미지를 얼굴에 덮어씌움> 라는 과정으로 input data를 생성해줌.


train data/test data 나누기와 모델링 생략

전이학습의 방법 사용 modeling1

+ 최적화 방법 modeling2


0. 코랩 환경에서 시작

  1. 우선 편하게 진행할 수 있도록 제 깃허브에서 repository를 클론합니다.
!git clone https://github.com/gachonyws/face-mask-detector.git
  1. 디렉토리 이동 후 작업 시작
cd face-mask-detector/

1. 모델 로드

from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
from tensorflow.keras.models import load_model
import numpy as np
import cv2
import os
import matplotlib.pyplot as plt

# 사진 속에서 얼굴을 탐지하는 face_detector 모델
facenet = cv2.dnn.readNet('face_detector/deploy.prototxt','face_detector/res10_300x300_ssd_iter_140000.caffemodel')
# 얼굴인식 후 마스크 착용 여부를 확인하는 모델
model = load_model('mask_detector.model')

2. 이미지 로드

img = cv2.imread('/content/face-mask-detector/examples/example_01.png')
h,w = img.shape[:2]
plt.figure(figsize=(16,10))
plt.imshow(img[:,:,::-1]) # BGR -> RGB 변환

example1

3. Preprocessing for Face Detection

blob = cv2.dnn.blobFromImage(img, scalefactor=1.0, size=(300, 300), mean=
	(104.0, 177.0, 123.0))
facenet.setInput(blob) # 모델에 들어가는 input
detections = facenet.forward() # 결과를 inference

4. Detect Faces

faces = []

# 사진속 얼굴 개수가 여러 개 있을 수 있으니 반복문 사용
for i in range(detections.shape[2]):
  confidence = detections[0,0,i,2]

  if confidence < 0.5:
    continue
  else:
     x1 = int(detections[0,0,i,3] * w)
     y1 = int(detections[0,0,i,4] * h)
     x2 = int(detections[0,0,i,5] * w)
     y2 = int(detections[0,0,i,6] * h)

     face = img[y1:y2, x1:x2]
     faces.append(face)

plt.figure(figsize=(10,5))

for i, face in enumerate(faces):
    plt.subplot(1, len(faces), i+1)
    plt.imshow(face[:, :, ::-1])

example2

Detect Masks from faces

plt.figure(figsize=(10,5))

for i, face in enumerate(faces):
    face_input = cv2.cvtColor(face, cv2.COLOR_BGR2RGB)
    face_input = cv2.resize(face_input, dsize=(224, 224))
    face_input = preprocess_input(face_input)
    face_input = np.expand_dims(face_input, axis=0)

    (mask, nomask) = model.predict(face_input)[0]

    plt.subplot(1, len(faces), i+1)
    plt.imshow(face[:, :, ::-1])
    plt.title('%.2f%%' % (mask * 100))

example3


이어서 동영상 재생


from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
from tensorflow.keras.models import load_model
import numpy as np
import cv2
import matplotlib.pyplot as plt
import os

cap = cv2.VideoCapture('examples/03.mp4')
ret, img = cap.read()

fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
out = cv2.VideoWriter('./output.mp4', fourcc, cap.get(cv2.CAP_PROP_FPS), (img.shape[1], img.shape[0]))

while cap.isOpened():
    ret, img = cap.read()
    if not ret:
        break

    h, w = img.shape[:2]

    blob = cv2.dnn.blobFromImage(img, scalefactor=1., size=(300, 300), mean=(104., 177., 123.))
    facenet.setInput(blob)
    dets = facenet.forward()

    result_img = img.copy()

    for i in range(dets.shape[2]):
        confidence = dets[0, 0, i, 2]
        if confidence < 0.5:
            continue

        x1 = int(dets[0, 0, i, 3] * w)
        y1 = int(dets[0, 0, i, 4] * h)
        x2 = int(dets[0, 0, i, 5] * w)
        y2 = int(dets[0, 0, i, 6] * h)

        face = img[y1:y2, x1:x2]

        face_input = cv2.resize(face, dsize=(224, 224))
        face_input = cv2.cvtColor(face_input, cv2.COLOR_BGR2RGB)
        face_input = preprocess_input(face_input)
        face_input = np.expand_dims(face_input, axis=0)

        mask, nomask = model.predict(face_input).squeeze()

        if mask > nomask:
            color = (0, 255, 0)
            label = 'Mask %d%%' % (mask * 100)
        else:
            color = (0, 0, 255)
            label = 'No Mask %d%%' % (nomask * 100)

        cv2.rectangle(result_img, pt1=(x1, y1), pt2=(x2, y2), thickness=2, color=color, lineType=cv2.LINE_AA)
        cv2.putText(result_img, text=label, org=(x1, y1 - 10), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.8, color=color, thickness=2, lineType=cv2.LINE_AA)

    out.write(result_img)
    #cv2_imshow(result_img) # colab 환경에서 출력 때문에 계속 Busy 상태라 ignore
    if cv2.waitKey(1) == ord('q'):
        break

out.release()
cap.release()

example4

코랩 내에서 동영상 재생에 문제가 있어 결과물을 로컬로 다운받아서 재생해 보시면 됩니다.


  • 결과

여러명의 사진도 정상적으로 작동 확인. example4

  • 동영상 실행 결과
  • 웹캠 라이브 녹화

IP캠이나 실시간 촬영이 가능한 카메라로 mask detection 의 결과가 no_mask 이면 경고음이 울리게 하는 등의 구현 가능. (화상 열감지 감시 등의 기능에서도 실제로 사용할 것이라고 추측)

Leave a comment