なぽろぐ

気ままに感じたことを記事にまとめます。Vtuberのイベントのことと、プログラム関連のことが多めだと思います。

opencvで顔認識しようとしたらカスケードファイルが見つからなかった

opencvのカスケードで顔認識をしたい!

今回の環境です

  • mac book Pro 2017
  • python 3.6.5
  • venvの仮想環境内でコードを走らせている

こんな感じです.windowsとかUbuntuではどうなるかよくわかりません

モザイクアートをつくっていたら画像の大きさがバラバラだったので,正方形にできたら楽だな〜って思いました. 今回は顔判別をしてトリミングするという目的でやっていきま!

Pythonopencvを使いたい!

pip install opencv-python
# pip3を使っているなら
pip3 install opencv-python

これだけでおk!pipは簡単でいいですね

カスケードファイルを取ってくる

opencvで顔認識をするにあたりopen-cv側ですでに用意されている顔認識モデルを使っていきます。

僕はここで結構躓いたんですけど・・・

だいたいのサイトでは

/usr/local/opt/opencv/share/OpenCV/haarcascades/

ここにカスケードファイルが入っているよ!とのことなのですが、僕の場合は仮想環境でインスコしたためかこのディレクトリがそもそも存在しませんでした.そこでcv2のライブラリが入っている場所を調べてみようと思いました.

import cv2
print(cv2)

これでopencvがどこに入っているかがわかります

<module 'cv2.cv2' from 'パスがうんにゃらってかいてある/python3.6/site-packages/cv2/cv2.cpython-36m-darwin.so'>

こんな感じ

どうやら /python3.6/site-packages/cv2/ のなかになにかありそうですね・・・ 僕の場合は/python3.6/site-packages/cv2/dataのなかにカスケードファイルが入っていました〜これ躓きポイントでは・・・?

こうやって詰まるたびに同じ思いを次の自分がして欲しくないのでmyModules.pyみたいなものを作っています.

"""
cv2カスケードファイルを探しに行って辞書で返す関数
castom_cascade_pathはカスケードファイルが格納されているディレクトリをさします。
自分の環境に合わせて作ったのでデフォルト引数がdataになっています。
カスケードファイルが見つからなかったらFalseを返します
"""
def search_cv2_cascade(castom_cascade_path="data"):
    from os.path import splitext, basename, join, dirname, isdir, isfile
    from glob import glob
    import cv2

    cv2_path = dirname(str(cv2).split()[-1].strip(">").strip("'"))
    cascade_dir_path = join(cv2_path, castom_cascade_path)
    if isdir(cascade_dir_path):
        cascade_xml_path_list = join(cascade_dir_path, "*.xml")
        cascade = {splitext(basename(path))[0][12:]:path for path in glob(cascade_xml_path_list)}
        return cascade
    else:
        return False

こんな感じで使えばxmlファイルがどさっと辞書型で返されます.なぜ辞書を使うかは,僕が好きだからです

search_cv2_cascade()

本題の顔認識

import cv2
import matplotlib.pyplot as plt
#画像を読み込む
src = cv2.imread("画像のパス")
#グレースケールにする
cv2_img = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
#黒色で認識した部分を囲む
color = (0, 0, 0)
#カスケードファイルの読み込み
face_cascade = cv2.CascadeClassifier(search_cv2_cascade()["frontalface_default"])

#まほうのことば(コピペソースなので全くまだ調べてないです)
facerect = face_cascade.detectMultiScale(cv2_img, scaleFactor=1.1, minNeighbors=1, minSize=(1, 1))

#1つ以上囲む部分があれば元の画像に矩形を付け足す
if len(facerect) > 0:
    #検出した顔を囲む矩形の作成
    for rect in facerect:
        cv2.rectangle(src, tuple(rect[0:2]),tuple(rect[0:2]+rect[2:4]), color, thickness=2)
#結果をmatplotlibで表示
plt.imshow(cv2.cvtColor(src, cv2.COLOR_BGR2RGB))
#保存
cv2.imwrite("detected.jpg", src)

Twitterの僕のアイコン f:id:Naporitan:20190219023343j:plain

顔認識させて見た結果 f:id:Naporitan:20190219023348j:plain

微妙で草・・・・

おわりに

なんとなくopencvを触って見ました。画像処理をMNISTでしか(PyTrochでMNISTをDNNで判別しただけ・・)触ったことがなかったので結構面白かったです。なんとかモザイクアートスクリプトを早く完成たせたいところ・・・!!!