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

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

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

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

Python

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

Q&A

解決済

2回答

670閲覧

写真フォルダからアップの写真一枚、全身の写真一枚をピックアップしたい

TakayukiMoriya

総合スコア26

OpenCV

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

Python

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

0グッド

0クリップ

投稿2020/02/12 23:02

このように背景紙の前で撮影したたくさんの写真の中から、プロフィール用にアップの写真一枚と全身の写真を一枚、計二枚取り出したいと考えております。
イメージ説明

OpenCVを使って顔認識をさせて、顔の幅が最も大きな写真を一枚、顔の幅が最も小さな写真を一枚ピックアップできれば要件を満たすと考え、以下のようなプログラムを組みました。

python

1import os 2import cv2 3import math 4import numpy as np 5from PIL import Image 6 7face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')#学習データ 8 9img_dir_path = input('画像フォルダのパスを入力してください:')# 10 11#img_dir_path = '/Users/user/Desktop/drive-download' 12pictures = os.listdir(img_dir_path)#フォルダリストの中身をリスト化 13 14if '.DS_Store' in pictures: 15 pictures.remove('.DS_Store') 16 17if 'Thumbs.db' in pictures: 18 pictures.remove('Thumbs.db') 19 20print(pictures) 21 22#os.mkdir(os.path.join(img_dir_path,'output')) 23all_faces = []#写真ごと全ての顔の座標や大きさの情報を入れるリスト 24 25i = 0 26 27while i < len(pictures): 28 29 img = cv2.imread(os.path.join(img_dir_path,pictures[i])) 30 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 31 faces = face_cascade.detectMultiScale(gray, scaleFactor = 1.2, minSize = (250,250), maxSize = (1600,1600)) 32 33 print(pictures[i]) 34 35#顔認証に失敗した場合 36 if len(faces) == 0: 37 img = cv2.imread(os.path.join(img_dir_path,pictures[i])) 38 39 40# 回転角の指定 41 for j in range(-15,15):#-45°〜45°まで画像を回転 42 angle = 5*j 43 scale = 1.0 44 height, width = img.shape[:2] 45#回転の中心を指定 46 center = (int(width/2), int(height/2)) 47 trans = cv2.getRotationMatrix2D(center, angle , scale) 48#アフィン変換 49 img_rot = cv2.warpAffine(img, trans, (width,height)) 50 gray = cv2.cvtColor(img_rot, cv2.COLOR_BGR2GRAY) 51 faces = face_cascade.detectMultiScale(gray, scaleFactor = 1.2, minSize = (250,250), maxSize = (1600,1600)) 52 if len(faces) > 0: 53 print('回転させた結果認識!' + str(faces)) 54 face_max = faces[faces[:, 2].argmax()] 55 # img[top : bottom, left : right] 56 #np.insert(all_faces, faces)#空のリストに顔リストを一つ追加 57 58 all_faces.append(face_max) 59 break 60 61 62#顔認証に成功した場合 63 elif len(faces) > 0: 64 face_max = faces[faces[:, 2].argmax()] 65 66 #print(face_max) 67 68 #np.insert(all_faces, faces)#空のリストに顔リストを一つ追加 69 all_faces.append(face_max) 70 71 img = Image.open(os.path.join(img_dir_path,pictures[i])) 72 width, height = img.size 73 74 #print(face_max[0]) 75 76 77 78 79 80 i = i + 1 81 82print('END') 83print(all_faces) 84 85 86 87

その結果、最終行のprint(all_faces)が以下のような形式で書き出されました。

all_faces

1[array([1122, 564, 365, 365], dtype=int32), 2array([1245, 680, 369, 369], dtype=int32), 3array([1157, 605, 378, 378], dtype=int32), 4array([810, 505, 710, 710], dtype=int32), 5array([901, 877, 706, 706], dtype=int32), 6array([783, 652, 723, 723], dtype=int32), 7array([1414, 1150, 1104, 1104], dtype=int32), 8array([1365, 1395, 920, 920], dtype=int32), 9array([669, 976, 476, 476], dtype=int32)]

ここから先つまづいてしまったのですが、この中から幅の最大値と最小値を持つ要素をそれぞれ指定したいと考えております。

OpenCVの顔認識は[X,Y,W,H]の形式で書き出されるので、最大値は下から3行目の1104で最小値は1行目の365だということが自分ではわかるのですが、これをプログラムで指定したいと考えております。

基礎的な部分なのかもしれませんが、ご教示いただければ幸いです。

ここから先は、「最小値がN行目にあるから、写真リストのN番目のが全身の写真だ!」といったプログラムを書いて発展させていこうと考えております。

以上、よろしくお願いいたします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

以下のような感じでnp.arrayにすると最大、最小の行位置が得られます。

Python

1import numpy as np 2 3l =[np.array([1122, 564, 365, 365]), 4 np.array([1245, 680, 369, 369]), 5 np.array([1157, 605, 378, 378]), 6 np.array([810, 505, 710, 710]), 7 np.array([901, 877, 706, 706]), 8 np.array([783, 652, 723, 723]), 9 np.array([1414, 1150, 1104, 1104]), 10 np.array([1365, 1395, 920, 920]), 11 np.array([669, 976, 476, 476])] 12 13a = np.array([v.tolist() for v in l]) 14 15print(a[:,2].argmin()) # 0 16print(a[:,2].argmax()) # 6

ちなみに私なら、幅ではなく画像全体の面積と顔(と認識された領域)の面積の比率で判定させたいと思います。

投稿2020/02/13 13:35

can110

総合スコア38341

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

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

TakayukiMoriya

2020/02/13 22:11

tolist()で解決する方法、ありがとうございました! >画像全体の面積と顔(と認識された領域)の面積の比率で判定させたいと思います。 確かにその方が汎用性が高いですね。今回は質問ページに貼った画像のようにひたすら縦に撮った人物写真のみが対象なので幅の数値をそのまま使う予定ですが、今後のシステム増強時には実装してみようと思います。
guest

0

シンプルに考えると、 all_facesはndarrayだと思うので、

w_list = all_faces[:,2]

のようにリストにWの値を全部突っ込んで、

リストの最大値(最小値)のindexを取得する6つの方法を計測してみた にあるような方法でリストのindexと最小値を算出すれば良さそうです。

投稿2020/02/13 01:06

tetsunosuke

総合スコア1295

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

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

TakayukiMoriya

2020/02/13 12:58

ありがとうございます、ですが TypeError: list indices must be integers or slices, not tuple このエラーが出てしまい、うまく指定できません
tetsunosuke

2020/02/13 13:04

all_faces[:,2] がすでにエラーでしたか。。 ndarrayのつもりで検証していましたが、違ったのかもしれません。改めて検証してみます
TakayukiMoriya

2020/02/13 22:08

ありがとうございます。解決しました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問