2019年10月15日火曜日

[OpenCV] 静止画の顔認識 Object Detection (objdetect module) Cascade Classifier

前回投稿したPython3 + OpenCVによる顔認識では,Cascade Classifier を使用しています.
以下は,OpenCVのページに示されている説明に関してのメモです(ほぼ,直訳).

Goal 目標
In this tutorial,

  • We will learn how the Haar cascade object detection works.
  • We will see the basics of face detection and eye detection using the Haar Feature-based Cascade Classifiers.
  • We will use the cv::CascadeClassifier class to detect objects in a video stream. Particularly, we will use the functions:
  • cv::CascadeClassifier::load to load a .xml classifier file. It can be either a Haar or a LBP classifer
  • cv::CascadeClassifier::detectMultiScale to perform the detection.

このチュートリアルでは

  • Haar cascade 検出の仕組みを学習します.
  • Haar Feature-based Cascade 検出器を使用した顔検出と目の検出の基本について説明します.
  • cv::CascadeClassifierクラスを使用して、ビデオストリーム内のオブジェクトを検出します.特に,次の関数を使用します.
  • cv::CascadeClassifier::load 分類器ファイルを読み込む(HaarまたはLBP分類器のいずれか).
  • cv::CascadeClassifier::detectMultiScale 検出を実行する.


Theory 理論
Object Detection using Haar feature-based cascade classifiers is an effective object detection method proposed by Paul Viola and Michael Jones in their paper, "Rapid Object Detection using a Boosted Cascade of Simple Features" in 2001. It is a machine learning based approach where a cascade function is trained from a lot of positive and negative images. It is then used to detect objects in other images.
Haarの特徴に基づくカスケード分類器を使用したオブジェクト検出は,2001年にPaul ViolaとMichael Jonesの論文「単純な特徴のブーストカスケードを使用した迅速なオブジェクト検出」で提案された効果的なオブジェクト検出方法です.カスケード機能は,多くのポジティブ(正解)またはネガティブ(不正解)画像によってトレーニングされた機械学習です.その後,他の画像内のオブジェクトを検出するために使用されます.

Here we will work with face detection. Initially, the algorithm needs a lot of positive images (images of faces) and negative images (images without faces) to train the classifier. Then we need to extract features from it. For this, Haar features shown in the below image are used. They are just like our convolutional kernel. Each feature is a single value obtained by subtracting sum of pixels under the white rectangle from sum of pixels under the black rectangle.
ここでは,顔検出を行います.最初に,アルゴリズムは分類器を訓練するために多くのポジティブ(正解)画像(顔の画像)とネガティブ(不正解)画像(顔のない画像)を必要とします.次に,そこから(顔の)特徴を抽出する必要があります.このために,下図に示されているHaar機能を使用します.それらは畳み込みカーネルのようなものです.各特徴は,黒い長方形の下のピクセルの合計から白い長方形の下のピクセルの合計を引いて得られる一つの値となります.
image 画像

Now, all possible sizes and locations of each kernel are used to calculate lots of features. (Just imagine how much computation it needs? Even a 24x24 window results over 160000 features). For each feature calculation, we need to find the sum of the pixels under white and black rectangles. To solve this, they introduced the integral image. However large your image, it reduces the calculations for a given pixel to an operation involving just four pixels. Nice, isn't it? It makes things super-fast.
ここで,各カーネルのすべての可能なサイズと場所が多くの特徴を計算するために使用されます(必要な計算量を想像すると,24x24のウィンドウで160000以上の特徴が得られる).特徴の計算ごとに,白と黒の長方形の下にあるピクセルの合計を見つける必要があります.これを解決するために,彼ら(論文の著者達)は積分画像を導入しました.画像がどれほど大きくても,指定されたピクセルの計算は,4つのピクセルのみを含む演算に削減されます.素晴らしいでしょう.それによって超高速になります.

But among all these features we calculated, most of them are irrelevant. For example, consider the image below. The top row shows two good features. The first feature selected seems to focus on the property that the region of the eyes is often darker than the region of the nose and cheeks. The second feature selected relies on the property that the eyes are darker than the bridge of the nose. But the same windows applied to cheeks or any other place is irrelevant. So how do we select the best features out of 160000+ features? It is achieved by Adaboost.
しかし,計算した,全てのこれらの特徴のほとんどは(目とは)無関係です.たとえば,下の画像について考えてください.一番上の行は、2つのわかりやすい特徴を示しています.最初の特徴は,目の領域が鼻と頬よりも暗い色であるという特性にフォーカスしています.二番目の特徴は,しかし,目が鼻梁よりも暗い色である特徴です.しかし,ウィンドウが頬やその他の場所に適用される同じウィンドウは無関係です.それでは,160000以上の特徴の中から最適な特徴を選択するにはどうすればよいでしょうか? それは,Adaboostによって達成されます.
image 画像

For this, we apply each and every feature on all the training images. For each feature, it finds the best threshold which will classify the faces to positive and negative. Obviously, there will be errors or misclassifications. We select the features with minimum error rate, which means they are the features that most accurately classify the face and non-face images. (The process is not as simple as this. Each image is given an equal weight in the beginning. After each classification, weights of misclassified images are increased. Then the same process is done. New error rates are calculated. Also new weights. The process is continued until the required accuracy or error rate is achieved or the required number of features are found).
これによって,すべての特徴を,すべてのトレーニング画像に適用します.各々の特徴に対して,顔を正しいものを間違っているものに分類する,最適なしきい値を見つけますが,明らかに,エラーや誤分類が生じます.なので,エラー率が最小の特徴,すなわち顔と顔以外の画像を最も正確に分類する特徴を選択します(プロセスはこれほど単純ではありません.各々の画像には,最初に等しい重みが与えられます.各分類の後に,誤分類された画像の重みが増加します.その後,同じプロセスが実行されます.その後,新しいエラー率が計算されて,必要な精度またはエラー率が達成されるか,必要な機能の数が見つかるまでプロセスが実行されます).

The final classifier is a weighted sum of these weak classifiers. It is called weak because it alone can't classify the image, but together with others forms a strong classifier. The paper says even 200 features provide detection with 95% accuracy. Their final setup had around 6000 features. (Imagine a reduction from 160000+ features to 6000 features. That is a big gain).
最終的な分類器は,これらの弱い分類器の重みの和になります.それらは,単独では画像を分類できないために,弱いと呼ばれますが,他のものと一緒になって強力な分類器を形成します.この論文では,200の特徴ですら,95%の精度で検出できると述べています.最終的にセットアップされたものには約6000の特徴がありました (160000以上の特徴から6000の特徴への削減は,大きなメリットです).

So now you take an image. Take each 24x24 window. Apply 6000 features to it. Check if it is face or not. Wow.. Isn't it a little inefficient and time consuming? Yes, it is. The authors have a good solution for that.
撮影した画像に対して, 24 x 24の各ウィンドウを取得します.これに, 6000の特徴を適用して,顔かどうかを判断します.この方法は,非効率的で時間がかかると思いませんか?その通りです.著者はこの良い解決策を持っています.

In an image, most of the image is non-face region. So it is a better idea to have a simple method to check if a window is not a face region. If it is not, discard it in a single shot, and don't process it again. Instead, focus on regions where there can be a face. This way, we spend more time checking possible face regions.
画像では,画像のほとんどは顔以外の領域になるので,ウィンドウが顔領域でないかどうかを確認する簡単な方法を用意することをお勧めします.そうでない場合は,1回のショットで破棄し,再度処理はせずに,顔が存在する可能性のある領域にフォーカスします.このようにして,顔の可能性の高い領域を確認することに時間を費やします.

For this they introduced the concept of Cascade of Classifiers. Instead of applying all 6000 features on a window, the features are grouped into different stages of classifiers and applied one-by-one. (Normally the first few stages will contain very many fewer features). If a window fails the first stage, discard it. We don't consider the remaining features on it. If it passes, apply the second stage of features and continue the process. The window which passes all stages is a face region. How is that plan!
このように,彼ら(著者)は分類器のカスケードの概念を導入しました.ウィンドウに6000個のすべての(顔の)特徴判定機能を適用する代わりに,特徴は分類器のさまざまな段階にグループ化されて,1つずつ適用されます(通常,最初の数段階には非常に少ない機能が含まれます).ウィンドウが最初の段階で誤りである(顔ではない)と判断した場合には,そのウィンドウを破棄して,残りの特徴については考慮しません.正しい(顔である)と判断した場合は,次の特徴を判断するステージを適用して,プロセスを続行します.すべてのステージを通過する(顔だと判断される)ウィンドウは,顔の領域となります.この計画はどうでしょう!

The authors' detector had 6000+ features with 38 stages with 1, 10, 25, 25 and 50 features in the first five stages. (The two features in the above image are actually obtained as the best two features from Adaboost). According to the authors, on average 10 features out of 6000+ are evaluated per sub-window.
著者の検出器には、最初の5つの段階で1、10、25、25、および50の機能を備えた38の段階で6000以上の機能がありました(上の画像の2つの特徴は,Adaboostから最高の2つの特徴として実際に取得されています).著者によるとサブウィンドウごとに,平均して6000以上の10個の機能で評価されます.

So this is a simple intuitive explanation of how Viola-Jones face detection works. Read the paper for more details or check out the references in the Additional Resources section.
これは,Viola-Jonesの顔検出をどのように機能するかについての簡単かつ直感的な説明です.詳細については論文を読むか「その他のリソース」セクションを参照して確認してください.

Haar-cascade Detection in OpenCV 
OpenCV provides a training method (see Cascade Classifier Training) or pretrained models, that can be read using the cv::CascadeClassifier::loadmethod. The pretrained models are located in the data folder in the OpenCV installation or can be found here.
The following code example will use pretrained Haar cascade models to detect faces and eyes in an image. First, a cv::CascadeClassifier is created and the necessary XML file is loaded using the cv::CascadeClassifier::load method. Afterwards, the detection is done using the cv::CascadeClassifier::detectMultiScale method, which returns boundary rectangles for the detected faces or eyes.
This tutorial code's is shown lines below. You can also download it from here

objectDetection.cpp
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>

using namespace std;
using namespace cv;

/** Function Headers */
void detectAndDisplay( Mat frame );

/** Global variables */
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;

/** @function main */
int main( int argc, const char** argv )
{
    CommandLineParser parser(argc, argv,
                             "{help h||}"
                             "{face_cascade|data/haarcascades/haarcascade_frontalface_alt.xml|Path to face cascade.}"
                             "{eyes_cascade|data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|Path to eyes cascade.}"
                             "{camera|0|Camera device number.}");

    parser.about( "\nThis program demonstrates using the cv::CascadeClassifier class to detect objects (Face + eyes) in a video stream.\n"
                  "You can use Haar or LBP features.\n\n" );
    parser.printMessage();

    String face_cascade_name = samples::findFile( parser.get<String>("face_cascade") );
    String eyes_cascade_name = samples::findFile( parser.get<String>("eyes_cascade") );

    //-- 1. Load the cascades
    if( !face_cascade.load( face_cascade_name ) )
    {
        cout << "--(!)Error loading face cascade\n";
        return -1;
    };
    if( !eyes_cascade.load( eyes_cascade_name ) )
    {
        cout << "--(!)Error loading eyes cascade\n";
        return -1;
    };

    int camera_device = parser.get<int>("camera");
    VideoCapture capture;
    //-- 2. Read the video stream
    capture.open( camera_device );
    if ( ! capture.isOpened() )
    {
        cout << "--(!)Error opening video capture\n";
        return -1;
    }

    Mat frame;
    while ( capture.read(frame) )
    {
        if( frame.empty() )
        {
            cout << "--(!) No captured frame -- Break!\n";
            break;
        }

        //-- 3. Apply the classifier to the frame
        detectAndDisplay( frame );

        if( waitKey(10) == 27 )
        {
            break; // escape
        }
    }
    return 0;
}

/** @function detectAndDisplay */
void detectAndDisplay( Mat frame )
{
    Mat frame_gray;
    cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
    equalizeHist( frame_gray, frame_gray );

    //-- Detect faces
    std::vector<Rect> faces;
    face_cascade.detectMultiScale( frame_gray, faces );

    for ( size_t i = 0; i < faces.size(); i++ )
    {
        Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
        ellipse( frame, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4 );

        Mat faceROI = frame_gray( faces[i] );

        //-- In each face, detect eyes
        std::vector<Rect> eyes;
        eyes_cascade.detectMultiScale( faceROI, eyes );

        for ( size_t j = 0; j < eyes.size(); j++ )
        {
            Point eye_center( faces[i].x + eyes[j].x + eyes[j].width/2, faces[i].y + eyes[j].y + eyes[j].height/2 );
            int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
            circle( frame, eye_center, radius, Scalar( 255, 0, 0 ), 4 );
        }
    }

    //-- Show what you got
    imshow( "Capture - Face detection", frame );

}

Result
1. Here is the result of running the code above and using as input the video stream of a built-in webcam:
1. 以下は,上記のコードを実行して,入力として組み込みWebカメラのビデオストリームを使用した結果です.

Be sure the program will find the path of files haarcascade_frontalface_alt.xml and haarcascade_eye_tree_eyeglasses.xml. They are located in opencv/data/haarcascades
プログラムがhaarcascade_frontalface_alt.xmlファイルとhaarcascade_eye_tree_eyeglasses.xmlファイルのパスを見つけられるようにしてください.それらはopencv / data / haarcascadesに置いてあります.

2. This is the result of using the file lbpcascade_frontalface.xml (LBP trained) for the face detection. For the eyes we keep using the file used in the tutorial.
2. これは,顔検出にファイルlbpcascade_frontalface.xml(LBPトレーニング済み)を使用した結果です.目のために,チュートリアルで使用したファイルを使用し続けています.

Additional Resources

  1. Paul Viola and Michael J. Jones. Robust real-time face detection. International Journal of Computer Vision, 57(2):137–154, 2004. [239]
  2. Rainer Lienhart and Jochen Maydt. An extended set of haar-like features for rapid object detection. In Image Processing. 2002. Proceedings. 2002 International Conference on, volume 1, pages I–900. IEEE, 2002. [136]
  3. Video Lecture on Face Detection and Tracking
  4. An interesting interview regarding Face Detection by Adam Harvey
  5. OpenCV Face Detection: Visualized on Vimeo by Adam Harvey


0 件のコメント :

コメントを投稿