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:
@@ -405,7 +405,7 @@ def load_normal_result_image(path, source_object):
|
||||
return image
|
||||
|
||||
|
||||
def create_pixel_result_image(source_image, pixels, output_size, suffix=""):
|
||||
def create_image_edit_result(source_image, pixels, output_size):
|
||||
"""Create a packed Image datablock from edited RGBA pixels."""
|
||||
output_width, output_height = (int(value) for value in output_size)
|
||||
if output_width <= 0 or output_height <= 0:
|
||||
@@ -413,7 +413,7 @@ def create_pixel_result_image(source_image, pixels, output_size, suffix=""):
|
||||
if len(pixels) != output_width * output_height * 4:
|
||||
raise ValueError("The edited pixels do not match the image dimensions")
|
||||
image = bpy.data.images.new(
|
||||
f"{image_base_name(source_image)}{suffix}",
|
||||
source_image.name,
|
||||
width=output_width,
|
||||
height=output_height,
|
||||
alpha=True,
|
||||
@@ -525,11 +525,12 @@ def place_empty_image_result(
|
||||
|
||||
|
||||
|
||||
def load_color_result_image(
|
||||
def _load_packed_result_image(
|
||||
source_object,
|
||||
output_directory,
|
||||
*,
|
||||
frame_prefix="image.",
|
||||
frame_prefix,
|
||||
result_name,
|
||||
):
|
||||
output_directory = Path(output_directory)
|
||||
color_paths = sorted_frame_paths(output_directory, frame_prefix)
|
||||
@@ -555,7 +556,6 @@ def load_color_result_image(
|
||||
raise RuntimeError("Unable to load the color result") from error
|
||||
|
||||
try:
|
||||
result_name = color_data_name(source_object)
|
||||
if animated:
|
||||
pack_sequence_if_possible(result_image, len(color_paths))
|
||||
else:
|
||||
@@ -567,6 +567,36 @@ def load_color_result_image(
|
||||
return result_image
|
||||
|
||||
|
||||
def load_image_edit_result(
|
||||
source_object,
|
||||
output_directory,
|
||||
*,
|
||||
frame_prefix="image.",
|
||||
):
|
||||
"""Load one packed Job result that directly edits the source Image."""
|
||||
return _load_packed_result_image(
|
||||
source_object,
|
||||
output_directory,
|
||||
frame_prefix=frame_prefix,
|
||||
result_name=source_object.data.name,
|
||||
)
|
||||
|
||||
|
||||
def load_color_result_image(
|
||||
source_object,
|
||||
output_directory,
|
||||
*,
|
||||
frame_prefix="image.",
|
||||
):
|
||||
"""Load one packed Color texture result for a generated material."""
|
||||
return _load_packed_result_image(
|
||||
source_object,
|
||||
output_directory,
|
||||
frame_prefix=frame_prefix,
|
||||
result_name=color_data_name(source_object),
|
||||
)
|
||||
|
||||
|
||||
def image_empty_bounds(source_object):
|
||||
image_width, image_height = source_object.data.size
|
||||
if image_width <= 0 or image_height <= 0:
|
||||
|
||||
@@ -208,6 +208,10 @@ def create_image_material(
|
||||
material_inputs.outputs["Roughness"],
|
||||
shader.inputs["Roughness"],
|
||||
)
|
||||
links.new(
|
||||
material_inputs.outputs["Color"],
|
||||
shader.inputs["Specular IOR Level"],
|
||||
)
|
||||
links.new(shader.outputs["BSDF"], output.inputs["Surface"])
|
||||
|
||||
if displacement_image is not None:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import json
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class ImageEditWarning(ValueError):
|
||||
@@ -86,6 +87,29 @@ class SelectionMask:
|
||||
return result
|
||||
|
||||
|
||||
def save_selection_mask(path, selection_mask):
|
||||
"""Save one local Selection Mask beside a prepared image input."""
|
||||
import numpy as np
|
||||
|
||||
path = Path(path).parent / "selection-mask.npy"
|
||||
np.save(path, selection_mask.values, allow_pickle=False)
|
||||
return path
|
||||
|
||||
|
||||
def load_selection_mask(path, bounds):
|
||||
"""Load a local Selection Mask sidecar without allowing object data."""
|
||||
import numpy as np
|
||||
|
||||
values = np.load(Path(path), allow_pickle=False)
|
||||
return SelectionMask(values, bounds)
|
||||
|
||||
|
||||
def cleanup_selection_mask(path):
|
||||
"""Remove a local Selection Mask sidecar."""
|
||||
if path:
|
||||
Path(path).unlink(missing_ok=True)
|
||||
|
||||
|
||||
def selection_path_bounds(points):
|
||||
import numpy as np
|
||||
|
||||
|
||||
Reference in New Issue
Block a user