From cf8302ea102ef801ddf86534659c6ae618f67395 Mon Sep 17 00:00:00 2001 From: bruefire Date: Sun, 10 Dec 2023 07:26:13 +0900 Subject: [PATCH] fixed server side logics for trimming, etc. --- AnimateDiffInpaint.py | 42 ++++++++++++++++---------------------- LICENSE.txt | 21 +++++++++++++++++++ js/MaskEditorForVframes.js | 2 +- js/main.js | 4 ++-- readme.md | 27 ++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 27 deletions(-) create mode 100644 LICENSE.txt diff --git a/AnimateDiffInpaint.py b/AnimateDiffInpaint.py index ebec8ce..3a1c45b 100644 --- a/AnimateDiffInpaint.py +++ b/AnimateDiffInpaint.py @@ -1,4 +1,5 @@ import os +import sys import torch import numpy as np from PIL import Image, ImageOps @@ -9,11 +10,11 @@ class LoadImagesFromDirInpaint: def INPUT_TYPES(s): return { "required": { - "images_id": ("STRING", {"frames_upload": True}), + "sequence_id": ("STRING", {"frames_upload": True}), }, "optional": { - "image_load_cap": ("INT", {"default": 0, "min": 0, "step": 1}), "start_index": ("INT", {"default": 0, "min": 0, "step": 1}), + "end_index": ("INT", {"default": 0, "min": 0, "step": 1}), } } @@ -24,11 +25,16 @@ class LoadImagesFromDirInpaint: CATEGORY = "image" - def load_images(self, images_id: str, image_load_cap: int = 0, start_index: int = 0): + def load_images(self, sequence_id: str, start_index: int = 0, end_index: int = 0): + if start_index != 0: + start_index -= 1 + if end_index == 0: + end_index = sys.maxsize + comfy_custom_dir = os.path.dirname(os.path.abspath(__file__)) comfy_root_dir = os.path.join(comfy_custom_dir, "..", "..") - pathParts = images_id.split(":") + pathParts = sequence_id.split(":") vframeIds = pathParts[len(pathParts) - 1].split("/") filenames = pathParts[:-1] @@ -37,7 +43,7 @@ class LoadImagesFromDirInpaint: if len(vframeIds) == 1: imageDir = os.path.join(comfy_root_dir, "input", "extVideoFrame" + vframeIds[0]) - images = self.load_from_dir(imageDir, image_load_cap, start_index) + images = self.load_from_dir(imageDir, end_index, start_index) masks = [image.clone() for image in images] for mask in masks: mask.fill_(0) @@ -46,30 +52,24 @@ class LoadImagesFromDirInpaint: maskDir = os.path.join(comfy_root_dir, "input", "extVideoFrame" + vframeIds[1]) sketchDir = os.path.join(comfy_root_dir, "input", "extVideoFrame" + vframeIds[2]) - images = self.load_from_dir_sketch(imageDir, sketchDir, image_load_cap, start_index) - masks = self.load_from_dir(maskDir, image_load_cap, start_index) + images = self.load_from_dir_sketch(imageDir, sketchDir, end_index, start_index) + masks = self.load_from_dir(maskDir, end_index, start_index) return (torch.cat(images, dim=0), torch.cat(masks, dim=0), len(images)) - def load_from_dir(self, imageDir, image_load_cap, start_index): + def load_from_dir(self, imageDir, end_index, start_index): img_files = self.getImagePaths(imageDir) - img_files = img_files[start_index:] + img_files = img_files[start_index:end_index] images = [] - - limit_images = False - if image_load_cap > 0: - limit_images = True image_count = 0 for image_path in img_files: if os.path.isdir(image_path): continue - if limit_images and image_count >= image_load_cap: - break i = Image.open(image_path) i = ImageOps.exif_transpose(i) image = i.convert("RGB") @@ -85,25 +85,19 @@ class LoadImagesFromDirInpaint: return images - def load_from_dir_sketch(self, imageDir, sketchDir, image_load_cap, start_index): + def load_from_dir_sketch(self, imageDir, sketchDir, end_index, start_index): img_files = self.getImagePaths(imageDir) - img_files = img_files[start_index:] + img_files = img_files[start_index:end_index] skt_files = self.getImagePaths(sketchDir) - skt_files = skt_files[start_index:] + skt_files = skt_files[start_index:end_index] images = [] - - limit_images = False - if image_load_cap > 0: - limit_images = True image_count = 0 for idx, image_path in enumerate(img_files): if os.path.isdir(image_path): continue - if limit_images and image_count >= image_load_cap: - break i = Image.open(image_path) i = ImageOps.exif_transpose(i).convert("RGBA") s = Image.open(skt_files[idx]) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..cc115b6 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Adam Veldhousen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/js/MaskEditorForVframes.js b/js/MaskEditorForVframes.js index abe8331..dd5e371 100644 --- a/js/MaskEditorForVframes.js +++ b/js/MaskEditorForVframes.js @@ -126,7 +126,7 @@ class MaskEditorDialog extends ComfyDialog { text.style.top = "0"; text.style.right = "0"; text.style.fontFamily = "sans-serif"; - text.style.fontSize = "15px"; + text.style.fontSize = "20px"; text.style.color = "#fff"; text.innerText = content; return text; diff --git a/js/main.js b/js/main.js index eec6a43..c78dec0 100644 --- a/js/main.js +++ b/js/main.js @@ -110,7 +110,7 @@ app.registerExtension({ // widget setting // Adds an upload button to the nodes - if (nodeData?.input?.required?.images_id?.[1]?.frames_upload === true) { + if (nodeData?.input?.required?.sequence_id?.[1]?.frames_upload === true) { nodeData.input.required.upload = ["VFRAMESUPLOAD"]; } }, @@ -118,7 +118,7 @@ app.registerExtension({ { return { VFRAMESUPLOAD(node, inputName, inputData, app) { - const idWidget = node.widgets.find((w) => w.name === "images_id"); + const idWidget = node.widgets.find((w) => w.name === "sequence_id"); function showImage(name) { const img = new Image(); diff --git a/readme.md b/readme.md index e69de29..6dcd8d8 100644 --- a/readme.md +++ b/readme.md @@ -0,0 +1,27 @@ +# ComfyUI Sequential Image Loader + +## Overview +これはGUI上でフレーム毎にマスキング(とスケッチ)を行うためのComfyUI用の拡張ノードです。 + +## Usage + +### ノードについて +#### input +* sequence_id: 無視してください (内部処理でのみ使います)。 +* upload button: ダイアログから動画のフレームを含むディレクトリ世指定します。 +* start_index: 開始フレーム番号を指定します。0で無効。 +* end_index: 終了フレーム番号を指定します。0で無効。 +#### output +* images: 読み込んだフレームデータです。スケッチした場合、その内容が適用されます。 +* mask_images: 各フレームのマスクが画像として出力されます。Mask To Imageノード等でマスクデータに変換が必要です。 +* image_count: 処理フレーム数。 + +### マスクエディターについて + 1. フレームを読み込んだ後にノードを右クリックして、"Open In MaskEditor"を選択します。 + 2. 出現したエディタ上でマスキングと必要に応じてスケッチを行います。 + +## Example + + +## Other +input/ディレクトリに作業中の一時フレームデータが溜まっていくので、適当なタイミングで使わなくなったデータを削除してください。