演習問題解答「三次元点群処理 Pythonによる基礎アルゴリズムの実装」

三次元点群処理 Pythonによる基礎アルゴリズムの実装を読みながら、演習問題の解答を記録していきます. 解答はあくまで僕が考えた物なので、合っているかは保証できませんが、参考にはなると思います.(間違い等あればご指摘ください)

第一章 はじめに

問題 1.1

2次元画像ではできないが、3次元データであれば可能になることを3つ述べる.

  • 建設現場の3次元測量
  • 空気抵抗の計算
  • 3Dゲームへの組み込み

問題 1.2

下の右図のような直線で分離不能な2次元データも、3次元空間に拡張すると分離可能な平面が出現する.そのような変数 zz と分離平面の例を挙げる.

sampleData

目的変数が 00 の点を z=1z= -1 、目的変数が 11 の点を z=1z=1 に設定したときの、 z=0z=0 の平面が分離平面となる.

問題 1.3

次元の呪いとは何か?
次元が増えるほど、必要なデータ量が指数関数的に増加してしまうこと.

問題 1.4

身近な製品に搭載されている3次元センサー

スマートフォン

  • LiDARセンサー
  • フォトグラメトリ

ロボット掃除機

  • ToFセンサー
  • VSLAM

自動車

  • LiDARセンサー

問題 1.5

基本的にはベースラインが大きくなるほど精度が向上するが、極端に大きくなると逆に精度が低下しそう.


第二章 点群処理の基礎

問題 2.1

インターネットから3次元データを入手し、Microsoft 3D Builderで描画する.

show-3d-data

お借りした3次元データ

問題 2.2

zxzzxz 系のオイラー角 α,β,γ\alpha, \beta, \gamma を用いて回転行列 RR を求める.

solution_2-2

問題 2.3

回転行列を四元数で表現する.

solution_2-3

問題 2.4

並進と回転の処理の順番を変えると結果は変わるか?

ソースコード
import numpy as np
import open3d as o3d
import copy


mesh = o3d.geometry.TriangleMesh.create_coordinate_frame()

# 並進
t = [.5, .7, 1]
mesh_t = copy.deepcopy(mesh).translate(t)

# 回転
R = o3d.geometry.get_rotation_matrix_from_yxz([np.pi/3, 0,0])
print ("R: ", np.round(R, 7))

R = o3d.geometry.get_rotation_matrix_from_axis_angle([0, np.pi/3, 0])
print ("R: ", np.round(R, 7))

R = o3d.geometry.get_rotation_matrix_from_quaternion([np.cos(np.pi/6), 0, np.sin(np.pi/6), 0])
print ("R: ", np.round(R, 7))

mesh_r = copy.deepcopy(mesh_t)
mesh_r.rotate(R, center=[0,0,0])

print("Type q to continue.")
o3d.visualization.draw_geometries([mesh, mesh_t]) # 並進 -> 回転

# 回転と並進
T = np.eye(4)
T[:3, :3] = R
T[:3, 3] = t 
mesh_r = copy.deepcopy(mesh).transform(T)
print("Type q to continue.")
o3d.visualization.draw_geometries([mesh, mesh_r]) # 回転 -> 並進
solution_2-4

並進に関して

この例だと絶対座標で並進しているため、最終的な物体の位置は変化しない.

回転に関して

回転時の基準となる原点との相対位置が並進により変化しているため、回転の結果も変化する.

問題 2.5

ボクセル化を実装する.

ソースコード
import sys
import open3d as o3d
import open3d.core as o3c
import numpy as np


def voxel_down_sample(last_pcd, voxel_size):
    min_bound = last_pcd.get_min_bound() + 0.051 # 補正用の係数(実験値)

    new_points = []

    for point in last_pcd.points:
        new_point = min_bound + ((point-min_bound) // voxel_size) * voxel_size + voxel_size / 2

        new_points.append(new_point)

    new_points = o3d.utility.Vector3dVector(np.unique(np.asarray(new_points), axis=0).astype(np.float64))

    last_pcd.points = new_points
    
    return last_pcd

filename = sys.argv[1]
s = float(sys.argv[2])
print("Loading a point cloud from", filename)
pcd = o3d.io.read_point_cloud(filename)
print(pcd)

o3d.visualization.draw_geometries([pcd], zoom=0.3412,
                                  front=[0.4257, -0.2125, -0.8795],
                                  lookat=[2.6172, 2.0475, 1.532],
                                  up=[-0.0694, -0.9768, 0.2024])

downpcd = voxel_down_sample(pcd, voxel_size=s)
print(downpcd)

o3d.visualization.draw_geometries([downpcd], zoom=0.3412,
                                  front=[0.4257, -0.2125, -0.8795],
                                  lookat=[2.6172, 2.0475, 1.532],
                                  up=[-0.0694, -0.9768, 0.2024])

solution_2-5

処理後の点群数が例題と一致していることを確認済み.今回は色の情報は無視しているので、将来的に実装するかも.

問題 2.6、 2.7

未来の自分へ

頑張ってください.

第三章 特徴点・特徴量の抽出

問題 3.1

Bunny.ply以外の3次元データに対して特徴点を抽出、表示する.

solution_3-1

問題 3.2

抽出する特徴点の数を増やすにはどうすれば良いか?

Harris3D

  • radiusを変えても特徴点数は変わらない.
  • max_nnを小さくすると特徴点数は増える.
  • thresholdを小さくすると特徴点数は増える.

ISS

  • gamma21gamma32を大きくすると特徴点数は増える.

問題 3.3

分からん

問題 3.4

それぞれの位数はいくつか?

正四面体群 ⋯ 12

正六面体群 ⋯ 24

問題 3.5以降

分からん


点群レジストレーション(位置合わせ)