반응형
COLMAP을 사용하고 나면 나오는 결과 파일은 총 ( images, cameras, points3D ) 3개다.
bin 파일이나 txt 파일로 저장되도록 설정이 되어있는데, 이를 주로 사용하는 python으로 가져오기가 매번 heuristic하기엔 번거로워 read function을 작성했다.
아래 함수를 통해서, colmap의 결과값을 각 요소 별로 list 형태로 얻을 수 있다. 이후에 원하는 형태로 사용하면 된다.
먼저 bin 파일을 갖고 있을 경우, txt 파일로 변환하는 것으로 시작한다.
colmap model_converter --input_path /path/to/dir-of-bins/ --output_path /path/to/dir-of-txts/ --output_type TXT
1. cameras.txt
def read_cam_txt(cam_txt_path):
if not os.path.exists(cam_txt_path):
raise Exception(f"No such file : {cam_txt_path}")
with open(cam_txt_path, 'r') as f:
lines = f.readlines()
if len(lines) < 3:
raise Exception(f"Invalid cameras.txt file : {cam_txt_path}")
comments = lines[:3]
contents = lines[3:]
ids = []
Ks = []
dists = []
img_dims = [] # (w, h)
for cam_idx, content in enumerate(contents):
content_items = content.split(' ')
cam_id = content_items[0]
cam_type = content_items[1]
img_w, img_h = int(content_items[2]), int(content_items[3])
if cam_type == "OPENCV":
fx, fy = content_items[4], content_items[5]
cx, cy = content_items[6], content_items[7]
K = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]], dtype=np.float32)
dist = content_items[8:] + [0] # k1 k2 p1 p2 + k3(0)
dist = np.asarray(dist)
ids.append(cam_id)
Ks.append(K)
dists.append(dist)
img_dims.append((img_w, img_h))
elif cam_type== "PINHOLE":
fx, fy = content_items[4], content_items[5]
cx, cy = content_items[6], content_items[7]
K = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]], dtype=np.float32)
dist = np.zeros([5], dtype=np.float32)
ids.append(cam_id)
Ks.append(K)
dists.append(dist)
img_dims.append((img_w, img_h))
else:
raise NotImplementedError(f"Only opencv/pinhole camera will be supported.")
return ids, Ks, dists, img_dims
2. images.txt : pose는 T_cw 방향이다. (notation이 뭔지 모르면 https://jseobyun.tistory.com/31 참고)
def read_images_txt(images_path):
if not os.path.exists(images_path):
raise Exception(f"No such file : {images_path}")
with open(images_path, 'r') as f:
lines = f.readlines()
if len(lines) < 2:
raise Exception(f"Invalid cameras.txt file : {images_path}")
comments = lines[:4]
contents = lines[4:]
img_ids = []
cam_ids = []
img_names = []
poses = []
for img_idx, content in enumerate(contents[::2]):
content_items = content.split(' ')
img_id = content_items[0]
q_xyzw = np.array(content_items[2:5] + content_items[1:2], dtype=np.float32) # colmap uses wxyz
t_xyz = np.array(content_items[5:8], dtype=np.float32)
cam_id = content_items[8]
img_name = content_items[9]
R = Rot.from_quat(q_xyzw).as_matrix()
T = np.eye(4)
T[:3, :3] = R
T[:3, -1] = t_xyz
img_ids.append(img_id)
cam_ids.append(cam_id)
img_names.append(img_name)
poses.append(T)
return img_ids, cam_ids, img_names, poses
3. points3D.txt : PCD 이므로 point id는 무시했음.
def read_point3d_txt(point3d_path):
if not os.path.exists(point3d_path):
raise Exception(f"No such file : {point3d_path}")
with open(point3d_path, 'r') as f:
lines = f.readlines()
if len(lines) < 2:
raise Exception(f"Invalid cameras.txt file : {point3d_path}")
comments = lines[:3]
contents = lines[3:]
XYZs = []
RGBs = []
candidate_ids = {}
for pt_idx, content in enumerate(contents):
content_items = content.split(' ')
pt_id = content_items[0]
XYZ = content_items[1:4]
RGB = content_items[4:7]
error = content_items[7],
candidate_id = content_items[8::2]
XYZs.append(np.array(XYZ, dtype=np.float32).reshape(1,3))
RGBs.append(np.array(RGB, dtype=np.float32).reshape(1, 3) / 255.0)
candidate_ids[pt_id] = candidate_id
XYZs = np.concatenate(XYZs, axis=0)
RGBs = np.concatenate(RGBs, axis=0)
return XYZs, RGBs, candidate_ids
def inverse_relation(candidate_img_ids):
candidate_point_ids = {}
pt_ids = list(candidate_img_ids.keys())
for pt_id in pt_ids:
candidate_img_id = candidate_img_ids[pt_id]
for img_id in candidate_img_id:
if img_id in list(candidate_point_ids.keys()):
candidate_point_ids[img_id].append(pt_id)
else:
candidate_point_ids[img_id] = [pt_id]
return candidate_point_ids
(4. database.db )
Check failed: existing_image.Name() == image.second.Name()
위 에러가 나는 경우의 원인이, database.db 내 이미지 index와 images.txt 내 이미지 index가 다르기 때문인데 이를 해결하기 위해 database.db 파일을 열어봐야 하는 경우가 있다.
def read_db(db_path):
conn = sqlite3.connect(db_path)
c = conn.cursor()
c.execute("SELECT * FROM images")
images_tuples = c.fetchall()
c.execute("SELECT * FROM cameras")
cameras_tuples = c.fetchall()
return cameras_tuples, images_tuples
직접 쓰는 일은 드물기 때문에 세부적으로 정리하진 않고 list of tuples이 return되도록 냅두었다.
반응형
'Knowhow > Vision' 카테고리의 다른 글
COLMAP[CLI] SfM/MVS with known camera parameters and poses (0) | 2022.07.14 |
---|---|
COLMAP write txt files in python (0) | 2022.07.13 |
COLMAP[GUI] multi-camera setting (0) | 2022.07.07 |
Open3d RGB/Depth image rendering (0) | 2022.07.01 |
Obj file의 manifold/non-manifold 구분 (0) | 2022.06.30 |