전처리 단계: 3D 구조 및 카메라 정보 추출
3D 가우시안 스플래팅 파이프라인의 초기 단계에서는 입력된 이미지 시퀀스로부터 카메라의 내·외부 파라미터와 장면의 희소한 3D 구조를 복원하는 작업이 수행된다. 이 과정은 COLMAP 기반의 SfM(Simultaneous Localization and Mapping) 기술을 활용하며, 주로 convert.py 스크립트에 의해 자동화된다.
1. 특징점 기반 3D 재구성
입력 영상들로부터 3D 구조를 추출하기 위해 다음과 같은 세 단계의 처리가 진행된다:
import os
import logging
# 특징점 추출 (SIFT)
feature_extraction_cmd = (
f"{colmap_path} feature_extractor "
f"--database_path {source_path}/distorted/database.db "
f"--image_path {source_path}/input "
f"--ImageReader.single_camera 1 "
f"--ImageReader.camera_model OPENCV "
f"--SiftExtraction.use_gpu {use_gpu}"
)
if os.system(feature_extraction_cmd) != 0:
logging.error("특징점 추출 실패")
exit(1)
# 특징점 매칭
matching_cmd = (
f"{colmap_path} exhaustive_matcher "
f"--database_path {source_path}/distorted/database.db "
f"--SiftMatching.use_gpu {use_gpu}"
)
if os.system(matching_cmd) != 0:
logging.error("특징점 매칭 실패")
exit(1)
# 번들 조정 (Sparse Reconstruction)
mapper_cmd = (
f"{colmap_path} mapper "
f"--database_path {source_path}/distorted/database.db "
f"--image_path {source_path}/input "
f"--output_path {source_path}/distorted/sparse "
f"--Mapper.ba_global_function_tolerance=0.000001"
)
if os.system(mapper_cmd) != 0:
logging.error("3D 재구성 실패")
exit(1)
- Feature Extractor: 각 프레임에서 SIFT 기반의 특징점을 감지한다.
- Exhaustive Matcher: 다중 뷰 간 공통 특징점을 매칭하여 2D-2D 대응 관계를 구성한다.
- Mapper: 번들 조정(Bundle Adjustment)을 통해 카메라 외부 파라미터(자세)와 3D 점군을 동시에 최적화한다.
2. 영상 비왜곡 처리
원본 영상은 렌즈 왜곡을 포함할 수 있으므로, 이를 보정하기 위해 image_undistorter 도구를 사용한다.
undistort_cmd = (
f"{colmap_path} image_undistorter "
f"--image_path {source_path}/input "
f"--input_path {source_path}/distorted/sparse/0 "
f"--output_path {source_path} "
f"--output_type COLMAP"
)
os.system(undistort_cmd)
이 과정에서 다음 작업이 수행된다:
- 카메라 모델(OPENCV 등)의 왜곡 계수를 기반으로 영상의 기하학적 왜곡을 제거한다.
- 새로운 왜곡 없는 핀홀 카메라 모델(PINHOLE)로 재투영하여 정합된 영상을 생성한다.
- 결과는
sparse/디렉터리 아래cameras.bin,images.bin,points3D.bin형태로 저장된다.
3. 멀티스케일 이미지 생성
훈련 효율성을 높이기 위해 다중 해상도 이미지를 준비한다.
from PIL import Image
import shutil
def resize_image(src, dst, scale):
img = Image.open(src)
w, h = img.size
img.resize((int(w * scale), int(h * scale)), Image.LANCZOS).save(dst)
# 예: 50% 크기 이미지 생성
resize_image("images/00001.png", "images_2/00001.png", 0.5)
해상도별로 images_2(1/2), images_4(1/4), images_8(1/8) 디렉터리에 저장되어 렌더링 속도 조절에 활용된다.
출력 데이터 구조
SfM 단계 후 생성되는 주요 바이너리 파일들은 다음과 같다:
cameras.bin: 카메라 내부 파라미터 (초점 거리, 주점, 왜곡 계수)images.bin: 각 프레임의 외부 파라미터 (회전, 평행 이동)points3D.bin: 3D 공간 상의 특징점 좌표 및 색상 정보
텍스트 형식으로 변환
바이너리 데이터는 직접 확인이 어려우므로, 다음과 같이 텍스트 형식으로 변환 가능하다:
colmap model_converter \
--input_path ./sparse/0 \
--output_path ./export \
--output_type TXT
cameras.txt
비왜곡 처리 전후의 카메라 모델 비교:
# 왜곡 보정 전 (OPENCV 모델) 1 OPENCV 1366 768 fx fy cx cy k1 k2 p1 p2 # 왜곡 보정 후 (PINHOLE 모델) 1 PINHOLE 1342 753 fx fy cx cy
처리 후 이미지 해상도가 약간 감소하고, 왜곡 계수가 제거된 것을 확인할 수 있다.
points3D.txt
각 3D 점은 다음과 같은 정보를 포함한다:
# POINT3D_ID X Y Z R G B ERROR TRACK[] 1 -4.6429 -0.1268 5.4171 163 177 139 0.3665 91 228 97 1097 ...
- 3D 좌표와 RGB 값
- 재투영 오차 (ERROR)
- 어떤 프레임의 몇 번째 2D 특징점과 연결되어 있는지(TRACK)
images.txt
카메라 자세 및 2D-3D 대응 정보를 포함한다. 첫 번째 줄에는 자세 데이터가, 두 번째 줄에는 2D 특징점 목록이 위치한다.
# IMAGE_ID QW QX QY QZ TX TY TZ CAMERA_ID NAME 1 0.9984 0.0419 0.0388 0.0010 -0.2513 -1.2153 3.0254 1 00001.png # X Y POINT3D_ID ... 825.15 -5.64 -1 164.01 -3.14 -1 ...
여기서 POINT3D_ID = -1은 아직 3D 점과 연결되지 않은 2D 특징점을 의미한다.
좌표계 변환
세계 좌표계의 점 \( P_{\text{world}} \)를 카메라 좌표계로 변환하려면 다음 수식을 사용한다:
여기서 \( R \)은 사원수(quaternion)로부터 유도된 회전 행렬이며, \( T \)는 카메라의 위치 벡터이다.