import torch import numpy as np from sklearn.metrics.pairwise import cosine_similarity from pytorch3d.renderer import ( PerspectiveCameras, look_at_view_transform ) # customized import sys sys.path.append(".") from lib.constants import VIEWPOINTS # ---------------- UTILS ---------------------- def degree_to_radian(d): return d * np.pi / 180 def radian_to_degree(r): return 180 * r / np.pi def xyz_to_polar(xyz): """ assume y-axis is the up axis """ x, y, z = xyz theta = 180 * np.arccos(z) / np.pi phi = 180 * np.arccos(y) / np.pi return theta, phi def polar_to_xyz(theta, phi, dist): """ assume y-axis is the up axis """ theta = degree_to_radian(theta) phi = degree_to_radian(phi) x = np.sin(phi) * np.sin(theta) * dist y = np.cos(phi) * dist z = np.sin(phi) * np.cos(theta) * dist return [x, y, z] # ---------------- VIEWPOINTS ---------------------- def filter_viewpoints(pre_viewpoints: dict, viewpoints: dict): """ return the binary mask of viewpoints to be filtered """ filter_mask = [0 for _ in viewpoints.keys()] for i, v in viewpoints.items(): x_v, y_v, z_v = polar_to_xyz(v["azim"], 90 - v["elev"], v["dist"]) for _, pv in pre_viewpoints.items(): x_pv, y_pv, z_pv = polar_to_xyz(pv["azim"], 90 - pv["elev"], pv["dist"]) sim = cosine_similarity( np.array([[x_v, y_v, z_v]]), np.array([[x_pv, y_pv, z_pv]]) )[0, 0] if sim > 0.9: filter_mask[i] = 1 return filter_mask def init_viewpoints(mode, sample_space, init_dist, init_elev, principle_directions, use_principle=True, use_shapenet=False, use_objaverse=False): if mode == "predefined": ( dist_list, elev_list, azim_list, sector_list ) = init_predefined_viewpoints(sample_space, init_dist, init_elev) elif mode == "hemisphere": ( dist_list, elev_list, azim_list, sector_list ) = init_hemisphere_viewpoints(sample_space, init_dist) else: raise NotImplementedError() # punishments for views -> in case always selecting the same view view_punishments = [1 for _ in range(len(dist_list))] if use_principle: ( dist_list, elev_list, azim_list, sector_list, view_punishments ) = init_principle_viewpoints( principle_directions, dist_list, elev_list, azim_list, sector_list, view_punishments, use_shapenet, use_objaverse ) return dist_list, elev_list, azim_list, sector_list, view_punishments def init_principle_viewpoints( principle_directions, dist_list, elev_list, azim_list, sector_list, view_punishments, use_shapenet=False, use_objaverse=False ): if use_shapenet: key = "shapenet" pre_elev_list = [v for v in VIEWPOINTS[key]["elev"]] pre_azim_list = [v for v in VIEWPOINTS[key]["azim"]] pre_sector_list = [v for v in VIEWPOINTS[key]["sector"]] num_principle = 10 pre_dist_list = [dist_list[0] for _ in range(num_principle)] pre_view_punishments = [0 for _ in range(num_principle)] elif use_objaverse: key = "objaverse" pre_elev_list = [v for v in VIEWPOINTS[key]["elev"]] pre_azim_list = [v for v in VIEWPOINTS[key]["azim"]] pre_sector_list = [v for v in VIEWPOINTS[key]["sector"]] num_principle = 10 pre_dist_list = [dist_list[0] for _ in range(num_principle)] pre_view_punishments = [0 for _ in range(num_principle)] else: num_principle = 6 pre_elev_list = [v for v in VIEWPOINTS[num_principle]["elev"]] pre_azim_list = [v for v in VIEWPOINTS[num_principle]["azim"]] pre_sector_list = [v for v in VIEWPOINTS[num_principle]["sector"]] pre_dist_list = [dist_list[0] for _ in range(num_principle)] pre_view_punishments = [0 for _ in range(num_principle)] dist_list = pre_dist_list + dist_list elev_list = pre_elev_list + elev_list azim_list = pre_azim_list + azim_list sector_list = pre_sector_list + sector_list view_punishments = pre_view_punishments + view_punishments return dist_list, elev_list, azim_list, sector_list, view_punishments def init_predefined_viewpoints(sample_space, init_dist, init_elev): viewpoints = VIEWPOINTS[sample_space] assert sample_space == len(viewpoints["sector"]) dist_list = [init_dist for _ in range(sample_space)] # always the same dist elev_list = [viewpoints["elev"][i] for i in range(sample_space)] azim_list = [viewpoints["azim"][i] for i in range(sample_space)] sector_list = [viewpoints["sector"][i] for i in range(sample_space)] return dist_list, elev_list, azim_list, sector_list def init_hemisphere_viewpoints(sample_space, init_dist): """ y is up-axis """ num_points = 2 * sample_space ga = np.pi * (3. - np.sqrt(5.)) # golden angle in radians flags = [] elev_list = [] # degree azim_list = [] # degree for i in range(num_points): y = 1 - (i / float(num_points - 1)) * 2 # y goes from 1 to -1 # only take the north hemisphere if y >= 0: flags.append(True) else: flags.append(False) theta = ga * i # golden angle increment elev_list.append(radian_to_degree(np.arcsin(y))) azim_list.append(radian_to_degree(theta)) radius = np.sqrt(1 - y * y) # radius at y x = np.cos(theta) * radius z = np.sin(theta) * radius elev_list = [elev_list[i] for i in range(len(elev_list)) if flags[i]] azim_list = [azim_list[i] for i in range(len(azim_list)) if flags[i]] dist_list = [init_dist for _ in elev_list] sector_list = ["good" for _ in elev_list] # HACK don't define sector names for now return dist_list, elev_list, azim_list, sector_list # ---------------- CAMERAS ---------------------- def init_camera(dist, elev, azim, image_size, device): R, T = look_at_view_transform(dist, elev, azim) image_size = torch.tensor([image_size, image_size]).unsqueeze(0) cameras = PerspectiveCameras(R=R, T=T, device=device, image_size=image_size) return cameras