[Mesh] o3d poisson reconstruction
Poisson Surface Reconstruction์ ์๋ฆฌ
Poisson surface reconstruction์ ์ฃผ์ด์ง ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ๋ก๋ถํฐ ์ผ๊ฐํ ๋ฉ์ฌ๋ฅผ ์์ฑํ๋๋ฐ, ์ด ๋ฐฉ๋ฒ์ ์ ์ ์์น๋ฟ๋ง ์๋๋ผ ๊ฐ ์ ์ ๋ ธ๋ฉ ๋ฒกํฐ ์ ๋ณด๋ฅผ ์ฌ์ฉํฉ๋๋ค.
Poisson Surface Reconstruction์ points์ ๋์ํ๋ normals ์ ๋ณด ๋ํ ์กด์ฌํด์ผํ๋ค๋ ์ ์ open3d์ poisson surface reconstruction official document์๋ ๋ํ๋ ์์ต๋๋ค.
์ด๋ Poisson Surface Reconstruction์ด points์ normals๋ก surface๋ฅผ ์ฐพ๊ธฐ ๋๋ฌธ์ ๋๋ค.
์๋ฆฌ
- ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ:
- ์ ๋ค์ ์ขํ (points)
- ๊ฐ ์ ์์์ ์์ ์ ๋ณด (colors)
- ๊ฐ ์ ์์์ ๋ ธ๋ฉ ๋ฒกํฐ (normals)
- Octree ์์ฑ:
- ์ฃผ์ด์ง ๊น์ด(depth)์ ๋ฐ๋ผ ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ๋ฅผ ์ฅํธ๋ฆฌ ๊ตฌ์กฐ๋ก ๋ถํ ํฉ๋๋ค. ๊น์ด๊ฐ ๊น์์๋ก ๋ ์ธ๋ฐํ ๊ตฌ์กฐ๊ฐ ์์ฑ๋ฉ๋๋ค.
- Poisson ๋ฐฉ์ ์ ํ์ด:
- ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ์ ๋ ธ๋ฉ ๋ฒกํฐ๋ฅผ ์ด์ฉํด Poisson ๋ฐฉ์ ์์ ํ๋๋ค. ์ด๋ฅผ ํตํด ์ ๋ค์ด ๋ํ๋ด๋ ํ๋ฉด์ ์ฐ์์ ์ธ ๊ตฌ์กฐ๋ฅผ ์ถ์ ํฉ๋๋ค.
- ์ผ๊ฐํ ๋ฉ์ฌ ์์ฑ:
- Poisson ๋ฐฉ์ ์์ ํด๋ฅผ ๋ฐํ์ผ๋ก ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ๋ฅผ ์ผ๊ฐํ ๋ฉ์ฌ๋ก ๋ณํํฉ๋๋ค. ์ด๋ ์ ๋ค์ด ๋งค๋๋ฌ์ด ํ๋ฉด์ ๋ํ๋ด๋๋ก ํฉ๋๋ค.
Input Requirements
- ํฌ์ธํธ ๋ฐ์ดํฐ (3D ์ขํ)
- ๋ ธ๋ฉ ๋ฐ์ดํฐ (๊ฐ ์ ์์์ ํ๋ฉด ๋ ธ๋ฉ ๋ฒกํฐ)
- ์ถ๊ฐ์ ์ผ๋ก ์ปฌ๋ฌ ๋ฐ์ดํฐ๋ ์๊ฐํ๋ฅผ ์ํด ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ๊ฐ ์ถฉ๋ถํ ๋ฐ์ง๋๊ณ , ๋ ธ๋ฉ ๋ฒกํฐ๊ฐ ์ ํํ๊ฒ ๊ณ์ฐ๋ ๊ฒฝ์ฐ, Poisson surface reconstruction์ ํตํด ๋งค๋๋ฝ๊ณ ์ ํํ ํ๋ฉด์ ์์ฑํ ์ ์์ต๋๋ค.
Poisson surface reconstruction์ ์ฑ๊ณต ์ฌ๋ถ๋ ์ ๋ ฅ๋ ํฌ์ธํธ ํด๋ผ์ฐ๋์ ํ์ง์ ํฌ๊ฒ ์์กดํฉ๋๋ค. ํนํ, ๋ ธ๋ฉ ๋ฒกํฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ๋์ง ์์ผ๋ฉด ํ๋ฉด์ ์ ํ๋๊ฐ ๋จ์ด์ง ์ ์์ต๋๋ค.
์์ฝ
Poisson surface reconstruction์ ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ์ ํด๋น ๋ฐ์ดํฐ์ ๋ ธ๋ฉ ๋ฒกํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ผ๊ฐํ ๋ฉ์ฌ๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์ด ๊ณผ์ ์์ ์ฅํธ๋ฆฌ ๊น์ด(depth) ์ค์ ์ ์์ฑ๋ ๋ฉ์ฌ์ ์ธ๋ฐํจ์ ์กฐ์ ํฉ๋๋ค.
poisson reconstruction์ o3d๋ก ๊ตฌํ์, points์ normals์ ๋ชจ๋ ๊ฐ์ง pcd๋ฅผ poisson reconstruction์ ์ํํ๋ ํจ์์ ๋ฃ์ด์ค๋๋ค.
pcd
์ ๋ํด์ points, colors, normals ์ ๋ณด๋ฅผ ๋ฃ์ด์ฃผ๊ณ , outlier๋ฅผ ์ ๊ฑฐํด์ฃผ๊ณ ,o3d.geometry.TriangleMesh.create_from_point_cloud_poisson
๋กpcd
๋ฅผ ์ฃผ๋ฉด mesh์ densities๋ฅผ ๊ตฌํ ์ ์์ต๋๋ค.- ์๋ ์ฝ๋์์ fg_pcd์ fg_points, fg_colors, fg_normals์ Vector๋ก ๋ฃ์ด์ฃผ๊ณ , fg_pcd์์ outlier๋ฅผ ์ ๊ฑฐํ ๊ฒ์ poisson ํจ์์ ๋ฃ๊ณ , poisson_depth(=octree depth)๋ฅผ ์ค์ ํ์ฌ, fg_mesh์ fg_densities๋ฅผ ์ป์ต๋๋ค.
o3d_fg_mesh, o3d_fg_densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(fg_pcd, depth=poisson_depth)
- fg_pcd์์ ๋ง์ง๋ง์ผ๋ก low density value๋ฅผ ๊ฐ๋ vertices๋ ์ ๊ฑฐํด์ค๋๋ค.
- ์ ์์ ์ด๋ค vertex๊ฐ low density value๋ฅผ ๊ฐ์ง๋ค๋ ๊ฒ์ input point cloud์์ ๊ทธ vertex๋ฅผ ์ฐธ์กฐํ๋ points์๊ฐ ์ ๋ค๋ ์๋ฏธ์ ๋๋ค.
- ์ด ๋ง์ mesh์ ๊ฒฝ๊ณ์ชฝ์ผ๋ก ๊ฐ์๋ก ์ด๋ค vertex์ ๋ํ density๋ ๋ฎ์์ง์ ์๋ฏธํฉ๋๋ค.
-
์ด๋ฅผ ์ ํํํ ๊ทธ๋ฆผ์ด ์์ต๋๋ค.
vertices_to_remove = o3d_fg_densities < np.quantile(o3d_fg_densities, vertices_density_quantile) o3d_fg_mesh.remove_vertices_by_mask(vertices_to_remove)
- bg_pcd์ ๋ํด์๋ ๋์ผํ๊ฒ ์งํํฉ๋๋ค.
# sugar_extractors/coarse_mesh.py
def extract_mesh_from_coarse_sugar(args):
...
# ---Compute foreground mesh---
CONSOLE.print("\n-----Foreground mesh-----")
if fg_points.shape[0] > 0:
CONSOLE.print("Computing points, colors and normals...")
fg_pcd = o3d.geometry.PointCloud()
fg_pcd.points = o3d.utility.Vector3dVector(fg_points.double().cpu().numpy())
fg_pcd.colors = o3d.utility.Vector3dVector(fg_colors.double().cpu().numpy())
fg_pcd.normals = o3d.utility.Vector3dVector(fg_normals.double().cpu().numpy())
# outliers removal
cl, ind = fg_pcd.remove_statistical_outlier(nb_neighbors=20, std_ratio=20.)
CONSOLE.print("Cleaning Point Cloud...")
fg_pcd = fg_pcd.select_by_index(ind)
CONSOLE.print("Finished computing points, colors and normals.")
CONSOLE.print("Now computing mesh...")
o3d_fg_mesh, o3d_fg_densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
fg_pcd, depth=poisson_depth) #, width=0, scale=1.1, linear_fit=False) # depth=10 should be the default value? 11 is good to (but it starts to make a big number of triangles)
if vertices_density_quantile > 0.:
CONSOLE.print("Removing vertices with low densities...")
vertices_to_remove = o3d_fg_densities < np.quantile(o3d_fg_densities, vertices_density_quantile)
o3d_fg_mesh.remove_vertices_by_mask(vertices_to_remove)
else:
CONSOLE.print("\n[WARNING] Foreground is empty.")
o3d_fg_mesh = None
# ---Compute background mesh---
CONSOLE.print("\n-----Background mesh-----")
if bg_points.shape[0] > 0:
CONSOLE.print("Computing points, colors and normals...")
bg_pcd = o3d.geometry.PointCloud()
bg_pcd.points = o3d.utility.Vector3dVector(bg_points.double().cpu().numpy())
bg_pcd.colors = o3d.utility.Vector3dVector(bg_colors.double().cpu().numpy())
bg_pcd.normals = o3d.utility.Vector3dVector(bg_normals.double().cpu().numpy())
# outliers removal
cl, ind = bg_pcd.remove_statistical_outlier(nb_neighbors=20, std_ratio=20.)
CONSOLE.print("Cleaning Point Cloud...")
bg_pcd = bg_pcd.select_by_index(ind)
CONSOLE.print("Finished computing points, colors and normals.")
CONSOLE.print("Now computing mesh...")
o3d_bg_mesh, o3d_bg_densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
bg_pcd, depth=poisson_depth) #, width=0, scale=1.1, linear_fit=False) # depth=10 should be the default value? 11 is good to (but it starts to make a big number of triangles)
if vertices_density_quantile > 0.:
CONSOLE.print("Removing vertices with low densities...")
vertices_to_remove = o3d_bg_densities < np.quantile(o3d_bg_densities, vertices_density_quantile)
o3d_bg_mesh.remove_vertices_by_mask(vertices_to_remove)
else:
CONSOLE.print("\n[WARNING] Background is empty.")
o3d_bg_mesh = None
CONSOLE.print("Finished computing meshes.")
CONSOLE.print("Foreground mesh:", o3d_fg_mesh)
CONSOLE.print("Background mesh:", o3d_bg_mesh)
pcd์์ outlier removal์ ๋ค์๊ณผ ๊ฐ์ด ์งํํฉ๋๋ค.
Point cloud outlier removal
remove_statistical_outlier
ํจ์
remove_statistical_outlier
ํจ์๋ ํฌ์ธํธ ํด๋ผ์ฐ๋(point cloud) ๋ฐ์ดํฐ์์ ํต๊ณ์ ์ผ๋ก ์ด๋ก์ ์ธ(outlier) ์ ๋ค์ ์ ๊ฑฐํฉ๋๋ค.
์ด ํจ์๋ ๋ ๊ฐ์ ์ ๋ ฅ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ต๋๋ค:
nb_neighbors
: ์ฃผ์ด์ง ์ ์ ๋ํด ํ๊ท ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํด ๊ณ ๋ คํ ์ด์์ ์๋ฅผ ์ง์ ํฉ๋๋ค.std_ratio
: ํฌ์ธํธ ํด๋ผ์ฐ๋ ์ ๋ฐ์ ํ๊ท ๊ฑฐ๋ฆฌ์ ํ์คํธ์ฐจ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์๊ณ๊ฐ ์์ค์ ์ค์ ํ ์ ์๊ฒ ํฉ๋๋ค. ์ด ๊ฐ์ด ๋ฎ์์๋ก ํํฐ๊ฐ ๋ ๊ณต๊ฒฉ์ ์ผ๋ก ์๋ํฉ๋๋ค.
์ด ํจ์๋ ๋ ๊ฐ์ง ๋ฐํ ๊ฐ์ ๊ฐ์ง๋๋ค:
cl
: Clustered point cloud data- ํต๊ณ์ ์ผ๋ก ์ด๋ก์ ์ด์ง ์์ ์ ๋ค๋ก ๊ตฌ์ฑ๋ ์๋ก์ด ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ
- ์๋ ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ์์ ์ด๋ก์น๊ฐ ์ ๊ฑฐ๋ ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ
ind
: Index list of inliers- ์๋ ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ์์ ์ด๋ก์ ์ด์ง ์์ ์ ๋ค์ ์ธ๋ฑ์ค๋ฅผ ๋ํ๋ด๋ ๋ฆฌ์คํธ
- ์ด ์ธ๋ฑ์ค๋ฅผ ์ฌ์ฉํ์ฌ ์๋ ํฌ์ธํธ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ์์ ์ ์์ ์ธ ์ ๋ค์ ์ ํํ ์ ์์
select_by_index
ํจ์
select_by_index
, which takes a binary mask to output only the selected points.
Leave a comment