Expand latent upscale spatial stitch controls
This commit is contained in:
@@ -1164,6 +1164,7 @@ What this really means:
|
|||||||
- the conditioning is rebuilt at that target size
|
- the conditioning is rebuilt at that target size
|
||||||
- the node then runs a short refinement pass over the upscaled latent with the sampler, scheduler, step count, denoise, and megapixel target you picked on the latent-upscale params node
|
- the node then runs a short refinement pass over the upscaled latent with the sampler, scheduler, step count, denoise, and megapixel target you picked on the latent-upscale params node
|
||||||
- if the target is larger than the spatial tile size, that refinement pass is processed in spatial batches using the same tile defaults as the upstream latent-split node
|
- if the target is larger than the spatial tile size, that refinement pass is processed in spatial batches using the same tile defaults as the upstream latent-split node
|
||||||
|
- the spatial stitch mode follows the upstream overlap controls, including `linear`, `smoothstep`, `overwrite`, and `midpoint`
|
||||||
|
|
||||||
Good starting point:
|
Good starting point:
|
||||||
|
|
||||||
@@ -1172,6 +1173,7 @@ Good starting point:
|
|||||||
- start with `euler_ancestral`, `simple`, `2` steps, and `0.2` denoise
|
- start with `euler_ancestral`, `simple`, `2` steps, and `0.2` denoise
|
||||||
- leave width and height at `0` unless you want an exact override; otherwise `megapixels` drives the target size
|
- leave width and height at `0` unless you want an exact override; otherwise `megapixels` drives the target size
|
||||||
- leave the spatial tile inputs at their defaults first: `512x512` tiles, `64` overlap, `0` fade width, `earlier` overlap mode
|
- leave the spatial tile inputs at their defaults first: `512x512` tiles, `64` overlap, `0` fade width, `earlier` overlap mode
|
||||||
|
- keep `linear` blend first unless you want to reproduce a specific upstream stitch style
|
||||||
|
|
||||||
The important part is that this stage is still a latent pass, not a pixel-space resize:
|
The important part is that this stage is still a latent pass, not a pixel-space resize:
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
- Per-shot directives now support `continuity:`, `ref_mode:`, `ref_noise_aug:`, `anchor_add:`, `soundscape:`, and `music:` in addition to the existing timing and wardrobe directives.
|
- Per-shot directives now support `continuity:`, `ref_mode:`, `ref_noise_aug:`, `anchor_add:`, `soundscape:`, and `music:` in addition to the existing timing and wardrobe directives.
|
||||||
|
|
||||||
- `Dumas H3 Latent Upscale Params`
|
- `Dumas H3 Latent Upscale Params`
|
||||||
- Inputs: `mode`, `model_name`, `method`, `width`, `height`, `device`, `precision`, `sampler_name`, `scheduler`, `steps`, `denoise`, `megapixels`, `tile_width`, `tile_height`, `overlap`, `fade_width`, `overlap_mode`
|
- Inputs: `mode`, `model_name`, `method`, `width`, `height`, `device`, `precision`, `sampler_name`, `scheduler`, `steps`, `denoise`, `megapixels`, `tile_width`, `tile_height`, `overlap`, `fade_width`, `overlap_mode`, `overlap_blend`
|
||||||
- Output: `latent_upscale_param`
|
- Output: `latent_upscale_param`
|
||||||
- Bundles the optional latent-space upscaler settings used by `Dumas H3 Long Videos` before decode, so the main node can rebuild conditioning at the target size and run a short refinement pass with your chosen sampler, scheduler, step count, denoise, and optional spatial batching.
|
- Bundles the optional latent-space upscaler settings used by `Dumas H3 Long Videos` before decode, so the main node can rebuild conditioning at the target size and run a short refinement pass with your chosen sampler, scheduler, step count, denoise, and optional spatial batching.
|
||||||
|
|
||||||
|
|||||||
@@ -473,10 +473,12 @@ class H3LatentUpscaleParams:
|
|||||||
"tooltip": "Width in pixels of the freeze-to-free transition inside each overlap strip. 0 freezes the whole strip, matching the upstream default."}),
|
"tooltip": "Width in pixels of the freeze-to-free transition inside each overlap strip. 0 freezes the whole strip, matching the upstream default."}),
|
||||||
"overlap_mode": (["earlier", "later"], {"default": "earlier",
|
"overlap_mode": (["earlier", "later"], {"default": "earlier",
|
||||||
"tooltip": "Which tile wins the overlap band when stitching the spatial batches back together."}),
|
"tooltip": "Which tile wins the overlap band when stitching the spatial batches back together."}),
|
||||||
|
"overlap_blend": (["linear", "smoothstep", "overwrite", "midpoint"], {"default": "linear",
|
||||||
|
"tooltip": "How overlap bands are blended when the spatial batches are stitched back together."}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def build(self, mode, model_name, method, width, height, device, precision, sampler_name, scheduler, steps, denoise, megapixels, tile_width, tile_height, overlap, fade_width, overlap_mode):
|
def build(self, mode, model_name, method, width, height, device, precision, sampler_name, scheduler, steps, denoise, megapixels, tile_width, tile_height, overlap, fade_width, overlap_mode, overlap_blend):
|
||||||
width = int(width)
|
width = int(width)
|
||||||
height = int(height)
|
height = int(height)
|
||||||
steps = int(steps)
|
steps = int(steps)
|
||||||
@@ -500,6 +502,7 @@ class H3LatentUpscaleParams:
|
|||||||
"overlap": overlap,
|
"overlap": overlap,
|
||||||
"fade_width": fade_width,
|
"fade_width": fade_width,
|
||||||
"overlap_mode": overlap_mode,
|
"overlap_mode": overlap_mode,
|
||||||
|
"overlap_blend": overlap_blend,
|
||||||
},)
|
},)
|
||||||
if width > 0:
|
if width > 0:
|
||||||
width = int(round(width / 32.0)) * 32
|
width = int(round(width / 32.0)) * 32
|
||||||
@@ -524,6 +527,7 @@ class H3LatentUpscaleParams:
|
|||||||
"overlap": overlap,
|
"overlap": overlap,
|
||||||
"fade_width": fade_width,
|
"fade_width": fade_width,
|
||||||
"overlap_mode": overlap_mode,
|
"overlap_mode": overlap_mode,
|
||||||
|
"overlap_blend": overlap_blend,
|
||||||
},)
|
},)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+16
-6
@@ -4104,10 +4104,18 @@ def _latent_spatial_grid(h, w, th, tw, ol_h, ol_w):
|
|||||||
return rows, cols, trows, tcols
|
return rows, cols, trows, tcols
|
||||||
|
|
||||||
|
|
||||||
def _latent_spatial_blend_weights(t, overlap_mode):
|
def _latent_spatial_blend_weights(t, overlap_mode, overlap_blend="linear"):
|
||||||
|
if overlap_blend == "overwrite":
|
||||||
|
return torch.ones_like(t) if overlap_mode == "later" else torch.zeros_like(t)
|
||||||
|
if overlap_blend == "midpoint":
|
||||||
|
base = (t >= 0.5).to(t.dtype)
|
||||||
|
elif overlap_blend == "smoothstep":
|
||||||
|
base = t * t * (3.0 - 2.0 * t)
|
||||||
|
else:
|
||||||
|
base = t
|
||||||
if overlap_mode == "later":
|
if overlap_mode == "later":
|
||||||
return 1.0 - t
|
return base
|
||||||
return t
|
return 1.0 - base
|
||||||
|
|
||||||
|
|
||||||
def _nested_tensor_parts(samples):
|
def _nested_tensor_parts(samples):
|
||||||
@@ -6510,6 +6518,7 @@ class H3LongVideos:
|
|||||||
overlap_px = max(0, int(latent_upscale_param.get("overlap", 64) or 64))
|
overlap_px = max(0, int(latent_upscale_param.get("overlap", 64) or 64))
|
||||||
fade_px = max(0, int(latent_upscale_param.get("fade_width", 0) or 0))
|
fade_px = max(0, int(latent_upscale_param.get("fade_width", 0) or 0))
|
||||||
overlap_mode = str(latent_upscale_param.get("overlap_mode", "earlier"))
|
overlap_mode = str(latent_upscale_param.get("overlap_mode", "earlier"))
|
||||||
|
overlap_blend = str(latent_upscale_param.get("overlap_blend", "linear"))
|
||||||
tile_tw = max(1, min(int(up_w), max(1, tile_w_px // 16)))
|
tile_tw = max(1, min(int(up_w), max(1, tile_w_px // 16)))
|
||||||
tile_th = max(1, min(int(up_h), max(1, tile_h_px // 16)))
|
tile_th = max(1, min(int(up_h), max(1, tile_h_px // 16)))
|
||||||
ol_tw = max(0, min(tile_tw - 1, overlap_px // 16))
|
ol_tw = max(0, min(tile_tw - 1, overlap_px // 16))
|
||||||
@@ -6548,7 +6557,7 @@ class H3LongVideos:
|
|||||||
region.copy_(tile_video_out)
|
region.copy_(tile_video_out)
|
||||||
if col_index > 0 and ol_tw > 0:
|
if col_index > 0 and ol_tw > 0:
|
||||||
t = torch.linspace(0.0, 1.0, ol_tw, device=region.device, dtype=region.dtype)
|
t = torch.linspace(0.0, 1.0, ol_tw, device=region.device, dtype=region.dtype)
|
||||||
w = _latent_spatial_blend_weights(t, overlap_mode)
|
w = _latent_spatial_blend_weights(t, overlap_mode, overlap_blend)
|
||||||
if fw_tw > 0:
|
if fw_tw > 0:
|
||||||
w = w.clone()
|
w = w.clone()
|
||||||
w[:fw_tw] = 0.0
|
w[:fw_tw] = 0.0
|
||||||
@@ -6558,7 +6567,7 @@ class H3LongVideos:
|
|||||||
)
|
)
|
||||||
if row_index > 0 and ol_th > 0:
|
if row_index > 0 and ol_th > 0:
|
||||||
t = torch.linspace(0.0, 1.0, ol_th, device=region.device, dtype=region.dtype)
|
t = torch.linspace(0.0, 1.0, ol_th, device=region.device, dtype=region.dtype)
|
||||||
w = _latent_spatial_blend_weights(t, overlap_mode)
|
w = _latent_spatial_blend_weights(t, overlap_mode, overlap_blend)
|
||||||
if fw_th > 0:
|
if fw_th > 0:
|
||||||
w = w.clone()
|
w = w.clone()
|
||||||
w[:fw_th] = 0.0
|
w[:fw_th] = 0.0
|
||||||
@@ -6707,8 +6716,9 @@ class H3LongVideos:
|
|||||||
tile_w_px = int(latent_upscale_param.get("tile_width", 512) or 512)
|
tile_w_px = int(latent_upscale_param.get("tile_width", 512) or 512)
|
||||||
tile_h_px = int(latent_upscale_param.get("tile_height", 512) or 512)
|
tile_h_px = int(latent_upscale_param.get("tile_height", 512) or 512)
|
||||||
overlap_px = max(0, int(latent_upscale_param.get("overlap", 64) or 64))
|
overlap_px = max(0, int(latent_upscale_param.get("overlap", 64) or 64))
|
||||||
|
overlap_blend = str(latent_upscale_param.get("overlap_blend", "linear"))
|
||||||
if tile_w_px > 0 and tile_h_px > 0 and (tile_w_px < target_w or tile_h_px < target_h):
|
if tile_w_px > 0 and tile_h_px > 0 and (tile_w_px < target_w or tile_h_px < target_h):
|
||||||
batch_note = f"; spatial batches {tile_w_px}x{tile_h_px}px overlap {overlap_px}px"
|
batch_note = f"; spatial batches {tile_w_px}x{tile_h_px}px overlap {overlap_px}px {overlap_blend}"
|
||||||
latent_upscale_note = (
|
latent_upscale_note = (
|
||||||
f" latent upscale: target {target_w}x{target_h}px{detail}; "
|
f" latent upscale: target {target_w}x{target_h}px{detail}; "
|
||||||
f"{int(latent_upscale_param.get('steps', 2) or 2)}-step refinement "
|
f"{int(latent_upscale_param.get('steps', 2) or 2)}-step refinement "
|
||||||
|
|||||||
@@ -1132,6 +1132,7 @@ class DumasH3LongVideosHelperTests(unittest.TestCase):
|
|||||||
self.assertEqual(required["overlap"][1]["default"], 64)
|
self.assertEqual(required["overlap"][1]["default"], 64)
|
||||||
self.assertEqual(required["fade_width"][1]["default"], 0)
|
self.assertEqual(required["fade_width"][1]["default"], 0)
|
||||||
self.assertEqual(required["overlap_mode"][1]["default"], "earlier")
|
self.assertEqual(required["overlap_mode"][1]["default"], "earlier")
|
||||||
|
self.assertEqual(required["overlap_blend"][1]["default"], "linear")
|
||||||
|
|
||||||
def test_compose_persistent_does_not_expand_ambiguous_plural_to_full_cast(self):
|
def test_compose_persistent_does_not_expand_ambiguous_plural_to_full_cast(self):
|
||||||
active = self.module.parse_wardrobe(
|
active = self.module.parse_wardrobe(
|
||||||
|
|||||||
Reference in New Issue
Block a user