Python | OpenCVで笑顔を検出する

Python | OpenCVで笑顔を検出する

こんにちは!今回は「笑顔検出」を検証します。

利用するもの

前回の記事同様「Haar Cascades(Haar特徴ベースのCascade型分類器)」のうち、「Haarcascade_smile.xml」を利用します。

画像の笑顔識別

以下が今回作成したプログラムです。

#------------------------------------------------------------
#笑顔の検出(画像)
#------------------------------------------------------------
import cv2

try:

    # 1)画像を読み取る
    img = cv2.imread('lena_std.bmp')
    if img is None:
        raise FileNotFoudError('IMG Not Found!')
    
    # 2)サイズを 縦400px にリサイズする(高さは連動) 
    img_h,img_w = img.shape[:2]
    size = (400,int(400/img_w*img_h),)
    img = cv2.resize(img,size)
    
    # 3)検出器をロードする
    #   face_cascade : 顔を検出
    #   smile_cascade : 笑顔を検出
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    smile_cascade = cv2.CascadeClassifier('haarcascade_smile.xml')
    if face_cascade is None or smile_cascade is None:
        raise FileNotFoudError('XML Not Found!')
    
    # 4)画像に検出器を適用する
    for (x1,y1,w1,h1) in face_cascade.detectMultiScale(img):
    
        # 5)顔領域(下半分)だけを抽出する
        #   行、列の順なので img[y,x] で記載
        only_mouse_img = img[int(y1+h1/2):(y1+h1),x1:x1+w1]
                
        # 6)face_only_imgに対して、笑顔判定を掛ける
        smile = smile_cascade.detectMultiScale(only_mouse_img)

        # 7)顔領域を囲む
        cv2.rectangle(img, (x1,y1), (x1+w1,y1+h1),(0,0,255), thickness=2)
        
        # 8)笑顔の要素を囲む
        if len(smile)>0:
            for (x2,y2,w2,h2) in smile:
                cv2.rectangle(img, (x1+x2,int(y1+h1/2)+y2), (x1+x2+w2,int(y1+h1/2)+y2+h2),(0,255,0), thickness=2)
        else:
            print('Not Smile')

        # 9)画像を表示
        cv2.imshow('lena',img)

    # 10)キーイベントの待機 / 引数=0 で何か入力されるまで待つ
    cv2.waitKey(0)

    # 11)入力されたら、ウィンドウを閉じる
    cv2.destroyAllWindows()

# except) Error時
except FileNotFoundError as e:
    print(e)

Lenaの口元を検出することができました。

応用:動画から識別する

今回はカメラで投影したものに対して、笑顔か否かを判定します。

眼鏡等を外した状態で、笑顔時と無表情時の反応を比較してみてください。

#------------------------------------------------------------
#顔検出のプログラム(カメラ)
#------------------------------------------------------------
import cv2

try:
    
    # 1)カメラIDを設定
    camera = cv2.VideoCapture(0)
    
    # 2)検出器をロードする
    #   face_cascade : 顔を検出
    #   smile_cascade : 笑顔を検出
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    smile_cascade = cv2.CascadeClassifier('haarcascade_smile.xml')
    if face_cascade is None or smile_cascade is None:
        raise FileNotFoudError('XML Not Found!')
        
    # 3)繰り返し画像を取得する
    while True:
        
        # 4)設定したカメラから画像を取得
        ret, img = camera.read()
    
        # 5)サイズを 縦400px にリサイズする(高さは連動) 
        img_h,img_w = img.shape[:2]
        size = (400,int(400/img_w*img_h),)
        img = cv2.resize(img,size)

        # 6)グレースケールに変換 
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

         # 7)画像に検出器を適用する
        for (x1,y1,w1,h1) in face_cascade.detectMultiScale(img_gray):
    
            # 8)顔領域(下半分)だけを抽出する
            #   行、列の順なので img[y,x] で記載
            only_mouse_img = img_gray[int(y1+h1/2):(y1+h1),x1:x1+w1]
                
            # 9)face_only_imgに対して、笑顔判定を掛ける
            smile = smile_cascade.detectMultiScale(only_mouse_img)

            # 10)顔領域を囲む
            cv2.rectangle(img, (x1,y1), (x1+w1,y1+h1),(0,0,255), thickness=2)
            
            # 11)笑顔の要素を囲む
            if len(smile)>0:
                for (x2,y2,w2,h2) in smile:
                    cv2.rectangle(img, (x1+x2,int(y1+h1/2)+y2), (x1+x2+w2,int(y1+h1/2)+y2+h2),(0,255,0), thickness=2)

        # 12) 画像を表示
        cv2.imshow('Face_Capture',img)

        # 13) Escが入力されたらループ処理を終了する
        key = cv2.waitKey(10)
        if key == 27:
            break       
        
    # 14)入力されたら、ウィンドウを閉じる
    cv2.destroyAllWindows()
    
    # 15)カメラのメモリを解放する
    camera.release()

# except) Error時
except FileNotFoundError as e:
    print(e)

今回は以上です。

ではまた。