Refactor Cutout and Image Editing Logic

- Renamed "Base Plane Depth" to "Reference Depth" across validate_cutout.py for consistency.
- Introduced a new specification for Cutout mesh sampling to ensure source pixel spacing is preserved and limits are applied correctly.
- Unified naming conventions for image editing results to maintain consistency across Remove Background, Upscale, and Crop operations.
- Updated the handling of Refine Selection to ensure it retains the original bounds and does not apply unnecessary cropping.
- Enhanced material generation logic to connect image color directly to IOR Level, improving the rendering of dark areas.
- Established clear requirements for geometry depth controls and image result materials to ensure consistent behavior across different components.
- Removed outdated logic and ensured all changes are documented and tested for regression.
This commit is contained in:
2026-09-03 01:02:10 +08:00
parent a6041cbe03
commit bdbde1a10d
47 changed files with 1120 additions and 257 deletions

View File

@@ -34,10 +34,10 @@ from anyimage.server.models import da3 as da3_model
from anyimage.server.models.geometry import GeometryFrame
def test_cutout_mesh_detail_uses_the_cropped_analysis_scale():
assert cutout_geometry.limit_cutout_mesh_resolution(256, (4096, 1024), 2048) == 128
assert cutout_geometry.limit_cutout_mesh_resolution(256, (1024, 512), 2048) == 256
assert cutout_geometry.limit_cutout_mesh_resolution(8, (8192, 4096), 2048) == 4
def test_cutout_mesh_limit_caps_actual_sampling_resolution():
assert cutout_geometry.limit_cutout_point_spacing(32, (4096, 1024), 1024) == 32
assert cutout_geometry.limit_cutout_point_spacing(32, (4096, 1024), 64) == 64
assert cutout_geometry.limit_cutout_point_spacing(4, (8192, 4096), 1024) == 8
def test_depth_metadata_loader_uses_one_schema_for_plane_and_cutout(tmp_path):
@@ -378,17 +378,20 @@ def test_blender_cutout_contour_resolution_tracks_mesh_detail():
components=(((((0, 0), (1, 0), (0, 1))),),),
image_size=(1, 1),
)
selection_mask = SelectionMask(np.ones((2, 2), dtype=np.float32), (0, 0, 2, 2))
values = SimpleNamespace(shape=(1024, 1024))
with patch.object(cutout_geometry, "extract_selection_contours", return_value=expected) as trace:
assert cutout_geometry.extract_cutout_contours(selection_mask.values, 32) == expected
assert cutout_geometry.extract_cutout_contours(selection_mask.values, 256) == expected
assert cutout_geometry.extract_cutout_contours(values, 32) == expected
assert cutout_geometry.extract_cutout_contours(values, 4) == expected
assert trace.call_args_list[0].kwargs["max_resolution"] == 512
assert trace.call_args_list[1].kwargs["max_resolution"] == 1024
def test_cutout_sampling_spacing_uses_the_complete_source_plane():
source = SimpleNamespace(matrix_world=object())
source = SimpleNamespace(
data=SimpleNamespace(size=(400, 200)),
matrix_world=object(),
)
with (
patch.object(cutout_geometry, "image_empty_bounds", return_value=(-2.0, 2.0, -1.0, 1.0)),
patch.object(
@@ -397,9 +400,32 @@ def test_cutout_sampling_spacing_uses_the_complete_source_plane():
return_value=(((1.0, 0.0), (0.0, 1.0)), 1.0),
),
):
spacing = cutout_geometry.cutout_sampling_spacing(source, 200)
spacing = cutout_geometry.cutout_sampling_spacing(source, 32)
assert spacing == 0.02
assert spacing == 0.32
def test_cutout_sampling_spacing_tracks_upscaled_source_pixels():
original = SimpleNamespace(
data=SimpleNamespace(size=(2048, 1024)),
matrix_world=object(),
)
upscaled = SimpleNamespace(
data=SimpleNamespace(size=(8192, 4096)),
matrix_world=object(),
)
with (
patch.object(cutout_geometry, "image_empty_bounds", return_value=(-2.0, 2.0, -1.0, 1.0)),
patch.object(
cutout_geometry,
"world_plane_metric",
return_value=(((1.0, 0.0), (0.0, 1.0)), 1.0),
),
):
original_spacing = cutout_geometry.cutout_sampling_spacing(original, 32)
upscaled_spacing = cutout_geometry.cutout_sampling_spacing(upscaled, 32)
assert upscaled_spacing == original_spacing / 4
def test_cutout_cleanup_value_scales_the_ui_without_changing_node_area():