- Added a proposal for depth surface strip cleanup, detailing the rationale and changes to the depth plane and cutout nodes. - Created specifications for the new cleanup requirements, including scenarios for strip removal and boundary edge detection. - Developed tasks for implementing shared strip detection logic and integrating new interfaces for depth nodes. - Established a new CLI structure for organizing node groups and model commands, replacing old entry points with a more intuitive command structure. - Introduced a prototype for panorama surface generation, including requirements for distance reconstruction and geometry node surfaces. - Added comprehensive tests for depth strip cleanup functionality, ensuring correct behavior for various mesh topologies and edge cases.
94 lines
3.7 KiB
Python
94 lines
3.7 KiB
Python
"""Behavior checks with independent spherical and room geometry references."""
|
|
|
|
import numpy as np
|
|
|
|
from geometry import (camera_bases, merge_distances, panorama_directions,
|
|
room_reference, sample_panorama, view_rays)
|
|
from prototype import fixed_fov_distance
|
|
|
|
|
|
def test_fixed_fov_recovers_shift_and_metric_distance():
|
|
rays = view_rays(64)
|
|
depth = 2 + 0.3 * rays[..., 0]
|
|
points = rays * depth[..., None]
|
|
points[..., 2] -= 0.7
|
|
distance, mask = fixed_fov_distance(points, np.ones((64, 64)), 1.5)
|
|
np.testing.assert_allclose(distance, depth * np.linalg.norm(rays, axis=-1) * 1.5, rtol=1e-5)
|
|
assert mask.all()
|
|
|
|
|
|
def test_longitude_sampling_wraps_without_a_seam():
|
|
directions = panorama_directions(256, 128)
|
|
image = 2 + directions[..., 0]
|
|
rays = np.array(((1, 1e-8, 0), (1, -1e-8, 0)))
|
|
sampled = sample_panorama(image, rays)
|
|
np.testing.assert_allclose(sampled[0], sampled[1], atol=1e-6)
|
|
np.testing.assert_allclose(sampled, 3, atol=0.001)
|
|
|
|
|
|
def test_fusion_removes_per_view_scale_offsets():
|
|
bases = camera_bases()
|
|
scales = np.exp(np.linspace(-0.4, 0.4, 12))
|
|
distances = []
|
|
for scale, basis in zip(scales, bases):
|
|
rays = view_rays(128) @ basis
|
|
rays /= np.linalg.norm(rays, axis=-1, keepdims=True)
|
|
distances.append((3 + 0.4 * rays[..., 0] + 0.2 * rays[..., 2]) * scale)
|
|
merged, mask = merge_distances(distances, np.ones((12, 128, 128), bool), bases, 64, 32)
|
|
rays = panorama_directions(64, 32)
|
|
expected = 3 + 0.4 * rays[..., 0] + 0.2 * rays[..., 2]
|
|
merged *= np.median(expected / merged)
|
|
assert mask.all()
|
|
assert np.mean(np.abs(merged / expected - 1)) < 0.002
|
|
assert np.max(np.abs(merged[:, [0, -1]] / expected[:, [0, -1]] - 1)) < 0.005
|
|
|
|
|
|
def test_room_distance_lands_on_floor():
|
|
rays = np.array(((0.0, 0.0, -1.0), (0.2, -0.3, -1.0)))
|
|
rays /= np.linalg.norm(rays, axis=-1, keepdims=True)
|
|
distance, _ = room_reference(rays)
|
|
np.testing.assert_allclose((rays * distance[:, None])[:, 2], -1.6)
|
|
|
|
|
|
def test_sky_view_returns_invalid_samples():
|
|
distance, mask = fixed_fov_distance(np.ones((32, 32, 3)), np.zeros((32, 32)), 1)
|
|
assert not mask.any()
|
|
assert np.isfinite(distance).all()
|
|
|
|
|
|
def test_room_projection_fusion_preserves_geometry():
|
|
bases = camera_bases()
|
|
distances = [room_reference(view_rays(256) @ basis)[0] for basis in bases]
|
|
merged, mask = merge_distances(distances, np.ones((12, 256, 256), bool), bases, 128, 64)
|
|
expected, _ = room_reference(panorama_directions(128, 64))
|
|
assert mask.all()
|
|
assert np.mean(np.abs(merged / expected - 1)) < 0.005
|
|
|
|
|
|
def test_input_alpha_survives_panorama_export(tmp_path, monkeypatch):
|
|
from PIL import Image
|
|
from prototype import main
|
|
|
|
rgba = np.full((16, 32, 4), 255, dtype=np.uint8)
|
|
rgba[:, :16, 3] = 0
|
|
source = tmp_path / "source.png"
|
|
destination = tmp_path / "result"
|
|
Image.fromarray(rgba).save(source)
|
|
monkeypatch.setattr("sys.argv", ["prototype", "--image", str(source), "--output", str(destination),
|
|
"--reference-only", "--size", "32", "--width", "32"])
|
|
main()
|
|
with Image.open(destination / "panorama.png") as exported:
|
|
np.testing.assert_array_equal(np.asarray(exported)[..., 3], rgba[..., 3])
|
|
with np.load(destination / "prediction.npz") as data:
|
|
assert np.all(data["alpha"][:, :16] == 0)
|
|
assert np.any(data["alpha"][:, 16:] > 0)
|
|
|
|
|
|
def test_depth_alpha_combines_mask_and_source_alpha_once():
|
|
from prototype import depth_alpha
|
|
|
|
image = np.ones((2, 4, 4), dtype=np.float32)
|
|
image[..., 3] = (0, 0.5, 0.75, 1)
|
|
mask = np.full((2, 4), 0.5, dtype=np.float32)
|
|
np.testing.assert_allclose(depth_alpha(image, mask), np.tile((0, 0.25, 0.375, 0.5), (2, 1)))
|