2022년 3월 2일 수요일

3차원 데이터 처리를 위한 오픈소스 Open3D 라이브러리 소개

Open3D는 3차원 데이터를 다루는 소프트웨어 개발을 지원하는 오픈소스 라이브러리이다. C++, Python을 지원하며, 데이터 구조 및 알고리즘을 제공한다. 빠른 성능을 위해 최적화, 병렬화되었다. Open3D는 로보틱스, 무인자율차, 3차원 비전 기술 개발 등에 사용된다.  


핵심 기능은 다음과 같다.
  • conda, pip를 통한 간단한 설치
  • 3차원 자료 구조 및 알고리즘 제공
  • 장면 렌더링 및 3차원 시각화
  • 표면 정렬
  • 좌표 변환 행렬 지원
  • 메쉬 간 교차, 라플라시안 연산 등 제공
  • 공간 인덱싱 제공
  • 레이캐스팅, 거리 질의 등 연산 제공
  • 다양한 파일 포맷 지원
  • 파이썬 개발 지원. NumPy와 연동
  • CUDA 지원
  • 리눅스, 윈도우 등 다중 플랫폼 지원
  • Google CoLab 지원


사용 시작 
설치는 virtualenv 환경을 만든 후 open3d를 설치한다.
virtualenv venv
pip install open3d

제대로 설치되었으면, Getting started 문서를 참고해 다음 코드를 실행한다. 성공하면 제대로 설치된 것이다.

# Verify installation
python -c "import open3d as o3d; print(o3d.__version__)"

# Python API
python -c "import open3d as o3d; \
           mesh = o3d.geometry.TriangleMesh.create_sphere(); \
           mesh.compute_vertex_normals(); \
           o3d.visualization.draw(mesh, raw_mode=True)"

# Open3D CLI
open3d example visualization/draw

소스 코드 분석
우선 소스 코드를 분석을 위해, 소스 파일을 다운로드 받는다. 
git clone https://github.com/isl-org/Open3D

Open3D 파일구조는 다음과 같다. 

우분투에서 설치할 경우, util 폴더 아래 셀 명령을 실행해 디펜던시를 설치한다.
util/install_deps_ubuntu.sh

다운로드된 소스 파일 중에는 3차원 점군 가시화를 위한 예제들이 있는 데, 파이썬으로 실행해 볼 수 있다.

다음 코드는 open3d의 일반적인 동작 방식을 보여준다. 
import open3d as o3d
ply_point_cloud = o3d.data.PLYPointCloud()             # 포인트 클라우드 객체 생성
pcd = o3d.io.read_point_cloud(ply_point_cloud.path)  # PLY 파일 로딩
print(pcd)
print(np.asarray(pcd.points))
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 = pcd.voxel_down_sample(voxel_size=0.05)
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])

DBScan 알고리즘을 이용해 평면을 세그먼테이션해 줄 수도 있다(물론 알고리즘 특성상 완벽하지는 않음).
ply_point_cloud = o3d.data.PLYPointCloud()
pcd = o3d.io.read_point_cloud(ply_point_cloud.path)

with o3d.utility.VerbosityContextManager(
        o3d.utility.VerbosityLevel.Debug) as cm:
    labels = np.array(
        pcd.cluster_dbscan(eps=0.02, min_points=10, print_progress=True))

max_label = labels.max()
print(f"point cloud has {max_label + 1} clusters")
colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1))
colors[labels < 0] = 0
pcd.colors = o3d.utility.Vector3dVector(colors[:, :3])
o3d.visualization.draw_geometries([pcd],
                                  zoom=0.455,
                                  front=[-0.4999, -0.1659, -0.8499],
                                  lookat=[2.1813, 2.0619, 2.0999],
                                  up=[0.1204, -0.9852, 0.1215])


이외, 다양한 기능은 아래 튜토리얼을 참고한다. 
라벨링 점군 데이터 가시화 프로그램 개발
이 장에서는 다음과 같이 각 점군에 대한 라벨링 데이터가 포함된 파일을 읽어 가시화해주는 프로그램을 간단히 개발해 보겠다. 

다음은 코드 구현 내용이다. 
import copy
import numpy as np
import open3d as o3d
import argparse, readline

cmap = np.array([[1.00, 1.00, 1.00], [0.00, 0.00, 0.00], \
                    [1.00, 0.00, 0.00], [1.00, 0.00, 0.40], \
                    [1.00, 0.00, 0.80], [1.00, 0.20, 1.00], \
                    [1.00, 0.60, 1.00], [0.60, 0.80, 1.00], \
                    [0.20, 0.80, 1.00], [0.20, 0.80, 0.60], \
                    [0.20, 0.80, 0.00], [0.20, 0.40, 0.00], \
                    [0.20, 0.45, 0.40], [0.20, 0.40, 0.80], \
                    [0.60, 0.40, 0.80], [0.60, 0.80, 0.80], \
                    [0.60, 0.80, 0.40], [1.00, 0.60, 0.80]],'f')    # 컬러맵 정의

if __name__ == "__main__":
    parser = argparse.ArgumentParser()   # 명령행 인자 파싱
    parser.add_argument('--input_pcd', type=str, required=True)    # pcd format is txt. xyzrgb
    parser.add_argument('--input_label', type=str, required=True)
    args = parser.parse_args() 
    
    label = np.loadtxt(args.input_label)    # 라벨링 파일 로딩
    label = label.astype(np.int32)           

    pcd_origin = np.loadtxt(args.input_pcd, delimiter=' ')    # 텍스트 점군 파일 로딩. xyzrgb 포맷
    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(pcd_origin[:,0:3])  # XYZ points
    pcd.colors = o3d.utility.Vector3dVector(cmap[label])       # 라벨을 컬러로 변환해 각 점군마다 설정

    o3d.visualization.draw_geometries([pcd])  # 가시화
    print('end')

결과는 다음과 같다.


마무리
지금까지 Open3D 라이브러리 개념, 기능 및 사용법을 설명하고, 간단한 프로그램을 개발해 보았다. 대중적인 알고리즘이 포함되어 있어, 컴퓨터 그래픽스 관련 기술 개발 시 유용하다. 


댓글 없음:

댓글 쓰기