konchangakita

KPSを一番楽しんでいたブログ 会社の看板を背負いません 転載はご自由にどうぞ

ラズパイで物体認識シリーズ HaarCascades を使った物体検出

OpenCV単体でできる物体検出を試してみます

f:id:konchangakita:20200730155602p:plain:w300

【ラズパイで物体認識シリーズ】
OpenCV の準備
・HaarCascades を使った物体検出 ←イマココ
YOLO v5のセットアップ
・Xi IoTへの組み込み ちょっと延期

カメラの映像に文字を入れてみる

これはいたって簡単です
取り込んだカメラフレーム(ret, frame = cap.read())と表示(cv.imshow('OpenCV - test', frame))の間に”cv.putText()”をつっこみます

            # ビデオ上にテキストを表示 (カメラデータ, 文字, (表示位置), フォント, フォントサイズ, 色, 太さ, 線の種類)
            cv.putText(frame, 'mokemoke', (200,50), cv.FONT_HERSHEY_PLAIN, 3, (0, 255,0), 3, cv.LINE_AA)


前回のコードと組み合わせるとこんな感じに

import cv2 as cv

#カメラインスタンス作成
cap = cv.VideoCapture(0)

try:   
    while True:
        ret, frame = cap.read()
        if frame is None:
            print('--(!) No captured frame -- Break!')
            break

            # ビデオ上にテキストを表示 (カメラデータ, 文字, (表示位置), フォント, フォントサイズ, 色, 太さ, 線の種類)
            cv.putText(frame, 'mokemoke', (200,50), cv.FONT_HERSHEY_PLAIN, 3, (0, 255,0), 3, cv.LINE_AA)

        cv.imshow('OpenCV - test', frame)
        
        if cv.waitKey(10) == 27:
            break

except KeyboardInterrupt: # except the program gets interrupted by Ctrl+C on the keyboard.
    print("\nCamera Interrupt")

finally:
    cap.release()
    cv.destroyAllWindows()

mokemokeしました
f:id:konchangakita:20200730155412p:plain


OpenCVで顔検出

OpenCVでは、あらかじめ Haar-like特徴を用いた分類器 (haarcascade~.xml)という物体検出用の学習済みデータが用意されています
OpenCVGithubから入手できます
opencv/data at master · opencv/opencv · GitHub

ファイル名 対象物体
haarcascade_eye.xml
haarcascade_eye_tree_eyeglasses.xml メガネ
haarcascade_frontalcatface.xml 猫の顔(正面)
haarcascade_frontalcatface_extended.xml 猫の顔(正面)
haarcascade_frontalface_alt.xml 顔(正面)
haarcascade_frontalface_alt2.xml 顔(正面)
haarcascade_frontalface_alt_tree.xml 顔(正面)
haarcascade_frontalface_default.xml 顔(正面)
haarcascade_fullbody.xml 全身
haarcascade_lefteye_2spits.xml 左目
haarcascade_licence_plate_rus_16stages.xml ロシアのナンバープレート(全体)
haarcascade_lowerbody.xml 下半身
haarcascade_profileface.xml 顔(証明写真)
haarcascade_righteye_2splits.xml 右目
haarcascade_russian_plate_number.xml 笑顔
haarcascade_upperbody.xml 上半身

これを使って人間の顔検出を実装してみます


チュートリアルを参照しながら、すすめていきましょう
OpenCV: Cascade Classifier

ポイントその1.顔検出データ(haarcascade_frontalface_default.xml)の読み込み
# ファイルパスの指定
face_cascade_name = 'opencv-master/data/haarcascades/haarcascade_frontalface_default.xml'

# 物体検出用のインスタンス作成
face_cascade = cv.CascadeClassifier()
face_cascade.load(cv.samples.findFile(face_cascade_name))
ポイントその2.グレースケールしてから検出

物体検出には大抵の場合カラー情報が必要になることはないので、白黒画像にして処理を軽くして検出します(逆にどういう時にカラーが必要なんだろう?)

frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
frame_gray = cv.equalizeHist(frame_gray)

im.show('OpenCV - gray', frame_gray)

白黒画像に変更した図
f:id:konchangakita:20200730211552p:plain

ポイントその3.顔検出し場所に線を描画する
# 顔の検出
faces = face_cascade.detectMultiScale(frame_gray)

# 複数の顔が検出された場合、ひとつづつ枠を付ける場所を決める
for (x,y,w,h) in faces:
    center = (x + w//2, y + h//2)
    frame = cv.ellipse(frame, center, (w//2, h//2), 0, 0, 360, (255, 0, 255), 4)
        
    frame = frame_gray[y:y+h,x:x+w]

# カラー画像の上に枠を描画する
cv.imshow('OpenCV - facedetect', frame)

試しにYouTube動画にカメラを向けてみると顔が検出されました、できるもんですね
(吉Pとモルボルさんと、光の戦士まで)
f:id:konchangakita:20200730140455p:plain
【リバイバル放送】みんなで観よう! 第12回 PLLより
https://www.youtube.com/watch?v=QQbr0xgafk0&feature=youtu.be

もちろんカメラを向けるのではなく動画をそのまま読み込ませた方が、精度は上がります

目の検出とモザイク処理

同じ要領で目の検出を行なってみます

# 目の検出用がデータ
eyes_cascade_name = 'opencv-master/data/haarcascades/haarcascade_eye.xml'

# インスタンス作成
eyes_cascade = cv.CascadeClassifier()
eyes_cascade.load(cv.samples.findFile(eyes_cascade_name))

顔検出した範囲の中で目の位置を検出
def detectAndDisplay(frame):
    frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    frame_gray = cv.equalizeHist(frame_gray)

    # 顔の検出
    faces = face_cascade.detectMultiScale(frame_gray)

    # 複数の顔が検出された場合、ひとつづつ枠を付ける
    for (x,y,w,h) in faces:
        center = (x + w//2, y + h//2)
        frame = cv.ellipse(frame, center, (w//2, h//2), 0, 0, 360, (255, 0, 255), 4)
        
        faceROI = frame_gray[y:y+h,x:x+w]

        # 顔ごとに目を検出する
        eyes = eyes_cascade.detectMultiScale(faceROI)
        for (x2,y2,w2,h2) in eyes:
            eye_center = (x + x2 + w2//2, y + y2 + h2//2)
            radius = int(round((w2 + h2)*0.25))
            frame = cv.circle(frame, eye_center, radius, (255, 0, 0 ), -1)

    cv.imshow('OpenCV - facedetect', frame)

なんだかそれっぽい箇所が青い丸で検出しています
f:id:konchangakita:20200730140414p:plain

目の部分にモザイクかけてみる

Python + OpenCVでモザイクをかけるというのを見つけたので、ちょっと目を検出した部分に使ってみます

モザイクをかける関数、定番らしい

def mosaic(src, ratio=0.1):
    small = cv.resize(src, None, fx=ratio, fy=ratio, interpolation=cv.INTER_NEAREST)
    return cv.resize(small, src.shape[:2][::-1], interpolation=cv.INTER_NEAREST)

def mosaic_area(src, x, y, width, height, ratio=0.1):
    dst = src.copy()
    dst[y:y + height, x:x + width] = mosaic(dst[y:y + height, x:x + width], ratio)
    return dst


モザイクをかける部分の左上を指定してやる必要があるので、検出側も少し工夫してやります

def detectAndDisplay(frame):
    frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    frame_gray = cv.equalizeHist(frame_gray)

    # 顔の検出
    faces = face_cascade.detectMultiScale(frame_gray)

    # 複数の顔が検出された場合、ひとつづつ枠を付ける
    for (x,y,w,h) in faces:
        center = (x + w//2, y + h//2)
        frame = cv.ellipse(frame, center, (w//2, h//2), 0, 0, 360, (255, 0, 255), 4)
        
        faceROI = frame_gray[y:y+h,x:x+w]

        # 顔ごとに目を検出する
        eyes = eyes_cascade.detectMultiScale(faceROI)
        for (x2,y2,w2,h2) in eyes:
            # 目を検出した場所の左上とモザイクの幅を決めてやる
            ex = int((x + x2) - w2 / 2)
            ey = int(y + y2)
            ew = int(w2 * 2.5)
            frame = mosaic_area(frame, ex, ey, ew, h2)

    cv.imshow('OpenCV - facedetect', frame)

怪しい感じでモザイクがかかりました
f:id:konchangakita:20200730155030p:plain
© 2010 - 2020 SQUARE ENIX CO., LTD. All Rights Reserved.


全容はコチラ


次はYOLOやってみます