Initial upload: BPN deblur pipeline code (scripts, triangle-splatting, BAGS, EVSSM forks)
c75b162 verified | #!/usr/bin/env python3 | |
| """Generate points3D.txt from TUM depth frames using scipy for pose conversion.""" | |
| import os, numpy as np | |
| from PIL import Image | |
| from pathlib import Path | |
| from scipy.spatial.transform import Rotation | |
| BASE = "/home/szha0669/storage/blur_slam_exp" | |
| TUM_DIR = f"{BASE}/data/TUM_RGBD/rgbd_dataset_freiburg1_desk" | |
| OUT = f"{BASE}/data/tum_fr1desk/scene/sparse/0/points3D.txt" | |
| FX, FY, CX, CY = 517.3, 516.5, 318.6, 255.3 | |
| DEPTH_SCALE = 5000.0 | |
| def read_timestamps(path): | |
| data = {} | |
| with open(path) as f: | |
| for line in f: | |
| if line.startswith('#'): continue | |
| parts = line.strip().split() | |
| if len(parts) >= 2: | |
| try: | |
| data[float(parts[0])] = parts[1:] | |
| except ValueError: | |
| pass | |
| return data | |
| def nearest_ts(query, ts_sorted, max_dt=0.05): | |
| idx = np.searchsorted(ts_sorted, query) | |
| best = None | |
| for i in [idx-1, idx]: | |
| if 0 <= i < len(ts_sorted): | |
| dt = abs(ts_sorted[i] - query) | |
| if dt < max_dt and (best is None or dt < best[0]): | |
| best = (dt, ts_sorted[i]) | |
| return best[1] if best else None | |
| rgb_data = read_timestamps(f"{TUM_DIR}/rgb.txt") | |
| depth_data = read_timestamps(f"{TUM_DIR}/depth.txt") | |
| gt_data = read_timestamps(f"{TUM_DIR}/groundtruth.txt") | |
| depth_ts = sorted(depth_data.keys()) | |
| gt_ts = sorted(gt_data.keys()) | |
| rgb_ts = sorted(rgb_data.keys()) | |
| # Sample every 30th frame | |
| sampled = rgb_ts[::30] | |
| print(f"Sampling {len(sampled)} frames") | |
| all_pts, all_colors = [], [] | |
| for rgb_t in sampled: | |
| d_t = nearest_ts(rgb_t, depth_ts) | |
| g_t = nearest_ts(rgb_t, gt_ts) | |
| if d_t is None or g_t is None: continue | |
| tx, ty, tz, qx, qy, qz, qw = map(float, gt_data[g_t]) | |
| R_c2w = Rotation.from_quat([qx, qy, qz, qw]).as_matrix() | |
| t_c2w = np.array([tx, ty, tz]) | |
| depth_path = f"{TUM_DIR}/{depth_data[d_t][0]}" | |
| rgb_path = f"{TUM_DIR}/{rgb_data[rgb_t][0]}" | |
| depth_img = np.array(Image.open(depth_path)).astype(np.float32) / DEPTH_SCALE | |
| rgb_img = np.array(Image.open(rgb_path)) | |
| H_d, W_d = depth_img.shape | |
| ys, xs = np.meshgrid(np.arange(0, H_d, 8), np.arange(0, W_d, 8), indexing='ij') | |
| ys, xs = ys.ravel(), xs.ravel() | |
| zs = depth_img[ys, xs] | |
| valid = (zs > 0.2) & (zs < 4.0) | |
| ys, xs, zs = ys[valid], xs[valid], zs[valid] | |
| xc = (xs - CX) / FX * zs | |
| yc = (ys - CY) / FY * zs | |
| pts_cam = np.stack([xc, yc, zs], axis=1) | |
| pts_world = (R_c2w @ pts_cam.T).T + t_c2w | |
| colors = rgb_img[ys, xs] | |
| all_pts.append(pts_world) | |
| all_colors.append(colors) | |
| all_pts = np.concatenate(all_pts, axis=0) | |
| all_colors = np.concatenate(all_colors, axis=0) | |
| print(f"Total: {len(all_pts)} points") | |
| with open(OUT, 'w') as f: | |
| f.write("# 3D point list: POINT3D_ID X Y Z R G B ERROR TRACK[]\n") | |
| for i, (pt, col) in enumerate(zip(all_pts, all_colors)): | |
| f.write(f"{i+1} {pt[0]:.6f} {pt[1]:.6f} {pt[2]:.6f} " | |
| f"{int(col[0])} {int(col[1])} {int(col[2])} 0.5\n") | |
| print(f"Written: {OUT}") | |