3DGS convert.py 오류 해결

chaenyang·2025년 6월 25일
0

3D

목록 보기
5/9

convert.py는 COLMAP을 자동으로 실행하고, 그 결과(=카메라 pose, 이미지)를 3DGS 학습에 맞게 변환해주는 스크립트이다.

convert.py는 SfM, Undistortion으로 이루어져 있는데 아래 오류는 SfM 과정 중에서 Initialization 이후에 발생했다.

I20250625 13:55:57.943927 17224 incremental_pipeline.cc:282] Finding good initial image pair
I20250625 13:55:57.945971 17224 incremental_pipeline.cc:286] => No good initial image pair found.
I20250625 13:55:57.947114 17224 timer.cc:91] Elapsed time: 0.195 [minutes]
I20250625 13:55:58.062740 17436 misc.cc:44] 
==============================================================================
Reading reconstruction
==============================================================================
I20250625 13:55:58.067806 17436 image.cc:347] => Reconstruction with 2 images and 3 points
I20250625 13:55:58.067951 17436 misc.cc:44]
==============================================================================
Image undistortion
==============================================================================
I20250625 13:55:58.069137 17436 undistortion.cc:215] Undistorting image [1/2]
I20250625 13:56:00.673870 17436 undistortion.cc:215] Undistorting image [2/2]
I20250625 13:56:00.674079 17436 undistortion.cc:225] Writing reconstruction...
I20250625 13:56:00.712746 17436 undistortion.cc:230] Writing configuration...
I20250625 13:56:00.713411 17436 undistortion.cc:234] Writing scripts...
I20250625 13:56:00.714180 17436 timer.cc:91] Elapsed time: 0.044 [minutes]
Done. 

SfM

일단 SfM에서는 input 이미지들을 넣으면 Camera parameter와 point cloud를 얻는다.

첫번째 Correspondence Search 단계에서는 feature간 관계성을 추출한다.
이미지마다 SIFT feature을 뽑고 모든 이미지 pair를 매칭한다. 이미지들 중에 겹치는 장면을 찾는 단계이다. Overlap 되는 이미지 pair들을 결과로 출력한다. 그러고 매칭이 잘 되었는지 검증하는 과정을 거친다. 그럼 검증된 이미지 pair와 correspondence map이 output으로 나온다.

그 다음 Incremental Reconstruction에서는 camera parameter와 3D points를 반복적으로 추정한다. 이렇게 해서 camera intrinsics, extrinsics를 얻는다.

먼저 Initialization 단계에서는 최초로 register하는 이미지 2장을 고른다. 이때 특징이 잘 나타난 이미지가 선택되어야 reconstruction 결과가 좋다. 그리고 input 이미지들의 장면이 어느정도는 overlap되어야 중복되는 영역이 반복적으로 초기화돼서 renconstruction의 정확도가 높아진다.
그리고 애초에 overlap 안되고 장면 휙휙 바뀌면 연결되는 지점을 못찾아서 reconstruction에 쓰일 이미지 고를 때 다 걸러진다.

사진 2장을 초기에 잘 뽑고 3D reconstruction process에 등록하고나서 Triangulation이 이어지는데, 선택된 이미지 feature에 삼각함수 써서 임의로 3D point를 추가하는 과정이다. 그러고 이미지들의 feature와 임의로 추가된 3D point들로 카메라 파라미터를 최적화하는 Bundle Adjustment가 이어진다.

그럼 output으로 각 이미지의 pose 값, scene structure가 나온다.

여기까지가 SfM이고

convert.py

convert.py는

[Original image]
↓
Feature extraction 
: 이미지마다 SIFT feature 뽑음
↓
Feature matching
: exhaustive_matcher
↓
Sparse Reconstruction (SfM)
: 매칭 결과 기반으로 camera pose 추정
: sparse 3D points 생성 (distorted/sparse/0/points3D.bin)
↓
Undistortion
- images/ 폴더 생성 (이미지 undistort해서)
- sparse/0/cameras.bin (camera intrinsics)
- sparse/0/points3D.bin (undistorted point) 
↓
[sparse/0/ + undistorted images] → 3DGS train

이런 과정으로 진행된다.


SfM 뒤에 이어지는 Undistortion은 COLMAP이 기본적으로 왜곡된 카메라 모델 (Opencv 등)을 사용해서 Gaussian splatting이나 NeRF에 맞게 undistorted pinhole 카메라 모델로 보정하는 단계이다.

convert.py 돌리면 이렇게 된다.
원래 있던 파일이 input(원본 이미지들)이다. 꼭 파일 이름 input으로 해줘야 한다. 아님 convert.py에서 수정해야 한다.

여기서 input/은 convert.py의 input인 이미지들이 담긴 폴더이다.

  • distorted/: COLMAP에서 원래 카메라 모델(distortion 포함)로 recon한 겨과 들어있음

  • distorted/database.db: 추출한 feature와 매칭 기록이 저장된 DB

  • distorted/sparse/: COLMAP의 sparse reconstruction 결과이다.
    - 여러 sub model이 생길 경우 0/, 1/, 2/로 여러 모델로 나뉜다. 보통 0/이 주모델이다.

  • images/: undistorted image들이 들어 있는 폴더로 image_undistorter가 생성한다. Gaussian Splatting 학습할 때 여기있는 이미지들이 사용된다.

  • sparse/0/: COLMAP의 undistorted camera pose+ 3D point 정보

  • cameras.bin: camera intrinsics (focal length, distortion 계수 등)

  • images.bin: 이미지마다 pose(위치, 회전)

  • points3D.bin: 재구성된 3D points

  • points3D.ply: point들 시각화할 수 있게 ply로 저장

  • stereo/: COLMAP의 Dense Reconstruction 결과 (MVS 기반) → Gaussian Splatting에는 안쓰임

Error

그래서 처음에 발생한 오류는

I20250625 13:55:57.943927 17224 incremental_pipeline.cc:282] Finding good initial image pair
I20250625 13:55:57.945971 17224 incremental_pipeline.cc:286] => No good initial image pair found.
I20250625 13:55:57.947114 17224 timer.cc:91] Elapsed time: 0.195 [minutes]
I20250625 13:55:58.062740 17436 misc.cc:44] 
==============================================================================
Reading reconstruction
==============================================================================
I20250625 13:55:58.067806 17436 image.cc:347] => Reconstruction with 2 images and 3 points
I20250625 13:55:58.067951 17436 misc.cc:44]
==============================================================================
Image undistortion
==============================================================================
I20250625 13:55:58.069137 17436 undistortion.cc:215] Undistorting image [1/2]
I20250625 13:56:00.673870 17436 undistortion.cc:215] Undistorting image [2/2]
I20250625 13:56:00.674079 17436 undistortion.cc:225] Writing reconstruction...
I20250625 13:56:00.712746 17436 undistortion.cc:230] Writing configuration...
I20250625 13:56:00.713411 17436 undistortion.cc:234] Writing scripts...
I20250625 13:56:00.714180 17436 timer.cc:91] Elapsed time: 0.044 [minutes]
Done. 

일단 feature 추출이랑 matching까진 잘 됐는데 그 다음에 initialization에서 이미지 2장 잘 고르고 그 이후부터 발생했다. 이유는 정확히 모르겠는데 내가 찍은 데이터셋 뿐만 아니라 mipnerf360으로 했을 떄도 그랬다.

  • overlap없음 ? → 있었음
  • feature 없음 ? 벽 가까이 찍거나 패턴이라할게 없나? → 아님

그래서 원인을 모르겠었다.

이미지 2장 고르고나서 연결할 이미지들을 못찾은 상태가 계속 이어져서 결국 recon에 사용할 이미지가 초기 이미지인 2장으로 끝나버렸다. 그래서 3DGS 학습할 때도 이미지를 2장만! 사용한다는 문제가 생겼다.

알고보니까 COLMAP은 이미지들을 여러 개의 submodel로 분리해서 reconstruction하는데 일부 이미지들을 다른 submodel로 분리해버려서 아까 위에 언급한 것처럼 sparse/0/, sparse/1/... 가 생긴다.

근데 convert.py는 기본적으로 sparse/0/만 처리해서 나머지 submodel들은 무시된다.

Solution

https://github.com/Anttwo/SuGaR/issues/153

여기에 나온 방법으로 해결했다. 난 턴테이블 방식으로 데이터 찍은건 아니고 내가 직접 찍었지만.. 해결은 잘 됐다.

가장 큰 submodel만 남기고 다시 convert.py를 실행하는 방법으로 해결했다.

  1. distorted/sparse/ 가서 여러 submodel 폴더가 있으면 (0/, 1/, 2/..)

  2. 가장 큰 submodel만 남기고 나머지 삭제 (이미지 수 가장 많은 폴더 선택하면 된다. images.bin이나 points3D.bin 용량 큰거로 판단하면 된다.)

  3. 남긴 submodel 폴더 이름 0/으로 바꾼다.

  4. convert.py 다시 실행하는데, matching은 건너뛴다.

>>> python convert.py -s path/to/your/scene --skip_matching

그럼 정상적으로

(gsenv) PS C:\Users\cglab\Documents\3d\gaussian-splatting> python convert.py -s cglab2 --skip_matching
I20250625 17:05:48.717338 19360 misc.cc:44] 
==============================================================================
Reading reconstruction
==============================================================================
I20250625 17:05:48.763906 19360 image.cc:347] => Reconstruction with 91 images and 13020 points
I20250625 17:05:48.764148 19360 misc.cc:44] 
==============================================================================
Image undistortion
==============================================================================
I20250625 17:05:48.765669 19360 undistortion.cc:215] Undistorting image [1/91]
I20250625 17:05:48.996879 19360 undistortion.cc:215] Undistorting image [2/91]
I20250625 17:05:49.002096 19360 undistortion.cc:215] Undistorting image [3/91]
I20250625 17:05:49.003242 19360 undistortion.cc:215] Undistorting image [4/91]
I20250625 17:05:49.019108 19360 undistortion.cc:215] Undistorting image [5/91]
I20250625 17:05:49.024722 19360 undistortion.cc:215] Undistorting image [6/91]

이미지들을 recon에 잘 사용한다는걸 알 수 있다.

images 폴더에 잘 생성됨 이미지들!


추가설명

Submodel (fragment)

COLMAP에서 이미지들을 reconstruction할 때, 이미지들이 하나로 연결되지 않으면 독립된 여러개의 submodel들이 생긴다.

그래서 sparse/0/, sparse/1/, ... 생기는데 각 서브모델 폴더에는 images.bin, points3D.bin이 존재한다.

COLMAP은 내부적으로 connected component를 구성해서 이미지들이 연결돼 있는 부분들끼리만 하나의 모델로 만들고, 연결이 끊긴 이미지는 fragment로 빼버린다.

근데 convert.py나 3DGS 학습에서는 submodel 0만 사용하게 돼있어서 나머지 submodel에 더 많은 이미지가 들어 있어도 무시되는 문제가 생긴다.

그래서 이미지 수가 가장 많은 submodel만 남기고 매칭 이후부터 convert.py를 다시 실행해서 해결했다.


submodel은 COLMAP reconstruction의 결과이고,
convert.py는 그 중 하나의 submodel만 사용해서 후처리를 한다.

먼저 COLMAP이 reconstruction을 실행했을 때, 모든 이미지가 1 component에 포함되지 않는 경우 여러개의 submodel을 생성한다.

convert.py는 이 중 sparse/0/ 하나만 사용해서

  • undistorted/images/를 생성하고
  • sparse/0/을 gaussian splatting 학습용으로 정리하고
  • images.bin, cameras.bin, points3D.bin을 sparse/0/으로 옮김 (원래 distorted/sparse/0/ 안의 결과 파일들임!)
profile
잉공지능

0개의 댓글