diff --git a/__init__.py b/__init__.py index ca7e124..34d72b1 100644 --- a/__init__.py +++ b/__init__.py @@ -18,17 +18,21 @@ try: from .nodes import FaceProcessorLoader, ApplyFaceProcessor from .videoinput import VideoInputPreprocessor from .videocombine import VideoBackgroundRestorer + from .choose_face_only_mode import FaceOnlyModeSwitch # Map the class names to the classes themselves NODE_CLASS_MAPPINGS["FaceProcessorLoader"] = FaceProcessorLoader NODE_CLASS_MAPPINGS["ApplyFaceProcessor"] = ApplyFaceProcessor NODE_CLASS_MAPPINGS["VideoInputPreprocessor"] = VideoInputPreprocessor NODE_CLASS_MAPPINGS["VideoBackgroundRestorer"] = VideoBackgroundRestorer + NODE_CLASS_MAPPINGS["FaceOnlyModeSwitch"] = FaceOnlyModeSwitch + NODE_DISPLAY_NAME_MAPPINGS["FaceProcessorLoader"] = "Stand-In Processor Loader" NODE_DISPLAY_NAME_MAPPINGS["ApplyFaceProcessor"] = "Apply Stand-In Processor" NODE_DISPLAY_NAME_MAPPINGS["VideoInputPreprocessor"] = "Stand-In VideoInputPreprocessor" NODE_DISPLAY_NAME_MAPPINGS["VideoBackgroundRestorer"] = "Stand-In Background Restorer" + NODE_DISPLAY_NAME_MAPPINGS["FaceOnlyModeSwitch"] = "Face Only Mode Switch (Stand-In)" logger.info("Successfully loaded all Stand-In nodes.") diff --git a/choose_face_only_mode.py b/choose_face_only_mode.py new file mode 100644 index 0000000..58187ef --- /dev/null +++ b/choose_face_only_mode.py @@ -0,0 +1,30 @@ +class FaceOnlyModeSwitch: + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "enabled": ("BOOLEAN", { + "default": False, + "label_on": "FACE ONLY", + "label_off": "FULL MASK" + }), + } + } + + RETURN_TYPES = ("BOOLEAN",) + RETURN_NAMES = ("face_only_mode",) + FUNCTION = "toggle" + CATEGORY = "Stand-In" + + def toggle(self, enabled: bool): + return (enabled,) + + +NODE_CLASS_MAPPINGS = { + "FaceOnlyModeSwitch": FaceOnlyModeSwitch, +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "FaceOnlyModeSwitch": "Face Only Mode Switch (Stand-In)", +} \ No newline at end of file diff --git a/example/face_swap.json b/example/face_swap.json index f8cd683..b502367 100644 --- a/example/face_swap.json +++ b/example/face_swap.json @@ -1,8 +1,8 @@ { "id": "206247b6-9fec-4ed2-8927-e4f388c674d4", "revision": 0, - "last_node_id": 146, - "last_link_id": 258, + "last_node_id": 150, + "last_link_id": 264, "nodes": [ { "id": 50, @@ -16,7 +16,7 @@ 200 ], "flags": {}, - "order": 18, + "order": 19, "mode": 2, "inputs": [ { @@ -56,7 +56,7 @@ 200 ], "flags": {}, - "order": 17, + "order": 18, "mode": 2, "inputs": [ { @@ -202,7 +202,7 @@ 46 ], "flags": {}, - "order": 24, + "order": 25, "mode": 0, "inputs": [ { @@ -354,7 +354,7 @@ 46 ], "flags": {}, - "order": 29, + "order": 30, "mode": 0, "inputs": [ { @@ -450,7 +450,7 @@ 274 ], "flags": {}, - "order": 19, + "order": 20, "mode": 0, "inputs": [ { @@ -536,7 +536,7 @@ "flags": { "collapsed": true }, - "order": 22, + "order": 23, "mode": 2, "inputs": [ { @@ -577,7 +577,7 @@ 246 ], "flags": {}, - "order": 25, + "order": 27, "mode": 0, "inputs": [ { @@ -594,29 +594,6 @@ }, "widgets_values": [] }, - { - "id": 129, - "type": "MarkdownNote", - "pos": [ - 791.3861694335938, - -356.8863830566406 - ], - "size": [ - 362.6117858886719, - 143.0945281982422 - ], - "flags": {}, - "order": 8, - "mode": 0, - "inputs": [], - "outputs": [], - "properties": {}, - "widgets_values": [ - "Prompt Writing Tip: If you do not wish to alter the subject's facial features, simply use \"a man\" or \"a woman\" without adding extra descriptions of their appearance. Prompts support both Chinese and English input. The prompt is intended for generating frontal, medium-to-close-up videos.\n\nInput Image Recommendation: For best results, use a high-resolution frontal face image. There are no restrictions on resolution or file extension, as our built-in preprocessing pipeline will handle them automatically.\n\n[https://github.com/WeChatCV/Stand-In](https://github.com/WeChatCV/Stand-In)" - ], - "color": "#322", - "bgcolor": "#533" - }, { "id": 38, "type": "WanVideoVAELoader", @@ -629,7 +606,7 @@ 82 ], "flags": {}, - "order": 9, + "order": 8, "mode": 0, "inputs": [ { @@ -717,7 +694,7 @@ 873.39453125 ], "flags": {}, - "order": 32, + "order": 33, "mode": 0, "inputs": [ { @@ -867,47 +844,6 @@ false ] }, - { - "id": 58, - "type": "LoadImage", - "pos": [ - -737.1319580078125, - -174.04302978515625 - ], - "size": [ - 413.10479736328125, - 498.3180847167969 - ], - "flags": {}, - "order": 10, - "mode": 0, - "inputs": [], - "outputs": [ - { - "name": "IMAGE", - "type": "IMAGE", - "links": [ - 226 - ] - }, - { - "name": "MASK", - "type": "MASK", - "links": [] - } - ], - "properties": { - "cnr_id": "comfy-core", - "ver": "0.3.26", - "Node name for S&R": "LoadImage" - }, - "widgets_values": [ - "ruonan.jpg", - "image" - ], - "color": "#2a363b", - "bgcolor": "#3f5159" - }, { "id": 16, "type": "WanVideoTextEncode", @@ -920,7 +856,7 @@ 355.67169189453125 ], "flags": {}, - "order": 23, + "order": 24, "mode": 0, "inputs": [ { @@ -961,62 +897,6 @@ "color": "#332922", "bgcolor": "#593930" }, - { - "id": 134, - "type": "WanVideoEncode", - "pos": [ - 112.84590911865234, - 229.7924346923828 - ], - "size": [ - 270, - 242 - ], - "flags": {}, - "order": 30, - "mode": 0, - "inputs": [ - { - "name": "vae", - "type": "WANVAE", - "link": 234 - }, - { - "name": "image", - "type": "IMAGE", - "link": 245 - }, - { - "name": "mask", - "shape": 7, - "type": "MASK", - "link": null - } - ], - "outputs": [ - { - "name": "samples", - "type": "LATENT", - "links": [ - 233 - ] - } - ], - "properties": { - "cnr_id": "ComfyUI-WanVideoWrapper", - "ver": "b08f10ffd8c5e6ee867b514616853aa1edb5610b", - "Node name for S&R": "WanVideoEncode" - }, - "widgets_values": [ - false, - 272, - 272, - 144, - 128, - 0, - 1 - ] - }, { "id": 104, "type": "WanVideoEncode", @@ -1029,7 +909,7 @@ 242 ], "flags": {}, - "order": 26, + "order": 28, "mode": 0, "inputs": [ { @@ -1085,7 +965,7 @@ 200 ], "flags": {}, - "order": 11, + "order": 9, "mode": 0, "inputs": [ { @@ -1134,7 +1014,7 @@ 126 ], "flags": {}, - "order": 28, + "order": 26, "mode": 0, "inputs": [ { @@ -1206,7 +1086,7 @@ 130 ], "flags": {}, - "order": 12, + "order": 10, "mode": 0, "inputs": [], "outputs": [ @@ -1329,7 +1209,7 @@ 143.0945281982422 ], "flags": {}, - "order": 13, + "order": 11, "mode": 0, "inputs": [], "outputs": [], @@ -1340,181 +1220,6 @@ "color": "#432", "bgcolor": "#653" }, - { - "id": 143, - "type": "MarkdownNote", - "pos": [ - -270.9808044433594, - 479.54229736328125 - ], - "size": [ - 300, - 240 - ], - "flags": {}, - "order": 14, - "mode": 0, - "inputs": [], - "outputs": [], - "properties": {}, - "widgets_values": [ - "## **With a higher denoise strength, the face blends better with the background, but the background changes slightly more. With a lower denoise strength, the background changes less. You can adjust it according to your needs.**\n" - ], - "color": "#432", - "bgcolor": "#653" - }, - { - "id": 138, - "type": "VideoInputPreprocessor", - "pos": [ - -274.0709533691406, - 247.68026733398438 - ], - "size": [ - 306.6597595214844, - 194 - ], - "flags": {}, - "order": 27, - "mode": 0, - "inputs": [ - { - "name": "face_processor", - "type": "FACE_PROCESSOR", - "link": 242 - }, - { - "name": "images", - "type": "IMAGE", - "link": 244 - }, - { - "name": "face_rgba", - "type": "IMAGE", - "link": 243 - } - ], - "outputs": [ - { - "name": "processed_images", - "type": "IMAGE", - "links": [ - 245 - ] - }, - { - "name": "denoise_strength", - "type": "FLOAT", - "links": [ - 252 - ] - } - ], - "properties": { - "aux_id": "WeChatCV/Stand-In_Preprocessor_ComfyUI", - "ver": "db0d3d966dada4c5c242f9da5287988b533120e4", - "Node name for S&R": "VideoInputPreprocessor" - }, - "widgets_values": [ - 0.5, - 0.5, - 1.5, - 10, - true - ] - }, - { - "id": 128, - "type": "ApplyFaceProcessor", - "pos": [ - -258.21417236328125, - -111.67808532714844 - ], - "size": [ - 270, - 198 - ], - "flags": {}, - "order": 20, - "mode": 0, - "inputs": [ - { - "name": "face_processor", - "type": "FACE_PROCESSOR", - "link": 230 - }, - { - "name": "image", - "type": "IMAGE", - "link": 226 - } - ], - "outputs": [ - { - "name": "processed_image", - "type": "IMAGE", - "links": [ - 227, - 229, - 231 - ] - }, - { - "name": "face_rgba", - "type": "IMAGE", - "links": [ - 243 - ] - } - ], - "properties": { - "aux_id": "WeChatCV/Stand-In_Preprocessor_ComfyUI", - "ver": "db0d3d966dada4c5c242f9da5287988b533120e4", - "Node name for S&R": "ApplyFaceProcessor" - }, - "widgets_values": [ - 512, - 10, - 1.5, - 0.5, - false - ] - }, - { - "id": 130, - "type": "FaceProcessorLoader", - "pos": [ - -298.89288330078125, - 120.64043426513672 - ], - "size": [ - 319.3335876464844, - 58 - ], - "flags": {}, - "order": 15, - "mode": 0, - "inputs": [], - "outputs": [ - { - "name": "face_processor", - "type": "FACE_PROCESSOR", - "links": [ - 230, - 242, - 255 - ] - } - ], - "properties": { - "aux_id": "WeChatCV/Stand-In_Preprocessor_ComfyUI", - "ver": "db0d3d966dada4c5c242f9da5287988b533120e4", - "Node name for S&R": "FaceProcessorLoader" - }, - "widgets_values": [ - "model.pt" - ] - }, { "id": 28, "type": "WanVideoDecode", @@ -1527,7 +1232,7 @@ 198 ], "flags": {}, - "order": 33, + "order": 34, "mode": 0, "inputs": [ { @@ -1567,19 +1272,185 @@ "color": "#322", "bgcolor": "#533" }, + { + "id": 122, + "type": "ImageConcatMulti", + "pos": [ + 1819.03466796875, + -562.8757934570312 + ], + "size": [ + 270, + 150 + ], + "flags": {}, + "order": 36, + "mode": 0, + "inputs": [ + { + "name": "image_1", + "type": "IMAGE", + "link": 258 + }, + { + "name": "image_2", + "type": "IMAGE", + "link": 229 + } + ], + "outputs": [ + { + "name": "images", + "type": "IMAGE", + "links": [ + 217 + ] + } + ], + "properties": { + "cnr_id": "comfyui-kjnodes", + "ver": "87d0cf42db7d59992daba4d58a83655b5b359f44" + }, + "widgets_values": [ + 2, + "left", + true, + null + ] + }, + { + "id": 134, + "type": "WanVideoEncode", + "pos": [ + 112.84590911865234, + 229.7924346923828 + ], + "size": [ + 210, + 242 + ], + "flags": {}, + "order": 32, + "mode": 0, + "inputs": [ + { + "name": "vae", + "type": "WANVAE", + "link": 234 + }, + { + "name": "image", + "type": "IMAGE", + "link": 245 + }, + { + "name": "mask", + "shape": 7, + "type": "MASK", + "link": null + } + ], + "outputs": [ + { + "name": "samples", + "type": "LATENT", + "links": [ + 233 + ] + } + ], + "properties": { + "cnr_id": "ComfyUI-WanVideoWrapper", + "ver": "b08f10ffd8c5e6ee867b514616853aa1edb5610b", + "Node name for S&R": "WanVideoEncode" + }, + "widgets_values": [ + false, + 272, + 272, + 144, + 128, + 0, + 1 + ] + }, + { + "id": 129, + "type": "MarkdownNote", + "pos": [ + 990, + -420 + ], + "size": [ + 310, + 210 + ], + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "Prompt Writing Tip: If you do not wish to alter the subject's facial features, simply use \"a man\" or \"a woman\" without adding extra descriptions of their appearance. Prompts support both Chinese and English input. The prompt is intended for generating frontal, medium-to-close-up videos.\n\nInput Image Recommendation: For best results, use a high-resolution frontal face image. There are no restrictions on resolution or file extension, as our built-in preprocessing pipeline will handle them automatically.\n\n[https://github.com/WeChatCV/Stand-In](https://github.com/WeChatCV/Stand-In)" + ], + "color": "#322", + "bgcolor": "#533" + }, + { + "id": 58, + "type": "LoadImage", + "pos": [ + -737.1319580078125, + -174.04302978515625 + ], + "size": [ + 413.10479736328125, + 498.3180847167969 + ], + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 226 + ] + }, + { + "name": "MASK", + "type": "MASK", + "links": [] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.26", + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "12.jpg", + "image" + ], + "color": "#2a363b", + "bgcolor": "#3f5159" + }, { "id": 131, "type": "VHS_LoadVideo", "pos": [ - -1440.3040771484375, - -369.4672546386719 + 2823.573486328125, + -359.01287841796875 ], "size": [ 660, 693.2307739257812 ], "flags": {}, - "order": 16, + "order": 14, "mode": 0, "inputs": [ { @@ -1630,7 +1501,7 @@ "Node name for S&R": "VHS_LoadVideo" }, "widgets_values": { - "video": "woman.mp4", + "video": "13.mp4", "force_rate": 0, "custom_width": 0, "custom_height": 0, @@ -1643,7 +1514,7 @@ "hidden": false, "paused": false, "params": { - "filename": "woman.mp4", + "filename": "13.mp4", "type": "input", "format": "video/mp4", "force_rate": 0, @@ -1656,19 +1527,42 @@ } } }, + { + "id": 143, + "type": "MarkdownNote", + "pos": [ + -270.9808044433594, + 546.54931640625 + ], + "size": [ + 300, + 240 + ], + "flags": {}, + "order": 15, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "## **With a higher denoise strength, the face blends better with the background, but the background changes slightly more. With a lower denoise strength, the background changes less. You can adjust it according to your needs.**\n" + ], + "color": "#432", + "bgcolor": "#653" + }, { "id": 74, "type": "VHS_VideoCombine", "pos": [ - 1806.443115234375, - -332.1434020996094 + 1870, + -350 ], "size": [ 959.076171875, - 691.564453125 + 334 ], "flags": {}, - "order": 36, + "order": 37, "mode": 0, "inputs": [ { @@ -1722,76 +1616,96 @@ "hidden": false, "paused": false, "params": { - "filename": "WanVideoWrapper_T2V_Stand_In_00007.mp4", + "filename": "WanVideoWrapper_T2V_Stand_In_00008.mp4", "subfolder": "", "type": "temp", "format": "video/h264-mp4", "frame_rate": 16, - "workflow": "WanVideoWrapper_T2V_Stand_In_00007.png", - "fullpath": "/FirstIntelligence/home/bowen/ComfyUI/temp/WanVideoWrapper_T2V_Stand_In_00007.mp4" + "workflow": "WanVideoWrapper_T2V_Stand_In_00008.png", + "fullpath": "/FirstIntelligence/home/bowen/ComfyUI/temp/WanVideoWrapper_T2V_Stand_In_00008.mp4" } } } }, { - "id": 122, - "type": "ImageConcatMulti", + "id": 128, + "type": "ApplyFaceProcessor", "pos": [ - 1819.03466796875, - -562.8757934570312 + -258.21417236328125, + -111.67808532714844 ], "size": [ 270, - 150 + 198 ], "flags": {}, - "order": 35, + "order": 22, "mode": 0, "inputs": [ { - "name": "image_1", - "type": "IMAGE", - "link": 258 + "name": "face_processor", + "type": "FACE_PROCESSOR", + "link": 230 }, { - "name": "image_2", + "name": "image", "type": "IMAGE", - "link": 229 + "link": 226 + }, + { + "name": "face_only_mode", + "type": "BOOLEAN", + "widget": { + "name": "face_only_mode" + }, + "link": 263 } ], "outputs": [ { - "name": "images", + "name": "processed_image", "type": "IMAGE", "links": [ - 217 + 227, + 229, + 231 + ] + }, + { + "name": "face_rgba", + "type": "IMAGE", + "links": [ + 243 ] } ], "properties": { - "cnr_id": "comfyui-kjnodes", - "ver": "87d0cf42db7d59992daba4d58a83655b5b359f44" + "aux_id": "WeChatCV/Stand-In_Preprocessor_ComfyUI", + "ver": "db0d3d966dada4c5c242f9da5287988b533120e4", + "Node name for S&R": "ApplyFaceProcessor" }, "widgets_values": [ - 2, - "left", - true, - null + 512, + 10, + 1.5, + 0.5, + false, + true ] }, { "id": 146, "type": "VideoBackgroundRestorer", "pos": [ - 2116.058349609375, - -585.5603637695312 + 2122.31494140625, + -669.4810180664062 ], "size": [ 289.0025329589844, - 194 + 266 ], "flags": {}, - "order": 34, + "order": 35, "mode": 0, "inputs": [ { @@ -1808,6 +1722,14 @@ "name": "orig_images", "type": "IMAGE", "link": 257 + }, + { + "name": "face_only_mode", + "type": "BOOLEAN", + "widget": { + "name": "face_only_mode" + }, + "link": 264 } ], "outputs": [ @@ -1826,10 +1748,154 @@ }, "widgets_values": [ 0.5, - 2, + 3, + 25, 50, - 50, - false + false, + true, + 0.9, + true + ] + }, + { + "id": 138, + "type": "VideoInputPreprocessor", + "pos": [ + -274.0709533691406, + 247.68026733398438 + ], + "size": [ + 306.6597595214844, + 266 + ], + "flags": {}, + "order": 29, + "mode": 0, + "inputs": [ + { + "name": "face_processor", + "type": "FACE_PROCESSOR", + "link": 242 + }, + { + "name": "images", + "type": "IMAGE", + "link": 244 + }, + { + "name": "face_rgba", + "type": "IMAGE", + "link": 243 + }, + { + "name": "face_only_mode", + "type": "BOOLEAN", + "widget": { + "name": "face_only_mode" + }, + "link": 262 + } + ], + "outputs": [ + { + "name": "processed_images", + "type": "IMAGE", + "links": [ + 245 + ] + }, + { + "name": "denoise_strength", + "type": "FLOAT", + "links": [ + 252 + ] + } + ], + "properties": { + "aux_id": "WeChatCV/Stand-In_Preprocessor_ComfyUI", + "ver": "db0d3d966dada4c5c242f9da5287988b533120e4", + "Node name for S&R": "VideoInputPreprocessor" + }, + "widgets_values": [ + 0.5, + 0.5, + 1.5, + 10, + true, + true, + 21, + 0.15 + ] + }, + { + "id": 130, + "type": "FaceProcessorLoader", + "pos": [ + -285.0195007324219, + 125.5952377319336 + ], + "size": [ + 319.3335876464844, + 58 + ], + "flags": {}, + "order": 16, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "face_processor", + "type": "FACE_PROCESSOR", + "links": [ + 230, + 242, + 255 + ] + } + ], + "properties": { + "aux_id": "WeChatCV/Stand-In_Preprocessor_ComfyUI", + "ver": "db0d3d966dada4c5c242f9da5287988b533120e4", + "Node name for S&R": "FaceProcessorLoader" + }, + "widgets_values": [ + "model.pt" + ] + }, + { + "id": 150, + "type": "FaceOnlyModeSwitch", + "pos": [ + -704.624267578125, + 416.7978515625 + ], + "size": [ + 313.8716735839844, + 58 + ], + "flags": {}, + "order": 17, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "face_only_mode", + "type": "BOOLEAN", + "links": [ + 262, + 263, + 264 + ] + } + ], + "properties": { + "aux_id": "WeChatCV/Stand-In_Preprocessor_ComfyUI", + "ver": "c8feda62cc0f7da246678624ce17360e0aa5746b", + "Node name for S&R": "FaceOnlyModeSwitch" + }, + "widgets_values": [ + true ] } ], @@ -2161,6 +2227,30 @@ 122, 0, "IMAGE" + ], + [ + 262, + 150, + 0, + 138, + 3, + "BOOLEAN" + ], + [ + 263, + 150, + 0, + 128, + 2, + "BOOLEAN" + ], + [ + 264, + 150, + 0, + 146, + 3, + "BOOLEAN" ] ], "groups": [ @@ -2181,10 +2271,10 @@ "config": {}, "extra": { "ds": { - "scale": 0.45949729863573774, + "scale": 0.3452271214393293, "offset": [ - 1252.005220023947, - 985.0972195240975 + 2196.1039676207993, + 1308.1874027167953 ] }, "frontendVersion": "1.24.4",