Implement BiRefNet and HAT Sharper models with background removal capabilities
- Added validation documentation for AI model tiers. - Introduced `background.py` for background removal logic, including inference functions for alpha and foreground extraction. - Created `onnx_birefnet.py` to handle BiRefNet model sessions and alpha inference. - Developed tests for background models, ensuring proper dispatch and session reuse. - Added tests for BiRefNet ONNX model to validate alpha output and error handling for invalid values. - Implemented model export scripts for BiRefNet and HAT Sharper, ensuring proper weight compression and licensing. - Created `deform_sampling.py` for deformable convolution operations used in BiRefNet. - Added utility functions for compressing ONNX weights without altering graph arithmetic. - Introduced a reference plane node for depth field adjustments in geometry processing.
This commit is contained in:
@@ -235,10 +235,67 @@ def test_surface_interface_and_node_structure(surface):
|
||||
validate_node_structure(obj.modifiers[0].node_group)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("thickness", [0.0, 0.4])
|
||||
@pytest.mark.parametrize("direction", [(0.2, -0.1, 1), (-0.2, 0.1, 1), (0.4, -0.2, 2), (0, 0, 0), (1, 0, 0)])
|
||||
def test_relief_direction_adjusts_depth_and_keeps_base(relief, thickness, direction):
|
||||
obj, set_value, _, _, image = relief
|
||||
pixels = np.ones((8, 16, 4), dtype=np.float32)
|
||||
pixels[..., 2] = 2
|
||||
image.pixels.foreach_set(pixels.ravel())
|
||||
image.update()
|
||||
set_value("Thickness", thickness)
|
||||
set_value("Reference Depth", 2.0)
|
||||
layers = evaluated(obj)[0]
|
||||
weights = np.clip(layers[:, 2] / thickness, 0, 1) if thickness else np.ones(len(layers))
|
||||
set_value("Depth Scale", 0.5)
|
||||
base = evaluated(obj)
|
||||
set_value("Depth Direction", direction)
|
||||
result = evaluated(obj)
|
||||
front = base[0][:, 2] > 0
|
||||
expected = base[0].copy()
|
||||
if direction[2]:
|
||||
expected[front, 2] += 0.5 * weights[front] * (expected[front, :2] @ np.array(direction[:2])) / direction[2]
|
||||
np.testing.assert_allclose(result[0], expected, atol=1e-6)
|
||||
assert result[1] == base[1]
|
||||
np.testing.assert_array_equal(result[2], base[2])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("thickness", [0.0, 0.4])
|
||||
def test_relief_smooth_preserves_topology_uv_and_materials(relief, thickness):
|
||||
obj, set_value, _, _, image = relief
|
||||
pixels = np.asarray(image.pixels[:], dtype=np.float32).reshape(8, 16, 4)
|
||||
pixels[..., 2] += (np.arange(16) % 2) * 0.5
|
||||
image.pixels.foreach_set(pixels.ravel())
|
||||
image.update()
|
||||
set_value("Thickness", thickness)
|
||||
set_value("Reference Depth", 2.0)
|
||||
set_value("Depth Scale", 1.0)
|
||||
set_value("Depth Direction", (0.1, -0.1, 1))
|
||||
base = evaluated(obj)
|
||||
set_value("Smooth", 3)
|
||||
result = evaluated(obj)
|
||||
assert np.isfinite(result[0]).all()
|
||||
assert np.max(abs(result[0] - base[0])) > 1e-4
|
||||
assert result[1] == base[1]
|
||||
np.testing.assert_array_equal(result[2], base[2])
|
||||
assert result[3:] == base[3:]
|
||||
set_value("Smooth Weight", 0.0)
|
||||
np.testing.assert_allclose(evaluated(obj)[0], base[0], atol=1e-6)
|
||||
set_value("Smooth Weight", 1.0)
|
||||
set_value("Smooth", 0)
|
||||
np.testing.assert_allclose(evaluated(obj)[0], base[0], atol=1e-6)
|
||||
|
||||
|
||||
def test_relief_interface_and_node_structure(relief):
|
||||
obj, _, _, inputs, _ = relief
|
||||
assert list(inputs) == ["Geometry", "Subdivide", "Thickness", "Depth Scale",
|
||||
"Reference Depth", "Uniform Scale", "Depth Image"]
|
||||
assert list(inputs) == ["Geometry", "Subdivide", "Thickness", "Depth Scale", "Smooth",
|
||||
"Reference Depth", "Smooth Weight", "Depth Direction", "Uniform Scale", "Depth Image"]
|
||||
assert inputs["Smooth"].default_value == 0
|
||||
assert (inputs["Smooth"].min_value, inputs["Smooth"].max_value) == (0, 20)
|
||||
assert inputs["Smooth Weight"].default_value == 1
|
||||
assert inputs["Smooth Weight"].subtype == "FACTOR"
|
||||
assert tuple(inputs["Depth Direction"].default_value) == (0, 0, 1)
|
||||
assert inputs["Depth Direction"].subtype == "DIRECTION"
|
||||
assert inputs["Thickness"].default_value == 0.5
|
||||
assert inputs["Subdivide"].default_value == 6
|
||||
assert inputs["Depth Scale"].default_value == 0.5
|
||||
@@ -356,6 +413,8 @@ def test_plane_interface_panels(source, kind):
|
||||
controls = ["Reference Depth"]
|
||||
if kind == "DEPTH":
|
||||
controls += ["Normal Smooth", "Smooth Weight", "Validity Threshold"]
|
||||
else:
|
||||
controls += ["Smooth Weight", "Depth Direction"]
|
||||
assert [item.name for item in panels[0].interface_items] == controls
|
||||
assert [item.name for item in panels[1].interface_items] == ["Uniform Scale", "Depth Image"]
|
||||
assert all(panel.default_closed for panel in panels)
|
||||
|
||||
Reference in New Issue
Block a user