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

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

新規登録して質問してみよう
ただいま回答率
85.47%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Q&A

解決済

1回答

1222閲覧

OpenCVを用いた物体検出

退会済みユーザー

退会済みユーザー

総合スコア0

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

0グッド

1クリップ

投稿2017/07/19 05:54

編集2017/08/18 10:09

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

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

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

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

  • 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内から、次のように呼び出されます。

C++

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

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

C++

1class CV_EXPORTS SimilarRects 2{ 3public: 4 SimilarRects(double _eps) : eps(_eps) {} 5 inline bool operator()(const Rect& r1, const Rect& r2) const 6 { 7 double delta = eps * ((std::min)(r1.width, r2.width) + (std::min)(r1.height, r2.height)) * 0.5; 8 return std::abs(r1.x - r2.x) <= delta && 9 std::abs(r1.y - r2.y) <= delta && 10 std::abs(r1.x + r1.width - r2.x - r2.width) <= delta && 11 std::abs(r1.y + r1.height - r2.y - r2.height) <= delta; 12 } 13 double eps; 14};

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

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


さて、最後の話題です。

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

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

C++

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

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

C++

1cascade.detectMultiScale(smallImg, faces, 2 1.1, // scaleFactor 3 0, // minNeighbors(仮) 4 CV_HAAR_SCALE_IMAGE, 5 cv::Size(30, 30)); 6// 以下の値は自由 7int groupThreshold = 3; 8double eps = 0.5; 9cv::groupRectangles(faces, gourpThreshold, eps);

Python

1facerect = cascade.detectMultiScale(image_gray, scaleFactor=1.04, minNeighbors=0, minSize=(80, 80), maxSize=(200, 200)) 2facerect, _ = cv2.groupRectangles(np.array(facerect).tolist(), groupThreshold=3, eps=0.5)

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


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

投稿2017/07/19 17:56

編集2017/07/21 04:34
LouiS0616

総合スコア35660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/07/20 08:07

ご丁寧なご回答ありがとうございます。 grouprectanglesを呼び出すコードを入れ、実行したのですが、上手くいきませんでした。 そこでeps値を変更しようと思い,OpenCV2.1/src/cv中のcvcascadedetect.cppの中のeps=0.2と書かれていた部分を手動変更しましたが同様に上手く実行できません。初心者でまだあまりよく理解できていないのですが、epsの値を手動で変更することは実質的には不可能なのでしょうか?
LouiS0616

2017/07/20 08:09

後者ですが、ビルドしなおさないと意味ないですね。OpenCVのcppファイルの書き換えはやめておいた方がいいです。
LouiS0616

2017/07/20 08:09

前者に関しては、どのように上手くいかなかったんでしょうか?
退会済みユーザー

退会済みユーザー

2017/08/18 10:08 編集

hid
退会済みユーザー

退会済みユーザー

2017/08/18 10:01 編集

LouiS0616

2017/07/20 08:54

OpenCV Error: Assertion failed (channels() == CV_MAT_CN(dtype)) in cv::Mat::copyTo, file C:\projects\opencv-python\opencv\modules\core\src\copy.cpp, line 259
LouiS0616

2017/07/20 09:12

ちょっと、「どう上手くいかなかったのか」わからないです。実行時にエラーが出たのか、関数の使い方がわからないのか、どっちでしょう?
退会済みユーザー

退会済みユーザー

2017/08/18 10:07 編集

hid
退会済みユーザー

退会済みユーザー

2017/08/18 10:02 編集

  ”
LouiS0616

2017/07/20 09:22

facesじゃなくてfacerectじゃないですか? そこらへんは適宜読み替えてください。 あと、Pythonの場合、文末のセミコロンは不要です。
LouiS0616

2017/07/20 09:24

あとは、Pythonだとキーワード引数が使えるので、 cv2.groupRectangles(facerect, groupThreshold=3, eps=5) という風に書けば、直前の二行は不要かと思います。
退会済みユーザー

退会済みユーザー

2017/08/18 10:07 編集

hid
LouiS0616

2017/07/20 09:37

私もちょうどいま同じエラーに苦しんでたんですが、ちょうど解決策を発見しました。回答に追記しますので少々お待ちください。
LouiS0616

2017/07/20 09:45

追記しました。
LouiS0616

2017/07/20 09:47

ついでに、detectMultiScaleを呼び出す際は、minNeighborsを0に指定してください。 そうでないと、内部でgroupRectangleが呼び出されますので、二重にクラスタリングを行ってしまいます。 18という値は、groupThresholdに与えてください。
退会済みユーザー

退会済みユーザー

2017/07/20 09:58

ご丁寧に追記していただきありがとうございます 最後に name 'np' is not defined とエラーが出てしまっているのですが,どう解消すればよろしいでしょうか. import numpy as np は追記したのですが...
LouiS0616

2017/07/20 10:02

import numpy as npは、プログラムの先頭の方で宣言してください。
退会済みユーザー

退会済みユーザー

2017/07/20 10:14

importの最初に宣言したことで,実行することが出来ました。 ただ実行後に再度以下の様なエラーが生じました Traceback (most recent call last); File "ファイル名.py", line 54 ,in <module> dst =image[y:y+height, x:x+width] IndexError: failed to coerce slice entry of type numpy.ndarray to integer 以上のようなエラーが出ました。何か型が合っていないということなのでしょうか
退会済みユーザー

退会済みユーザー

2017/08/18 10:07 編集

hid
退会済みユーザー

退会済みユーザー

2017/07/20 10:16

現在のプログラムはこちらとなっています
LouiS0616

2017/07/20 10:29

私のPython3の環境では再現できなかったのでちょっと自信がないんですが、 for文の直前にこいつを入れてみたらどうなります?   facerect = facerect.tolist() 試してみてください。
退会済みユーザー

退会済みユーザー

2017/08/18 10:07 編集

hid
退会済みユーザー

退会済みユーザー

2017/07/20 10:38

こちらのような結果となりました。
LouiS0616

2017/07/20 10:43

facerect = cv2.groupRectangles(np.array(facerect1).tolist(), groupThreshold=18, eps=0.2) ではなく、 facerect, _ = cv2.groupRectangles(np.array(facerect1).tolist(), groupThreshold=18, eps=0.2) としてください。二番目の出力も吸い取ってしまっています。
LouiS0616

2017/07/20 10:49

これは回答にちゃんと書いたはずなんですが...
LouiS0616

2017/07/20 10:55

detectMultiScaleは従来のままで大丈夫ですよ
退会済みユーザー

退会済みユーザー

2017/07/20 10:56

結果は出るようになりましたが,まだ以下のエラーが残ってしまいます face rectangle [[ 253 372 143 143] [ 502 388 143 143] [ 871 414 146 146] [1444 858 101 101] [ 732 347 100 100] [1045 360 136 136] [1297 496 136 136]] Traceback (most recent call last): File "createsample4new.py", line 64, in <module> cv2.rectangle(image, tuple(rect[0:2]),tuple(rect[0:2] + rect[2:4]), color, t hickness=2) TypeError: function takes exactly 2 arguments (4 given)
退会済みユーザー

退会済みユーザー

2017/08/18 10:07 編集

hid
LouiS0616

2017/07/20 11:01

すみません、やっぱり次の行は消してください。 facerect = facerect.tolist()
退会済みユーザー

退会済みユーザー

2017/07/20 11:04

無事出来るようになりました
退会済みユーザー

退会済みユーザー

2017/07/20 11:04

わざわざ遅い時間までお付き合いいただき本当にありがとうございます。
LouiS0616

2017/07/20 11:07

あ、動いたようで良かったです。 Python自体に対する理解がまだ足りていないようですので、基本的な部分もしっかり勉強してくださいね。
退会済みユーザー

退会済みユーザー

2017/07/20 11:11

最低限の質問で抑えられるようにしっかり勉強したいと思います。 本当にありがとうございました。
退会済みユーザー

退会済みユーザー

2017/07/21 01:50

すみません今関数について理解をしようとしておりまして、SimilarRectsのOperator()内の double delta = eps * ((std::min)(r1.width, r2.width) + (std::min)(r1.height, > r2.height)) * 0.5; という計算について、 (std::min)(r1.width, r2.width) ではr1.widthとr2.widthの小さい方が帰って来ることは分かっているのですが、 (std::min)(r1.height, > r2.height)では何が帰って来るのか参考書を見てもよく理解が出来なかったのでご教授頂きたいです。 申し訳ありませんが宜しくお願い致します
退会済みユーザー

退会済みユーザー

2017/08/18 10:08 編集

hid
LouiS0616

2017/07/21 04:33

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

退会済みユーザー

2017/07/21 05:51

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

2017/09/03 17:54

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問