import pickle import numpy as np import cv2 from skimage.io import imread def save_pickle(data, pkl_path): # os.system('mkdir -p {}'.format(os.path.dirname(pkl_path))) with open(pkl_path, 'wb') as f: pickle.dump(data, f) def read_pickle(pkl_path): with open(pkl_path, 'rb') as f: return pickle.load(f) def draw_epipolar_line(F, img0, img1, pt0, color): h1,w1=img1.shape[:2] hpt = np.asarray([pt0[0], pt0[1], 1], dtype=np.float32)[:, None] l = F @ hpt l = l[:, 0] a, b, c = l[0], l[1], l[2] pt1 = np.asarray([0, -c / b]).astype(np.int32) pt2 = np.asarray([w1, (-a * w1 - c) / b]).astype(np.int32) img0 = cv2.circle(img0, tuple(pt0.astype(np.int32)), 5, color, 2) img1 = cv2.line(img1, tuple(pt1), tuple(pt2), color, 2) return img0, img1 def draw_epipolar_lines(F, img0, img1,num=20): img0,img1=img0.copy(),img1.copy() h0, w0, _ = img0.shape h1, w1, _ = img1.shape for k in range(num): color = np.random.randint(0, 255, [3], dtype=np.int32) color = [int(c) for c in color] pt = np.random.uniform(0, 1, 2) pt[0] *= w0 pt[1] *= h0 pt = pt.astype(np.int32) img0, img1 = draw_epipolar_line(F, img0, img1, pt, color) return img0, img1 def compute_F(K1, K2, Rt0, Rt1=None): if Rt1 is None: R, t = Rt0[:,:3], Rt0[:,3:] else: Rt = compute_dR_dt(Rt0,Rt1) R, t = Rt[:,:3], Rt[:,3:] A = K1 @ R.T @ t # [3,1] C = np.asarray([[0,-A[2,0],A[1,0]], [A[2,0],0,-A[0,0]], [-A[1,0],A[0,0],0]]) F = (np.linalg.inv(K2)).T @ R @ K1.T @ C return F def compute_dR_dt(Rt0, Rt1): R0, t0 = Rt0[:,:3], Rt0[:,3:] R1, t1 = Rt1[:,:3], Rt1[:,3:] dR = np.dot(R1, R0.T) dt = t1 - np.dot(dR, t0) return np.concatenate([dR, dt], -1) def concat_images(img0,img1,vert=False): if not vert: h0,h1=img0.shape[0],img1.shape[0], if h00) if np.sum(mask0)>0: dpt[mask0]=1e-4 mask1=(np.abs(dpt) > -1e-4) & (np.abs(dpt) < 0) if np.sum(mask1)>0: dpt[mask1]=-1e-4 pts2d = pts[:,:2]/dpt[:,None] return pts2d, dpt def draw_keypoints(img, kps, colors=None, radius=2): out_img=img.copy() for pi, pt in enumerate(kps): pt = np.round(pt).astype(np.int32) if colors is not None: color=[int(c) for c in colors[pi]] cv2.circle(out_img, tuple(pt), radius, color, -1) else: cv2.circle(out_img, tuple(pt), radius, (0,255,0), -1) return out_img def output_points(fn,pts,colors=None): with open(fn, 'w') as f: for pi, pt in enumerate(pts): f.write(f'{pt[0]:.6f} {pt[1]:.6f} {pt[2]:.6f} ') if colors is not None: f.write(f'{int(colors[pi,0])} {int(colors[pi,1])} {int(colors[pi,2])}') f.write('\n') DEPTH_MAX, DEPTH_MIN = 2.4, 0.6 DEPTH_VALID_MAX, DEPTH_VALID_MIN = 2.37, 0.63 def read_depth_objaverse(depth_fn): depth = imread(depth_fn) depth = depth.astype(np.float32) / 65535 * (DEPTH_MAX-DEPTH_MIN) + DEPTH_MIN mask = (depth > DEPTH_VALID_MIN) & (depth < DEPTH_VALID_MAX) return depth, mask def mask_depth_to_pts(mask,depth,K,rgb=None): hs,ws=np.nonzero(mask) depth=depth[hs,ws] pts=np.asarray([ws,hs,depth],np.float32).transpose() pts[:,:2]*=pts[:,2:] if rgb is not None: return np.dot(pts, np.linalg.inv(K).transpose()), rgb[hs,ws] else: return np.dot(pts, np.linalg.inv(K).transpose()) def transform_points_pose(pts, pose): R, t = pose[:, :3], pose[:, 3] if len(pts.shape)==1: return (R @ pts[:,None] + t[:,None])[:,0] return pts @ R.T + t[None,:] def pose_apply(pose,pts): return transform_points_pose(pts, pose) def downsample_gaussian_blur(img, ratio): sigma = (1 / ratio) / 3 # ksize=np.ceil(2*sigma) ksize = int(np.ceil(((sigma - 0.8) / 0.3 + 1) * 2 + 1)) ksize = ksize + 1 if ksize % 2 == 0 else ksize img = cv2.GaussianBlur(img, (ksize, ksize), sigma, borderType=cv2.BORDER_REFLECT101) return img