from __future__ import print_function import numpy as np import open3d import trimesh import StructDiffusion.utils.transformations as tra from StructDiffusion.utils.brain2.pose import make_pose def get_camera_from_h5(h5): """ Simple reference to help make these """ proj_near = h5['cam_near'][()] proj_far = h5['cam_far'][()] proj_fov = h5['cam_fov'][()] width = h5['cam_width'][()] height = h5['cam_height'][()] return GenericCameraReference(proj_near, proj_far, proj_fov, width, height) class GenericCameraReference(object): """ Class storing camera information and providing easy image capture """ def __init__(self, proj_near=0.01, proj_far=5., proj_fov=60., img_width=640, img_height=480): self.proj_near = proj_near self.proj_far = proj_far self.proj_fov = proj_fov self.img_width = img_width self.img_height = img_height self.x_offset = self.img_width / 2. self.y_offset = self.img_height / 2. # Compute focal params aspect_ratio = self.img_width / self.img_height e = 1 / (np.tan(np.radians(self.proj_fov/2.))) t = self.proj_near / e b = -t r = t * aspect_ratio l = -r # pixels per meter alpha = self.img_width / (r-l) self.focal_length = self.proj_near * alpha self.fx = self.focal_length self.fy = self.focal_length self.pose = None self.inv_pose = None def set_pose(self, trans, rot): self.pose = make_pose(trans, rot) self.inv_pose = tra.inverse_matrix(self.pose) def set_pose_matrix(self, matrix): self.pose = matrix self.inv_pose = tra.inverse_matrix(matrix) def transform_to_world_coords(self, xyz): """ transform xyz into world coordinates """ #cam_pose = tra.inverse_matrix(self.pose).dot(tra.euler_matrix(np.pi, 0, 0)) #xyz = trimesh.transform_points(xyz, self.inv_pose) #xyz = trimesh.transform_points(xyz, cam_pose) #pose = tra.euler_matrix(np.pi, 0, 0) @ self.pose pose = self.pose xyz = trimesh.transform_points(xyz, pose) return xyz def get_camera_presets(): return [ "n/a", "azure_depth_nfov", "realsense", "azure_720p", "simple256", "simple512", ] def get_camera_preset(name): if name == "azure_depth_nfov": # Setting for depth camera is pretty different from RGB height, width, fov = 576, 640, 75 if name == "azure_720p": # This is actually the 720p RGB setting # Used for our color camera most of the time #height, width, fov = 720, 1280, 90 height, width, fov = 720, 1280, 60 elif name == "realsense": height, width, fov = 480, 640, 60 elif name == "simple256": height, width, fov = 256, 256, 60 elif name == "simple512": height, width, fov = 512, 512, 60 else: raise RuntimeError(('camera "%s" not supported, choose from: ' + str(get_camera_presets())) % str(name)) return height, width, fov def get_generic_camera(name): h, w, fov = get_camera_preset(name) return GenericCameraReference(img_height=h, img_width=w, proj_fov=fov) def get_matrix_of_indices(height, width): """ Get indices """ return np.indices((height, width), dtype=np.float32).transpose(1,2,0) # -------------------------------------------------------- # NOTE: this code taken from Arsalan and modified def compute_xyz(depth_img, camera, visualize_xyz=False, xmap=None, ymap=None, max_clip_depth=5): """ Compute xyz image from depth for a camera """ # We need thes eparameters height = camera.img_height width = camera.img_width assert depth_img.shape[0] == camera.img_height assert depth_img.shape[1] == camera.img_width fx = camera.fx fy = camera.fy cx = camera.x_offset cy = camera.y_offset """ # Create the matrix of parameters indices = np.indices((height, width), dtype=np.float32).transpose(1,2,0) # pixel indices start at top-left corner. for these equations, it starts at bottom-left # indices[..., 0] = np.flipud(indices[..., 0]) z_e = depth_img x_e = (indices[..., 1] - x_offset) * z_e / fx y_e = (indices[..., 0] - y_offset) * z_e / fy xyz_img = np.stack([x_e, y_e, z_e], axis=-1) # Shape: [H x W x 3] """ height = depth_img.shape[0] width = depth_img.shape[1] input_x = np.arange(width) input_y = np.arange(height) input_x, input_y = np.meshgrid(input_x, input_y) input_x = input_x.flatten() input_y = input_y.flatten() input_z = depth_img.flatten() # clip points that are farther than max distance input_z[input_z > max_clip_depth] = 0 output_x = (input_x * input_z - cx * input_z) / fx output_y = (input_y * input_z - cy * input_z) / fy raw_pc = np.stack([output_x, output_y, input_z], -1).reshape( height, width, 3 ) return raw_pc if visualize_xyz: unordered_pc = xyz_img.reshape(-1, 3) pcd = open3d.geometry.PointCloud() pcd.points = open3d.utility.Vector3dVector(unordered_pc) pcd.transform([[1,0,0,0], [0,1,0,0], [0,0,-1,0], [0,0,0,1]]) # Transform it so it's not upside down open3d.visualization.draw_geometries([pcd]) return xyz_img def show_pcs(xyz, rgb): """ Display point clouds """ if len(xyz.shape) > 2: unordered_pc = xyz.reshape(-1, 3) unordered_rgb = rgb.reshape(-1, 3) / 255. assert(unordered_rgb.shape[0] == unordered_pc.shape[0]) assert(unordered_pc.shape[1] == 3) assert(unordered_rgb.shape[1] == 3) pcd = open3d.geometry.PointCloud() pcd.points = open3d.utility.Vector3dVector(unordered_pc) pcd.colors = open3d.utility.Vector3dVector(unordered_rgb) pcd.transform([[1,0,0,0],[0,1,0,0],[0,0,-1,0],[0,0,0,1]]) # Transform it so it's not upside down open3d.visualization.draw_geometries([pcd])