Skip to content

Commit 123d638

Browse files
authored
Merge branch 'kijai:main' into main
2 parents 1b12478 + 6c996e1 commit 123d638

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"ImageCropByMaskAndResize": {"class": ImageCropByMaskAndResize, "name": "Image Crop By Mask And Resize"},
7272
"ImageCropByMaskBatch": {"class": ImageCropByMaskBatch, "name": "Image Crop By Mask Batch"},
7373
"ImageUncropByMask": {"class": ImageUncropByMask, "name": "Image Uncrop By Mask"},
74+
"ImageBatchExtendWithOverlap": {"class": ImageBatchExtendWithOverlap, "name": "Image Batch Extend With Overlap"},
7475
"ImageGrabPIL": {"class": ImageGrabPIL, "name": "Image Grab PIL"},
7576
"ImageGridComposite2x2": {"class": ImageGridComposite2x2, "name": "Image Grid Composite 2x2"},
7677
"ImageGridComposite3x3": {"class": ImageGridComposite3x3, "name": "Image Grid Composite 3x3"},

nodes/image_nodes.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,84 @@ def imagesfrombatch(self, start_index, num_frames, images=None, masks=None):
17741774
chosen_masks = masks[start_index:end_index]
17751775

17761776
return (chosen_images, chosen_masks,)
1777+
1778+
class ImageBatchExtendWithOverlap:
1779+
1780+
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", )
1781+
RETURN_NAMES = ("source_images", "start_images", "extended_images")
1782+
OUTPUT_TOOLTIPS = (
1783+
"The original source images (passthrough)",
1784+
"The input images used as the starting point for extension",
1785+
"The extended images with overlap, if no new images are provided this will be empty",
1786+
)
1787+
FUNCTION = "imagesfrombatch"
1788+
CATEGORY = "KJNodes/image"
1789+
DESCRIPTION = """
1790+
Helper node for video generation extension
1791+
First input source and overlap amount to get the starting frames for the extension.
1792+
Then on another copy of the node provide the newly generated frames and choose how to overlap them.
1793+
"""
1794+
1795+
@classmethod
1796+
def INPUT_TYPES(s):
1797+
return {
1798+
"required": {
1799+
"source_images": ("IMAGE", {"tooltip": "The source images to extend"}),
1800+
"overlap": ("INT", {"default": 13,"min": 1, "max": 4096, "step": 1, "tooltip": "Number of overlapping frames between source and new images"}),
1801+
"overlap_side": (["source", "new_images"], {"default": "source", "tooltip": "Which side to overlap on"}),
1802+
"overlap_mode": (["cut", "linear_blend", "ease_in_out"], {"default": "linear_blend", "tooltip": "Method to use for overlapping frames"}),
1803+
},
1804+
"optional": {
1805+
"new_images": ("IMAGE", {"tooltip": "The new images to extend with"}),
1806+
}
1807+
}
1808+
1809+
def imagesfrombatch(self, source_images, overlap, overlap_side, overlap_mode, new_images=None):
1810+
if overlap >= len(source_images):
1811+
return source_images, source_images, source_images
1812+
1813+
if new_images is not None:
1814+
if source_images.shape[1:3] != new_images.shape[1:3]:
1815+
raise ValueError(f"Source and new images must have the same shape: {source_images.shape[1:3]} vs {new_images.shape[1:3]}")
1816+
# Determine where to place the overlap
1817+
prefix = source_images[:-overlap]
1818+
if overlap_side == "source":
1819+
blend_src = source_images[-overlap:]
1820+
blend_dst = new_images[:overlap]
1821+
elif overlap_side == "new_images":
1822+
blend_src = new_images[:overlap]
1823+
blend_dst = source_images[-overlap:]
1824+
suffix = new_images[overlap:]
1825+
1826+
if overlap_mode == "linear_blend":
1827+
blended_images = [
1828+
crossfade(blend_src[i], blend_dst[i], (i + 1) / (overlap + 1))
1829+
for i in range(overlap)
1830+
]
1831+
blended_images = torch.stack(blended_images, dim=0)
1832+
extended_images = torch.cat((prefix, blended_images, suffix), dim=0)
1833+
elif overlap_mode == "ease_in_out":
1834+
blended_images = []
1835+
for i in range(overlap):
1836+
t = (i + 1) / (overlap + 1)
1837+
eased_t = ease_in_out(t)
1838+
blended_image = crossfade(blend_src[i], blend_dst[i], eased_t)
1839+
blended_images.append(blended_image)
1840+
blended_images = torch.stack(blended_images, dim=0)
1841+
extended_images = torch.cat((prefix, blended_images, suffix), dim=0)
1842+
1843+
elif overlap_mode == "cut":
1844+
extended_images = torch.cat((prefix, suffix), dim=0)
1845+
if overlap_side == "new_images":
1846+
extended_images = torch.cat((source_images, new_images[overlap:]), dim=0)
1847+
elif overlap_side == "source":
1848+
extended_images = torch.cat((source_images[:-overlap], new_images), dim=0)
1849+
else:
1850+
extended_images = torch.zeros((1, 64, 64, 3), device="cpu")
1851+
1852+
start_images = source_images[-overlap:]
1853+
1854+
return (source_images, start_images, extended_images)
17771855

17781856
class GetLatentRangeFromBatch:
17791857

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "comfyui-kjnodes"
33
description = "Various quality of life -nodes for ComfyUI, mostly just visual stuff to improve usability."
4-
version = "1.1.7"
4+
version = "1.1.8"
55
license = {file = "LICENSE"}
66
dependencies = ["librosa", "numpy", "pillow>=10.3.0", "scipy", "color-matcher", "matplotlib", "huggingface_hub"]
77

0 commit comments

Comments
 (0)