1. 사용자 정의 통합(Customized Integration)
- 추가 속성(예: 시맨틱 레이블)을 포함하는 새로운 RGB-D 볼륨 재구성 알고리즘을 합리적인 성능을 유지하면서 프로토타이핑할 수 있습니다.
- 예제는
examples/python/t_reconstruction_system/integrate_custom.py
에서 확인할 수 있습니다.
1.1. 활성화(Activation)
- 프러스텀 블록 선택은 동일하게 유지되지만,
- 이후에 이러한 블록을 수동으로 활성화하고 해시 맵에서 버퍼 인덱스를 얻음
- 버퍼는
데이터를 저장하는 공간
- 예를 들어, 컴퓨터 메모리 내에 복셀 블록의 데이터를 저장하는 영역을 "버퍼"라고 함
- 버퍼 인덱스: 이 버퍼에서 특정 데이터의 위치를 나타냄
- 즉, 해시 맵에서 어떤 블록이 저장되어 있는지 찾고자 할 때 그 위치를 나타내는 값이 버퍼 인덱스
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)
- 그런 다음 이러한 블록의 복셀 인덱스를 평탄화된 배열로 풀어내고, 해당하는 복셀 좌표를 함께 가져올 수 있습니다.
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까지)로 나타내는 것입니다.
- 여기까지가 준비 단계입니다.
- 이제 텐서 인터페이스에서 사용자 정의 기하학 변환을 수행할 수 있으며, 이는
numpy
나 pytorch
에서 처리하는 방식과 유사합니다.
1.3.1. 요약
- 복셀을 카메라 좌표계로 변환: extrinsic를 사용해
복셀의 좌표
를 카메라 좌표계
로 변환
- 이미지 공간으로 투영: intrinsic를 사용해 3D 좌표를 이미지 평면의 2D 좌표로 변환합니다.
- 유효한 좌표만 선택: 투영된 좌표 중 유효한 범위에 있는 것만 필터링하여 사용합니다.
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
)로부터 복셀을 읽습니다.
- 내부 수정을 수행합니다.

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을 해야할까?