4
0
mirror of https://github.com/nerfstudio-project/nerfstudio.git synced 2026-11-11 02:24:38 +08:00
nerfstudio/tests/utils/test_aabb_intersection.py
dozeri83 2120bd5dd9
CropBox GUI implementation (#1205)
* fixed an exception bug in case of num_samples is 0

fixed an exception bug when num samples is 0 , 
"IndexError tensors used as indices must be long, byte or bool tensors"

change type to long ( was float32)

* implemented crop box in gui. For now works on instant-ngp-bounded

* fixed import bugs

* update aabb every time and not only on training

* prevent crash when chosing accomulation and crop box

* Checkbox

* max_box is bounded by scevne box in the gui

* implemented altenative intesection to nerfacc

* convert str to bool correctly

* fixed isort bug

* fixed isort bug2

* update viewer version

* remove json bug

* Update UI

* Force black background

* Fix formatting

Co-authored-by: dror <you@example.com>
Co-authored-by: Matt Tancik <tancik@berkeley.edu>
Co-authored-by: Matthew Tancik <mattt4001@gmail.com>
2023-01-19 17:39:37 -08:00

179 lines
5.0 KiB
Python

"""
Test AABB intersection
"""
import importlib
import math
import os
import random
from distutils.util import strtobool
import torch
from nerfstudio.utils.math import intersect_aabb
test_device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
def _swap_minmax(x, y):
if x < y:
return x, y
return y, x
def _get_random_aabb_box(max_box, device):
"""
generate random aabb box
:param max_box:
:param device:
:return:
"""
x_min = random.uniform(-max_box, max_box)
x_max = random.uniform(-max_box, max_box)
x_min, x_max = _swap_minmax(x_min, x_max)
y_min = random.uniform(-max_box, max_box)
y_max = random.uniform(-max_box, max_box)
y_min, y_max = _swap_minmax(y_min, y_max)
z_min = random.uniform(-max_box, max_box)
z_max = random.uniform(-max_box, max_box)
z_min, z_max = _swap_minmax(z_min, z_max)
return torch.tensor([x_min, y_min, z_min, x_max, y_max, z_max], dtype=torch.float32, device=device)
def _get_random_rays(num_rays, max_box, aabb, device):
"""
genrate random rays that distribute in the general direction of the box.
The implementation is naive for now.
:param num_rays:
:param max_box:
:param aabb:
:param device:
:return:
"""
origins = []
directions = []
aabb_center = torch.tensor(
[0.5 * (aabb[0] + aabb[3]), 0.5 * (aabb[1] + aabb[4]), 0.5 * (aabb[2] + aabb[5])],
dtype=torch.float32,
device=device,
)
for _ in range(num_rays):
x = random.uniform(-max_box, max_box)
y = random.uniform(-max_box, max_box)
z = random.uniform(-max_box, max_box)
origin = torch.tensor([x, y, z], dtype=torch.float32, device=device)
dirs_to_cent = aabb_center - origin
dirs_to_cent = dirs_to_cent / torch.linalg.norm(dirs_to_cent)
phi = math.asin(dirs_to_cent[2])
theta = torch.atan2(dirs_to_cent[1], dirs_to_cent[0])
error_ang_phi = random.gauss(0, 0.05)
error_ang_theta = random.gauss(0, 0.1)
phi = phi + error_ang_phi
theta = theta + error_ang_theta
x_dir = math.cos(phi) * math.cos(theta)
y_dir = math.cos(phi) * math.sin(theta)
z_dir = math.sin(phi)
origins.append([x, y, z])
directions.append([x_dir, y_dir, z_dir])
origins = torch.tensor(origins, dtype=torch.float32, device=device)
directions = torch.tensor(directions, dtype=torch.float32, device=device)
return origins, directions
def _is_point_on_aabb_boundary(point, aabb):
# check
error_threshold = 0.001
for dim in range(3):
if point[dim] < (aabb[dim] - error_threshold) or point[dim] > (aabb[dim + 3] + error_threshold):
return False
# check that the points is near the boundary
for side in range(2):
for dim in range(3):
if abs(point[dim] - aabb[side * 3 + dim]) < error_threshold:
return True
return False
def _assert_points_on_aabb_boundary(points, aabb):
for point in points:
assert _is_point_on_aabb_boundary(point, aabb)
def test_rays_intersection_are_on_aabb_boundary():
"""
test that org + dir*t_min and org + dir*t_max are on aabb boundary
:return:
"""
random.seed(496)
max_box_size = 100
aabb = _get_random_aabb_box(max_box_size, test_device)
num_rays = 500
max_test_size = 1000
origins, directions = _get_random_rays(num_rays, max_test_size, aabb, test_device)
t_min, t_max = intersect_aabb(origins, directions, aabb)
mask = t_min < 1e10
t_min = t_min[mask]
t_max = t_max[mask]
origins = origins[mask]
directions = directions[mask]
# assert that we don't do something trivial
assert len(t_min) > 10
# assert that tmax is larger than t_min
assert torch.all(t_max >= t_min)
positions_min = origins + directions * t_min.view(-1, 1)
positions_max = origins + directions * t_max.view(-1, 1)
_assert_points_on_aabb_boundary(positions_min, aabb)
_assert_points_on_aabb_boundary(positions_max, aabb)
def test_equall_nerfacc():
"""
test that the output of intersect_aabb is close to nerfacc.intersect_aabb
:return:
"""
check_nerf_acc = strtobool(os.environ.get("INTERSECT_WITH_NERFACC", "FALSE"))
if check_nerf_acc:
nerfacc = importlib.import_module("nerfacc")
random.seed(8128)
max_box_size = 100
aabb = _get_random_aabb_box(max_box_size, test_device)
num_rays = 500
max_test_size = 1000
origins, directions = _get_random_rays(num_rays, max_test_size, aabb, test_device)
# time1 = time.time()
t_min, t_max = intersect_aabb(origins, directions, aabb)
# time2 = time.time()
# time3 = time.time()
t_min_nerfacc, t_max_nerfacc = nerfacc.ray_aabb_intersect(origins, directions, aabb)
# time4 = time.time()
# print("pytorch ", time2-time1)
# print("nerfacc ", time4-time3)
assert torch.allclose(t_min, t_min_nerfacc, rtol=0.001)
assert torch.allclose(t_max, t_max_nerfacc, rtol=0.001)