|
|
import math |
|
|
import sys |
|
|
import os |
|
|
|
|
|
from natsort import natsorted |
|
|
|
|
|
sys.path.insert(0, os.path.dirname(__file__) + '/../..') |
|
|
|
|
|
import argparse |
|
|
from tqdm import tqdm |
|
|
import numpy as np |
|
|
import torch |
|
|
import cv2 |
|
|
from PIL import Image |
|
|
from glob import glob |
|
|
from pycocotools import mask as masktool |
|
|
from lib.pipeline.masked_droid_slam import * |
|
|
from lib.pipeline.est_scale import * |
|
|
from hawor.utils.process import block_print, enable_print |
|
|
|
|
|
sys.path.insert(0, os.path.dirname(__file__) + '/../../thirdparty/Metric3D') |
|
|
from metric import Metric3D |
|
|
|
|
|
|
|
|
def get_all_mp4_files(folder_path): |
|
|
|
|
|
folder_path = os.path.abspath(folder_path) |
|
|
|
|
|
|
|
|
mp4_files = glob(os.path.join(folder_path, '**', '*.mp4'), recursive=True) |
|
|
|
|
|
return mp4_files |
|
|
|
|
|
def split_list_by_interval(lst, interval=1000): |
|
|
start_indices = [] |
|
|
end_indices = [] |
|
|
split_lists = [] |
|
|
|
|
|
for i in range(0, len(lst), interval): |
|
|
start_indices.append(i) |
|
|
end_indices.append(min(i + interval, len(lst))) |
|
|
split_lists.append(lst[i:i + interval]) |
|
|
|
|
|
return start_indices, end_indices, split_lists |
|
|
|
|
|
def hawor_slam(args, start_idx, end_idx): |
|
|
|
|
|
file = args.video_path |
|
|
video_root = os.path.dirname(file) |
|
|
video = os.path.basename(file).split('.')[0] |
|
|
seq_folder = os.path.join(video_root, video) |
|
|
os.makedirs(seq_folder, exist_ok=True) |
|
|
video_folder = os.path.join(video_root, video) |
|
|
|
|
|
img_folder = f'{video_folder}/extracted_images' |
|
|
imgfiles = natsorted(glob(f'{img_folder}/*.jpg')) |
|
|
|
|
|
first_img = cv2.imread(imgfiles[0]) |
|
|
height, width, _ = first_img.shape |
|
|
|
|
|
print(f'Running slam on {video_folder} ...') |
|
|
|
|
|
|
|
|
|
|
|
masks = np.load(f'{video_folder}/tracks_{start_idx}_{end_idx}/model_masks.npy', allow_pickle=True) |
|
|
masks = torch.from_numpy(masks) |
|
|
print(masks.shape) |
|
|
|
|
|
|
|
|
focal = args.img_focal |
|
|
if focal is None: |
|
|
try: |
|
|
with open(os.path.join(video_folder, 'est_focal.txt'), 'r') as file: |
|
|
focal = file.read() |
|
|
focal = float(focal) |
|
|
except: |
|
|
|
|
|
print('No focal length provided') |
|
|
focal = 600 |
|
|
with open(os.path.join(video_folder, 'est_focal.txt'), 'w') as file: |
|
|
file.write(str(focal)) |
|
|
calib = np.array(est_calib(imgfiles)) |
|
|
center = calib[2:] |
|
|
calib[:2] = focal |
|
|
|
|
|
|
|
|
droid, traj = run_slam(imgfiles, masks=masks, calib=calib) |
|
|
n = droid.video.counter.value |
|
|
tstamp = droid.video.tstamp.cpu().int().numpy()[:n] |
|
|
disps = droid.video.disps_up.cpu().numpy()[:n] |
|
|
print('DBA errors:', droid.backend.errors) |
|
|
|
|
|
del droid |
|
|
torch.cuda.empty_cache() |
|
|
|
|
|
|
|
|
block_print() |
|
|
metric = Metric3D('thirdparty/Metric3D/weights/metric_depth_vit_large_800k.pth') |
|
|
enable_print() |
|
|
min_threshold = 0.4 |
|
|
max_threshold = 0.7 |
|
|
|
|
|
print('Predicting Metric Depth ...') |
|
|
pred_depths = [] |
|
|
H, W = get_dimention(imgfiles) |
|
|
for t in tqdm(tstamp): |
|
|
pred_depth = metric(imgfiles[t], calib) |
|
|
pred_depth = cv2.resize(pred_depth, (W, H)) |
|
|
pred_depths.append(pred_depth) |
|
|
|
|
|
|
|
|
print('Estimating Metric Scale ...') |
|
|
scales_ = [] |
|
|
n = len(tstamp) |
|
|
for i in tqdm(range(n)): |
|
|
t = tstamp[i] |
|
|
disp = disps[i] |
|
|
pred_depth = pred_depths[i] |
|
|
slam_depth = 1/disp |
|
|
|
|
|
|
|
|
msk = masks[t].numpy().astype(np.uint8) |
|
|
scale = est_scale_hybrid(slam_depth, pred_depth, sigma=0.5, msk=msk, near_thresh=min_threshold, far_thresh=max_threshold) |
|
|
while math.isnan(scale): |
|
|
min_threshold -= 0.1 |
|
|
max_threshold += 0.1 |
|
|
scale = est_scale_hybrid(slam_depth, pred_depth, sigma=0.5, msk=msk, near_thresh=min_threshold, far_thresh=max_threshold) |
|
|
scales_.append(scale) |
|
|
|
|
|
median_s = np.median(scales_) |
|
|
print(f"estimated scale: {median_s}") |
|
|
|
|
|
|
|
|
os.makedirs(f"{seq_folder}/SLAM", exist_ok=True) |
|
|
save_path = f'{seq_folder}/SLAM/hawor_slam_w_scale_{start_idx}_{end_idx}.npz' |
|
|
np.savez(save_path, |
|
|
tstamp=tstamp, disps=disps, traj=traj, |
|
|
img_focal=focal, img_center=calib[-2:], |
|
|
scale=median_s) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|