import numpy as np from pathlib import Path from types import SimpleNamespace from simam3d_core import ( analyze_light_field, classify_scene_hypothesis, deterministic_demo_depth, estimate_depth_light, default_intrinsics, depth_to_camera_points, fuse_point_views, fusion_metrics, gaussian_initialization, normalize_map, normalize_prediction_contract, next_view_plan, orbit_project_points, project_world_points, reprojection_consistency, prepare_intrinsics, reveal_uncertainty, synthetic_orbit_poses, write_confidence_ply, write_gaussian_ply, ) def test_light_field_detector_returns_bright_side_and_bounded_confidence(): image = np.zeros((8, 8, 3), dtype=np.uint8) image[:, 6:] = 255 result = analyze_light_field(image) assert result["bright_centroid_x"] > 0.2 assert result["detector_confidence"] >= 0.0 assert result["detector_confidence"] <= 1.0 assert "directional" in result["lighting_label"] def test_depth_light_estimate_returns_normalized_camera_direction(): depth = np.tile(np.linspace(0.0, 1.0, 8, dtype=np.float32), (8, 1)) colors = np.zeros((8, 8, 3), dtype=np.uint8) colors[:, 5:] = 255 result = estimate_depth_light(depth, colors) direction = np.array([result["light_direction_x"], result["light_direction_y"], result["light_direction_z"]]) assert np.isfinite(direction).all() assert np.isclose(np.linalg.norm(direction), 1.0) assert 0.0 <= result["photometric_confidence"] <= 1.0 def test_deterministic_demo_depth_is_shape_stable_and_explicitly_numeric(): colors = np.array([[[0, 0, 0], [255, 255, 255]]], dtype=np.uint8) depth = deterministic_demo_depth(colors) assert depth.shape == (1, 2) assert np.allclose(depth, [[255.0, 0.0]]) def test_scene_hypothesis_is_explicit_and_transparent(): result = classify_scene_hypothesis("I think a garden is behind the portrait") assert result["user_guess"].startswith("I think") assert "outdoor" in result["semantic_cues"] assert "nature" in result["semantic_cues"] assert "not verified" in result["status"] def test_reveal_uncertainty_preserves_shape_and_confidence_signal(): depth = np.tile(np.linspace(0.0, 1.0, 8, dtype=np.float32), (8, 1)) confidence = np.ones_like(depth) result = reveal_uncertainty(depth, confidence) assert result.shape == depth.shape assert np.isfinite(result).all() assert float(result.max()) <= 1.0 assert float(result.mean()) < 0.1 def test_next_view_plan_is_deterministic_and_prefers_gaps(): plan = next_view_plan(1) assert len(plan) == 5 assert plan[0]["gap_from_existing_deg"] >= plan[-1]["gap_from_existing_deg"] assert all(item["reason"] == "largest unsupported azimuth" for item in plan) def test_orbit_projection_rotates_points_without_nan(): points = np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]], dtype=np.float32) xy, depth = orbit_project_points(points, 90.0) assert xy.shape == (2, 2) assert depth.shape == (2,) assert np.isfinite(xy).all() assert np.isfinite(depth).all() assert np.all(np.abs(xy) <= 1.0) def test_prediction_contract_normalizes_single_view_and_optional_fields(): prediction = SimpleNamespace(depth=np.ones((4, 5), dtype=np.float32), conf=None) depth, confidence, extrinsics, intrinsics, confidence_source, pose_source = normalize_prediction_contract(prediction, 1) assert depth.shape == (1, 4, 5) assert confidence.shape == depth.shape assert extrinsics.shape == (1, 4, 4) assert intrinsics.shape == (1, 3, 3) assert confidence_source == "baseline_uniform" assert pose_source == "synthetic_orbit_prior" def test_prediction_contract_rejects_mismatched_confidence(): prediction = SimpleNamespace( depth=np.ones((2, 4, 5), dtype=np.float32), conf=np.ones((1, 4, 5), dtype=np.float32), ) try: normalize_prediction_contract(prediction, 2) except ValueError as exc: assert "confidence" in str(exc) else: raise AssertionError("mismatched DA3 confidence should be rejected") def test_world_projection_reports_in_frame_points(): points = np.array([[0.0, 0.0, 1.0], [2.0, 0.0, 1.0]], dtype=np.float32) pixels, depths, inside = project_world_points(points, None, None, 10, 10) assert pixels.shape == (2, 2) assert np.allclose(pixels[0], [5.0, 5.0]) assert np.isclose(depths[0], 1.0) assert inside.tolist() == [True, False] def test_reprojection_consistency_detects_self_consistent_depth(): depth = np.tile(np.linspace(0.0, 1.0, 6, dtype=np.float32), (6, 1)) points, _ = depth_to_camera_points(depth) metrics = reprojection_consistency(points, depth, None, None) assert metrics["coverage"] > 0.8 assert metrics["mean_absolute_error"] < 0.05 def test_normalize_map_handles_constant_and_nan_values(): assert np.all(normalize_map(np.ones((2, 2))) == 0) normalized = normalize_map(np.array([[np.nan, 1.0], [2.0, 3.0]], dtype=np.float32)) assert normalized.shape == (2, 2) assert np.isfinite(normalized).all() assert normalized.max() == 1.0 def test_depth_projection_has_expected_shape(): depth = np.ones((4, 5), dtype=np.float32) points, weights = depth_to_camera_points(depth, default_intrinsics(5, 4)) assert points.shape == (20, 3) assert weights.shape == (20,) assert np.isfinite(points).all() def test_relative_depth_projection_matches_exporter_convention(): depth = np.array([[0.0, 1.0]], dtype=np.float32) points, _ = depth_to_camera_points(depth) assert points[0, 2] > points[1, 2] def test_fusion_is_deterministic_and_voxel_reduces_duplicates(): depth = np.ones((3, 3), dtype=np.float32) colors = np.zeros((3, 3, 3), dtype=np.uint8) views = [(depth, np.ones_like(depth), None, None, colors), (depth, np.ones_like(depth), None, None, colors)] first = fuse_point_views(views, voxel_size=0.1) second = fuse_point_views(views, voxel_size=0.1) assert len(first.points) < 18 assert np.array_equal(first.points, second.points) assert fusion_metrics(first)["point_count"] == len(first.points) assert fusion_metrics(first)["dominant_source_view_count"] == 1 assert fusion_metrics(first)["supported_source_view_count"] == 2 assert fusion_metrics(first)["multi_view_voxel_fraction"] == 1.0 def test_extrinsics_move_camera_points_into_world_coordinates(): depth = np.ones((2, 2), dtype=np.float32) colors = np.full((2, 2, 3), 127, dtype=np.uint8) translation = np.eye(4, dtype=np.float32) translation[0, 3] = 2.0 result = fuse_point_views([(depth, None, None, translation, colors)], voxel_size=0.0) camera_points, _ = depth_to_camera_points(depth) assert np.allclose(result.points[:, 0], camera_points[:, 0] - 2.0) def test_zero_confidence_points_are_excluded(): depth = np.ones((2, 2), dtype=np.float32) colors = np.zeros((2, 2, 3), dtype=np.uint8) confidence = np.array([[1.0, 0.0], [0.0, 1.0]], dtype=np.float32) result = fuse_point_views([(depth, confidence, None, None, colors)], voxel_size=0.0) assert len(result.points) == 2 def test_constant_positive_confidence_remains_usable(): depth = np.ones((2, 2), dtype=np.float32) colors = np.zeros((2, 2, 3), dtype=np.uint8) result = fuse_point_views([(depth, np.ones_like(depth), None, None, colors)], voxel_size=0.0) assert len(result.points) == 4 assert np.all(result.weights == 1.0) def test_synthetic_orbit_poses_are_valid_and_distinct(): assert np.allclose(synthetic_orbit_poses(1)[0], np.eye(4, dtype=np.float32)) poses = synthetic_orbit_poses(4) assert poses.shape == (4, 4, 4) assert np.isfinite(poses).all() assert not np.allclose(poses[0], poses[1]) assert np.allclose(poses[:, 3, :], np.array([[0, 0, 0, 1]] * 4, dtype=np.float32)) def test_gaussian_initialization_tracks_confidence(): opacity, log_scale = gaussian_initialization(np.array([0.0, 0.5, 1.0]), 3) assert np.all(np.diff(opacity) > 0) assert np.all(np.diff(log_scale) < 0) assert np.isclose(opacity[0], 0.05) assert np.isclose(opacity[-1], 0.95) def test_voxel_fusion_uses_confidence_weighted_centroid_and_color(): depth = np.ones((1, 2), dtype=np.float32) colors = np.array([[[255, 0, 0], [0, 0, 255]]], dtype=np.uint8) intrinsics = np.array([[2.0, 0.0, -1.0], [0.0, 2.0, 0.5], [0.0, 0.0, 1.0]], dtype=np.float32) first = fuse_point_views( [(depth, np.array([[1.0, 0.5]], dtype=np.float32), intrinsics, None, colors)], voxel_size=10.0, ) assert len(first.points) == 1 assert first.colors[0, 0] > first.colors[0, 2] assert np.isclose(first.weights[0], 0.75) assert first.source_views[0] == 0 assert first.source_masks[0] == 1 assert fusion_metrics(first)["multi_view_voxel_fraction"] == 0.0 def test_confidence_ply_retains_per_point_evidence(tmp_path=None): path = Path("confidence_test.ply") try: write_confidence_ply( path, np.array([[0.0, 0.0, 1.0]], dtype=np.float32), np.array([[10, 20, 30]], dtype=np.uint8), np.array([0.75], dtype=np.float32), ) contents = path.read_text(encoding="utf-8") assert "property float confidence" in contents assert "property int source_view" in contents assert "property int source_mask" in contents assert "0 0 1 10 20 30 0.75 -1 0" in contents finally: if path.exists(): path.unlink() def test_gaussian_ply_contains_3dgs_and_evidence_fields(): path = Path("gaussian_test.ply") try: write_gaussian_ply( path, np.array([[0.0, 0.0, 1.0]], dtype=np.float32), np.array([[10, 20, 30]], dtype=np.uint8), np.array([0.75], dtype=np.float32), np.array([2], dtype=np.int32), ) contents = path.read_text(encoding="utf-8") assert "property float opacity" in contents assert "property float confidence" in contents assert "property int source_view" in contents assert "property int source_mask" in contents assert contents.rstrip().endswith("0.75 2 4") finally: if path.exists(): path.unlink() def test_normalized_intrinsics_are_converted_to_pixels(): normalized = np.array([[0.8, 0.0, 0.5], [0.0, 0.8, 0.5], [0.0, 0.0, 1.0]], dtype=np.float32) pixels = prepare_intrinsics(normalized, 100, 50) assert np.allclose(pixels, [[80, 0, 50], [0, 40, 25], [0, 0, 1]]) def test_identity_intrinsics_use_centered_default(): pixels = prepare_intrinsics(np.eye(3, dtype=np.float32), 100, 50) assert np.allclose(pixels, default_intrinsics(100, 50)) def test_multiview_demo_contract_exports_reproducible_evidence(tmp_path): depth = np.tile(np.linspace(0.1, 0.9, 12, dtype=np.float32), (10, 1)) views = [] for index, pose in enumerate(synthetic_orbit_poses(3)): colors = np.zeros((10, 12, 3), dtype=np.uint8) colors[..., index] = 180 confidence = np.full_like(depth, 1.0 - 0.15 * index) views.append((depth, confidence, None, pose, colors)) result = fuse_point_views(views, voxel_size=0.03, max_points=5000) assert len(result.points) > 0 metrics = fusion_metrics(result) assert metrics["supported_source_view_count"] == 3 confidence_path = Path("fused_integration_test.ply") gaussian_path = Path("gaussians_integration_test.ply") try: write_confidence_ply(confidence_path, result.points, result.colors, result.weights, result.source_views, result.source_masks) write_gaussian_ply(gaussian_path, result.points, result.colors, result.weights, result.source_views, result.source_masks) confidence_text = confidence_path.read_text(encoding="utf-8") gaussian_text = gaussian_path.read_text(encoding="utf-8") assert "property int source_mask" in confidence_text assert "property float opacity" in gaussian_text assert "property int source_mask" in gaussian_text finally: confidence_path.unlink(missing_ok=True) gaussian_path.unlink(missing_ok=True)