👄

【opencv&python】低コストで口を検出

2023/03/04に公開

opencvによる口の検出

opencvによる口の検出は以下の流れで行う。(ソースコードは末尾)

1.画像内の顔の検出
2.顔内の口の検出

ここでopencvによる口の検出は以下のように偽陽性(過剰な検出)が多い。

またopencvによる検出では画像の上から順に領域が検出されるといったルールは確認できない。(https://github.com/sergicalsix/Detection/tree/master/test_mouth_rule)

ここで検出された口候補の領域の内、一番下の領域が口であると仮定する。(一般的に画像内で人間は逆立ちや横を向いていない、口より下に口と思われる領域が存在しにくいので)

そこで口領域のy座標でsortを行い、もっとも下にある領域を口とみなすことができる。

tmp_mouth = mouth_cascade.detectMultiScale(roi_gray) #
tmp_mouth = tmp_mouth[np.argsort(tmp_mouth[:, 1])]

口検出のソースコード

import cv2
import numpy as np

def detection_mask(img_path):
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    mouth_cascade = cv2.CascadeClassifier('haarcascade_mcs_mouth.xml')

    
    img = cv2.imread(img_path)

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    faces = face_cascade.detectMultiScale(gray, 1.3, 5)

    mask_flag = True
    if len(faces) > 0:
        (x,y,w,h) = faces[0] #最初の一人

        roi_gray = gray[y:y+h, x:x+w]

        roi_color = img[y:y+h, x:x+w]

        cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

        tmp_mouth = mouth_cascade.detectMultiScale(roi_gray)

        if len(tmp_mouth) > 0:
            tmp_mouth = tmp_mouth[np.argsort(tmp_mouth[:, 1])]
            (mx,my,mw,mh) =  tmp_mouth[-1] #口候補のうち一番下にあるもの

            cv2.rectangle(roi_color,(mx,my),(mx+mw,my+mh),(0,255,255),2)

Discussion