본문 바로가기

자율주행

DMS(Drive Monitoring System)

 

자율주행에 보조 시스템은 차에 달려있는 여러 센서와 카메라들을 사용합니다.

 

ADAS와 같이 주행을 보조하고 차량이 차선 이탈을 할 경우, 이를 알려줘 사고를 방지하거나 인-캐빈 모니터를 사용해서 탑승자와 반려동물에 대한 모니터링 및 차량에 실내 상태를 모니터링 할 수도 있습니다. 후방 카메라로 주차를 하는데 도움을 준다거나 AroundView Monitoring을 통해서 차량의 사각지대를 볼 수 있게 해주거나 DMS와 같이 졸음 전방 미주시와 같이 운전 자의 상태를 확인해 경고를 해주는 시스템도 존재합니다.

 

이번에는 DMS를 간단하게 알아보려고 합니다.

 

DMS란 감지 기술과 분석을 사용해서 머리와 몸의 자세 눈의 상태, 주의력 졸음, 감정 및 장애를 모니터링하는 창량내에 존재하는 시스템을 의미합니다.

 

DMS는 다음과 같은 효과가 있다고 합니다.

  • 효과적인 차량-운전자 핸드오버를 제공
  • 레벨 3 ~ 4 자율주생에서 중요한 역할을 하는 시스템
  • 운전자의 졸음 및 집중도 저하로 인한 자동차 사고 다수 발생
  • 왕립사고예방협회에서 수행한 연구에 따르면 운전자의 주의력은 사고의 상당 부분에서 중요한 요소로 작용
  • 따라서 주행 중 졸음, 전방미주시, 핸드폰 사용, 담배 사용 등을 감지하여, 이에 대하여 운전자에게 알리는 역할

이러한 역할을 수행함으로 사고를 줄이는데 도움을 주는 시스템이라고 합니다.

 

DMS를 구현하기 위해서는 우선 face detection을 수행해야합니다. 따라서 얼굴을 감지하기 위해서 공개된 open dataset을 사용해서 retinaface_mobile0.25 모델을 학습시켰습니다.

 

이후 찾은 얼굴로 부터, landmark detection 모델을 사용해서, 각 얼굴에 point들을 감지해야합니다. landmark detection에는 PFLD 모델을 사용했습니다.

 

이후 Calculate Ratio of Face를 계산합니다.

 

EAR은 눈의 감은 정도를 나타냅니다. 따라가 EAR 값이 작으면 작을수 록 운전자가 눈을 감고있는 상태라는 것을 알 수 있고, 해당 계산식은 각각 왼쪽눈과 오른쪽 눈을 계산한 것입니다.

 

p아래 첨자에 있는 숫자는 옆에 사람 얼굴에 있는 점의 번호입니다.

 

그리고 HR과 SR인데 2개의 계산을 결과를 사용해서 운전자가 전방을 현재 주시하고 있는지 아닌지를 판단할 수 있습니다. HR의 경우, a< HR< b일 경우에 전방을 주시하고 있지 않은 상황이고, SR의 경우 SR < a, b < SR일 경우에 전방을 주시하고 있지 않은 상황이라고 합니다.

 

DMS를 test할 데이터 셋은 AI-Hub에서 사용했습니다.

 

EAR, HR, SR을 계산하는 코드는 다음과 같습니다.

def ear(pts):
    A = dist.euclidean(pts[1], pts[7])
    B = dist.euclidean(pts[3], pts[5])
    C = dist.euclidean(pts[0], pts[4])
    return (A+B)/(2.0 * C)

def head_rate(pts):
    A = dist.euclidean(pts[51], pts[54])
    B = dist.euclidean(pts[54], pts[16])
    return A/B

def stir_rate(pts):
    A = dist.euclidean(pts[4], pts[54])
    B = dist.euclidean(pts[28], pts[54])
    return A/B

def face_metric(pts):
    left_EAR = ear(pts[60:68])
    right_EAR = ear(pts[68:76])
    EAR_avg = (left_EAR + right_EAR) / 2
    HR = head_rate(pts)
    SR = stir_rate(pts)
    return EAR_avg, HR, SR

 

 

졸음을 감지하기 위한 code입니다.

for i in tqdm(range(len(file_list)), bar_format='{desc:<5.5}{percentage:3.0f}%|{bar:10}{r_bar}'):
        # test image 읽어오기
        file = file_list[i]
        img = cv2.imread(os.path.join(data_folder, file))

        #Face detection 진행
        dets = face_detection(img, face_detection_model)
        cr = time.time()
        
        if len(dets) == 0 or dets[0][4] < vis_thresh:
            if face_detection_n == False:
                fd_time = cr
                face_detection_n = True
            if face_detection == True and cr - fd_time > time_th:
                face_detection_n_warning = True
                if face_detection_n_warning :
                    cv2.rectangle(img, (0,0), (300, 100), (255,0,0), -1, cv2.LINE_AA)  # filled
                    cv2.putText(img, 'Warning!', (5,70),cv2.FONT_HERSHEY_DUPLEX, 2,(255,255,255), thickness=3, lineType=cv2.LINE_AA)
            filename = f'm_{idx:04d}.png'
            cv2.imwrite(os.path.join(save_folder, filename), cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
            idx += 1
            continue
        
        face_detection_n = False
        face_detection_n_warning = False

 

if len(dets) == 0 or dets[0][4] < vis_thresh:
	if face_detection_n == False:
    	fd_time = cr
        face_detection_n = True
    if face_detection == True and cr - fd_time > time_th:
        face_detection_n_warning = True
        if face_detection_n_warning :
        	cv2.rectangle(img, (0,0), (300, 100), (255,0,0), -1, cv2.LINE_AA)  # filled
                cv2.putText(img, 'Warning!', (5,70),cv2.FONT_HERSHEY_DUPLEX, 2,(255,255,255), thickness=3, lineType=cv2.LINE_AA)
    filename = f'm_{idx:04d}.png'
    cv2.imwrite(os.path.join(save_folder, filename), cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    idx += 1
    continue

 

이 부분은 감지돈 얼굴이 없거나 감진된 얼굴이 socre보다 낮을경우 전방 미주시가 되고, 만약 이전에 문제가 없었을 경우, face_detection_n == False일 경우 현재 위치부터 문제가 발생한 시간을 넣어주게 됩니다. 또한 문제가 발생 했으므로, face_detection_n = True로 변경됩니다.

 

이전에도 face_detection_n = True이고(전방 미주시),2.5초 이상 전방을 보지 않았을 경우, warning이 발생하고, 이미지 결과를 저장하고 landmark detection을 하지 않고, 다음 loop로 이동합니다.

 

이후, 전방 주시에 대해서 아무 문제가 없었을 경우, face_detection_n = False와 face_detection_n_warning = False로 초기화 되고, landmark detection code가 진행됩니다.

 points = landmark_detection(img, dets[0], face_landmark_detection_model)
 EAR, HR, SR = face_metric(points)

 

그리고, 계산되 값이 아래 코드에서 와 같이 

 # EAR 이상 확인
if EAR < EAR_Thresh:
   cr = time.time()
   if ear_status == False:
      ear_time = cr
      ear_status = True
   if ear_status == True and cr - ear_time >time_th:
      ear_status_warning = True
else:
   ear_status = False
   ear_status_warning = False

# 고개 이상 확인
if (HR_Thresh[0] <HR and HR < HR_Thresh[1]) or (SR > SR_Thresh[0] and SR_Thresh[1] < SR):
   cr = time.time()
   if head_status == False:
      head_time = cr
      head_status = True
   if head_status == True and cr - head_time >time_th:
      head_status_warning = True
else:
   head_status = False
   head_status_warning = False

 

warning을 발생 시킬지 값을 초기화 시킬지를 결정하게 됩니다.

  • ear의 경우, 0.2보다 작을 경우 warning이 발생
  • HR의 경우, 0.5 < HR < 0.95 경우, warning이 발생
  • SR의 경우 SR < 0.5, SR > 2경우, warning이 발생

DMS 전체 구현 코드는 github에 있습니다.

 

GitHub - Kang812/KW_DMS: DMS(Drive Monitoring System)

DMS(Drive Monitoring System). Contribute to Kang812/KW_DMS development by creating an account on GitHub.

github.com

 

'자율주행' 카테고리의 다른 글

ADAS(Advanced Driver Assistance System)  (0) 2024.06.01