PythonでOpenCVとDlibを使って顔検出テスト

Pythonの学習がてらですが、顔検出をやっていなかったと思い、OpenCVとDlibをテストしてみました。

Pycharmいいですね!

venv環境でopencv-pythonはさくっと入ります。

問題はDlibで、公式ページ見ながら試行錯誤してなんとか入りました。

動画にしました。

 

ここからはコードの話です。

まずはOpenCVですが、カスケードは

face_cascade = cv2.CascadeClassifier('haar-like/data/haarcascade_frontalface_alt.xml')
leftEye_cascade = cv2.CascadeClassifier('haar-like/data/haarcascade_mcs_lefteye.xml')
rightEye_cascade = cv2.CascadeClassifier('haar-like/data/haarcascade_mcs_righteye.xml')
nose_cascade = cv2.CascadeClassifier('haar-like/data/haarcascade_mcs_nose.xml')
mouth_cascade = cv2.CascadeClassifier('haar-like/data/haarcascade_mcs_mouth.xml')
eye_cascade = cv2.CascadeClassifier('haar-like/data/haarcascade_eye.xml')

を使いました。

汚いソースですが、

def detector(faces):
    facePoint = ""
    for (x, y, w, h) in faces:
        # 検知した顔を矩形で囲む
        # 顔画像(グレースケール)
        roi_gray = gray[y:y + h, x:x + w]
        cv2.imshow('roi_gray',roi_gray)
        cv2.moveWindow('roi_gray', 100, 200)
        # 顔画像の左上(グレースケール)
        roi_gray_leftUpper = gray[y+h//4:y + h//2, x:x + w//2]
        cv2.imshow('roi_gray_leftUpper',roi_gray_leftUpper)
        cv2.moveWindow('roi_gray_leftUpper', 340, 200)
        # 顔画像の右上(グレースケール)
        roi_gray_rightUpper = gray[y+h//4:y + h//2, x+w//2:x + w]
        cv2.imshow('roi_gray_rightUpper',roi_gray_rightUpper)
        cv2.moveWindow('roi_gray_rightUpper', 500, 200)
        # 顔画像の下(グレースケール)
        roi_gray_under = gray[y+ h//2:y + h, x:x + w]
        cv2.imshow('roi_gray_under',roi_gray_under)
        cv2.moveWindow('roi_gray_under', 360, 400)
        # 顔画像の中央(グレースケール)
        roi_gray_center = gray[y +h//4 :y + h - h//4, x+w//4:x + w - w//4]
        cv2.imshow('roi_gray_center',roi_gray_center)
        cv2.moveWindow('roi_gray_center', 400, 300)
        # 顔画像(カラースケール)
        roi_color = frame[y:y + h, x:x + w]

        # 顔の中から左目を検知
        lefteye = leftEye_cascade.detectMultiScale(roi_gray_leftUpper,minNeighbors=1)
        if len(lefteye) > 0:
            # 3番目(幅)が一番大きい要素のみ取得
            ex, ey, ew, eh = lefteye[np.argmax(lefteye, axis=0)[2]]
            # 検知した目を矩形で囲む
            leftEyePoint = [x+ex, y+ey+h//4, x+ex + ew, y+ey + eh+h//4]
        # 顔の中から右目を検知
        righteye = rightEye_cascade.detectMultiScale(roi_gray_rightUpper,minNeighbors=1)
        if len(righteye) > 0:
            # 3番目(幅)が一番大きい要素のみ取得
            ex, ey, ew, eh = righteye[np.argmax(righteye, axis=0)[2]]
            # 検知した目を矩形で囲む
            rightEyePoint = [x+ex+w//2, y+ey+h//4, x+ ex + ew+w//2,y+ ey + eh+h//4]
        # 顔の中から鼻を検知
        nose = nose_cascade.detectMultiScale(roi_gray_under,minNeighbors=1)
        if len(nose) > 0:
            # 3番目(幅)が一番大きい要素のみ取得
            ex, ey, ew, eh = nose[np.argmax(nose, axis=0)[2]]
            # 検知した鼻を矩形で囲む
            nosePoint = [x+ex, y+ey+h//2,x+ ex + ew,y+ ey + eh+h//2]
        # 顔の中から口を検知
        mouth = mouth_cascade.detectMultiScale(roi_gray_under,minNeighbors=1)
        if len(mouth) > 0:
            # 3番目(幅)が一番大きい要素のみ取得
            ex, ey, ew, eh = mouth[np.argmax(mouth, axis=0)[2]]
            # 検知した口を矩形で囲む
            mouthPoint = [x + ex,y+ ey+h//2,x+ ex + ew, y+ey + eh+h//2]
        if len(lefteye) > 0 and len(righteye) > 0 and len(nose) > 0 and len(mouth) > 0:
            facePoint = [[x, y, x + w, y + h],leftEyePoint,rightEyePoint,nosePoint,mouthPoint]
            return facePoint

これを呼び出すと各顔のパーツが入ります。各パーツは必ず1つあるぞ、前提です。

 

次にDlibですが、

def face_shape_detector_dlib(frame,detector,predictor):
    frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # frontal_face_detectorクラスは矩形, スコア, サブ検出器の結果を返す
    dets, scores, idx = detector.run(frame_rgb, 0)
    if len(dets) > 0:
        for i, rect in enumerate(dets):
            shape = predictor(frame_rgb, rect)
            shape = face_utils.shape_to_np(shape)
            clone = frame.copy()
            cv2.putText(clone, "Dlib", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 2)
            # landmarkを画像に書き込む
            for (x, y) in shape[0:68]:
                cv2.circle(clone, (x, y), 1, (0, 0, 255), 5)
            # shapeで指定した個所の切り取り画像(ROI)を取得
            (x, y, w, h) = cv2.boundingRect(np.array([shape[48:68]])) #口の部位のみ切り出し
            roi = frame[y:y + h, x:x + w]
            roi = cv2.resize(roi,(160,100))
            (x, y, w, h) = cv2.boundingRect(np.array([shape[42:48]]))  # 左目の部位のみ切り出し
            leftEye = frame[y:y + h, x:x + w]
            leftEye = cv2.resize(leftEye, (100, 50))
            (x, y, w, h) = cv2.boundingRect(np.array([shape[36:42]]))  # 左目の部位のみ切り出し
            rightEye = frame[y:y + h, x:x + w]
            rightEye = cv2.resize(rightEye, (100, 50))
        return clone, roi
    else :
        return frame, None

Dlibはこちらを参考にさせていただきました。ありがとうございました。

結論というか感想は動画のほうを是非御覧ください。

 

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です