Files
cxntibor-ComfyUI-CXN/tests/test_shoe_pose_node.py

115 lines
3.6 KiB
Python

import numpy as np
import pytest
import trimesh
def _make_inputs():
image = np.zeros((64, 48, 3), dtype=np.float32)
mask = np.zeros((1, 64, 48), dtype=np.float32)
mask[0, 20:50, 10:38] = 1.0 # a blob
from cxn.types import Model3D
scene = trimesh.Scene(trimesh.creation.box(extents=(0.3, 0.1, 0.2)))
model = Model3D(scene=scene, source_path="shoe.glb", textures=[])
return model, image[None, ...], mask
def _patch_engine(monkeypatch):
import cxn.shoe_pose as sp
monkeypatch.setattr(
sp, "calibrate",
lambda img, use_gravity=True, fov_override=0.0: (47.0, np.array([0.0, 1.0, 0.0])),
)
captured = {}
def fake_solve(scene, target, init, **kw):
captured["scene"] = scene
captured["init"] = init
return dict(pitch=1.0, yaw=2.0, roll=3.0, cam_x=4.0, cam_y=5.0, cam_z=6.0)
monkeypatch.setattr(sp, "solve_pose", fake_solve)
return captured
def test_estimate_returns_eight_tuple_and_fov(monkeypatch):
_patch_engine(monkeypatch)
from cxn.shoe_pose import ShoePose
from cxn.types import Model3D
model, image, mask = _make_inputs()
out = ShoePose().estimate(model, image, mask, left_or_right=False)
assert len(out) == 8
assert isinstance(out[0], Model3D)
# (model, cam_x, cam_y, cam_z, pitch, yaw, roll, fov)
assert out[1:] == (4.0, 5.0, 6.0, 1.0, 2.0, 3.0, 47.0)
def test_left_foot_mirrors_scene(monkeypatch):
captured = _patch_engine(monkeypatch)
from cxn.shoe_pose import ShoePose
model, image, mask = _make_inputs()
n_before = len(model.scene.geometry)
ShoePose().estimate(model, image, mask, left_or_right=True)
# _mirror_shoe rebuilds geometry; the scene handed to solve_pose is a new one.
assert captured["scene"] is not model.scene
assert len(captured["scene"].geometry) == n_before
def test_return_signature_matches_matchfootpose():
from cxn.shoe_pose import ShoePose
from cxn.match_foot_pose import MatchFootPose
assert ShoePose.RETURN_TYPES == MatchFootPose.RETURN_TYPES
assert ShoePose.RETURN_NAMES == MatchFootPose.RETURN_NAMES
def test_empty_mask_raises(monkeypatch):
_patch_engine(monkeypatch)
from cxn.shoe_pose import ShoePose
model, image, _mask = _make_inputs()
empty = np.zeros((1, 64, 48), dtype=np.float32)
with pytest.raises(RuntimeError):
ShoePose().estimate(model, image, empty, left_or_right=False)
def test_initial_pose_centers_camera_offset_for_offcenter_mask():
from cxn.shoe_pose import _initial_pose
m = np.zeros((100, 100), dtype=bool)
m[10:30, 10:30] = True # top-left blob
init = _initial_pose(
m, np.array([0.0, 1.0, 0.0]), 45.0, (100, 100),
model_extent_m=0.3, depth_cz=None,
)
# Object is top-left (cx<center, cy<center): cam_x>0 (offset right), cam_y<0.
assert init["cam_x"] > 0
assert init["cam_y"] < 0
assert init["cam_z"] > 0
def test_initial_pose_uses_depth_cz_when_given():
from cxn.shoe_pose import _initial_pose
m = np.zeros((100, 100), dtype=bool)
m[40:60, 40:60] = True
init = _initial_pose(
m, np.array([0.0, 1.0, 0.0]), 45.0, (100, 100),
model_extent_m=0.3, depth_cz=1.234,
)
assert abs(init["cam_z"] - 1.234) < 1e-6
def test_image_and_mask_conversions():
from cxn.shoe_pose import image_to_rgb_uint8, mask_to_bool
img = np.ones((1, 8, 8, 3), dtype=np.float32) * 0.5
out = image_to_rgb_uint8(img)
assert out.shape == (8, 8, 3) and out.dtype == np.uint8 and out[0, 0, 0] == 128
mask = np.zeros((1, 8, 8), dtype=np.float32)
mask[0, 0, 0] = 1.0
mb = mask_to_bool(mask)
assert mb.shape == (8, 8) and mb[0, 0] and not mb[1, 1]