開発者ドキュメント

OpenCVとPythonを使用して画像から顔を検出して抽出する方法

著者は、 Open Internet / Free Speech Fund を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。

序章

画像は毎日生成される大量のデータを構成するため、これらの画像を処理する機能が重要になります。 画像を処理する1つの方法は、顔検出を使用することです。 顔検出は、機械学習を使用して画像内の顔を検出する画像処理の一分野です。

Haar Cascade は、画像内の関心のあるオブジェクトを見つけるために使用されるオブジェクト検出方法です。 アルゴリズムは、多数のポジティブサンプルとネガティブサンプルでトレーニングされます。ポジティブサンプルは、対象のオブジェクトを含む画像です。 ネガティブサンプルは、目的のオブジェクト以外のものを含む可能性のある画像です。 トレーニングが完了すると、分類器は新しい画像で対象のオブジェクトを見つけることができます。

このチュートリアルでは、OpenCVおよびPythonから事前にトレーニングされたHaarCascade モデルを使用して、画像から顔を検出して抽出します。 OpenCVは、画像の処理に使用されるオープンソースのプログラミングライブラリです。

前提条件

ステップ1—ローカル環境の構成

コードの記述を開始する前に、まずコードを保持するワークスペースを作成し、いくつかの依存関係をインストールします。

mkdirコマンドを使用して、プロジェクトのディレクトリを作成します。

  1. mkdir face_scrapper

新しく作成したディレクトリに移動します。

  1. cd face_scrapper

次に、このプロジェクトの仮想環境を作成します。 仮想環境はさまざまなプロジェクトを分離するため、さまざまな依存関係によって中断が発生することはありません。 このプロジェクトで使用するface_scrapperという名前の仮想環境を作成します。

  1. python3 -m venv face_scrapper

隔離された環境をアクティブ化します。

  1. source face_scrapper/bin/activate

これで、プロンプトの前に仮想環境の名前が付いていることがわかります。

仮想環境をアクティブ化したので、nanoまたはお気に入りのテキストエディタを使用してrequirements.txtファイルを作成します。 このファイルは、必要なPythonの依存関係を示しています。

  1. nano requirements.txt

次に、このチュートリアルを完了するには、3つの依存関係をインストールする必要があります。

次の依存関係をファイルに追加します。

Requirements.txt
numpy 
opencv-utils
opencv-python

ファイルを保存して閉じます。

requirements.txtファイルをPythonパッケージマネージャーpipに渡して、依存関係をインストールします。 -rフラグは、requirements.txtファイルの場所を指定します。

  1. pip install -r requirements.txt

このステップでは、プロジェクトの仮想環境をセットアップし、必要な依存関係をインストールします。 これで、次のステップで入力画像から顔を検出するコードの記述を開始する準備が整いました。

ステップ2—顔検出器スクリプトの作成と実行

このセクションでは、画像を入力として受け取り、次の2つを返すコードを記述します。

コードを保持するための新しいファイルを作成することから始めます。

  1. nano app.py

この新しいファイルで、最初に必要なライブラリをインポートして、コードの記述を開始します。 ここでは、cv2sysの2つのモジュールをインポートします。 cv2モジュールは、OpenCVライブラリをプログラムにインポートし、sysは、コードが使用するargvなどの一般的なPython関数をインポートします。

app.py
import cv2
import sys

次に、実行時に入力画像が引数としてスクリプトに渡されるように指定します。 最初の引数を読み取るPythonの方法は、sys.argv[1]関数によって返される値を変数に割り当てることです。

app.py
...
imagePath = sys.argv[1]

画像処理の一般的な方法は、最初に入力画像をグレースケールに変換することです。 これは、色ではなく輝度を検出すると、一般にオブジェクト検出でより良い結果が得られるためです。 次のコードを追加して、入力画像を引数として取得し、それをグレースケールに変換します。

app.py
...
image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

.imread()関数は、スクリプトに引数として渡される入力画像を取得し、それをOpenCVオブジェクトに変換します。 次に、OpenCVの.cvtColor()関数は、入力画像オブジェクトをグレースケールオブジェクトに変換します。

画像を読み込むコードを追加したので、指定した画像の顔を検出するコードを追加します。

app.py
...
faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
faces = faceCascade.detectMultiScale(
        gray,
        scaleFactor=1.3,
        minNeighbors=3,
        minSize=(30, 30)
) 

print("Found {0} Faces!".format(len(faces)))

このコードは、cv2.CascadeClassifierメソッドを使用してHaarカスケードファイルをロードするfaceCascadeオブジェクトを作成します。 これにより、PythonとコードでHaarカスケードを使用できるようになります。

次に、コードはOpenCVの.detectMultiScale()メソッドをfaceCascadeオブジェクトに適用します。 これにより、画像内で検出されたすべての面の長方形のリストが生成されます。 長方形のリストは、Rect(x,y,w,h)の形式で画像からのピクセル位置のコレクションです。

コードで使用するその他のパラメーターの概要は次のとおりです。

長方形のリストを生成した後、面はlen関数でカウントされます。 検出された顔の数は、スクリプトの実行後に出力として返されます。

次に、OpenCVの.rectangle()メソッドを使用して、検出された面の周りに長方形を描画します。

app.py
...
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2)

このコードは、 for loop を使用して、検出されたオブジェクトごとにfaceCascade.detectMultiScaleメソッドから返されたピクセル位置のリストを反復処理します。 rectangleメソッドは、次の4つの引数を取ります。

長方形を描画するコードを追加したので、OpenCVの.imwrite()メソッドを使用して、新しいイメージをfaces_detected.jpgとしてローカルファイルシステムに書き込みます。 このメソッドは、書き込みが成功した場合はtrueを返し、新しいイメージを書き込めなかった場合はfalseを返します。

app.py
...
status = cv2.imwrite('faces_detected.jpg', image)

最後に、このコードを追加して、.imwrite()関数のtrueまたはfalseステータスをコンソールに返すように出力します。 これにより、スクリプトの実行後に書き込みが成功したかどうかがわかります。

app.py
...
print ("Image faces_detected.jpg written to filesystem: ",status)

完成したファイルは次のようになります。

app.py
import cv2
import sys

imagePath = sys.argv[1]

image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
faces = faceCascade.detectMultiScale(
    gray,
    scaleFactor=1.3,
    minNeighbors=3,
    minSize=(30, 30)
)

print("[INFO] Found {0} Faces!".format(len(faces)))

for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)

status = cv2.imwrite('faces_detected.jpg', image)
print("[INFO] Image faces_detected.jpg written to filesystem: ", status)

すべてが正しく入力されていることを確認したら、ファイルを保存して閉じます。

注:このコードは、公開されているOpenCVドキュメントから提供されています。

コードが完成し、スクリプトを実行する準備が整いました。

ステップ3—スクリプトの実行

このステップでは、画像を使用してスクリプトをテストします。 テストに使用する画像が見つかったら、app.pyスクリプトと同じディレクトリに保存します。 このチュートリアルでは、次の画像を使用します。

同じイメージでテストする場合は、次のコマンドを使用してダウンロードします。

  1. curl -O https://assets.digitalocean.com/articles/CART-63965/people_with_phones.png

スクリプトをテストするイメージを取得したら、スクリプトを実行し、引数としてイメージパスを指定します。

  1. python app.py path/to/input_image

スクリプトの実行が終了すると、次のような出力が表示されます。

Output
[INFO] Found 4 Faces! [INFO] Image faces_detected.jpg written to filesystem: True

true出力は、更新されたイメージがファイルシステムに正常に書き込まれたことを示します。 ローカルマシンでイメージを開いて、新しいファイルの変更を確認します。

スクリプトが入力画像で4つの面を検出し、それらをマークするために長方形を描いたことがわかります。 次のステップでは、ピクセル位置を使用して画像から顔を抽出します。

ステップ4—顔を抽出してローカルに保存する(オプション)

前の手順では、OpenCVとHaar Cascadeを使用して、画像内の面の周りに長方形を検出して描画するコードを記述しました。 このセクションでは、コードを変更して、検出された顔を画像から独自のファイルに抽出します。

テキストエディタでapp.pyファイルを再度開くことから始めます。

  1. nano app.py

次に、cv2.rectangle行の下に強調表示された行を追加します。

app.py
...
for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
    roi_color = image[y:y + h, x:x + w] 
    print("[INFO] Object found. Saving locally.") 
    cv2.imwrite(str(w) + str(h) + '_faces.jpg', roi_color) 
...

roi_colorオブジェクトは、元の入力画像のfacesリストからピクセル位置をプロットします。 xyh、およびw変数は、faceCascade.detectMultiScaleメソッドから検出された各オブジェクトのピクセル位置です。 次に、コードは、オブジェクトが検出され、ローカルに保存されることを示す出力を出力します。

それが完了すると、コードはcv2.imwriteメソッドを使用してプロットを新しい画像として保存します。 プロットの幅と高さを、書き込まれる画像の名前に追加します。 これにより、複数の顔が検出された場合に名前が一意に保たれます。

更新されたapp.pyスクリプトは次のようになります。

app.py
import cv2
import sys

imagePath = sys.argv[1]

image = cv2.imread(imagePath)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
faces = faceCascade.detectMultiScale(
    gray,
    scaleFactor=1.3,
    minNeighbors=3,
    minSize=(30, 30)
)

print("[INFO] Found {0} Faces.".format(len(faces)))

for (x, y, w, h) in faces:
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
    roi_color = image[y:y + h, x:x + w]
    print("[INFO] Object found. Saving locally.")
    cv2.imwrite(str(w) + str(h) + '_faces.jpg', roi_color)

status = cv2.imwrite('faces_detected.jpg', image)
print("[INFO] Image faces_detected.jpg written to filesystem: ", status)

要約すると、更新されたコードはピクセル位置を使用して、画像から新しいファイルに顔を抽出します。 コードの更新が完了したら、ファイルを保存して閉じます。

コードを更新したので、スクリプトをもう一度実行する準備が整いました。

  1. python app.py path/to/image

スクリプトによる画像の処理が完了すると、同様の出力が表示されます。

Output
[INFO] Found 4 Faces. [INFO] Object found. Saving locally. [INFO] Object found. Saving locally. [INFO] Object found. Saving locally. [INFO] Object found. Saving locally. [INFO] Image faces_detected.jpg written to file-system: True

サンプル画像に含まれる顔の数に応じて、出力が増減する場合があります。

スクリプトの実行後に作業ディレクトリの内容を見ると、入力画像で見つかったすべての顔のヘッドショットのファイルが表示されます。

これで、作業ディレクトリに収集された入力画像から抽出されたヘッドショットが表示されます。

このステップでは、スクリプトを変更して、入力画像から検出されたオブジェクトを抽出し、ローカルに保存しました。

結論

このチュートリアルでは、OpenCVとPythonを使用して、入力画像から顔を検出、カウント、抽出するスクリプトを作成しました。 このスクリプトを更新して、OpenCVライブラリから事前にトレーニングされたさまざまなHaarカスケードを使用してさまざまなオブジェクトを検出するか、独自のHaarカスケードをトレーニングする方法を学ぶことができます。

モバイルバージョンを終了