OpenCVとPythonを使用して画像から顔を検出して抽出する方法
著者は、 Open Internet / Free Speech Fund を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。
序章
画像は毎日生成される大量のデータを構成するため、これらの画像を処理する機能が重要になります。 画像を処理する1つの方法は、顔検出を使用することです。 顔検出は、機械学習を使用して画像内の顔を検出する画像処理の一分野です。
Haar Cascade は、画像内の対象オブジェクトを見つけるために使用されるオブジェクト検出方法です。 アルゴリズムは、多数のポジティブサンプルとネガティブサンプルでトレーニングされます。ポジティブサンプルは、対象のオブジェクトを含む画像です。 ネガティブサンプルは、目的のオブジェクト以外のものを含む可能性のある画像です。 トレーニングが完了すると、分類器は新しい画像で目的のオブジェクトを見つけることができます。
このチュートリアルでは、OpenCVおよびPythonから事前にトレーニングされたHaarCascade モデルを使用して、画像から顔を検出して抽出します。 OpenCVは、画像の処理に使用されるオープンソースのプログラミングライブラリです。
前提条件
- ローカルPython3開発環境。Pythonパッケージをインストールするためのツールであるpipと、仮想環境を作成するためのvenvが含まれます。
ステップ1—ローカル環境の構成
コードの記述を開始する前に、まずコードを保持するワークスペースを作成し、いくつかの依存関係をインストールします。
mkdir
コマンドを使用して、プロジェクトのディレクトリを作成します。
mkdir face_scrapper
新しく作成したディレクトリに移動します。
cd face_scrapper
次に、このプロジェクトの仮想環境を作成します。 仮想環境はさまざまなプロジェクトを分離するため、さまざまな依存関係によって中断が発生することはありません。 このプロジェクトで使用するface_scrapper
という名前の仮想環境を作成します。
python3 -m venv face_scrapper
隔離された環境をアクティブ化します。
source face_scrapper/bin/activate
これで、プロンプトの前に仮想環境の名前が付いていることがわかります。
仮想環境をアクティブ化したので、nano
またはお気に入りのテキストエディタを使用してrequirements.txt
ファイルを作成します。 このファイルは、必要なPythonの依存関係を示しています。
nano requirements.txt
次に、このチュートリアルを完了するには、3つの依存関係をインストールする必要があります。
numpy
: numpy は、大規模な多次元配列のサポートを追加するPythonライブラリです。 また、配列を操作するための数学関数の大規模なコレクションも含まれています。opencv-utils
:これは、ヘルパー関数を含むOpenCVの拡張ライブラリです。opencv-python
:これはPythonが使用するコアOpenCVモジュールです。
次の依存関係をファイルに追加します。
Requirements.txt
numpy opencv-utils opencv-python
ファイルを保存して閉じます。
requirements.txt
ファイルをPythonパッケージマネージャーpip
に渡して、依存関係をインストールします。 -r
フラグは、requirements.txt
ファイルの場所を指定します。
pip install -r requirements.txt
このステップでは、プロジェクトの仮想環境をセットアップし、必要な依存関係をインストールします。 これで、次のステップで入力画像から顔を検出するコードの記述を開始する準備が整いました。
ステップ2—顔検出器スクリプトの作成と実行
このセクションでは、画像を入力として受け取り、次の2つを返すコードを記述します。
- 入力画像で見つかった顔の数。
- 検出された各面の周りに長方形のプロットがある新しい画像。
コードを保持するための新しいファイルを作成することから始めます。
nano app.py
この新しいファイルで、最初に必要なライブラリをインポートして、コードの記述を開始します。 ここでは、cv2
とsys
の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)
の形式で画像からのピクセル位置のコレクションです。
コードで使用するその他のパラメーターの概要は次のとおりです。
gray
:これは、以前にロードしたOpenCVグレースケール画像オブジェクトの使用を指定します。scaleFactor
:このパラメーターは、各画像スケールで画像サイズを縮小する速度を指定します。 モデルのトレーニング中のスケールは固定されているため、入力画像をスケールダウンして検出を向上させることができます。 このプロセスは、maxSize
およびminSize
で定義されたしきい値制限に達した後に停止します。minNeighbors
:このパラメーターは、各候補長方形が保持する必要のあるネイバーまたは検出の数を指定します。 値を大きくすると誤検知が少なくなる可能性がありますが、値が大きすぎると真陽性がなくなる可能性があります。minSize
:これにより、ピクセル単位で測定される可能な最小オブジェクトサイズを定義できます。 このパラメーターよりも小さいオブジェクトは無視されます。
長方形のリストを生成した後、面は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つの引数を取ります。
image
は、元の入力画像に長方形を描画するようにコードに指示します。(x,y), (x+w, y+h)
は、検出されたオブジェクトの4つのピクセル位置です。rectangle
はこれらを使用して、入力画像で検出されたオブジェクトの周囲に長方形を見つけて描画します。(0, 255, 0)
は形状の色です。 この引数は、BGRのタプルとして渡されます。 たとえば、青には(255, 0, 0)
を使用します。 この場合、緑を使用しています。2
は、ピクセル単位で測定された線の太さです。
長方形を描画するコードを追加したので、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
スクリプトと同じディレクトリに保存します。 このチュートリアルでは、次の画像を使用します。
同じイメージでテストする場合は、次のコマンドを使用してダウンロードします。
curl -O https://assets.digitalocean.com/articles/CART-63965/people_with_phones.png
スクリプトをテストするイメージを取得したら、スクリプトを実行し、引数としてイメージパスを指定します。
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
ファイルを再度開くことから始めます。
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
リストからピクセル位置をプロットします。 x
、y
、h
、および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)
要約すると、更新されたコードはピクセル位置を使用して、画像から新しいファイルに顔を抽出します。 コードの更新が完了したら、ファイルを保存して閉じます。
コードを更新したので、スクリプトをもう一度実行する準備が整いました。
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カスケードをトレーニングする方法を学ぶことができます。