実践型AIプログラミング特講 #14

実践型AIプログラミング特講 #14

では、顔認識アルゴリズムの第二回についてあらすじをご紹介させていただくと、今回は顔認識を用いて顔を認識した上で指定した範囲にモザイクをかけたり、また画像を自身のデータ処理として都合が良いように拡大縮小、傾き、大きさなど自動編集する技術を皆様に身につけて頂きたいと思います。まだ第一回に目を通していない方がいましたらこちらから第一回顔認識講座を一読ください。

OpenCVと機械学習 – 画像動画入門

顔検出 – 顔に自動でモザイクをかけよう最近のデジタルカメラでは、当たり前に人間の顔を認識して自動でフォーカスを合わせる機能がついていますが、OpenCV にも人間の顔がどこにあるのかを検出する機能があります。機械学習では、人間の顔を抽出して利用する場面も多くありますので、顔の検出を行う方法をマスターしましょう。こにでは、人間の顔に自動でモザイクをかけるツールを作ってみましょう。

顔認識について

顔認識とは、人間の顔を自動的に認識し抽出する技術です。顔認識を搭載したデジタルカメラであれば、自動的に顔にピントを合わせるので、ぶれない写真を撮影できます。また、顔の特徴を抽出して、複数の写真に写っている個人を特定することもできます。顔の特徴を利用したセキュリティ認証もありますし、Facebook などの SNS で写真に映っている顔を抽出して、写真を誰と共有するのか検出したり、タグ付けしたりできます。顔認識にはいろいろな方法がありますが、ここでは OpenCV の顔検出の方法を紹介します。OpenCVでは、Haar-like 特徴分類器と呼ばれる学習機械を用いて顔認識を行います。これは、機械学習で対象となる特徴量を学習させて、学習データを元にパターン認識を行うカスケード分類器の一種です。この仕組みですが、簡単に言うと、顔のデータベースを利用して、目·鼻·口といったパーツの位置関係を確かめて、顔かどうかを判定するという手法です。人間の顔の写真をグレースケールに変換すると、明るいところが白くなり、暗いところが黒くなります。たとえば、人間の顔のなかで「鼻」というのは、顔の中でも明るい部分で、鼻の左右の部分は暗くなります。つまり、顔と思われる領域のうち、中央が明るい(つまり鼻がある)と、それは顔かもしれないということがわかります。目についても上には眉があるので、目の上部分は暗く目の下は明るくなっています。このようにして、各パーツごとに明暗のパターンが合致するかどうかを調べていきます。

顔検出のプログラムを作ってみよう

それでは、実際に顔検出を行うプログラムを作ってみましょう。OpenCV で顔検出のプログラムを実行する場合、カスケードファイル(顔パーツのデータベース)が必要になります。このデータベースを利用して顔検出を行うため、最初にカスケードファイルをダウンロードしましょう。

顔検出カスケードファイルをダウンロードしよう

OpenCV をインストールすると、顔検出に使うカスケードファイル(顔パーツのデータベース)も緒にOpenCV のデータディレクトリーに保存されます。しかし、OS や Anaconda のバージョンでとに保存パスが異なるので、ここでは OpenCVの GitHub リポジトリーから最新のカスケードファイルを直接ダウンロードして利用しましょう。

GitHub > opencv > data > haarcascades[URL] https://github.com/opencv/opencv/tree/master/data/haarcascades

ここを見ると、顔検出用のカスケードファイルにも、正面の顔、笑顔検出するもの、目や体全体を検出するものなど、さまざまなカスケードファイルがあることがわかります。今回は、正面の顔を検出するファイル「haarcascade_frontalface_alt.xml」を利用してみましょう。GitHub でリポジトリーではなく単一のファイルをダウンロードするには、ファイルを表示し、データのプレビュー画面右上にある[RAW]のボタンをクリックします。そして、ブラウザーのメニューから[ファイル>名前をつけて保存(別名で保存)】で保存します。

顔検出の手順を確認しよう

OpenCV で顔検出を行うには、以下の手順に沿って処理を記述します。

(1) カスケードファイルを指定して検出器を作成

(2) 対象画像を読み込んで、グレースケールに変換

(3)顔検出を実行する

この手順に沿って、顔検出を行い、発見した部分に印をつけるプログラムを見てみましょう。

import matplotlib.py

plot as pltimport cv2

# カスケードファイルを指定して検出器を作成(*1)

cascade_file=”haarcascade_frontalface_alt.xml”

cascade = cv2. CascadeClassifier(cascade_file)

# 画像を読み込んでグレースケールに変換する(* 2)

img= cv2.imread(“girl.jpg”)

img gray =cv2.cvtColor (img, cv2.COLOR_BGR2GRAY)

# 顔認識を実行(* 3)

face_list = cascade.detectMultiScale(img_gray, minSize=(150,150))

# 結果を確認(*4)

if len(face_list)=0:

print (“# “)

quit ()

# 認識した部分に印をつける(*5)

for (x,y,w,h) in face_list:

print (” DE=”, x, y, w, h)

red=(0, 0, 255)

cv2.rectangle (img, (x, y), (x+w, y+h), red, thickness=20)

# 画像を出力

cv2.imwrite(“face-detect. png”, img)

plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

plt.show ()

プログラムを確認してみましょう。プログラムの(※1)の部分では、顔検出を行う検出器を作成します。cv2.CascadeClassifier() を使うことで、さまざまな物体を検出するための検出器を作成できます。この検出器ですが、第1引数にカスケードファイルを指定することで、顔のパーツを検出できます。プログラムの(※2)の部分では、女の子の画像を読み込んでグレースケールに変換します。なぜ、グレースケールに変換するのかというと、本節で紹介したように、画像中にある物体の明暗によって検出を行うためです。(※3)の部分では、顔検出を実行します。そのために、CascadeClassifier.detectMultiScale()メソッドを利用します。ここでは、第1引数にグレースケールの画像データを与え、第2引数ではキーワード引数を利用して、minSize を指定しています。つまりこれは、顔と認識する領域の最小サイズを与えていることになります。(※4)の部分では、検出結果を確認し、リストが空であればメッセージを出力して終了します。そして、(※5)の部分では、検出した顔の領域に赤色の枠を描画します。枠を描画するには、cv2.rectangle) を利用します。その後、描画した画像をファイルに出力し、Jupyter Notebook にも出力します。

OpenCV でモザイクをかける

OpenCVには、ぼかしやエッジ検出といったフィルター関数が用意されていますが、モザイク処理を行う関数がありません。そこで、モザイク処理のために簡単な関数を用意しましょう。モザイク処理をかけるには、モザイクをかけたい範囲を取り出して、一度縮小し、縮小した範囲に対して拡大を行います。縮小することによりピクセル情報が失われ、結果モザイクをかけたようになります。ここでは、mosaic() 関数を定義した mosaic.py というモジュールファイルを作成しました。

import cv2

def mosaic (img, rect, size):

# モザイクをかける領域を取得

(х1, у1, х2, у2) = rect

W = x2 -х1

h = y2 – y1

i_rect=img [y1:y2, x1:x2]

# モザイク処理のため、一度縮小して拡大する

i_small=cv2.resize(i_rect, ( size, size))

i_mos =cv2.resize(i_small, (w, h), interpolation=cv2.INTER_AREA)

# 画像にモザイク画像を重ねる

img2 = img.copy()

img2 [y1:y2, x1:x2]

return img2=i_mos

適当な画像ファイル「cat.jpg」を用意して、以下のプログラムをJupyter Notebook 上で実行してみます。モザイクをかけてみましょう。

import matplotlib.py

plot as plt

import cv2

from mosaic import mosaic as mosaic

# 画像を読み込んでモザイクをかける

img = cv2.imread (“cat.jpg”)

mos = mosaic(img, (50, 50, 450, 450), 10)

# モザイクをかけた画像を出力

cv2.imwrite(“cat-mosaic.png”, mos)

plt.imshow(cv2.cvtColor (mos, cv2.COLOR_BGR2RGB))

plt.show ()

人間の顔に自動でモザイクをかけよう

さて、ここまでの部分で「人間の顔を探して自動でモザイクをかけるプログラム」に必要な技術要素が出揃いました。それでは、プログラムを作ってみましょう。

import matplotlib.py

plot as plt

import cv2

from mosaic import mosaic as mosaic

# カスケードファイルを指定して分類器を作成(* 1)

cascade_file = “haarcascade_frontalface_alt.xml”

cascade = cv2.CascadeClassifier (cascade_file)

# 画像を読み込んでグレースケールに変換(* 2)

img = cv2.imread (“family.jpg”)

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 顔検出を実行(*3)

face_list = cascade.detectMultiScale(img_gray, minSize=(150,150))

if len (face_list) == 0

: quit ()

# 認識した部分の画像にモザイクをかける(*4)

for (x,y,w,h) in face_list:

img = mosaic(img, (x, y, x+w, y+h), 10)

# 画像を出力

cv2.imwrite(“family-mosaic.png”, img)

plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

plt.show ()

jupyterNotebook で実行してみましょう。しっかり、人の顔を検出してモザイクがかかっているのを確認できました。プログラムを確認してみましょう。(※1)の部分で顔検出のための分類器を作成します。(※2)でグレースケールに変換し、(※3)で顔検出を実行します。(※4)の部分で、検出した顔部分にモザイク処理を適用します。

OpenCVの顔検出は横顔や傾きに弱い

当然と言えば当然ですが、残念ながら OpenCV の顔検出は完全ではありません。正面の顔を検出することはできるのですが、横顔だったり、傾いている顔は検出できません。また、どのくらいまでの傾きを検出するでしょうか。以下のプログラムを実行して角度別に検証してみましょう。

import matplotlib.py

plot as pltimport cv2

from scipy import ndimage

# 検出器と画像の読み込み

cascade_file = “haarcascade_frontalface_alt.xml”

cascade = cv2.CascadeClassifier(cascade_file)

img = cv2.imread (“girl.jpg”)

# 顔検出を実行し、印をつける

def face_detect (img):

img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

face_list = cascade.detectMultiScale (img_gray, minSize=(300,300))

# 認識した部分に印をつける

for (x,y,w,h) in facelist:

print (” O =”, x, y, w, h)

red =(0, 0, 255)

cv2.rectangle(img, (x, y), (x+w, y+h), red, thickness=30)

# 角度ごとに検証する

for i in range(0, 9):

ang=i * 10

print(“—” + str(ang) +”—”)

img_r=ndimage.rotate(img, ang)

face_detect(img_r)

plt.subplot (3, 3, i + 1)

plt.axis (“off”)

plt.title(“angle=”+ str(ang))

plt.imshow (cv2.cvtColor(img_r, cv2.COLOR_BGR2RGB))

plt.show ()

jupyter Notebook で実行すると、30度くらいまで回転させても、顔を正しく認識していることがわかります。プログラムを見てみましょう。for 構文を使って、0度から 80度まで画像を回転させて、顔検出できるかどうかを確認します。このとき、複数のグラフを出力したいときに便利なpyplot.subplot) を利用してみます。この関数は、以下のように指定します。

[書式]複数のグラフを描画する

matplotlib.pyplot.subplot( 行数,列数 , 何番目を描画するか)

また、画像を回転させるには、scipy.ndimage モジュールの rotate() 関数を利用します。

改良·応用のヒント

ここでは、1枚の画像に対して、顔を検出してモザイクをかけるプログラムを作ってみました。しかし、そもそも1枚だけの写真しかないのであれば、プログラムを作る必要はありません。そこで、これを複数枚の写真に対して、一気に処理を行うプログラムに改良すると良いでしょう。また、画像を投稿するようなWeb サービスで、プライバシー保護を目的として、写真がWeb に公開される前に、自動で顔にモザイクをかけることもできます。他にも、検出した顔が誰なのかを判定することもできるでしょう。

この節のまとめ

OpenCV の顔検出器を使って、顔認識を行うことができる顔検出に画像の明度情報を利用するため、画像はグレースケールに変換するモザイク処理を行うには、画像を一度縮小しておいてから拡大するとモザイクになる

いかがでしたでしょうか、以上が顔認識を活用した編集アルゴリズムのご紹介でした。こちらの技術も高度であるものの特にコーディングを行うことなく簡単に実装できるものでしたね、ステップを少しずつ上りこんなことができたと自分で自画自賛していくことそれが一個人の意見ですがプログラミングを長く続け上達を促すコツだと思います。では次回から数字をopenCVを用いて検出する方法をご紹介していきたいと思います。

 

プログラミングカテゴリの最新記事