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

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

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

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

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

2431閲覧

Pythonのリストの近似値2要素のみ取り出したい

TakayukiMoriya

総合スコア26

OpenCV

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

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/04/13 02:16

編集2020/04/13 04:59

Open CVのeye_cascadeを使用した目の認識を行なっているのですが、誤検知を減らす上で、表題のような課題に突き当たりました。
イメージ説明

実際に書いたコード

下記コードのように、写真を読み込ませて顔認識した範囲で目認識をしようとします

pyton

1import os 2import cv2 3 4face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')#学習データ 5eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')#学習データ 6 7img = cv2.imread('DSC_0064.JPG') 8gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 9faces = face_cascade.detectMultiScale(gray, scaleFactor = 1.1, minSize = (400,400), maxSize = (int(width*0.8),int(width*0.8))) 10face_max = faces[faces[:, 2].argmax()] 11 12img1 = img[int(face_max[1]) : int(face_max[1]+face_max[2]), int(face_max[0]): int(face_max[0]+face_max[3])]#元画像を顔部分のみクロップ→その範囲のみ目顔認証をかける 13gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) 14eyes = eye_cascade.detectMultiScale(gray1, scaleFactor = 1.1,minNeighbors=10, minSize = (50,50), maxSize = (350,350)) 15 16print(type(eyes)) 17print(eyes)#[x,y,w,h]の形で書き出される

結果

<class 'numpy.ndarray'> [[ 99 143 112 112] [298 154 102 102] [141 37 80 80]]

ndarray形式でこのような結果が書き出され、左右2つの目を認識したいにも関わらず3箇所認識されている結果となりました。(前髪や口が誤認識されているようです。)

そこで考えたのですが、目というものは、左右2つはほぼ水平に写真に収められるものなので、各要素の2番目のy座標の値に注目し、上から143と154と37だと、37の値が他の2つに比べて逸脱しているのでこれが誤検知なのだと判断できます。

このように、y座標の値が近似な2つの要素のみ抽出する

[[ 99 143 112 112] [298 154 102 102]]

といった処理を行い誤検知の値を排除したいと考えているのですが、なかなかうまい方法が思いつきません。

良い方法をご存知でしたらご教授いただけたらと思い、質問させていただきました。よろしくお願いします。

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

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

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

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

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

Q71

2020/04/13 02:26

顔検出というデータファイルがありませんでしたか?顔として検出した中にある、とするのはどうでしょう?
TakayukiMoriya

2020/04/13 02:38

説明不足&画像の例が悪くてすみません。実はそれは既に行なっております。 この画像の例以外にも、口を誤検出したりすることが多いので、やはりy座標を根拠としたソートの方がより確実だと考えます。
quickquip

2020/04/13 04:01 編集

eyes = [[2264 1453 194 194] [2582 1589 166 166] [3388 2100 89 89]] この部分、Pythonとして正しいコードにしていただけないでしょうか? "intのリスト"のリストですか? numpy.ndarrayですか?
TakayukiMoriya

2020/04/13 04:17

ndarry形式です。リストと言っていたのはNumpyのリスト形式という意味ですね。知識不足で混同してました。
quickquip

2020/04/13 04:30 編集

Numpyだと普通は(カジュアルには)配列かarrayと呼ぶかと思います。 eyes = np.array([[2264, 1453, 194, 194], [2582, 1589, 166, 166], [3388, 2100, 89, 89]]) ですね。そう分かるように質問を編集しましょう。(ここは"質問への追記・修正の依頼"欄です)
TakayukiMoriya

2020/04/13 04:31

諸々コードが変なので、修正します。申し訳ございません
tiitoi

2020/04/13 04:49

eyes の矩形一覧を y座標が近いもの同士でグループ分けしたいということでしょうか?
t_obara

2020/04/13 04:52

顔の片側しか写っていない場合どうするのかなどあるので、外側から頑張るより、精度が良い別の手法の方が簡単だったりします(処理速度との兼ね合いはありますが)。
TakayukiMoriya

2020/04/13 05:01

tiitoiさん、そうですね。グループ分けで要件を満たすと思います!
TakayukiMoriya

2020/04/13 05:03

t_obaraさん 仮に1つしか目を認識できなかったら、それはうまく撮れていない写真と判定し、処理をスルーしてしまう予定でした。 精度が高い別の手法って何ですか???
t_obara

2020/04/13 06:47

mtcnnとかdlibとか。詳しくはググってみると良いです。
guest

回答1

0

ベストアンサー

そうですね。グループ分けで要件を満たすと思います!

y の値に基づいてグループ分けを行うコードを下記に貼ります。
y の値が小さい順に矩形をソートしておいて、1行前の y の値と今の行の y の値との差が50 px 以上ある場合はそこで区切るようにしました。

python

1import numpy as np 2 3a = np.array([[99, 143, 112, 112], 4 [298, 154, 102, 102], 5 [141, 37, 80, 80]]) 6 7sorted_a = a[np.argsort(a[:, 1])] 8 9 10groups = [] 11tmp = [] 12y = sorted_a[0, 1] 13 14for row in sorted_a: 15 if row[1] - y >= 50: # 差が50px以上なら区切る 16 groups.append(tmp) 17 tmp = [] 18 y = row[1] 19 tmp.append(row) 20groups.append(tmp) 21 22print(groups)

numpy の関数を使って上記処理を書くと以下のようにすることもできます。

python

1split_pos = np.nonzero(np.diff(sorted_a[:, 1]) >= 50)[0] + 1 # 分割する行 2groups = np.split(sorted_a, split_pos) # 行方向に分割 3print(groups)

y の値が近いもの同士でグループ分けするやり方について回答しましたが、目の位置の誤検出をへらすというのが最終目的であるとすると、このやり方だと不十分な気がします。
例えば、顔が斜めであれば、2つの目の y の値が違って来ますし、目の位置と y の値が同じ場所に誤検出が発生した場合は区別できません。

本質的な解決策はカスケード検出器ではなく、より精度のよいアルゴリズムを検討したほうがよいでしょう。

例えば、dlib の顔認識機能を Python から簡単に使えるようにした Face Recognition というライブラリがあります。

Python - 顔認識ライブラリ Face Recognition で顔検出を行う方法

投稿2020/04/13 08:09

編集2020/04/13 08:10
tiitoi

総合スコア21956

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問