質問: cv2.solvePnP(object_pts, image_pts, cam_matrix, dist_coeffs) ``` ### 補足情報 カメラのキャリブレーションは下記のサイトを参考にしました。 カメラキャリブレーション(参考サイト)
回答: 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 をまず検出画像に描画してみて、ちゃんとなっているか見てみるとよいと思います。 !イメージ説明 ``` import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from mpl_toolkits.mplot3d.art3d import Line3DCollection object_pts = np.float32( [[0.0, 0.0, 0.0], [0.0, -330.0, -65.0], [-225.0, 170.0, -135.0], [225.0, 170.0, -135.0], [-150.0, -150.0, -125.0], [150.0, -150.0, -125.0]]) / 4.5 print(object_pts) # [[ 0. 0. 0. ] # [ 0. -73.333336 -14.444445] # [-50. 37.77778 -30. ] # [ 50. 37.77778 -30. ] # [-33.333332 -33.333332 -27.777779] # [ 33.333332 -33.333332 -27.777779]] lines = np.float32([[10.0, 10.0, 10.0], [10.0, 10.0, -10.0], [10.0, -10.0, -10.0], [10.0, -10.0, 10.0], [-10.0, 10.0, 10.0], [-10.0, 10.0, -10.0], [-10.0, -10.0, -10.0], [-10.0, -10.0, 10.0]]) line_pairs = [[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6, 7], [7, 4], [0, 4], [1, 5], [2, 6], [3, 7]] # 描画する。 ################################################ # グラフを作成する。 fig = plt.figure(figsize=(6, 6)) axes = fig.add_subplot(111, projection='3d') # ラベル axes.set_xlabel("X-axis") axes.set_ylabel("Y-axis") axes.set_zlabel("Z-axis") # 範囲 axes.set_xlim(-80, 80) axes.set_ylim(-80, 80) axes.set_zlim(-80, 80) # object_pts を描画する。 axes.scatter(object_pts[:, 0], object_pts[:, 1], object_pts[:, 2], marker='o', color='b', s=30) # lines を描画する。 for pair in line_pairs: p1, p2 = lines[pair] axes.add_collection3d(Line3DCollection( [[p1, p2]], colors='black', linewidths=2)) # xyz 軸を描画する。 axes.add_collection3d(Line3DCollection( [[(0, 0, 0), (50, 0, 0)], [(0, 0, 0), (0, 50, 0)], [(0, 0, 0), (0, 0, 50)]], colors=['r', 'g', 'b'], linewidths=2)) plt.grid() plt.show() ```