Python OpenCV3で顔判定してモザイクをかける

この方法 だと一部分だけモザイク加工できなかったので。

[amazonjs asin="4061538225″ locale="JP" title="OpenCVによる画像処理入門 (KS情報科学専門書)"]

前提

ディレクトリ構成などはこことかこことかこことか。

 

元画像

顔判定の時の徳川慶喜(yoshinobu.jpg)を使った。
wikipediaから拝借して、source/imageディレクトリにyoshinobu.jpgファイルを設置しておく。

yoshinobu.jpg

 

pillowをインストール

OpenCVでは一部の画像の加工をスマートにやる方法が見つからなかったため、pillowを使った。

[shell title="pillowのインストール"]
(opencv_python)$ pip install pillow
[/shell]

 

顔の判定とモザイク加工

OpenCVで顔を判定し、判定された顔の座標を取得してpillowで切り抜き、縮小・拡大して再度貼り付けることでモザイク加工をする。
pillowで開いた画像はそのままではOpenCVで開けないため、OpenCV用に変換して表示する。
sourceディレクトリにface_mosaic.pyを作成する。

[python title="face_mosaic.pyの内容"]
# -*- coding: UTF-8 -*-

import cv2
import math
import numpy as np
import os
from PIL import Image

if __name__ == '__main__’:

# 顔判定で使うxmlファイルを指定する。
cascade_path = os.path.dirname(os.path.abspath(__file__)) + "/haarcascades/haarcascade_frontalface_alt.xml"
cascade = cv2.CascadeClassifier(cascade_path)

# 画像の読み込み
img_src = cv2.imread("./image/yoshinobu.jpg", 1)

# 結果を保存するための変数を用意しておく。
img_edit = Image.open("./image/yoshinobu.jpg")

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

#顔判定
"""
minSize で顔判定する際の最小の四角の大きさを指定できる。
(小さい値を指定し過ぎると顔っぽい小さなシミのような部分も判定されてしまう。)
"""
faces = cascade.detectMultiScale(img_gray, scaleFactor=1.1, minNeighbors=1, minSize=(100, 100))

# 顔があった場合
if len(faces) > 0:

# 複数の顔があった場合、1つずつ四角で囲っていく
for face in faces:

# 顔を切り抜く
cut_face = img_edit.crop((face[0],
face[1],
face[0]+face[2],
face[1]+face[3]))

# 切り抜いた画像を1/20に縮小する。
cut_face = cut_face.resize((int(face[2]/20), int(face[3]/20)), Image.LINEAR)

# 縮小した画像を本のサイズに戻す。
cut_face = cut_face.resize(face[2:], Image.LINEAR)

# 元の画像に加工した顔画像を貼り付ける。
img_edit.paste(cut_face, tuple(face[:2]))

#pillow用のデータをOpenCVデータに変換
img_dst = np.asarray(img_edit)

# 表示
cv2.imshow("Show MOSAIC FACES Image", img_dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

[/python]

実行してみる。

[shell]
(opencv_python)$ python face_mosaic.py
[/shell]

スクリーンショット 2015-07-11 3.03.39

 

複数人でも

今回も偉大なる物理学者の方々も顔判定してみる。
source/image ディレクトリにphysicists.jpgを設置する。

今回もひとりひとりの顔が小さいため、face_mosaic.pyの

[python]
faces = cascade.detectMultiScale(img_gray, scaleFactor=1.1, minNeighbors=1, minSize=(100, 100))
[/python]

のminSizeを(10, 10)にする。また、以下のように顔部分の縮小・拡大比率を変更する。

[python]
# 切り抜いた画像を1/4に縮小する。
cut_face = cut_face.resize((int(face[2]/4), int(face[3]/4)), Image.LINEAR)
[/python]

上記に基づいて、face_mosaic2.pyを作成する。

[python title="face2.pyの内容"]
# -*- coding: UTF-8 -*-

import cv2
import math
import numpy as np
import os
from PIL import Image

if __name__ == '__main__’:

# 顔判定で使うxmlファイルを指定する。
cascade_path = os.path.dirname(os.path.abspath(__file__)) + "/haarcascades/haarcascade_frontalface_alt.xml"
cascade = cv2.CascadeClassifier(cascade_path)

# 画像の読み込み
img_src = cv2.imread("./image/physicists.jpg", 1)

# 結果を保存するための変数を用意しておく。
img_edit = Image.open("./image/physicists.jpg")

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

#顔判定
"""
minSize で顔判定する際の最小の四角の大きさを指定できる。
(小さい値を指定し過ぎると顔っぽい小さなシミのような部分も判定されてしまう。)
"""
faces = cascade.detectMultiScale(img_gray, scaleFactor=1.1, minNeighbors=1, minSize=(10, 10))

# 顔があった場合
if len(faces) > 0:

# 複数の顔があった場合、1つずつ四角で囲っていく
for face in faces:

# 顔を切り抜く
cut_face = img_edit.crop((face[0],
face[1],
face[0]+face[2],
face[1]+face[3]))

# 切り抜いた画像を1/4に縮小する。
cut_face = cut_face.resize((int(face[2]/4), int(face[3]/4)), Image.LINEAR)

# 縮小した画像を本のサイズに戻す。
cut_face = cut_face.resize(face[2:], Image.LINEAR)

# 元の画像に加工した顔画像を貼り付ける。
img_edit.paste(cut_face, tuple(face[:2]))

#pillow用のデータをOpenCVデータに変換
img_dst = np.asarray(img_edit)

# 表示
cv2.imshow("Show MOSAIC FACES Image", img_dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

[/python]

実行してみる。

[shell]
(opencv_python)$ python face_mosaic2.py
[/shell]

スクリーンショット 2015-07-11 3.09.06

 

左上は相変わらずだけど、なんとかできた!