Weakly-Supervised-3DOD / ProposalNetwork /utils /visualise_random_rotation.py
AndreasLH's picture
upload repo
56bd2b5
import matplotlib.pyplot as plt
import numpy as np
import torch
from cubercnn import util
# From this awesome guy
# https://math.stackexchange.com/a/4832876
# https://math.stackexchange.com/questions/442418/random-generation-of-rotation-matrices/1602779#1602779
# http://home.lu.lv/~sd20008/papers/essays/Random%20unitary%20[paper].pdf
# https://github.com/alecjacobson/gptoolbox/blob/master/matrix/rand_rotation.m
def qr_full(num_samples=1):
z = np.random.randn(num_samples, 3, 3)
q, r = np.linalg.qr(z)
sign = 2 * (np.diagonal(r, axis1=-2, axis2=-1) >= 0) - 1
rot = q
rot *= sign[..., None, :]
rot[:, 0, :] *= np.linalg.det(rot)[..., None]
return rot
def qr_full_torch(num_samples=1):
z = torch.randn(num_samples, 3, 3)
q, r = torch.linalg.qr(z)
sign = 2 * (torch.diagonal(r, dim1=-2, dim2=-1) >= 0) - 1
rot = q
rot *= sign[..., None, :]
rot[:, 0, :] *= torch.linalg.det(rot)[..., None]
return rot
def randn_orthobasis_torch(num_samples=1):
z = torch.randn(num_samples, 3, 3)
z = z / torch.norm(z, p=2, dim=-1, keepdim=True)
z[:, 0] = torch.cross(z[:, 1], z[:, 2], dim=-1)
z[:, 0] = z[:, 0] / torch.norm(z[:, 0], dim=-1, keepdim=True)
z[:, 1] = torch.cross(z[:, 2], z[:, 0], dim=-1)
z[:, 1] = z[:, 1] / torch.norm(z[:, 1], dim=-1, keepdim=True)
return z
# https://math.stackexchange.com/questions/442418/random-generation-of-rotation-matrices/1288873#1288873
# https://math.stackexchange.com/questions/44689/how-to-find-a-random-axis-or-unit-vector-in-3d/44701#44701
def randn_orthobasis(num_samples=1):
z = np.random.randn(num_samples, 3, 3)
z = z / np.linalg.norm(z, axis=-1, keepdims=True)
z[:, 0] = np.cross(z[:, 1], z[:, 2], axis=-1)
z[:, 0] = z[:, 0] / np.linalg.norm(z[:, 0], axis=-1, keepdims=True)
z[:, 1] = np.cross(z[:, 2], z[:, 0], axis=-1)
z[:, 1] = z[:, 1] / np.linalg.norm(z[:, 1], axis=-1, keepdims=True)
return z
# https://math.stackexchange.com/questions/442418/random-generation-of-rotation-matrices/4394036#4394036
# https://math.stackexchange.com/questions/44689/how-to-find-a-random-axis-or-unit-vector-in-3d/44701#44701
def randn_axis(num_samples=1, corrected=True):
u = np.random.uniform(0, 1, size=num_samples)
z = np.random.randn(num_samples, 1, 3)
z = z / np.linalg.norm(z, axis=-1, keepdims=True)
if corrected:
t = np.linspace(0, np.pi, 1024)
cdf_psi = (t - np.sin(t)) / np.pi
psi = np.interp(u, cdf_psi, t, left=0, right=np.pi)
else:
psi = 2 * np.pi * u
return rot3x3_from_axis_angle(z, psi)
# https://math.stackexchange.com/questions/442418/random-generation-of-rotation-matrices/442423#442423
# https://math.stackexchange.com/questions/44689/how-to-find-a-random-axis-or-unit-vector-in-3d/44691#44691
def nbubis(num_samples=1, corrected=True):
u1 = np.random.uniform(0, 1, size=num_samples)
u2 = np.random.uniform(0, 1, size=num_samples)
u3 = np.random.uniform(0, 1, size=num_samples)
theta = np.arccos(2 * u1 - 1)
phi = 2 * np.pi * u2
axis_vector = [
np.sin(theta) * np.cos(phi),
np.sin(theta) * np.sin(phi),
np.cos(theta),
]
axis_vector = np.stack(axis_vector, axis=1).reshape(-1, 1, 3)
if corrected:
t = np.linspace(0, np.pi, 1024)
cdf_psi = (t - np.sin(t)) / np.pi
psi = np.interp(u3, cdf_psi, t, left=0, right=np.pi)
else:
psi = 2 * np.pi * u3
return rot3x3_from_axis_angle(axis_vector, psi)
# https://math.stackexchange.com/questions/442418/random-generation-of-rotation-matrices/1602779#1602779
def qr_half(num_samples=1):
z = np.random.randn(num_samples, 3, 3)
q, r = np.linalg.qr(z)
return q
def euler_angles(num_samples=1):
rx = np.random.rand(num_samples) * np.pi - np.pi/2
ry = np.random.rand(num_samples) * np.pi - np.pi/2
rz = np.random.rand(num_samples) * np.pi - np.pi/2
# loop over all
rotation_matrix = np.array([util.euler2mat([x,y,z]) for x, y, z in zip(rx,ry,rz)])
return rotation_matrix
# https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula#Matrix_notation
def rot3x3_from_axis_angle(axis_vector, angle):
angle = np.atleast_1d(angle)[..., None, None]
K = np.cross(np.eye(3), axis_vector)
return np.eye(3) + np.sin(angle) * K + (1 - np.cos(angle)) * (K @ K)
def plot_scatter(pointses, filename, kwargses):
fig = plt.figure()
ax = fig.add_subplot(projection="3d", computed_zorder=False)
for points, kwargs in zip(pointses, kwargses):
ax.scatter(*np.asarray(points).T, marker=".", **kwargs)
ax.view_init(elev=15, azim=41, roll=0)
ax.set(xlim=(-1, 1), ylim=(-1, 1), zlim=(-1, 1))
ax.set_aspect("equal", adjustable="box")
ax.set_title(filename)
fig.savefig('ProposalNetwork/output/random_rotation/rot3x3_'+filename+'.png', dpi=300, bbox_inches="tight", pad_inches=0)
# plt.show()
# exit()
plt.close(fig)
METHODS = {
"randn_orthobasis_torch": randn_orthobasis_torch,
"qr_full_torch": qr_full_torch,
"euler": euler_angles,
"randn_orthobasis": randn_orthobasis,
"randn_axis": randn_axis,
"randn_axis_incorrect": lambda **kwargs: randn_axis(corrected=False, **kwargs),
"nbubis": nbubis,
"nbubis_incorrect": lambda **kwargs: nbubis(corrected=False, **kwargs),
"qr_half": qr_half,
"qr_full": qr_full,
}
import time
import os
os.makedirs('ProposalNetwork/output/random_rotation',exist_ok=True)
# x is the starting point; y contains various sample rotated points.
# x = np.array([1.0, 0.0, 0.0])
x = np.array([1 / 9, -4 / 9, 8 / 9], dtype=np.float32)
x /= np.linalg.norm(x) # Normalize to unit vector, just in case.
for name, func in METHODS.items():
t1 = time.perf_counter()
rot = func(num_samples=5000 // (2 if "_half" in name else 1))
t2 = time.perf_counter()
print(f'{name}\t\t\t Time: {t2-t1:.4f}')
if 'torch' in name:
y = rot @ torch.from_numpy(x)
else:
y = rot @ x
plot_scatter(
[y, [x]],
f"{name}",
[{"s": 1, "alpha": 0.5}, {"s": 64, "color": "#ff77cc"}],
)