From bbf72e1c53ca271ae06e875002e2f9a2c19a2e20 Mon Sep 17 00:00:00 2001 From: luxdelux7 Date: Thu, 12 Mar 2026 08:52:40 +0100 Subject: [PATCH] workflow updates --- .../Forbidden_Vision_Mask_Only.json | 1 + .../Forbidden_Vision_Modular_Setup.json | 1 + .../Forbidden_Vision_workflow.json | 0 src/face_edit_nodes.py | 41 ++++++++++++++++++- 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 comfyui_workflows/Forbidden_Vision_Mask_Only.json create mode 100644 comfyui_workflows/Forbidden_Vision_Modular_Setup.json rename Forbidden_Vision_workflow.json => comfyui_workflows/Forbidden_Vision_workflow.json (100%) diff --git a/comfyui_workflows/Forbidden_Vision_Mask_Only.json b/comfyui_workflows/Forbidden_Vision_Mask_Only.json new file mode 100644 index 0000000..396980c --- /dev/null +++ b/comfyui_workflows/Forbidden_Vision_Mask_Only.json @@ -0,0 +1 @@ +{"id":"d97cddfb-e226-4b06-a66a-f57669cdb19c","revision":0,"last_node_id":4,"last_link_id":2,"nodes":[{"id":3,"type":"MaskPreview","pos":[1014.7427734375,130],"size":[140,246],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"mask","name":"mask","type":"MASK","link":2}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"MaskPreview","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[]},{"id":2,"type":"LoadImage","pos":[100,130],"size":[282.798828125,314],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[1]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"LoadImage","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":["example.png","image"]},{"id":1,"type":"ForbiddenVisionFaceFixerMaskOnly","pos":[570,130],"size":[344.7427734375,106],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"IMAGE","link":1},{"localized_name":"face_selection","name":"face_selection","type":"INT","widget":{"name":"face_selection"},"link":null},{"localized_name":"enable_segmentation","name":"enable_segmentation","type":"BOOLEAN","widget":{"name":"enable_segmentation"},"link":null},{"localized_name":"detection_confidence","name":"detection_confidence","type":"FLOAT","widget":{"name":"detection_confidence"},"link":null}],"outputs":[{"localized_name":"face_masks","name":"face_masks","type":"MASK","links":[2]}],"properties":{"cnr_id":"forbidden-vision","ver":"096f144c59815518bd12e2c8c7c3763a7e1d8e36","Node name for S&R":"ForbiddenVisionFaceFixerMaskOnly","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[0,true,0.8]},{"id":4,"type":"MarkdownNote","pos":[110,-120],"size":[460,200],"flags":{},"order":1,"mode":0,"inputs":[],"outputs":[],"title":"Welcome to Forbidden Vision","properties":{"ue_properties":{"widget_ue_connectable":{},"version":"7.5.1","input_ue_unconnectable":{}}},"widgets_values":["# Mask only\n\n**Nice and easy.**\n\n**Face Selection** — 0 captures all detected faces. 1 and up selects a face by highest detection confidence level\n\nLowering detection confidence makes the detection model return more \"unsure\" detections.\n\nYou can also disable segmentation and just use the detection box as the mask\n\nThe output is the face mask within the input image resolution.\n\n"],"color":"#223","bgcolor":"#335","shape":4}],"links":[[1,2,0,1,0,"IMAGE"],[2,1,0,3,0,"MASK"]],"groups":[],"config":{},"extra":{"workflowRendererVersion":"LG","ue_links":[],"ds":{"scale":1.1814332247557002,"offset":[239.3724787347927,262.3333333333333]},"links_added_by_ue":[]},"version":0.4} \ No newline at end of file diff --git a/comfyui_workflows/Forbidden_Vision_Modular_Setup.json b/comfyui_workflows/Forbidden_Vision_Modular_Setup.json new file mode 100644 index 0000000..22c1248 --- /dev/null +++ b/comfyui_workflows/Forbidden_Vision_Modular_Setup.json @@ -0,0 +1 @@ +{"id":"1fd64184-93c3-49e1-97f7-25f4beaf72d4","revision":0,"last_node_id":27,"last_link_id":47,"nodes":[{"id":7,"type":"MarkdownNote","pos":[910,-90],"size":[340,90],"flags":{},"order":1,"mode":0,"inputs":[],"outputs":[],"title":"Face Edit Merge","properties":{"ue_properties":{"widget_ue_connectable":{},"version":"7.5.1","input_ue_unconnectable":{}}},"widgets_values":["This will perform blending of the edit back into the original image"],"color":"#223","bgcolor":"#335","shape":4},{"id":10,"type":"PreviewImage","pos":[1360,60],"size":[140,246],"flags":{},"order":15,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":6}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"PreviewImage","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[]},{"id":3,"type":"MarkdownNote","pos":[50,-260],"size":[390,90],"flags":{},"order":2,"mode":0,"inputs":[],"outputs":[],"title":"Welcome to Forbidden Vision","properties":{"ue_properties":{"widget_ue_connectable":{},"version":"7.5.1","input_ue_unconnectable":{}}},"widgets_values":["# Modular detection and segmentation\n\nDetection and segmentation nodes with all sampling functionality removed."],"color":"#223","bgcolor":"#335","shape":4},{"id":13,"type":"KSampler","pos":[1310,700],"size":[270,474],"flags":{},"order":11,"mode":0,"inputs":[{"localized_name":"model","name":"model","type":"MODEL","link":26},{"localized_name":"positive","name":"positive","type":"CONDITIONING","link":38},{"localized_name":"negative","name":"negative","type":"CONDITIONING","link":39},{"localized_name":"latent_image","name":"latent_image","type":"LATENT","link":18},{"localized_name":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"steps","name":"steps","type":"INT","widget":{"name":"steps"},"link":null},{"localized_name":"cfg","name":"cfg","type":"FLOAT","widget":{"name":"cfg"},"link":null},{"localized_name":"sampler_name","name":"sampler_name","type":"COMBO","widget":{"name":"sampler_name"},"link":null},{"localized_name":"scheduler","name":"scheduler","type":"COMBO","widget":{"name":"scheduler"},"link":null},{"localized_name":"denoise","name":"denoise","type":"FLOAT","widget":{"name":"denoise"},"link":null}],"outputs":[{"localized_name":"LATENT","name":"LATENT","type":"LATENT","links":[19]}],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"KSampler","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[1042026559803898,"fixed",20,8,"euler_ancestral","simple",1]},{"id":11,"type":"InpaintModelConditioning","pos":[1300,490],"size":[270,138],"flags":{},"order":10,"mode":0,"inputs":[{"localized_name":"positive","name":"positive","type":"CONDITIONING","link":10},{"localized_name":"negative","name":"negative","type":"CONDITIONING","link":14},{"localized_name":"vae","name":"vae","type":"VAE","link":20},{"localized_name":"pixels","name":"pixels","type":"IMAGE","link":40},{"localized_name":"mask","name":"mask","type":"MASK","link":41},{"localized_name":"noise_mask","name":"noise_mask","type":"BOOLEAN","widget":{"name":"noise_mask"},"link":null}],"outputs":[{"localized_name":"positive","name":"positive","type":"CONDITIONING","links":[38]},{"localized_name":"negative","name":"negative","type":"CONDITIONING","links":[39]},{"localized_name":"latent","name":"latent","type":"LATENT","links":[18]}],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"InpaintModelConditioning","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[true]},{"id":24,"type":"ForbiddenVisionFaceEditPrep","pos":[70,80],"size":[334.058203125,338],"flags":{},"order":9,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"IMAGE","link":42},{"localized_name":"mask","name":"mask","shape":7,"type":"MASK","link":null},{"localized_name":"face_selection","name":"face_selection","type":"INT","widget":{"name":"face_selection"},"link":null},{"localized_name":"enable_segmentation","name":"enable_segmentation","type":"BOOLEAN","widget":{"name":"enable_segmentation"},"link":null},{"localized_name":"detection_confidence","name":"detection_confidence","type":"FLOAT","widget":{"name":"detection_confidence"},"link":null},{"localized_name":"processing_resolution","name":"processing_resolution","type":"INT","widget":{"name":"processing_resolution"},"link":null},{"localized_name":"crop_padding","name":"crop_padding","type":"FLOAT","widget":{"name":"crop_padding"},"link":null},{"localized_name":"mask_expansion","name":"mask_expansion","type":"INT","widget":{"name":"mask_expansion"},"link":null},{"localized_name":"sampling_mask_blur_size","name":"sampling_mask_blur_size","type":"INT","widget":{"name":"sampling_mask_blur_size"},"link":null},{"localized_name":"sampling_mask_blur_strength","name":"sampling_mask_blur_strength","type":"FLOAT","widget":{"name":"sampling_mask_blur_strength"},"link":null},{"localized_name":"enable_pre_upscale","name":"enable_pre_upscale","type":"BOOLEAN","widget":{"name":"enable_pre_upscale"},"link":null},{"localized_name":"upscaler_model","name":"upscaler_model","type":"COMBO","widget":{"name":"upscaler_model"},"link":null},{"localized_name":"isolate_face","name":"isolate_face","type":"BOOLEAN","widget":{"name":"isolate_face"},"link":null}],"outputs":[{"localized_name":"cropped_face","name":"cropped_face","type":"IMAGE","links":[40]},{"localized_name":"cropped_mask","name":"cropped_mask","type":"MASK","links":[41]},{"localized_name":"face_info","name":"face_info","type":"FACE_INFO","links":[43]}],"properties":{"cnr_id":"forbidden-vision","ver":"096f144c59815518bd12e2c8c7c3763a7e1d8e36","Node name for S&R":"ForbiddenVisionFaceEditPrep","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[0,true,0.8,1024,1.6,2,21,6,true,"Fast 4x (Lanczos)",false]},{"id":4,"type":"LoadImage","pos":[-290,50],"size":[282.798828125,314],"flags":{},"order":4,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[5,42]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"LoadImage","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":["example.png","image"]},{"id":18,"type":"PreviewImage","pos":[1630,640],"size":[140,246],"flags":{},"order":13,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":22}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"PreviewImage","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[]},{"id":17,"type":"VAEDecode","pos":[1630,510],"size":[140,46],"flags":{},"order":12,"mode":0,"inputs":[{"localized_name":"samples","name":"samples","type":"LATENT","link":19},{"localized_name":"vae","name":"vae","type":"VAE","link":21}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[22,27]}],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"VAEDecode","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[]},{"id":16,"type":"CheckpointLoaderSimple","pos":[490,500],"size":[270,98],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"ckpt_name","name":"ckpt_name","type":"COMBO","widget":{"name":"ckpt_name"},"link":null}],"outputs":[{"localized_name":"MODEL","name":"MODEL","type":"MODEL","links":[25]},{"localized_name":"CLIP","name":"CLIP","type":"CLIP","links":[23,24]},{"localized_name":"VAE","name":"VAE","type":"VAE","links":[20,21]}],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"CheckpointLoaderSimple","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":["novaAnimeXL_ilV140.safetensors"]},{"id":19,"type":"DifferentialDiffusion","pos":[500,670],"size":[270,58],"flags":{},"order":6,"mode":0,"inputs":[{"localized_name":"model","name":"model","type":"MODEL","link":25},{"localized_name":"strength","name":"strength","shape":7,"type":"FLOAT","widget":{"name":"strength"},"link":null}],"outputs":[{"localized_name":"MODEL","name":"MODEL","type":"MODEL","links":[26]}],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"DifferentialDiffusion","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[1]},{"id":14,"type":"CLIPTextEncode","pos":[800,500],"size":[400,200],"flags":{},"order":7,"mode":0,"inputs":[{"localized_name":"clip","name":"clip","type":"CLIP","link":23},{"localized_name":"text","name":"text","type":"STRING","widget":{"name":"text"},"link":null}],"outputs":[{"localized_name":"CONDITIONING","name":"CONDITIONING","type":"CONDITIONING","links":[10]}],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"CLIPTextEncode","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[""]},{"id":15,"type":"CLIPTextEncode","pos":[810,760],"size":[400,200],"flags":{},"order":8,"mode":0,"inputs":[{"localized_name":"clip","name":"clip","type":"CLIP","link":24},{"localized_name":"text","name":"text","type":"STRING","widget":{"name":"text"},"link":null}],"outputs":[{"localized_name":"CONDITIONING","name":"CONDITIONING","type":"CONDITIONING","links":[14]}],"properties":{"cnr_id":"comfy-core","ver":"0.15.1","Node name for S&R":"CLIPTextEncode","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[""]},{"id":9,"type":"MarkdownNote","pos":[460,260],"size":[380,110],"flags":{},"order":5,"mode":0,"inputs":[],"outputs":[],"title":"Your sampling process","properties":{"ue_properties":{"widget_ue_connectable":{},"version":"7.5.1","input_ue_unconnectable":{}}},"widgets_values":["# Do what you want with the outputs and then connect to edited_face\n\nThis is a basic example with regular comfyui inpaint sampling."],"color":"#223","bgcolor":"#335","shape":4},{"id":6,"type":"MarkdownNote","pos":[50,-110],"size":[550,140],"flags":{},"order":0,"mode":0,"inputs":[],"outputs":[],"title":"Face Edit Prep","properties":{"ue_properties":{"widget_ue_connectable":{},"version":"7.5.1","input_ue_unconnectable":{}}},"widgets_values":["Runs the detection and segmentation on the input image.\n\nThe output is then constrained within the processing_resolution value.\n\nYou can increase the amount of space around the mask with **crop_padding**\n\nYou can disable mask blurring (gaussian blur) by setting **sampling_mask_blur_strength** to 0.\n\nIsolate face -> outputs the masked face on black background. Could be useful for some workflows"],"color":"#223","bgcolor":"#335","shape":4},{"id":2,"type":"ForbiddenVisionFaceEditMerge","pos":[910,60],"size":[345.9390625,146],"flags":{},"order":14,"mode":0,"inputs":[{"localized_name":"original_image","name":"original_image","type":"IMAGE","link":5},{"localized_name":"edited_face","name":"edited_face","type":"IMAGE","link":27},{"localized_name":"face_info","name":"face_info","type":"FACE_INFO","link":43},{"localized_name":"blend_softness","name":"blend_softness","type":"INT","widget":{"name":"blend_softness"},"link":null},{"localized_name":"enable_color_correction","name":"enable_color_correction","type":"BOOLEAN","widget":{"name":"enable_color_correction"},"link":null},{"localized_name":"color_correction_strength","name":"color_correction_strength","type":"FLOAT","widget":{"name":"color_correction_strength"},"link":null}],"outputs":[{"localized_name":"final_image","name":"final_image","type":"IMAGE","links":[6]},{"localized_name":"compositing_mask","name":"compositing_mask","type":"MASK","links":null}],"properties":{"cnr_id":"forbidden-vision","ver":"096f144c59815518bd12e2c8c7c3763a7e1d8e36","Node name for S&R":"ForbiddenVisionFaceEditMerge","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.5.1"}},"widgets_values":[8,true,1]}],"links":[[5,4,0,2,0,"IMAGE"],[6,2,0,10,0,"IMAGE"],[10,14,0,11,0,"CONDITIONING"],[14,15,0,11,1,"CONDITIONING"],[18,11,2,13,3,"LATENT"],[19,13,0,17,0,"LATENT"],[20,16,2,11,2,"VAE"],[21,16,2,17,1,"VAE"],[22,17,0,18,0,"IMAGE"],[23,16,1,14,0,"CLIP"],[24,16,1,15,0,"CLIP"],[25,16,0,19,0,"MODEL"],[26,19,0,13,0,"MODEL"],[27,17,0,2,1,"IMAGE"],[38,11,0,13,1,"CONDITIONING"],[39,11,1,13,2,"CONDITIONING"],[40,24,0,11,3,"IMAGE"],[41,24,1,11,4,"MASK"],[42,4,0,24,0,"IMAGE"],[43,24,2,2,2,"FACE_INFO"]],"groups":[{"id":1,"title":"Basic example","bounding":[460,400,1350,820],"color":"#3f789e","font_size":24,"flags":{}}],"config":{},"extra":{"workflowRendererVersion":"LG","ue_links":[],"ds":{"scale":0.7627768444385465,"offset":[462.85776279696415,355.52030237776177]},"links_added_by_ue":[]},"version":0.4} \ No newline at end of file diff --git a/Forbidden_Vision_workflow.json b/comfyui_workflows/Forbidden_Vision_workflow.json similarity index 100% rename from Forbidden_Vision_workflow.json rename to comfyui_workflows/Forbidden_Vision_workflow.json diff --git a/src/face_edit_nodes.py b/src/face_edit_nodes.py index 9e28e59..7e777ee 100644 --- a/src/face_edit_nodes.py +++ b/src/face_edit_nodes.py @@ -12,6 +12,7 @@ from .face_processor_integrated import ForbiddenVisionFaceProcessorIntegrated from .utils import check_for_interruption, ensure_model_directories, get_ordered_upscaler_model_list, clean_model_name + class ForbiddenVisionFaceEditPrep: @classmethod def INPUT_TYPES(s): @@ -29,6 +30,12 @@ class ForbiddenVisionFaceEditPrep: "processing_resolution": ("INT", {"default": 1024, "min": 512, "max": 2048, "step": 64}), "crop_padding": ("FLOAT", {"default": 1.6, "min": 1.0, "max": 3.0, "step": 0.1}), "mask_expansion": ("INT", {"default": 2, "min": 0, "max": 100, "step": 1}), + # ── NEW ────────────────────────────────────────────────────────── + "sampling_mask_blur_size": ("INT", {"default": 21, "min": 0, "max": 101, "step": 2, + "tooltip": "Blur kernel size for the output mask. 0 or 1 = no blur."}), + "sampling_mask_blur_strength": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 6.0, "step": 0.1, + "tooltip": "Controls blur sigma relative to kernel size."}), + # ───────────────────────────────────────────────────────────────── "enable_pre_upscale": ("BOOLEAN", {"default": True}), "upscaler_model": (upscaler_models, {"default": default_upscaler}), "isolate_face": ("BOOLEAN", {"default": False}), @@ -50,6 +57,34 @@ class ForbiddenVisionFaceEditPrep: self.upscaler_model = None self.upscaler_model_name = None + # ── NEW HELPER ──────────────────────────────────────────────────────────── + def _blur_mask(self, mask_tensor, blur_size, blur_strength): + """ + Apply Gaussian blur to a (B, H, W) mask tensor. + Returns the mask unchanged when blur_size <= 1. + Mirrors the logic in process_inpaint_mask() from the main node. + """ + if blur_size <= 1: + return mask_tensor + + # kernel size must be odd + if blur_size % 2 == 0: + blur_size += 1 + + device = mask_tensor.device + mask_4d = mask_tensor.unsqueeze(1) # (B, 1, H, W) + + base_sigma = (blur_size - 1) / 8.0 + strength_t = torch.tensor(blur_strength - 1.0, device=device, dtype=torch.float32) + multiplier = 1.0 + torch.tanh(strength_t) * 2.0 + actual_sigma = base_sigma * multiplier.item() + + blurred = kornia.filters.gaussian_blur2d( + mask_4d, (blur_size, blur_size), (actual_sigma, actual_sigma) + ) + return blurred.squeeze(1) # back to (B, H, W) + # ───────────────────────────────────────────────────────────────────────── + def load_upscaler_model(self, model_name): clean_model_name_val = clean_model_name(model_name) @@ -193,6 +228,7 @@ class ForbiddenVisionFaceEditPrep: def prepare_face(self, image, face_selection, enable_segmentation, detection_confidence, processing_resolution, crop_padding, mask_expansion, + sampling_mask_blur_size, sampling_mask_blur_strength, # ← NEW enable_pre_upscale, upscaler_model, isolate_face, mask=None): try: check_for_interruption() @@ -259,6 +295,10 @@ class ForbiddenVisionFaceEditPrep: cropped_face = cropped_face.to(device) sampler_mask = sampler_mask.to(device) + # ── NEW: apply mask blur if requested ──────────────────────────── + sampler_mask = self._blur_mask(sampler_mask, sampling_mask_blur_size, sampling_mask_blur_strength) + # ───────────────────────────────────────────────────────────────── + if isolate_face: mask_bchw = sampler_mask.unsqueeze(1) kh = max(3, (processing_resolution // 32) | 1) @@ -309,7 +349,6 @@ class ForbiddenVisionFaceEditPrep: return (empty_face, empty_mask, empty_info) - class ForbiddenVisionFaceEditMerge: @classmethod def INPUT_TYPES(s):