質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.11%

OpenCVを用いた物体検出

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,863
退会済みユーザー

退会済みユーザー

現在OpenCV2.1を用いた上で顔検出にチャレンジしています。
学習等については問題なく行うことができ、顔の検出を行おうと思っているのですが、検出の段階で設定するパラメータの"minNeighbors"と"scaleFactor"の各値について疑問がわきました.

・minNeighborsについて
物体候補領域が何個以上重なっていたらそれを一つの物体として検出するといったイメージだと思ったのですが、実際にどの程度候補領域が重なっていたら重なりと定義されているのかという点が分かりません。またその重なりの程度のパラメータ等もございましたらそのパラメータ設定の場所も含めお教えいただければと思います。

・scaleFactorについて
色々とインターネットを見たのですが,「各画像スケールにおける縮小量」とだけ書かれておりよく意味が理解できませんでしたので、その意味について教えて頂きたいです。

以上となります。どなたかご存知の方、ご教授頂ければとおもいます。宜しくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    2017/09/06 09:38

    複数のユーザーから「意図的に内容が抹消された質問」という意見がありました
    解決後に編集機能を用いて質問内容を改変し関係のない内容にしたり、内容を削除する行為は禁止しています。
    投稿していただいた質問は、後に他の誰かが困ったときに助けになる情報資産になると考えるからです。
    「質問を編集する」ボタンから編集を行い、他のユーザにも質問内容が見えるように修正してください。

回答 1

checkベストアンサー

+4

まず、それぞれの言葉の意味について回答します。

  • minNeighborsについて
    『物体候補領域が何個以上重なっていたらそれを一つの物体として検出する』というイメージで大体あっていると思います。その重なり具合を指定するパラメータは存在します。詳しくは後述します。

  • scaleFactorについて
    OpenCVのカスケード分類器は、Sliding Windowという技法を使って候補となる矩形を検出しています。この動画は、われらがマドンナ・レナ姐さんの画像にSliding Windowを適用しているものです。文字通り、窓を滑らせて片端から候補を見つけ出しているんですが、一巡毎にこの窓枠は縮小します。この縮小率がscaleFactorです。(たまにscaleFactorを1.0にして困っている人を見ます。)


次に、「どの程度候補領域が重なっていたら重なりと定義されているか」という点について考えていきたいと思います。私もちょっと気になったもので、今回調べてみました。

  1. detectMultiScale(コード)が、Sliding Windowとカスケード分類で候補となる矩形のvectorを作る。
  2. 上記によって得られたvectorが、groupRectangle(コード)にrectListとして渡される。また、minNeighborsは、同時にgroupThresholdとして渡される。
  3. groupRectangleは、内部でpartition(コード)を呼び出す。partitionはクラスタリングを行うOpenCVの汎用関数で、第一引数にクラスタリング対象となるvectorを渡すと、第二引数にクラス番号のvectorを代入してくれる。もちろん、第一引数にはrectListが渡される。

ここで、partitionがむにゃむにゃとクラスタリングを行って、その結果を返すことがわかりましたね。その結果をもとに、groupThresholdことminNeighborsを用いて、『充分な回数検出されている領域か?』という判別が出来ます。


さて、次の問題は、partitionがどうクラスタリングを行っているかどうかですね。コードを見てみると、どうやら矩形の全通りを比較しているようです。比較して、『どうやら同じクラスらしい』と判別するための基準は、partitionの第三引数として与えられるようです。
partitionは、groupRectangle内から、次のように呼び出されます。

partition(rectList, labels, SimilarRects(eps));

と、いうわけで、SimilarRects(コード)に矩形の同一性の判断が任されていることがわかります。それでは、SimilarRectsのコードを見てみましょう。

class CV_EXPORTS SimilarRects
{
public:
    SimilarRects(double _eps) : eps(_eps) {}
    inline bool operator()(const Rect& r1, const Rect& r2) const
    {
        double delta = eps * ((std::min)(r1.width, r2.width) + (std::min)(r1.height, r2.height)) * 0.5;
        return std::abs(r1.x - r2.x) <= delta &&
            std::abs(r1.y - r2.y) <= delta &&
            std::abs(r1.x + r1.width - r2.x - r2.width) <= delta &&
            std::abs(r1.y + r1.height - r2.y - r2.height) <= delta;
    }
    double eps;
};

まさにoperator()の部分が、二つの矩形を引数にとって、それらの同一性を判断しているんですね。たった二文しかないですし、さっそくコードを読み解いてみましょう。

一文目: epsの値を基準に、判断指標deltaを決定しています。
二文目: 全ての辺の距離がdeltaより小さいとき、同一としてtrueを返します。


さて、最後の話題です。

またその重なりの程度のパラメータ等もございましたらそのパラメータ設定の場所も含めお教えいただければと思います。

partition内で判断基準として用いられたdeltaは、第三引数epsに比例して決定されました。また、この値は、もともとgroupRactangleの第三引数epsとして与えられたもので、次のように、デフォルト値は0.2となっています。

void groupRectangles(vector<Rect>& rectList, int groupThreshold, double eps=0.2);

ですので、groupRectanglesを自ら呼び出すようなコードを書けば、パラメータepsを指定できることになります。次のようにして、実際に実行することが出来ました。(ただし、再現環境はOpenCV3)

cascade.detectMultiScale(smallImg, faces,
                         1.1,   // scaleFactor
                         0,     // minNeighbors(仮)
                         CV_HAAR_SCALE_IMAGE,
                         cv::Size(30, 30));
// 以下の値は自由
int groupThreshold = 3;
double eps = 0.5;
cv::groupRectangles(faces, gourpThreshold, eps);
facerect = cascade.detectMultiScale(image_gray, scaleFactor=1.04, minNeighbors=0, minSize=(80, 80), maxSize=(200, 200))
facerect, _ = cv2.groupRectangles(np.array(facerect).tolist(), groupThreshold=3, eps=0.5)

こちらを参考にしました。事前にimport numpy as npするのを忘れずに。


Githubのコードを舐め回して、ようやくここまでわかりました... 私自身もいい勉強になりました。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/21 13:33

    前者については、誤植ですね。すみません。
    後者に関しては、質問者様のコードでも同じようなことをしているようなので、まずはご自身のコードを分析してみてください。
    長方形を表現するために必要な情報は、横幅と高さだけではないはずです。

    キャンセル

  • 2017/07/21 14:51

    わかりました。ありがとうございます

    キャンセル

  • 2017/09/04 02:54

    うーん。コメントが抹消されている...
    自分本位な使い方に思えます。非常に残念です...

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.11%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る