ソースに絡まるエスカルゴ

貧弱プログラマの外部記憶装置です。

【Blender/python】OpenCVの瞳認識の値を使ってBlenderのオブジェクトの座標を変更する

rikoubou.hatenablog.com

 以前の記事でBlenderOpenCVを使えるようにする方法を書きました。

 今回はOpenCVで瞳の認識をして、その値を使ってBlenderのオブジェクトを動かすというのをやっていきます。また今回のプログラムを実行するにはWebカメラが必要になります。


1:瞳認識を行うxmlファイルの場所を確認する
 最初に瞳認識を行うためのxmlファイルの場所を確認します。

 OpenCVのインストール先にdataというフォルダがあります。そのフォルダの中に「haarcascade_lefteye_2splits.xml」があるのでそこまでのパスをコピーしておきます。
f:id:rikoubou:20181127174235p:plain


2:瞳認識のソースコード
 Blenderで動かす瞳を認識するプログラムは以下のようになります。

・blenderPythonTest.py

# ---openCVを使えるようにする---
import sys
sys.path.append("/hogehoge/cv2/") # OpenCVのパス。適宜書き換える

# ---以下プログラム部分---
import bpy         # BlenderのpythonAPI
import numpy as np # 配列関係のライブラリ
import cv2         # OpenCV のインポート

# 左目認識部分のxml読み込み
left_eye_cascade = cv2.CascadeClassifier('/hogehogehogehoge/cv2/data/haarcascade_lefteye_2splits.xml') # 瞳認識用のパス。適宜書き換える

# VideoCaptureのインスタンスを作成する。
# 引数でカメラを選択
cap = cv2.VideoCapture(0)

OBJ_NAME = "Cube"

# メイン関数
def main():
    obj = bpy.data.objects[OBJ_NAME] # オブジェクトを取得

    while True:
        # VideoCaptureから1フレーム読み込む
        ret, frame = cap.read() # このframeがimg

        # リサイズしてグレースケール化
        frame = cv2.resize(frame, (int(frame.shape[1]/2), int(frame.shape[0]/2))) # リサイズ
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # グレースケール

        # 左目を検出
        left = left_eye_cascade.detectMultiScale(gray, scaleFactor=1.2, minNeighbors=2, minSize=(10,10))

        # 左目四角形で複数検出される
        for (x,y,w,h) in left:
            obj.location[0] = (x - (frame.shape[1]/2)) * 0.05
            # obj.location[1] = (y - (frame.shape[0]/2)) * 0.05
            bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) # Blender画面を更新

            cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2) # 四角形を描写
            break # 1個分しか使わないのでbreakする

        cv2.imshow('frame', frame)

        # キー入力を1ms待って、keyが「q」だったらbreak
        key = cv2.waitKey(1)&0xff
        if key == ord('q'):
            break

    # 座標を0に戻す
    obj.location[0] = 0.0
    obj.location[1] = 0.0

    # キャプチャをリリースして、ウィンドウをすべて閉じる    
    cap.release()
    cv2.destroyAllWindows()


if __name__ == '__main__':
    main()

 上記のプログラムを簡単に説明すると、Webカメラに映った瞳を四角形で検出してその四角の左上X座標の値を取得してBlenderのCubeオブジェクトのX座標に設定しているという内容です。Webカメラの画面上で「q」キーを押すと終了します。

 OpenCVまでのパスと読み込むxmlファイルのパスは適宜書き換えてください。


3:Blender上で動かす
 2のプログラムをBlender上で動かします。

 Blenderを起動させたら以下のようにプルダウンから「Scripting」を選択してスクリプト画面に切り替えます。
f:id:rikoubou:20181127175246p:plain

 以下のような画面に切り替わるので「New」ボタンを左クリックします。
f:id:rikoubou:20181127175432p:plain

 するとpythonスクリプトが記述できるようになるので、2で作成したプログラムをコピペします。
f:id:rikoubou:20181127175707p:plain

 コピペできたら「Run Script」ボタンを左クリックして実行します。
f:id:rikoubou:20181127181208p:plain

 実行すると以下のように目の部分が四角で覆われたWebカメラの映像が新しく立ち上がったウインドウに表示されます。新しく立ち上がったウインドウにフォーカスを合わせて「q」キーを押すとプログラムを終了できます。
f:id:rikoubou:20181127180402p:plain

 実際にWebカメラに瞳が映った状態で顔を左右に動かしてみると、以下のようにその動きに合わせてCubeオブジェクトも動きます。片目を隠した状態で顔を動かすとスムーズに動くようになります。
f:id:rikoubou:20181127180515g:plain


 以上がOpenCVの瞳認識の値を使ってBlenderのオブジェクト座標を変更してみた内容です。

 OpenCVBlenderで使えるようにしてからまだちゃんと連携させたことがなかったので、今回のようにうまく連携できることがわかってよかったです。
 もうちょっと色々わかればBlenderを使って擬似的なFaceRigも自作できそうなので挑戦してみたいです。


・参考資料