2Dステレオ画像からの3D点再構成の基本を理解しようとしています。これまでに理解したことは、以下のように要約できます。
3Dポイント(深度マップ)の再構成では、2つの異なるビューからの同じオブジェクトの2つの画像が必要です。このような画像ペアが必要な場合、カメラマトリックスも必要です(P1、P2など)
SIFTやSURFなどの方法を使用して、2つの画像で対応する点を見つけます。
対応するキーポイントを取得した後、最小8つのキーポイント(8ポイントアルゴリズムで使用)を使用して必須行列(Kなど)を見つけます。
カメラ1にいる場合、カメラ2のパラメーターを計算します。エッセンシャルマトリックスを使用して、4つの可能なカメラパラメーターを返します
最終的に、三角測量法を使用して3Dポイントを推定するために、対応するポイントと両方のカメラパラメーターを使用します。
理論セクションを通過した後、最初の実験として、利用可能なコードを実行しようとしました here 、これは期待どおりに機能しました。 example.py
コード次のように、この例をすべての連続する画像ペアで実行し、3次元の点群をマージして、オブジェクト(dino
)を3次元で再構築しました。
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import cv2
from camera import Camera
import structure
import processor
import features
def dino():
# Dino
img1 = cv2.imread('imgs/dinos/viff.003.ppm')
img2 = cv2.imread('imgs/dinos/viff.001.ppm')
pts1, pts2 = features.find_correspondence_points(img1, img2)
points1 = processor.cart2hom(pts1)
points2 = processor.cart2hom(pts2)
fig, ax = plt.subplots(1, 2)
ax[0].autoscale_view('tight')
ax[0].imshow(cv2.cvtColor(img1, cv2.COLOR_BGR2RGB))
ax[0].plot(points1[0], points1[1], 'r.')
ax[1].autoscale_view('tight')
ax[1].imshow(cv2.cvtColor(img2, cv2.COLOR_BGR2RGB))
ax[1].plot(points2[0], points2[1], 'r.')
fig.show()
height, width, ch = img1.shape
intrinsic = np.array([ # for dino
[2360, 0, width / 2],
[0, 2360, height / 2],
[0, 0, 1]])
return points1, points2, intrinsic
points3d = np.empty((0,0))
files = glob.glob("imgs/dinos/*.ppm")
len = len(files)
for item in range(len-1):
print(files[item], files[(item+1)%len])
#dino() function takes 2 images as input
#and outputs the keypoint point matches(corresponding points in two different views) along the camera intrinsic parameters.
points1, points2, intrinsic = dino(files[item], files[(item+1)%len])
#print(('Length', len(points1))
# Calculate essential matrix with 2d points.
# Result will be up to a scale
# First, normalize points
points1n = np.dot(np.linalg.inv(intrinsic), points1)
points2n = np.dot(np.linalg.inv(intrinsic), points2)
E = structure.compute_essential_normalized(points1n, points2n)
print('Computed essential matrix:', (-E / E[0][1]))
# Given we are at camera 1, calculate the parameters for camera 2
# Using the essential matrix returns 4 possible camera paramters
P1 = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]])
P2s = structure.compute_P_from_essential(E)
ind = -1
for i, P2 in enumerate(P2s):
# Find the correct camera parameters
d1 = structure.reconstruct_one_point(
points1n[:, 0], points2n[:, 0], P1, P2)
# Convert P2 from camera view to world view
P2_homogenous = np.linalg.inv(np.vstack([P2, [0, 0, 0, 1]]))
d2 = np.dot(P2_homogenous[:3, :4], d1)
if d1[2] > 0 and d2[2] > 0:
ind = i
P2 = np.linalg.inv(np.vstack([P2s[ind], [0, 0, 0, 1]]))[:3, :4]
#tripoints3d = structure.reconstruct_points(points1n, points2n, P1, P2)
tripoints3d = structure.linear_triangulation(points1n, points2n, P1, P2)
if not points3d.size:
points3d = tripoints3d
else:
points3d = np.concatenate((points3d, tripoints3d), 1)
fig = plt.figure()
fig.suptitle('3D reconstructed', fontsize=16)
ax = fig.gca(projection='3d')
ax.plot(points3d[0], points3d[1], points3d[2], 'b.')
ax.set_xlabel('x axis')
ax.set_ylabel('y axis')
ax.set_zlabel('z axis')
ax.view_init(elev=135, azim=90)
plt.show()
しかし、私は非常に予想外の結果を得ています。上記の方法が正しいかどうか、または複数の3D点群をマージして単一の3D構造を構築する方法を教えてください。
もう1つの考えられる理解の道は、モーションまたはSLAMからの構造のオープンソース実装を調べることです。これらのシステムは非常に複雑になる可能性があることに注意してください。ただし、OpenSfMはPythonで記述されており、ナビゲートと理解が容易だと思います。自分の作業のリファレンスとしてよく使用します。
開始するためにもう少し情報を提供するため(このパスを選択した場合)。動きからの構造は、2D画像のコレクションを取り、それらから3Dモデル(点群)を作成するアルゴリズムであり、その点群に対する各カメラの位置も解決します(つまり、返されたすべてのカメラポーズは世界にあります)フレームなどの点群です)。
ハイレベルでのOpenSfMのステップ:
使用できる以前の情報(焦点距離など)について画像exifを読み取ります
特徴点を抽出する(例:SIFT)
特徴点を一致させる
これらの特徴点の一致をトラックに変換します(たとえば、画像1、2、および3で特徴点を見た場合は、それをmatch(1,2)、match(2,3)などの代わりにトラックに接続できます)。 ..)
増分再構成(グローバルなアプローチもあることに注意してください)。このプロセスでは、トラックを使用して画像を増分的に再構成に追加し、新しいポイントを三角形分割し、バンドル調整と呼ばれるプロセスを使用してポーズ/ポイントの位置を調整します。
うまくいけば、それが役立ちます。