File size: 3,882 Bytes
19a1abb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
import numpy as np
from numpy import sin, cos
from math import pi as π
from my3d import camera_pose
from my.config import BaseConf
def get_K(H, W, FoV_x):
FoV_x = FoV_x / 180 * π # to rad
f = 1 / np.tan(FoV_x / 2) * (W / 2)
K = np.array([
[f, 0, -(W/2 - 0.5)],
[0, -f, -(H/2 - 0.5)],
[0, 0, -1]
])
return K
SIDEVIEW_PROMPTS = [
"front view of", "side view of", "backside view of", "side view of"
]
TOPVIEW_PROMPT = "overhead view of"
def train_eye_with_prompts(r, n):
hs = np.random.rand(n) * 360
vs = np.random.rand(n) * np.deg2rad(100)
vs = np.clip(vs, 1e-2, π-1e-2)
prompts = []
v_thresh = np.deg2rad(30)
for i in range(n):
_p = ""
if vs[i] < v_thresh:
_p = TOPVIEW_PROMPT
else:
_a = hs[i]
_a = (_a + 45) % 360
_quad = int(_a // 90)
_p = SIDEVIEW_PROMPTS[_quad]
prompts.append(_p)
θ = np.deg2rad(hs)
# φ = v
φ = np.arccos(1 - 2 * (vs / π))
horz = hs
elev = np.rad2deg(π / 2 - φ)
eyes = np.zeros((n, 3))
eyes[:, 0] = r * sin(φ) * cos(π-θ) # x
eyes[:, 2] = r * sin(φ) * sin(π-θ) # z
eyes[:, 1] = r * cos(φ) # y
return eyes, prompts, horz, elev
def spiral_poses(
radius, height,
num_steps=20, num_rounds=1,
center=np.array([0, 0, 0]), up=np.array([0, 1, 0]),
):
eyes = []
for i in range(num_steps):
ratio = (i + 1) / num_steps
Δz = height * (1 - ratio)
θ = ratio * (360 * num_rounds)
θ = θ / 180 * π
# _r = max(radius * ratio, 0.5)
_r = max(radius * sin(ratio * π / 2), 0.5)
Δx, Δy = _r * np.array([np.cos(θ), np.sin(θ)])
eyes.append(center + [Δx, Δz, Δy])
poses = [
camera_pose(e, center - e, up) for e in eyes
]
return poses
def circular_poses(
radius, height,
num_steps=36, num_rounds=1,
center=np.array([0, 0, 0]), up=np.array([0, 1, 0]),
):
eyes = []
horz = []
for i in range(num_steps):
ratio = (i + 1) / num_steps
Δz = radius * (np.cos(np.deg2rad(60)))
θ = ratio * (360 * num_rounds)
θ = θ / 180 * π
# _r = max(radius * ratio, 0.5)
_r = max(radius * sin(ratio * π / 2), 0.5)
Δx, Δy = radius * np.array([np.sin(np.deg2rad(60))*np.cos(θ), np.sin(np.deg2rad(60))*np.sin(θ)])
eyes.append(center + [Δx, Δz, Δy])
horz.append(np.rad2deg(θ))
poses = [
camera_pose(e, center - e, up) for e in eyes
]
horz=np.array(horz)
return poses
class PoseConfig(BaseConf):
rend_hw: int = 64
FoV: float = 60.0
R: float = 1.5
def make(self):
cfgs = self.dict()
hw = cfgs.pop("rend_hw")
cfgs["H"] = hw
cfgs["W"] = hw
return Poser(**cfgs)
class Poser():
def __init__(self, H, W, FoV, R):
self.H, self.W = H, W
self.R = R
self.K = get_K(H, W, FoV)
self.FoV = FoV
def sample_train(self, n, device):
eyes, prompts, horz, elev = train_eye_with_prompts(r=self.R, n=n)
up = np.array([0, 1, 0])
poses = [
camera_pose(e, -e, up) for e in eyes
]
poses = np.stack(poses, 0)
FoV = np.random.rand(n) * 30 + 40
random_Ks = [
get_K(self.H, self.W, FoV[i])
for i in range(len(poses))
]
angles_list = []
for horizontal, elevation, fov in zip(horz, elev, FoV):
angles_list.append([horizontal, elevation, fov])
return random_Ks, poses, prompts, angles_list
def sample_test(self, n):
poses = circular_poses(self.R, self.R, n, num_rounds=3)
poses = np.stack(poses, axis=0)
return self.K, poses |