Feather Smart Tile focus patches without masks
This commit is contained in:
@@ -749,6 +749,43 @@ def _ttp_tile_object_mask_array(tile, out_width, out_height, mask_blend_mode="ma
|
||||
return array[:, :, None]
|
||||
|
||||
|
||||
def _ttp_should_rect_feather_tile(tile, is_large_tile, mask_blend_mode):
|
||||
if str(mask_blend_mode) not in ("auto", "mask_feather"):
|
||||
return False
|
||||
if is_large_tile or tile.get("object_mask"):
|
||||
return False
|
||||
label = str(tile.get("label", "") or "").lower()
|
||||
name = str(tile.get("name", "") or "").lower()
|
||||
source = str(tile.get("source", "") or "").lower()
|
||||
text = " ".join((label, name, source))
|
||||
if any(word in text for word in ("background", "context", "full image", "full_image", "large context")):
|
||||
return False
|
||||
focus_keywords = (
|
||||
"face", "head", "eye", "eyes", "eyelash", "eyebrow", "glasses",
|
||||
"hand", "hands", "finger", "fingers", "mouth", "lip", "lips",
|
||||
"teeth", "nose", "ear", "ears", "text", "letter", "logo",
|
||||
"detail", "focus", "foreground", "object",
|
||||
)
|
||||
if any(keyword in text for keyword in focus_keywords):
|
||||
return True
|
||||
if source in ("auto", "paint", "sam", "sam3", "sam3.1", "qwen", "qwenvl"):
|
||||
return float(tile.get("occlusion_priority", 0.0)) >= 100.0 or float(tile.get("layer", 0.0)) >= 2.0
|
||||
edges = tile.get("overlap_edges_px_source", {})
|
||||
has_surrounding_overlap = all(float(edges.get(edge, 0.0)) > 0.0 for edge in ("left", "right", "top", "bottom"))
|
||||
return has_surrounding_overlap and (
|
||||
float(tile.get("occlusion_priority", 0.0)) > 0.0 or float(tile.get("layer", 0.0)) > 0.0
|
||||
)
|
||||
|
||||
|
||||
def _ttp_rect_feather_mask(width, height, feather):
|
||||
feather = int(round(float(feather)))
|
||||
if feather <= 0:
|
||||
return np.ones((height, width, 1), dtype=np.float32)
|
||||
edge_limit = max(1, min(int(width), int(height)) // 3)
|
||||
feather = max(1, min(feather, edge_limit))
|
||||
return _ttp_create_feather_mask(int(width), int(height), feather)
|
||||
|
||||
|
||||
def _ttp_decode_interactive_paint_mask(mask_payload, image_width, image_height):
|
||||
try:
|
||||
payload = json.loads(str(mask_payload or "").strip() or "{}")
|
||||
@@ -3957,6 +3994,8 @@ class TTP_Smart_Tile_Assemble_Experimental:
|
||||
mask = object_mask
|
||||
else:
|
||||
mask = mask * object_mask
|
||||
elif _ttp_should_rect_feather_tile(tile, is_large_tile, str(mask_blend_mode)):
|
||||
mask = mask * _ttp_rect_feather_mask(out_w, out_h, blend)
|
||||
coverage_mask = np.clip(mask.copy(), 0.0, 1.0)
|
||||
importance = max(0.0, float(tile.get("importance", 1.0)))
|
||||
priority = max(0.0, float(tile.get("priority", 50.0)))
|
||||
|
||||
@@ -1019,6 +1019,61 @@ small_above, _small_above_weights = assemble_node.assemble_tiles(
|
||||
small_above_pixel = small_above.array[0, 4, 4]
|
||||
assert_equal(float(small_above_pixel[2]) > float(small_above_pixel[0]), True, "small_tile_on_top should stack smaller tiles above larger context tiles")
|
||||
|
||||
feather_stack_meta = {
|
||||
"type": "ttp_smart_tile",
|
||||
"original_size": [16, 16],
|
||||
"tiles": [
|
||||
{
|
||||
"name": "background",
|
||||
"label": "background",
|
||||
"core_box": [0, 0, 16, 16],
|
||||
"sample_box": [0, 0, 16, 16],
|
||||
"tile_canvas_size": [16, 16],
|
||||
"tile_canvas_box": [0, 0, 16, 16],
|
||||
"overlap_edges_px_source": {"left": 0, "right": 0, "top": 0, "bottom": 0},
|
||||
"blend": 0,
|
||||
"importance": 1.0,
|
||||
"priority": 0.0,
|
||||
"layer": 0,
|
||||
"occlusion_priority": 0,
|
||||
},
|
||||
{
|
||||
"name": "face_detail",
|
||||
"label": "face detail",
|
||||
"core_box": [4, 4, 8, 8],
|
||||
"sample_box": [4, 4, 8, 8],
|
||||
"tile_canvas_size": [8, 8],
|
||||
"tile_canvas_box": [0, 0, 8, 8],
|
||||
"overlap_edges_px_source": {"left": 0, "right": 0, "top": 0, "bottom": 0},
|
||||
"blend": 4,
|
||||
"importance": 1.0,
|
||||
"priority": 0.0,
|
||||
"layer": 2,
|
||||
"occlusion_priority": 1000,
|
||||
},
|
||||
],
|
||||
}
|
||||
feather_tile_set = {
|
||||
"type": "ttp_smart_tile_set",
|
||||
"tile_meta": feather_stack_meta,
|
||||
"tile_images": [
|
||||
ttp.pil2tensor(Image.new("RGB", (16, 16), (220, 20, 20)))[0],
|
||||
ttp.pil2tensor(Image.new("RGB", (8, 8), (20, 20, 220)))[0],
|
||||
],
|
||||
}
|
||||
feathered_stack, _feathered_weights = assemble_node.assemble_tiles(
|
||||
blend_multiplier=1.0,
|
||||
output_scale=1.0,
|
||||
use_priority=True,
|
||||
base_canvas_mode="black",
|
||||
mask_blend_mode="mask_feather",
|
||||
tile_set=feather_tile_set,
|
||||
)
|
||||
feather_edge_pixel = feathered_stack.array[0, 4, 8]
|
||||
feather_center_pixel = feathered_stack.array[0, 8, 8]
|
||||
assert_equal(float(feather_edge_pixel[0]) > float(feather_edge_pixel[2]), True, "focus tile fallback feather should keep lower pixels visible at the rectangle edge")
|
||||
assert_equal(float(feather_center_pixel[2]) > float(feather_center_pixel[0]), True, "focus tile fallback feather should keep the focus tile strong in the center")
|
||||
|
||||
deferred_output, deferred_weights = assemble_node.assemble_tiles(
|
||||
blend_multiplier=1.0,
|
||||
output_scale=1.0,
|
||||
|
||||
Reference in New Issue
Block a user