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

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

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

dlibは、機械学習のC++の画像処理ライブラリの一つ。性能の高い顔の器官検出が簡単にでき、Pythonバインドもあります。オープンソースで無料で使用でき、機械学習以外の様々な機能も搭載されています。

OpenCV

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

2975閲覧

OpenCVとDlibを用いた顔向き推定

masayuki.west

総合スコア13

dlib

dlibは、機械学習のC++の画像処理ライブラリの一つ。性能の高い顔の器官検出が簡単にでき、Pythonバインドもあります。オープンソースで無料で使用でき、機械学習以外の様々な機能も搭載されています。

OpenCV

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2018/09/27 08:56

映像から顔向き角度を算出する方法

現在、私はDlibとOpenCV用いて顔向き角度を算出しています。

映像からDlibを用いて顔を検出し、顔の特徴点と3Dモデル座標を対応させるopenCVのsolvePnPで算出しているのですが正確な顔向き角度を算出することができません。
具体的には右方向や左方向の正負(数値が不適当)は合っているのですが、10、20度のような細かい角度が算出できません。

細かい角度を算出するためには3Dモデルにあたるobject_ptsを正確に設定しなければならないでしょうか?(いい値があるなら教えていただけたら幸いです)

もしくは、他の方法で映像から精度の高い顔向きを算出する方法あるのでしょうか?

該当のソースコード(一部抜粋)

Python

1K = [1.153752569389803966e+03,0.000000000000000000e+00,5.962752942372259213e+02, 2 0.000000000000000000e+00,1.211255746170439807e+03,2.448367548714677469e+02, 3 0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00] 4D = [1.174542892072836936e-01, 2.963230480639748032e-01, -6.327104166740647739e-02, -1.601237498454269326e-02, -7.110347802929409822e-01] 5 6cam_matrix = np.array(K).reshape(3, 3).astype(np.float32) 7dist_coeffs = np.array(D).reshape(5, 1).astype(np.float32) 8 9object_pts = np.float32([[0.0, 0.0, 0.0], 10 [0.0, -330.0, -65.0], 11 [-225.0, 170.0, -135.0], 12 [225.0, 170.0, -135.0], 13 [-150.0, -150.0, -125.0], 14 [150.0, -150.0, -125.0], 15 ])/4.5 16 17image_pts = np.float32([shape[30], shape[8], shape[36], shape[45], shape[48], shape[54]]) 18 19_, rotation_vec, translation_vec = cv2.solvePnP(object_pts, image_pts, cam_matrix, dist_coeffs)

補足情報

カメラのキャリブレーションは下記のサイトを参考にしました。
カメラキャリブレーション(参考サイト)

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

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

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

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

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

guest

回答1

0

ベストアンサー

cv2.solvePnP() で外部パラメータを求めたあと、object_pts を cv2.projectPoints() で画像上の点に変換し、画像に描画したらどう表示されるか確認してみてはどうでしょうか?

  • objectPoints: 画像上に投影する3次元上の点一覧
  • rvec: 回転ベクトル
  • tvec: 並進ベクトル
  • cameraMatrix: カメラ行列
  • distCoeffs: 歪みパラメータ

こちら なども参考にして、 objectPoints を画像上に描画してみてください。


顔検出のプログラムの意図

  1. カメラキャリブレーションで内部パラメータは推定済みとする。
  2. 顔が写っている画像から顔の特徴点を抽出し、それから画像座標上の点 (image_pts) を作成する。
  3. 画像上の点が対応する世界座標上の点 (object_pts) を、顔の中心が原点となるように作成する。
  4. その対応関係を満たすアフィン変換行列を推定する。
  5. 4 で求めたのは世界座標から見たカメラのポーズである。世界座標の原点が顔の中心になるのだったから、カメラから見て顔がどの方向を向いているかはアフィン変換行列からわかる。

うまくいかない原因となりうる可能性

  • カメラキャリブレーションが精度よくできていない。
  • 顔検出がうまくいっていない。
  • object_pts と image_pts の対応関係はあっている?object_pts を matplotlib で3Dプロット、image_pts を画像上に描画して確認
  • SolvePnP() の外部パラメータ推定はうまくいっている?こちら を参考に、xyz 軸を描画してみる。object_pts を画像上に描画してみる。

object_pts、lines を描画してみました。

青の点は object_pts、黒の線は lines を描画したものです。
image_pts をまず検出画像に描画してみて、ちゃんとなっているか見てみるとよいと思います。

イメージ説明

python

1import numpy as np 2import matplotlib.pyplot as plt 3from mpl_toolkits.mplot3d import Axes3D 4from mpl_toolkits.mplot3d.art3d import Line3DCollection 5 6object_pts = np.float32( 7 [[0.0, 0.0, 0.0], 8 [0.0, -330.0, -65.0], 9 [-225.0, 170.0, -135.0], 10 [225.0, 170.0, -135.0], 11 [-150.0, -150.0, -125.0], 12 [150.0, -150.0, -125.0]]) / 4.5 13print(object_pts) 14# [[ 0. 0. 0. ] 15# [ 0. -73.333336 -14.444445] 16# [-50. 37.77778 -30. ] 17# [ 50. 37.77778 -30. ] 18# [-33.333332 -33.333332 -27.777779] 19# [ 33.333332 -33.333332 -27.777779]] 20 21lines = np.float32([[10.0, 10.0, 10.0], 22 [10.0, 10.0, -10.0], 23 [10.0, -10.0, -10.0], 24 [10.0, -10.0, 10.0], 25 [-10.0, 10.0, 10.0], 26 [-10.0, 10.0, -10.0], 27 [-10.0, -10.0, -10.0], 28 [-10.0, -10.0, 10.0]]) 29 30line_pairs = [[0, 1], [1, 2], [2, 3], [3, 0], 31 [4, 5], [5, 6], [6, 7], [7, 4], 32 [0, 4], [1, 5], [2, 6], [3, 7]] 33 34# 描画する。 35################################################ 36 37# グラフを作成する。 38fig = plt.figure(figsize=(6, 6)) 39axes = fig.add_subplot(111, projection='3d') 40 41# ラベル 42axes.set_xlabel("X-axis") 43axes.set_ylabel("Y-axis") 44axes.set_zlabel("Z-axis") 45 46# 範囲 47axes.set_xlim(-80, 80) 48axes.set_ylim(-80, 80) 49axes.set_zlim(-80, 80) 50 51# object_pts を描画する。 52axes.scatter(object_pts[:, 0], object_pts[:, 1], object_pts[:, 2], 53 marker='o', color='b', s=30) 54 55# lines を描画する。 56for pair in line_pairs: 57 p1, p2 = lines[pair] 58 axes.add_collection3d(Line3DCollection( 59 [[p1, p2]], colors='black', linewidths=2)) 60 61# xyz 軸を描画する。 62axes.add_collection3d(Line3DCollection( 63 [[(0, 0, 0), (50, 0, 0)], 64 [(0, 0, 0), (0, 50, 0)], 65 [(0, 0, 0), (0, 0, 50)]], 66 colors=['r', 'g', 'b'], 67 linewidths=2)) 68 69plt.grid() 70plt.show()

投稿2018/09/27 17:55

編集2018/09/28 03:08
tiitoi

総合スコア21956

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

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

masayuki.west

2018/09/28 02:27

2度の丁寧なご回答誠にありがとうございます。 cv2.solvePnP()算出後、cv2.projectPoints()を行いimagePointsを映像内に表示させたのですが xyzの方向が見当外れな方向を向いております。 この要因として ・3Dモデルの対応が合っていない ・カメラのキャリブレーションが間違っている になるのでしょか?
tiitoi

2018/09/28 03:09

回答を追記したので、どこが原因か調べてみてください。 カメラキャリブレーションもしくは顔検出結果に依存する image_pts が怪しいと思っています。
masayuki.west

2018/10/03 13:55

返答遅くなり申し訳ごさいません 丁寧なご回答誠にありがとうございます。 もう一度一から確認してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問