LoginSignup
3
3

More than 5 years have passed since last update.

CascadeClassifier::setImageとrunAt

Last updated at Posted at 2015-12-18

これは、OpenCV Advent Calendar 2015 19日目の記事です。関連記事は目次にまとめられています。
一部修正しました。12/20 00:50

はじめに

多くの人がOpenCVでためしてみる機能は、もちろんCascade ClassifierのdetectMultiScaleを使用した顔検出ですね。

この関数のチュートリアルは、ここです。
Cascade Classifierクラスの説明はここで見ることができます。detectMultiScaleの説明はここです。

detectMultiScaleはこのように使用します、以下の例は最小限の使い方です。(細かいところは気にしないでください)

sample.cpp
cv::CascadeClassifier face_cascade;
std::vector<Rect> faces;
cv::Mat image = cv::imread("lena.jpg");
face_cascade.load( "haarcascade_frontalface_alt2.xml") 
face_cascade.detectMultiScale( image, faces);

これだけでOKです。検出結果の領域データは、facesに格納されています。

サンプルの補足

本来なら、imageをグレースケールに変換し、equalizeHistを行うべきでしょうが省略しています
また、equalizeHistを行い内のであれば、グレースケールへの変換も省略できます。
detectMultiScaleはカラー画像にも対応しており、内部でchannelを調べ、カラーの場合必要は、変換して処理します。

このコードを実行すると、1つの候補が見つかります。lenaさんに描画するとこうなります。

lena - コピー.PNG

左上の座標は、219,203でサイズは 174x174です。

前置きが長くなりましたがここからが本題です。

本日のとりあげる知られざる機能はsetImageです。説明はここです。

この関数は、detectMultiScaleの内部で使用されており、通常使う機会はないと思います。
ただ一部の人には、使えると検出結果のさらなる絞込みができるので、うれしいことがあるかと思いますが、その話は別の機会に

setImageは、runAtと対で使用されるものです。runAtの説明はここです
setImageを簡単に説明すると、設定されたimageに対し、FeatureEvaluatorで指定した特徴量を作成しています。
runAtは、設定されたFeatureEvaluatorで、指定した場所を左上とし、辞書サイズの大きさの部分領域の画像の分類を行います。

runAtを実行した結果
対象の領域がpositiveの場合は戻り値が1となります。negativeの場合は、0 および マイナスになります。戻り値の解釈は、使用する特徴量により異なります。また、wは判定に使用した評価値であり、この解釈も特徴量により異なります。

不思議なことに
setImageとrunAtは対で使用するはずですが、なぜかsetImageはpublicで、runAtは protectedの属性が指定されており、CascadeClassifierからは、runAtを呼び出すことはできません

そこで、CascadeClassifierクラスをpublic 継承した CMyCascadeクラスを作成し、自作のdetect関数内でこの2つにアクセスすることになります。

CMyCascade.h
#pragma once
#include <opencv2/opencv.hpp>

class CMyCascade : public cv::CascadeClassifier
{
    cv::CascadeClassifier cascade;

public:
    CMyCascade();
    ~CMyCascade();

    void    detect(cv::Mat);
};
CMyCascade.cpp
void CMyCascade::detect(cv::Mat image)
{
    load("haarcascade_frontalface_alt2.xml");

    cv::Mat gray;
    cv::cvtColor(image, gray, CV_BGR2GRAY);

    cv::Ptr<cv::FeatureEvaluator> evaluator = this->featureEvaluator;
    setImage(evaluator, gray);

    double w;

    for (int j = 0; j < image.size().height - 20; j++){
        for (int i = 0; i < image.size().width - 20; i++) {
            cv::Point p(i, j);
            int r = this->runAt(evaluator, p, w);
            if (r > 0) {
                std::cout << i << "," << j << " " << w << std::endl;
            }
        }
    }
}

CMyCascadeを呼び出すメイン関数

main.cpp
#include "MyCascade.h"

    cv::Mat image = cv::imread("lena.jpg");
    cv::Mat small;
    cv::resize(image, small, cv::Size(59,59));

    CMyCascade cascade2;
    cascade2.detect(small);

今回のサンプルで入力されるimageは,lenaの画像そのものではなく、512x512の大きさの元画像を59x59に縮尺した画像を使用しています。このサイズは、検出された174x174のサイズから辞書サイズ20x20の比率に合わせて縮小しています。

サンプルを実行すると、5点の座標がpositive(顔領域)として判定されます。

detectMultiScale内では、複数の処理が行われております。物体検出の基本は、setImageとrunAtで実現されていますが、
ここに至る前処理と、後処理の説明はそれなりの量になりますので省略しています。
そのため上のサンプルだけでは、まったく理解できないかと思います。

詳しく知りたい場合は

cascadedetectのソースを読めば全体の流れがわかるかと思います。ソースは
opencv2411\sources\modules\objdetect\src\cascadedetect.cpp です

余談ですが
高速化のために、並列処理が行われており、13日に取り上げられた parallel_for_が使用されています.
(並列化の処理内でpositive発見ごとに、mutexのlockを行っているのはどうかと思いますが)

今回の話は、
OpenCV 2.4.11
OS Windows 7 Home 64bit
Visual Studio 2013 update 5
で動作確認したものです。

補足

**18日の記事でICFが取り上げられています。
3.1のDraftが公開されています。そこで
the results are available as a part of OpenCV 3.1 のリストに
Improved ICF detector, waldboost implementation - opencv_contrib/xobjdetect
が含まれており、プロジェクトの場所が移動しただけだと思います。
(すいません 裏はまだ取っていませんので本当になくなったかも知れません)

調べてみました。
12/20のマスターにはありません。
Tagの3.0.0には含まれています。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3