import torch import numpy as np import random import pdb def recover_metric_depth(pred, gt): if type(pred).__module__ == torch.__name__: pred = pred.cpu().numpy() if type(gt).__module__ == torch.__name__: gt = gt.cpu().numpy() gt = gt.squeeze() pred = pred.squeeze() mask = (gt > 1e-8) & (pred > 1e-8) gt_mask = gt[mask] pred_mask = pred[mask] a, b = np.polyfit(pred_mask, gt_mask, deg=1) #print("scale {}".format(a)) #print("shift {}".format(b)) pred_metric = a * pred + b return pred_metric def recover_scale_shift(pred, gt): if type(pred).__module__ == torch.__name__: pred = pred.cpu().numpy() if type(gt).__module__ == torch.__name__: gt = gt.cpu().numpy() gt = gt.squeeze() pred = pred.squeeze() mask = (gt > 1e-8) & (pred > 1e-8) gt_mask = gt[mask] pred_mask = pred[mask] a, b = np.polyfit(pred_mask, gt_mask, deg=1) #print("scale {}".format(a)) #print("shift {}".format(b)) pred_metric = a * pred + b return a, b def normal_from_depth(depth, focal_length): """ Compute surface normal from depth map """ def normalization(data): mo_chang = np.sqrt( np.multiply(data[:, :, 0], data[:, :, 0]) + np.multiply(data[:, :, 1], data[:, :, 1]) + np.multiply(data[:, :, 2], data[:, :, 2]) ) mo_chang = np.dstack((mo_chang, mo_chang, mo_chang)) return data/mo_chang width = 1024 height = 768 K = np.array([ [focal_length, 0, width / 2], [0, focal_length, height / 2], [0, 0, 1], ]) x, y = np.meshgrid(np.arange(0, width), np.arange(0, height)) x = x.reshape([-1]) y = y.reshape([-1]) xyz = np.vstack((x, y, np.ones_like(x))) pts_3d = np.dot(np.linalg.inv(K), xyz*depth.reshape([-1])) pts_3d_world = pts_3d.reshape((3, height, width)) f = pts_3d_world[:, 1:height-1, 2:width] - pts_3d_world[:, 1:height-1, 1:width-1] t = pts_3d_world[:, 2:height, 1:width-1] - pts_3d_world[:, 1:height-1, 1:width-1] normal_map = np.cross(f, t, axisa=0, axisb=0) normal_map = normalization(normal_map) # pad it to 400x600 normal_map = np.pad(normal_map, ((1, 1), (1, 1), (0, 0)), 'edge') return normal_map def estimate_equation(points): # use linear system if points.shape[0] == points.shape[1]: normal = np.linalg.solve(points, np.ones(points.shape[0])) else: normal = np.linalg.lstsq(points, np.ones(points.shape[0]), rcond=None)[0] offset = -1 / np.linalg.norm(normal) normal /= np.linalg.norm(normal) if normal[2] > 0: # make sure n_z is negative normal = -normal return normal, offset def fit_plane(points, thres=0.01, debug=False): final_inliers = [] final_equation = np.array([0, 0, 0]) final_offset = 0.0 for i in range(200): # Sample 3 points sample = np.array([random.choice(points) for _ in range(3)]) # n_x * x + n_y * y + n_z * z = offset try: equation, offset = estimate_equation(sample) except np.linalg.LinAlgError: # typically a singular matrix continue error = points @ equation - offset inliers = points[error < thres] if debug: print('n and inliers: {} {}'.format(equation, len(inliers))) if len(inliers) > len(final_inliers): final_inliers = inliers final_offset = offset final_equation = equation equation, offset = estimate_equation(final_inliers) if debug: print('Best Results:') print(final_equation) print(len(final_inliers)) print('Final Fit:') print(equation) print(offset) return equation, offset