[open3d / reconstruction system (Tensor)] 3. Customized Integration

About_work·2024년 9월 14일
0

SLAM

목록 보기
6/12

1. 사용자 정의 통합(Customized Integration)

  • 추가 속성(예: 시맨틱 레이블)을 포함하는 새로운 RGB-D 볼륨 재구성 알고리즘을 합리적인 성능을 유지하면서 프로토타이핑할 수 있습니다.
  • 예제는 examples/python/t_reconstruction_system/integrate_custom.py에서 확인할 수 있습니다.

1.1. 활성화(Activation)

  • 프러스텀 블록 선택은 동일하게 유지되지만,
    • 이후에 이러한 블록을 수동으로 활성화하고 해시 맵에서 버퍼 인덱스를 얻음
  • 버퍼는 데이터를 저장하는 공간
    • 예를 들어, 컴퓨터 메모리 내에 복셀 블록의 데이터를 저장하는 영역을 "버퍼"라고 함
  • 버퍼 인덱스: 이 버퍼에서 특정 데이터의 위치를 나타냄
    • 즉, 해시 맵에서 어떤 블록이 저장되어 있는지 찾고자 할 때 그 위치를 나타내는 값이 버퍼 인덱스
# examples/python/t_reconstruction_system/integrate_custom.py
# 입력으로부터 활성 프러스텀 블록 좌표 가져오기
frustum_block_coords = vbg.compute_unique_block_coordinates(
    depth, intrinsic, extrinsic, config.depth_scale, config.depth_max)

# 해시 맵에서 활성화 (이미 삽입되었을 수 있음)
vbg.hashmap().activate(frustum_block_coords)

# 엔진에서 버퍼 인덱스 찾기
buf_indices, masks = vbg.hashmap().find(frustum_block_coords)
  • buf_indices:
    • 활성화된 각 블록이 메모리(버퍼) 내에서 어떤 위치에 있는지를 나타냄
    • 이를 통해 특정 블록의 데이터를 접근할 수 있게 됩니다.
  • masks:
    • 활성화된 블록이 유효한지 여부를 나타내는 마스크 배열
    • 이를 통해 유효하지 않은 블록을 거를 수 있습니다.

1.2. 복셀 인덱스(Voxel Indices)

  • 그런 다음 이러한 블록의 복셀 인덱스를 평탄화된 배열로 풀어내고, 해당하는 복셀 좌표를 함께 가져올 수 있습니다.
# examples/python/t_reconstruction_system/integrate_custom.py
voxel_coords, voxel_indices = vbg.voxel_coordinates_and_flattened_indices(
    buf_indices)
  • 이 함수는 활성화된 복셀 블록 내부의 각 복셀에 대한 정보를 가져옵니다. 여기서 buf_indices는 이전 단계에서 얻은 버퍼 인덱스들로, 메모리 내에서 각 복셀 블록의 위치를 나타냅니다.
  • voxel_coords:
    • 각 복셀의 3D 좌표
    • 복셀 블록 내의 복셀들은 각자 고유한 위치를 가지고 있으며, 이 위치를 (x, y, z) 좌표 형태로 나타냅니다.
  • voxel_indices:
    • 블록 내의 각 복셀의 위치를 "평탄화된 인덱스(flattened index)"로 표현
    • 예를 들어, (16 \times 16 \times 16) 블록 안에 4,096개의 복셀이 있다고 할 때, 각 복셀의 3D 좌표를 1차원 인덱스(0부터 4095까지)로 나타내는 것입니다.

  • 여기까지가 준비 단계입니다.
  • 이제 텐서 인터페이스에서 사용자 정의 기하학 변환을 수행할 수 있으며, 이는 numpypytorch에서 처리하는 방식과 유사합니다.

1.3. 기하학 변환(Geometry Transformation)

1.3.1. 요약

  1. 복셀을 카메라 좌표계로 변환: extrinsic를 사용해 복셀의 좌표카메라 좌표계로 변환
  2. 이미지 공간으로 투영: intrinsic를 사용해 3D 좌표를 이미지 평면의 2D 좌표로 변환합니다.
  3. 유효한 좌표만 선택: 투영된 좌표 중 유효한 범위에 있는 것만 필터링하여 사용합니다.
# examples/python/t_reconstruction_system/integrate_custom.py
extrinsic_dev = extrinsic.to(device, o3c.float32)
xyz = extrinsic_dev[:3, :3] @ voxel_coords.T() + extrinsic_dev[:3, 3:]

intrinsic_dev = intrinsic.to(device, o3c.float32)
uvd = intrinsic_dev @ xyz
d = uvd[2]
u = (uvd[0] / d).round().to(o3c.int64)
v = (uvd[1] / d).round().to(o3c.int64)
o3d.core.cuda.synchronize()
end = time.time()

start = time.time()
mask_proj = (d > 0) & (u >= 0) & (v >= 0) & (u < depth.columns) & (
    v < depth.rows)

v_proj = v[mask_proj]
u_proj = u[mask_proj]
d_proj = d[mask_proj]

  • 이 과정은 3D 공간의 복셀 데이터를 카메라의 뷰에 연결하는 중요한 단계

1.4. 사용자 정의 통합(Customized Integration)

  • 데이터 연관이 완료되면 통합을 수행할 수 있습니다.
  • 이 예제에서는 벡터화된 파이썬 코드를 사용하여 기존 TSDF 통합을 보여줍니다.
  • 관련된 u, v 인덱스에서 컬러/깊이 이미지로부터 RGB-D 속성을 읽습니다.
  • 마스크된 voxel_indices에서 복셀 버퍼 배열(vbg.attribute)로부터 복셀을 읽습니다.
  • 내부 수정을 수행합니다.
# examples/python/t_reconstruction_system/integrate_custom.py
depth_readings = depth.as_tensor()[v_proj, u_proj, 0].to(
    o3c.float32) / config.depth_scale
sdf = depth_readings - d_proj

mask_inlier = (depth_readings > 0) \
    & (depth_readings < config.depth_max) \
    & (sdf >= -trunc)

sdf[sdf >= trunc] = trunc
sdf = sdf / trunc
weight = vbg.attribute('weight').reshape((-1, 1))
tsdf = vbg.attribute('tsdf').reshape((-1, 1))

valid_voxel_indices = voxel_indices[mask_proj][mask_inlier]
w = weight[valid_voxel_indices]
wp = w + 1

tsdf[valid_voxel_indices] \
    = (tsdf[valid_voxel_indices] * w +
       sdf[mask_inlier].reshape(w.shape)) / (wp)
if config.integrate_color:
    color = o3d.t.io.read_image(color_file_names[i]).to(device)
    color_readings = color.as_tensor()[v_proj, u_proj].to(o3c.float32)

    color = vbg.attribute('color').reshape((-1, 3))
    color[valid_voxel_indices] \
        = (color[valid_voxel_indices] * w +
                 color_readings[mask_inlier]) / (wp)

weight[valid_voxel_indices] = wp
  • 이 예제를 따라 사용자 정의 속성에 맞게 코드를 조정할 수 있습니다.
  • Open3D는 PyTorch 텐서로의 변환을 메모리 복사 없이 지원하며, 이는 자동 미분 및 기타 연산자를 활용하는 데 사용할 수 있습니다.
  • 자세한 내용은 DLPack 메모리 맵을 사용하는 PyTorch I/O를 참조

  • 이 코드는 TSDF (Truncated Signed Distance Function) 통합 과정에서 사용자 정의 통합(Customized Integration)을 수행하는 방법을 보여줌

1.4.0. 생각할 점

  • trunc 길이를 짧게 잡아야 함. (noise 오차 범위 정도?)

1.4.1. 개선할 점: 장애물이 없는 ray의 경우 어떻게 처리할 것인가?

  • 현재는 아마 depth_readings가 0 이하의 값을 지니도록 설정되어, 업데이트가 되지 않을 것 같음
  • 제안: 장애물이 없는 ray의 경우 -> 해당 ray를 전부 1로 채워서 업데이트하자.
    • trunc는 고려해서 업데이트해도 괜찮을 것 같다.
    • 방법:
      • depth_readings를 config.depth_max + trunc 로 처리
      • 대신, ray의 모든 voxel을 반영하지 말고, config.depth_max = d_proj > trunc인 voxel들만 반영하자.

1.4.2. 개선할 점: weight에 max clipping을 해야할까?

  • 하면 좋을 것 같기도 하다.
profile
새로운 것이 들어오면 이미 있는 것과 충돌을 시도하라.

0개의 댓글