Denys Rozumnyi
commited on
Commit
·
7258769
1
Parent(s):
a0cd1aa
update
Browse files- geom_solver.py +67 -63
- helpers.py +2 -3
- my_solution.py +1 -5
- testing.ipynb +0 -0
geom_solver.py
CHANGED
|
@@ -1,16 +1,15 @@
|
|
| 1 |
import numpy as np
|
| 2 |
from pytorch3d.ops import ball_query
|
| 3 |
from helpers import *
|
| 4 |
-
from handcrafted_solution import
|
|
|
|
| 5 |
import hoho
|
| 6 |
import itertools
|
| 7 |
import torch
|
| 8 |
from pytorch3d.renderer import PerspectiveCameras
|
| 9 |
-
|
| 10 |
|
| 11 |
def my_empty_solution():
|
| 12 |
-
'''Return a minimal valid solution, i.e. 2 vertices and 1 edge.'''
|
| 13 |
-
# return np.zeros((1,3)), [(0, 0)]
|
| 14 |
return np.zeros((18,3)), [(0, 0)]
|
| 15 |
|
| 16 |
|
|
@@ -19,54 +18,28 @@ class GeomSolver(object):
|
|
| 19 |
def __init__(self):
|
| 20 |
self.min_vertices = 18
|
| 21 |
self.kmeans_th = 150
|
| 22 |
-
self.clr_th = 2.5
|
| 23 |
self.device = 'cuda:0'
|
| 24 |
|
| 25 |
-
def process_vertices(self):
|
| 26 |
-
human_entry = self.human_entry
|
| 27 |
-
col_cams = [hoho.Rt_to_eye_target(human_entry['ade20k'][0], to_K(*human_entry['cameras'][1].params), quaternion_to_rotation_matrix(colmap_img.qvec), colmap_img.tvec) for colmap_img in human_entry['images'].values()]
|
| 28 |
-
eye, target, up, fov = col_cams[0]
|
| 29 |
-
|
| 30 |
-
cameras, images, points3D = human_entry['cameras'], human_entry['images'], human_entry['points3d']
|
| 31 |
-
colmap_cameras_tf = list(human_entry['images'].keys())
|
| 32 |
-
xyz = np.stack([p.xyz for p in points3D.values()])
|
| 33 |
-
color = np.stack([p.rgb for p in points3D.values()])
|
| 34 |
-
|
| 35 |
-
gestalt_camcet = np.stack([eye for eye, target, up, fov in itertools.starmap(hoho.Rt_to_eye_target, zip(*[human_entry[k] for k in 'ade20k K R t'.split()]))])
|
| 36 |
-
col_camcet = np.stack([eye for eye, target, up, fov in col_cams])
|
| 37 |
-
gestalt_to_colmap_cams = [colmap_cameras_tf[np.argmin(((gcam - col_camcet)**2).sum(1)**0.5)] for gcam in gestalt_camcet]
|
| 38 |
-
broken_cams = np.array([np.min(((gcam - col_camcet)**2).sum(1)**0.5) for gcam in gestalt_camcet]) > 300
|
| 39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
N = len(gestalt_to_colmap_cams)
|
| 44 |
-
K = to_K(*human_entry['cameras'][1].params)[None].repeat(N, 0)
|
| 45 |
-
R = np.stack([quaternion_to_rotation_matrix(human_entry['images'][gestalt_to_colmap_cams[ind]].qvec) for ind in range(N)])
|
| 46 |
-
T = np.stack([human_entry['images'][gestalt_to_colmap_cams[ind]].tvec for ind in range(N)])
|
| 47 |
-
|
| 48 |
-
R = np.linalg.inv(R)
|
| 49 |
-
image_size = torch.Tensor([height, width]).repeat(N, 1)
|
| 50 |
-
pyt_cameras = PerspectiveCameras(device=self.device, R=R, T=T, in_ndc=False, focal_length=K[:, 0, :1], principal_point=K[:, :2, 2], image_size=image_size)
|
| 51 |
-
|
| 52 |
-
verts = torch.from_numpy(xyz.astype(np.float32)).to(self.device)
|
| 53 |
-
|
| 54 |
-
apex_color = np.array(gestalt_color_mapping['apex'])
|
| 55 |
-
eave_end_color = np.array(gestalt_color_mapping['eave_end_point'])
|
| 56 |
-
|
| 57 |
-
dist_points = np.zeros((xyz.shape[0], ))
|
| 58 |
-
visible_counts = np.zeros((xyz.shape[0], ), dtype=int)
|
| 59 |
proj_uv = []
|
| 60 |
-
for ki in range(
|
| 61 |
-
if broken_cams[ki]:
|
| 62 |
proj_uv.append(([], []))
|
| 63 |
continue
|
| 64 |
-
cki = gestalt_to_colmap_cams[ki]
|
| 65 |
|
| 66 |
-
gest =
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
|
|
|
| 70 |
vert_mask = (vert_mask > 0).astype(np.uint8)
|
| 71 |
|
| 72 |
dist = cv2.distanceTransform(1-vert_mask, cv2.DIST_L2, 3)
|
|
@@ -74,11 +47,9 @@ class GeomSolver(object):
|
|
| 74 |
ndist = np.zeros_like(dist)
|
| 75 |
ndist = cv2.normalize(dist, ndist, 0, 1.0, cv2.NORM_MINMAX)
|
| 76 |
|
| 77 |
-
in_this_image = np.array([cki in p.image_ids for p in points3D.values()])
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
uv = torch.round(pyt_cameras[ki].transform_points(verts)[:, :2]).cpu().numpy().astype(int)
|
| 81 |
-
uv_inl = (uv[:, 0] >= 0) * (uv[:, 1] >= 0) * (uv[:, 0] < width) * (uv[:, 1] < height) * in_this_image
|
| 82 |
proj_uv.append((uv, uv_inl))
|
| 83 |
uv = uv[uv_inl]
|
| 84 |
|
|
@@ -88,17 +59,17 @@ class GeomSolver(object):
|
|
| 88 |
selected_points = (dist_points / (visible_counts + 1e-6)) <= 10
|
| 89 |
selected_points[visible_counts < 1] = False
|
| 90 |
|
| 91 |
-
|
| 92 |
-
pnts = torch.from_numpy(xyz[selected_points].astype(np.float32))[None]
|
| 93 |
bdists, inds, nn = ball_query(pnts, pnts, K=3, radius=30)
|
| 94 |
dense_pnts = (bdists[0] > 0).sum(1) == 2
|
| 95 |
|
| 96 |
-
|
| 97 |
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 200, 0.3)
|
| 98 |
flags = cv2.KMEANS_RANDOM_CENTERS
|
| 99 |
-
centers =
|
|
|
|
|
|
|
| 100 |
for tempi in range(1, 20):
|
| 101 |
-
retval, bestLabels, temp_centers = cv2.kmeans(xyz[selected_points][dense_pnts].astype(np.float32), tempi, None, criteria, 200,flags)
|
| 102 |
cpnts = torch.from_numpy(temp_centers.astype(np.float32))[None]
|
| 103 |
bdists, inds, nn = ball_query(cpnts, cpnts, K=1, radius=100)
|
| 104 |
if bdists.max() > 0:
|
|
@@ -108,23 +79,56 @@ class GeomSolver(object):
|
|
| 108 |
if closest_nn < self.kmeans_th:
|
| 109 |
break
|
| 110 |
centers = temp_centers
|
| 111 |
-
if centers
|
| 112 |
centers = temp_centers
|
| 113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
# pyt_centers = torch.from_numpy(centers).to(device)
|
| 115 |
|
| 116 |
-
z_th = centers[:,-1].min() -
|
| 117 |
-
self.wf_center = xyz[xyz[:,-1] > z_th].mean(0)
|
| 118 |
self.wf_center[-1] = centers[:, -1].mean()
|
| 119 |
-
self.with_broken_cams = broken_cams.any()
|
| 120 |
|
| 121 |
self.vertices = centers
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
vertices = self.vertices
|
| 125 |
print("There are broken cams.")
|
| 126 |
else:
|
| 127 |
-
nvert =
|
| 128 |
# added_one = (self.min_vertices * self.wf_center - self.vertices.sum(0)) / (self.min_vertices - nvert)
|
| 129 |
added_one = self.wf_center
|
| 130 |
added = added_one[None].repeat(self.min_vertices - nvert,0)
|
|
|
|
| 1 |
import numpy as np
|
| 2 |
from pytorch3d.ops import ball_query
|
| 3 |
from helpers import *
|
| 4 |
+
from handcrafted_solution import convert_entry_to_human_readable
|
| 5 |
+
import cv2
|
| 6 |
import hoho
|
| 7 |
import itertools
|
| 8 |
import torch
|
| 9 |
from pytorch3d.renderer import PerspectiveCameras
|
| 10 |
+
from hoho.color_mappings import gestalt_color_mapping
|
| 11 |
|
| 12 |
def my_empty_solution():
|
|
|
|
|
|
|
| 13 |
return np.zeros((18,3)), [(0, 0)]
|
| 14 |
|
| 15 |
|
|
|
|
| 18 |
def __init__(self):
|
| 19 |
self.min_vertices = 18
|
| 20 |
self.kmeans_th = 150
|
|
|
|
| 21 |
self.device = 'cuda:0'
|
| 22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
+
def cluster_points(self, point_types, clr_th = 2.5):
|
| 25 |
+
point_colors = []
|
| 26 |
+
for point_type in point_types:
|
| 27 |
+
point_colors.append(np.array(gestalt_color_mapping[point_type]))
|
| 28 |
|
| 29 |
+
dist_points = np.zeros((self.verts.shape[0], ))
|
| 30 |
+
visible_counts = np.zeros((self.verts.shape[0], ), dtype=int)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
proj_uv = []
|
| 32 |
+
for ki in range(len(self.gestalt_to_colmap_cams)):
|
| 33 |
+
if self.broken_cams[ki]:
|
| 34 |
proj_uv.append(([], []))
|
| 35 |
continue
|
| 36 |
+
cki = self.gestalt_to_colmap_cams[ki]
|
| 37 |
|
| 38 |
+
gest = self.gests[ki]
|
| 39 |
+
vert_mask = 0
|
| 40 |
+
for point_color in point_colors:
|
| 41 |
+
my_mask = cv2.inRange(gest, point_color-clr_th, point_color+clr_th)
|
| 42 |
+
vert_mask = vert_mask + my_mask
|
| 43 |
vert_mask = (vert_mask > 0).astype(np.uint8)
|
| 44 |
|
| 45 |
dist = cv2.distanceTransform(1-vert_mask, cv2.DIST_L2, 3)
|
|
|
|
| 47 |
ndist = np.zeros_like(dist)
|
| 48 |
ndist = cv2.normalize(dist, ndist, 0, 1.0, cv2.NORM_MINMAX)
|
| 49 |
|
| 50 |
+
in_this_image = np.array([cki in p.image_ids for p in self.points3D.values()])
|
| 51 |
+
uv = torch.round(self.pyt_cameras[ki].transform_points(self.verts)[:, :2]).cpu().numpy().astype(int)
|
| 52 |
+
uv_inl = (uv[:, 0] >= 0) * (uv[:, 1] >= 0) * (uv[:, 0] < self.width) * (uv[:, 1] < self.height) * in_this_image
|
|
|
|
|
|
|
| 53 |
proj_uv.append((uv, uv_inl))
|
| 54 |
uv = uv[uv_inl]
|
| 55 |
|
|
|
|
| 59 |
selected_points = (dist_points / (visible_counts + 1e-6)) <= 10
|
| 60 |
selected_points[visible_counts < 1] = False
|
| 61 |
|
| 62 |
+
pnts = torch.from_numpy(self.xyz[selected_points].astype(np.float32))[None]
|
|
|
|
| 63 |
bdists, inds, nn = ball_query(pnts, pnts, K=3, radius=30)
|
| 64 |
dense_pnts = (bdists[0] > 0).sum(1) == 2
|
| 65 |
|
|
|
|
| 66 |
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 200, 0.3)
|
| 67 |
flags = cv2.KMEANS_RANDOM_CENTERS
|
| 68 |
+
centers = np.zeros((0, 3))
|
| 69 |
+
if len(self.xyz[selected_points][dense_pnts]) == 0:
|
| 70 |
+
return centers
|
| 71 |
for tempi in range(1, 20):
|
| 72 |
+
retval, bestLabels, temp_centers = cv2.kmeans(self.xyz[selected_points][dense_pnts].astype(np.float32), tempi, None, criteria, 200,flags)
|
| 73 |
cpnts = torch.from_numpy(temp_centers.astype(np.float32))[None]
|
| 74 |
bdists, inds, nn = ball_query(cpnts, cpnts, K=1, radius=100)
|
| 75 |
if bdists.max() > 0:
|
|
|
|
| 79 |
if closest_nn < self.kmeans_th:
|
| 80 |
break
|
| 81 |
centers = temp_centers
|
| 82 |
+
if centers.shape[0] == 0:
|
| 83 |
centers = temp_centers
|
| 84 |
+
|
| 85 |
+
return centers
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def process_vertices(self):
|
| 89 |
+
human_entry = self.human_entry
|
| 90 |
+
col_cams = [hoho.Rt_to_eye_target(human_entry['ade20k'][0], to_K(*human_entry['cameras'][1].params), quaternion_to_rotation_matrix(colmap_img.qvec), colmap_img.tvec) for colmap_img in human_entry['images'].values()]
|
| 91 |
+
eye, target, up, fov = col_cams[0]
|
| 92 |
+
|
| 93 |
+
cameras, images, self.points3D = human_entry['cameras'], human_entry['images'], human_entry['points3d']
|
| 94 |
+
colmap_cameras_tf = list(human_entry['images'].keys())
|
| 95 |
+
self.xyz = np.stack([p.xyz for p in self.points3D.values()])
|
| 96 |
+
color = np.stack([p.rgb for p in self.points3D.values()])
|
| 97 |
+
self.gests = [np.array(gest0) for gest0 in human_entry['gestalt']]
|
| 98 |
+
|
| 99 |
+
gestalt_camcet = np.stack([eye for eye, target, up, fov in itertools.starmap(hoho.Rt_to_eye_target, zip(*[human_entry[k] for k in 'ade20k K R t'.split()]))])
|
| 100 |
+
col_camcet = np.stack([eye for eye, target, up, fov in col_cams])
|
| 101 |
+
self.gestalt_to_colmap_cams = [colmap_cameras_tf[np.argmin(((gcam - col_camcet)**2).sum(1)**0.5)] for gcam in gestalt_camcet]
|
| 102 |
+
self.broken_cams = np.array([np.min(((gcam - col_camcet)**2).sum(1)**0.5) for gcam in gestalt_camcet]) > 300
|
| 103 |
+
|
| 104 |
+
self.height, self.width = cameras[1].height, cameras[1].width
|
| 105 |
+
N = len(self.gestalt_to_colmap_cams)
|
| 106 |
+
K = to_K(*human_entry['cameras'][1].params)[None].repeat(N, 0)
|
| 107 |
+
R = np.stack([quaternion_to_rotation_matrix(human_entry['images'][self.gestalt_to_colmap_cams[ind]].qvec) for ind in range(N)])
|
| 108 |
+
T = np.stack([human_entry['images'][self.gestalt_to_colmap_cams[ind]].tvec for ind in range(N)])
|
| 109 |
+
|
| 110 |
+
R = np.linalg.inv(R)
|
| 111 |
+
image_size = torch.Tensor([self.height, self.width]).repeat(N, 1)
|
| 112 |
+
self.pyt_cameras = PerspectiveCameras(device=self.device, R=R, T=T, in_ndc=False, focal_length=K[:, 0, :1], principal_point=K[:, :2, 2], image_size=image_size)
|
| 113 |
+
self.verts = torch.from_numpy(self.xyz.astype(np.float32)).to(self.device)
|
| 114 |
+
|
| 115 |
+
centers_apex = self.cluster_points(['apex'])
|
| 116 |
+
centers_eave = self.cluster_points(['eave_end_point'])
|
| 117 |
+
centers = np.concatenate((centers_apex, centers_eave))
|
| 118 |
+
|
| 119 |
+
# image_ids = np.array([p.id for p in self.points3D.values()])
|
| 120 |
# pyt_centers = torch.from_numpy(centers).to(device)
|
| 121 |
|
| 122 |
+
z_th = centers[:,-1].min() - 50
|
| 123 |
+
self.wf_center = self.xyz[self.xyz[:,-1] > z_th].mean(0)
|
| 124 |
self.wf_center[-1] = centers[:, -1].mean()
|
|
|
|
| 125 |
|
| 126 |
self.vertices = centers
|
| 127 |
+
if self.broken_cams.any():
|
| 128 |
+
vertices = centers
|
|
|
|
| 129 |
print("There are broken cams.")
|
| 130 |
else:
|
| 131 |
+
nvert = centers.shape[0]
|
| 132 |
# added_one = (self.min_vertices * self.wf_center - self.vertices.sum(0)) / (self.min_vertices - nvert)
|
| 133 |
added_one = self.wf_center
|
| 134 |
added = added_one[None].repeat(self.min_vertices - nvert,0)
|
helpers.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
| 1 |
import numpy as np
|
| 2 |
from PIL import Image as PImage
|
| 3 |
import io
|
|
|
|
|
|
|
| 4 |
|
| 5 |
|
| 6 |
def to_K(f, cx, cy):
|
|
@@ -21,9 +23,6 @@ def quaternion_to_rotation_matrix(qvec):
|
|
| 21 |
return R
|
| 22 |
|
| 23 |
|
| 24 |
-
from scipy.spatial.distance import cdist
|
| 25 |
-
from scipy.optimize import linear_sum_assignment
|
| 26 |
-
|
| 27 |
def preregister_mean_std(verts_to_transform, target_verts, single_scale=True):
|
| 28 |
mu_target = target_verts.mean(axis=0)
|
| 29 |
mu_in = verts_to_transform.mean(axis=0)
|
|
|
|
| 1 |
import numpy as np
|
| 2 |
from PIL import Image as PImage
|
| 3 |
import io
|
| 4 |
+
from scipy.spatial.distance import cdist
|
| 5 |
+
from scipy.optimize import linear_sum_assignment
|
| 6 |
|
| 7 |
|
| 8 |
def to_K(f, cx, cy):
|
|
|
|
| 23 |
return R
|
| 24 |
|
| 25 |
|
|
|
|
|
|
|
|
|
|
| 26 |
def preregister_mean_std(verts_to_transform, target_verts, single_scale=True):
|
| 27 |
mu_target = target_verts.mean(axis=0)
|
| 28 |
mu_in = verts_to_transform.mean(axis=0)
|
my_solution.py
CHANGED
|
@@ -39,6 +39,7 @@ def predict(entry, visualize=False) -> Tuple[np.ndarray, List[int]]:
|
|
| 39 |
vertices = GeomSolver().solve(entry)
|
| 40 |
edges = edges0
|
| 41 |
except:
|
|
|
|
| 42 |
vertices, edges = vertices0, edges0
|
| 43 |
|
| 44 |
if vertices.shape[0] < vertices0.shape[0]:
|
|
@@ -46,11 +47,6 @@ def predict(entry, visualize=False) -> Tuple[np.ndarray, List[int]]:
|
|
| 46 |
verts_new[:vertices.shape[0]] = vertices
|
| 47 |
vertices = verts_new
|
| 48 |
|
| 49 |
-
# if len(vertices) == 1:
|
| 50 |
-
# # print("Added one more vertex")
|
| 51 |
-
# vertices = np.concatenate((vertices, np.zeros((1,3))))
|
| 52 |
-
# edges = [(0,0)]
|
| 53 |
-
|
| 54 |
if (len(edges) < 1) and (len(vertices) >= 2):
|
| 55 |
# print("Added only edges")
|
| 56 |
edges = edges0
|
|
|
|
| 39 |
vertices = GeomSolver().solve(entry)
|
| 40 |
edges = edges0
|
| 41 |
except:
|
| 42 |
+
print('ERROR')
|
| 43 |
vertices, edges = vertices0, edges0
|
| 44 |
|
| 45 |
if vertices.shape[0] < vertices0.shape[0]:
|
|
|
|
| 47 |
verts_new[:vertices.shape[0]] = vertices
|
| 48 |
vertices = verts_new
|
| 49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
if (len(edges) < 1) and (len(vertices) >= 2):
|
| 51 |
# print("Added only edges")
|
| 52 |
edges = edges0
|
testing.ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|