z2p / render_util.py
galmetzer's picture
app
cd438c2
import torch
import numpy as np
import math
import cv2
world_mat_object = torch.tensor([
[0.5085, 0.3226, 0.7984, 0.0000],
[-0.3479, 0.9251, -0.1522, 0.0000],
[-0.7877, -0.2003, 0.5826, 0.3384],
[0.0000, 0.0000, 0.0000, 1.0000]
])
world_mat_inv = torch.tensor([
[0.4019, 0.9157, 0.0000, 0.3359],
[-0.1932, 0.0848, 0.9775, -1.0227],
[0.8951, -0.3928, 0.2110, -7.0748],
[-0.0000, 0.0000, -0.0000, 1.0000]
])
proj = torch.tensor([
[2.1875, 0.0000, 0.0000, 0.0000],
[0.0000, 3.8889, 0.0000, 0.0000],
[0.0000, 0.0000, -1.0020, -0.2002],
[0.0000, 0.0000, -1.0000, 0.0000]
])
RANGES = [[0, 540], [100, 960]]
TARGET = [500, -1]
def resize(img):
if TARGET[1] == -1:
r = img.shape[0] / img.shape[1]
img = cv2.resize(img, (TARGET[0], int(r * TARGET[0])))
else:
img = cv2.resize(img, (TARGET[0], TARGET[1]))
return img
def scatter(u_pix, v_pix, distances, res, radius=5):
distances -= 6
img = np.zeros(res)
for (u, v, d) in zip(u_pix, v_pix, distances):
v, u = int(v), int(u)
f = np.exp(-d / 0.7)
if radius == 0:
img[v, u] = max(img[v, u], f)
else:
for t1 in range(-radius, radius):
for t2 in range(-radius, radius):
ty, tx = v - t1, u - t2
ty, tx = max(0, ty), max(0, tx)
ty, tx = min(res[0] - 1, ty), min(res[1] - 1, tx)
img[ty, tx] = max(img[ty, tx], f)
return img
def generate_roation(phi_x, phi_y, phi_z):
def Rx(theta):
return torch.tensor([[1, 0, 0],
[0, math.cos(theta), -math.sin(theta)],
[0, math.sin(theta), math.cos(theta)]])
def Ry(theta):
return torch.tensor([[math.cos(theta), 0, math.sin(theta)],
[0, 1, 0],
[-math.sin(theta), 0, math.cos(theta)]])
def Rz(theta):
return torch.tensor([[math.cos(theta), -math.sin(theta), 0],
[math.sin(theta), math.cos(theta), 0],
[0, 0, 1]])
return Rz(phi_z) @ Ry(phi_y) @ Rx(phi_x)
def rotate_pc(pc, rx, ry, rz):
rotation = generate_roation(rx, ry, rz)
rotated = pc.clone()
rotated[:, :3] = rotated[:, :3] @ rotation.T
if rotated.shape[-1] == 6:
rotated[:, 3:] = rotated[:, 3:] @ rotation.T
return rotated
def draw_pc(pc: torch.Tensor, res=(540, 960), radius=5, timer=None, dy=0, scale=1):
xyz = pc[:, :3]
xyz -= xyz.mean(dim=0)
t_scale = xyz.norm(dim=-1).max()
xyz /= t_scale
xyz *= scale
xyz[:, -1] += xyz[:, -1].min()
n, _ = xyz.shape
if timer is not None:
with timer('project'):
xyz_pad = torch.cat([xyz, torch.ones_like(pc[:, :1])], dim=-1)
xyz_local = xyz_pad @ world_mat_inv.T
distances = -xyz_local[:, 2]
projected = xyz_local @ proj.T
projected = projected / projected[:, 3:4]
projected = projected[:, :3]
u_pix = ((projected[0] + 1) / 2) * res[1]
v_pix = ((projected[1] + 1) / 2) * res[0] + dy
with timer('z-buffer'):
z_buffer = scatter(u_pix, v_pix, distances, res, radius=radius)[:, :]
else:
xyz_pad = torch.cat([xyz, torch.ones_like(pc[:, :1])], dim=-1)
xyz_local = xyz_pad @ world_mat_inv.T
distances = -xyz_local[:, 2]
projected = xyz_local @ proj.T
projected = projected / projected[:, 3:4]
projected = projected[:, :3]
u_pix = ((projected[:, 0] + 1) / 2) * res[1]
v_pix = ((projected[:, 1] + 1) / 2) * res[0] + dy
z_buffer = scatter(u_pix, v_pix, distances, res, radius=radius)[:, :]
z_buffer = z_buffer[RANGES[0][0]: RANGES[0][1], :]
z_buffer = z_buffer[:, RANGES[1][0]:RANGES[1][1]]
z_buffer = resize(z_buffer)
return z_buffer