fix the import

This commit is contained in:
KBRASK
2025-08-13 21:21:36 +08:00
parent 3e80a86cbd
commit db0d3d966d
3 changed files with 463 additions and 429 deletions
+37
View File
@@ -0,0 +1,37 @@
import logging
import os
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
logging.basicConfig(
level=getattr(logging, log_level, logging.INFO),
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)
NODE_PACK_NAME = "Stand-In"
logger.info("=" * 40 + f" {NODE_PACK_NAME} " + "=" * 40)
NODE_CLASS_MAPPINGS = {}
NODE_DISPLAY_NAME_MAPPINGS = {}
try:
from .nodes import FaceProcessorLoader, ApplyFaceProcessor
# Map the class names to the classes themselves
NODE_CLASS_MAPPINGS["FaceProcessorLoader"] = FaceProcessorLoader
NODE_CLASS_MAPPINGS["ApplyFaceProcessor"] = ApplyFaceProcessor
NODE_DISPLAY_NAME_MAPPINGS["FaceProcessorLoader"] = "Stand-In Processor Loader"
NODE_DISPLAY_NAME_MAPPINGS["ApplyFaceProcessor"] = "Apply Stand-In Processor"
logger.info("Successfully loaded all Stand-In nodes.")
except ImportError:
logger.exception(f"Failed to import nodes for {NODE_PACK_NAME}. Please ensure all dependencies are installed.")
except Exception as e:
logger.exception(f"An unexpected error occurred while loading nodes for {NODE_PACK_NAME}: {e}")
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
# --- Footer Banner ---
logger.info("=" * (82 + len(NODE_PACK_NAME)))
+15 -20
View File
@@ -5,16 +5,13 @@ import torch
import numpy as np
import PIL.Image
import PIL.ImageOps
# The ultralytics library is required for YOLOv8. Install with: pip install ultralytics
from ultralytics import YOLO
from facexlib.parsing import init_parsing_model
from torchvision.transforms.functional import normalize
from typing import Union, Optional
import folder_paths
# This code now requires the 'ultralytics' package.
# Please install it via pip:
# pip install ultralytics
LOADED_PROCESSORS = {}
@@ -32,7 +29,6 @@ def set_extra_config_model_path(extra_config_models_dir_key, models_dir_name: st
else:
folder_paths.add_model_folder_path(extra_config_models_dir_key, models_dir_default, is_default=True)
# Set up paths for YOLO and face parsing models
set_extra_config_model_path("yolo", "yolo")
set_extra_config_model_path("face_parsing", "face_parsing")
@@ -41,12 +37,10 @@ def download_yolo_model(model_name="model.pt"):
"""
Checks if a YOLO model exists and downloads it from a public source if not.
"""
# Publicly accessible model URL
model_url = f"https://huggingface.co/arnabdhar/YOLOv8-Face-Detection/resolve/main/{model_name}"
yolo_dir = os.path.join(folder_paths.get_folder_paths("yolo")[0])
model_path = os.path.join(yolo_dir, model_name)
# Ensure the target directory exists
os.makedirs(yolo_dir, exist_ok=True)
if not os.path.exists(model_path):
@@ -64,7 +58,6 @@ def download_yolo_model(model_name="model.pt"):
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
downloaded += len(chunk)
# Simple progress bar
done = int(50 * downloaded / total_size) if total_size > 0 else 0
progress_mb = downloaded / (1024*1024)
total_mb = total_size / (1024*1024)
@@ -72,16 +65,11 @@ def download_yolo_model(model_name="model.pt"):
print(f"\nModel successfully downloaded to: {model_path}")
except Exception as e:
print(f"\nFailed to download model: {e}")
print("Please check your internet connection or try downloading the model manually from:")
print(model_url)
print(f"And place it in the '{yolo_dir}' directory.")
# Clean up incomplete file if download failed
if os.path.exists(model_path):
os.remove(model_path)
raise e
return model_path
# --- Utility Functions ---
def _img2tensor(img: np.ndarray, bgr2rgb: bool = True) -> torch.Tensor:
if bgr2rgb:
@@ -141,7 +129,6 @@ class FaceProcessorLoader:
if not yolo_model_name.endswith(('.pt', '.onnx')):
raise ValueError(f"Invalid model name: '{yolo_model_name}'. Model filename must end with '.pt' or '.onnx'.")
# Call the download function to ensure the model file exists
model_path = download_yolo_model(yolo_model_name)
print(f"Loading YOLO model from local path: {model_path}")
@@ -176,14 +163,16 @@ class ApplyFaceProcessor:
"border_thresh": ("INT", {"default": 10, "min": 0, "max": 100, "step": 1}),
"face_crop_scale": ("FLOAT", {"default": 1.5, "min": 1.0, "max": 3.0, "step": 0.1}),
"confidence_threshold": ("FLOAT", {"default": 0.5, "min": 0.1, "max": 1.0, "step": 0.05}),
# --- NEW INPUT ---
"with_neck": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
}
}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "apply_processing"
CATEGORY = "FaceUtils"
CATEGORY = "Stand-In"
def apply_processing(self, face_processor, image, resize_to, border_thresh, face_crop_scale, confidence_threshold):
def apply_processing(self, face_processor, image, resize_to, border_thresh, face_crop_scale, confidence_threshold, with_neck):
detection_model, parsing_model, device = face_processor
frame = tensor_to_cv2_img(image)
@@ -228,12 +217,18 @@ class ApplyFaceProcessor:
with torch.no_grad():
normalized_face = normalize(face_tensor, [0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
parsing_out = parsing_model(normalized_face)[0]
parsing_mask = parsing_out.argmax(dim=1, keepdim=True)
parsing_map_tensor = parsing_out.argmax(dim=1, keepdim=True)
mask = (parsing_mask.squeeze().cpu().numpy() != 0).astype(np.uint8)
parsing_map_np = parsing_map_tensor.squeeze().cpu().numpy().astype(np.uint8)
if with_neck:
final_mask_np = (parsing_map_np != 0).astype(np.uint8)
else:
parts_to_remove = [0, 14, 16]
final_mask_np = np.isin(parsing_map_np, parts_to_remove, invert=True).astype(np.uint8)
white_background = np.ones_like(image_resized, dtype=np.uint8) * 255
mask_3channel = cv2.cvtColor(mask * 255, cv2.COLOR_GRAY2BGR)
mask_3channel = cv2.cvtColor(final_mask_np * 255, cv2.COLOR_GRAY2BGR)
result_img_bgr = np.where(mask_3channel != 0, image_resized, white_background)
@@ -250,4 +245,4 @@ NODE_CLASS_MAPPINGS = {
NODE_DISPLAY_NAME_MAPPINGS = {
"FaceProcessorLoader": "Stand-In Processor Loader",
"ApplyFaceProcessor": "Apply Stand-In Processor"
}
}
+411 -409
View File
@@ -1,8 +1,8 @@
{
"id": "206247b6-9fec-4ed2-8927-e4f388c674d4",
"revision": 0,
"last_node_id": 129,
"last_link_id": 229,
"last_node_id": 130,
"last_link_id": 231,
"nodes": [
{
"id": 50,
@@ -235,159 +235,6 @@
"color": "#223",
"bgcolor": "#335"
},
{
"id": 27,
"type": "WanVideoSampler",
"pos": [
1434.9656982421875,
-536.9714965820312
],
"size": [
315,
873.39453125
],
"flags": {},
"order": 29,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "WANVIDEOMODEL",
"link": 108
},
{
"name": "image_embeds",
"type": "WANVIDIMAGE_EMBEDS",
"link": 172
},
{
"name": "text_embeds",
"shape": 7,
"type": "WANVIDEOTEXTEMBEDS",
"link": 30
},
{
"name": "samples",
"shape": 7,
"type": "LATENT",
"link": null
},
{
"name": "feta_args",
"shape": 7,
"type": "FETAARGS",
"link": null
},
{
"name": "context_options",
"shape": 7,
"type": "WANVIDCONTEXT",
"link": null
},
{
"name": "cache_args",
"shape": 7,
"type": "CACHEARGS",
"link": null
},
{
"name": "flowedit_args",
"shape": 7,
"type": "FLOWEDITARGS",
"link": null
},
{
"name": "slg_args",
"shape": 7,
"type": "SLGARGS",
"link": null
},
{
"name": "loop_args",
"shape": 7,
"type": "LOOPARGS",
"link": null
},
{
"name": "experimental_args",
"shape": 7,
"type": "EXPERIMENTALARGS",
"link": null
},
{
"name": "sigmas",
"shape": 7,
"type": "SIGMAS",
"link": null
},
{
"name": "unianimate_poses",
"shape": 7,
"type": "UNIANIMATE_POSE",
"link": null
},
{
"name": "fantasytalking_embeds",
"shape": 7,
"type": "FANTASYTALKING_EMBEDS",
"link": null
},
{
"name": "uni3c_embeds",
"shape": 7,
"type": "UNI3C_EMBEDS",
"link": null
},
{
"name": "multitalk_embeds",
"shape": 7,
"type": "MULTITALK_EMBEDS",
"link": null
},
{
"name": "freeinit_args",
"shape": 7,
"type": "FREEINITARGS",
"link": null
}
],
"outputs": [
{
"name": "samples",
"type": "LATENT",
"slot_index": 0,
"links": [
33
]
},
{
"name": "denoised_samples",
"type": "LATENT",
"links": null
}
],
"properties": {
"cnr_id": "ComfyUI-WanVideoWrapper",
"ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50",
"Node name for S&R": "WanVideoSampler"
},
"widgets_values": [
4,
1,
5,
44,
"fixed",
true,
"dpm++_sde",
0,
1,
"",
"comfy",
0,
-1,
false
]
},
{
"id": 35,
"type": "WanVideoTorchCompileSettings",
@@ -778,62 +625,6 @@
"color": "#2a363b",
"bgcolor": "#3f5159"
},
{
"id": 104,
"type": "WanVideoEncode",
"pos": [
193.28677368164062,
-85.77310180664062
],
"size": [
270,
242
],
"flags": {},
"order": 26,
"mode": 0,
"inputs": [
{
"name": "vae",
"type": "WANVAE",
"link": 175
},
{
"name": "image",
"type": "IMAGE",
"link": 228
},
{
"name": "mask",
"shape": 7,
"type": "MASK",
"link": null
}
],
"outputs": [
{
"name": "samples",
"type": "LATENT",
"links": [
174
]
}
],
"properties": {
"cnr_id": "ComfyUI-WanVideoWrapper",
"ver": "06863fe2d283e89ba2386260ad2700557dda1897",
"Node name for S&R": "WanVideoEncode"
},
"widgets_values": [
false,
272,
272,
144,
128,
0,
1
]
},
{
"id": 38,
"type": "WanVideoVAELoader",
@@ -1144,6 +935,124 @@
"color": "#223",
"bgcolor": "#335"
},
{
"id": 46,
"type": "WanVideoTextEmbedBridge",
"pos": [
943.1697387695312,
1096.8651123046875
],
"size": [
315,
46
],
"flags": {
"collapsed": true
},
"order": 22,
"mode": 2,
"inputs": [
{
"name": "positive",
"type": "CONDITIONING",
"link": 54
},
{
"name": "negative",
"shape": 7,
"type": "CONDITIONING",
"link": 55
}
],
"outputs": [
{
"name": "text_embeds",
"type": "WANVIDEOTEXTEMBEDS",
"links": null
}
],
"properties": {
"cnr_id": "ComfyUI-WanVideoWrapper",
"ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50",
"Node name for S&R": "WanVideoTextEmbedBridge"
},
"widgets_values": []
},
{
"id": 126,
"type": "MarkdownNote",
"pos": [
-653.9163818359375,
-382.01556396484375
],
"size": [
362.6117858886719,
143.0945281982422
],
"flags": {},
"order": 13,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {},
"widgets_values": [
"LoRA link:\n\n[https://huggingface.co/BowenXue/Stand-In](https://huggingface.co/BowenXue/Stand-In)\n\nThis LoRA is not the traditional kind and it HAS TO connect to the model loader directly."
],
"color": "#432",
"bgcolor": "#653"
},
{
"id": 121,
"type": "PreviewImage",
"pos": [
37.458839416503906,
-72.97832489013672
],
"size": [
140,
246
],
"flags": {},
"order": 25,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 227
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.49",
"Node name for S&R": "PreviewImage"
},
"widgets_values": []
},
{
"id": 129,
"type": "MarkdownNote",
"pos": [
791.3861694335938,
-356.8863830566406
],
"size": [
362.6117858886719,
143.0945281982422
],
"flags": {},
"order": 14,
"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": 16,
"type": "WanVideoTextEncode",
@@ -1188,7 +1097,7 @@
"Node name for S&R": "WanVideoTextEncode"
},
"widgets_values": [
"一位男性舒适地坐在书桌前,正对着镜头,仿佛在与屏幕前的亲友对话。他的眼神专注而温柔,嘴角带着自然的笑意。背景是他精心布置的个人空间,墙上贴着照片和一张世界地图,传达出一种亲密而现代的沟通感。",
"一位男性舒适地坐在书桌前,正对着镜头,仿佛在与屏幕前的亲友对话。他的眼神专注而温柔,嘴角带着自然的笑意。背景是他精心布置的个人空间,墙上贴着照片和一张世界地图,传达出一种亲密而现代的沟通感",
"色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走",
true,
false,
@@ -1197,6 +1106,200 @@
"color": "#332922",
"bgcolor": "#593930"
},
{
"id": 27,
"type": "WanVideoSampler",
"pos": [
1434.9656982421875,
-536.9714965820312
],
"size": [
315,
873.39453125
],
"flags": {},
"order": 29,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "WANVIDEOMODEL",
"link": 108
},
{
"name": "image_embeds",
"type": "WANVIDIMAGE_EMBEDS",
"link": 172
},
{
"name": "text_embeds",
"shape": 7,
"type": "WANVIDEOTEXTEMBEDS",
"link": 30
},
{
"name": "samples",
"shape": 7,
"type": "LATENT",
"link": null
},
{
"name": "feta_args",
"shape": 7,
"type": "FETAARGS",
"link": null
},
{
"name": "context_options",
"shape": 7,
"type": "WANVIDCONTEXT",
"link": null
},
{
"name": "cache_args",
"shape": 7,
"type": "CACHEARGS",
"link": null
},
{
"name": "flowedit_args",
"shape": 7,
"type": "FLOWEDITARGS",
"link": null
},
{
"name": "slg_args",
"shape": 7,
"type": "SLGARGS",
"link": null
},
{
"name": "loop_args",
"shape": 7,
"type": "LOOPARGS",
"link": null
},
{
"name": "experimental_args",
"shape": 7,
"type": "EXPERIMENTALARGS",
"link": null
},
{
"name": "sigmas",
"shape": 7,
"type": "SIGMAS",
"link": null
},
{
"name": "unianimate_poses",
"shape": 7,
"type": "UNIANIMATE_POSE",
"link": null
},
{
"name": "fantasytalking_embeds",
"shape": 7,
"type": "FANTASYTALKING_EMBEDS",
"link": null
},
{
"name": "uni3c_embeds",
"shape": 7,
"type": "UNI3C_EMBEDS",
"link": null
},
{
"name": "multitalk_embeds",
"shape": 7,
"type": "MULTITALK_EMBEDS",
"link": null
},
{
"name": "freeinit_args",
"shape": 7,
"type": "FREEINITARGS",
"link": null
}
],
"outputs": [
{
"name": "samples",
"type": "LATENT",
"slot_index": 0,
"links": [
33
]
},
{
"name": "denoised_samples",
"type": "LATENT",
"links": null
}
],
"properties": {
"cnr_id": "ComfyUI-WanVideoWrapper",
"ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50",
"Node name for S&R": "WanVideoSampler"
},
"widgets_values": [
4,
1,
5,
44,
"fixed",
true,
"dpm++_sde",
0,
1,
"",
"comfy",
0,
-1,
false
]
},
{
"id": 58,
"type": "LoadImage",
"pos": [
-737.1319580078125,
-174.04302978515625
],
"size": [
413.10479736328125,
498.3180847167969
],
"flags": {},
"order": 15,
"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": [
"GettyImages-540680934-thumb.webp",
"image"
],
"color": "#2a363b",
"bgcolor": "#3f5159"
},
{
"id": 74,
"type": "VHS_VideoCombine",
@@ -1206,7 +1309,7 @@
],
"size": [
959.076171875,
691.564453125
334
],
"flags": {},
"order": 32,
@@ -1275,58 +1378,102 @@
}
},
{
"id": 46,
"type": "WanVideoTextEmbedBridge",
"id": 104,
"type": "WanVideoEncode",
"pos": [
943.1697387695312,
1096.8651123046875
185.17897033691406,
-134.4200897216797
],
"size": [
315,
46
270,
242
],
"flags": {
"collapsed": true
},
"order": 22,
"mode": 2,
"flags": {},
"order": 26,
"mode": 0,
"inputs": [
{
"name": "positive",
"type": "CONDITIONING",
"link": 54
"name": "vae",
"type": "WANVAE",
"link": 175
},
{
"name": "negative",
"name": "image",
"type": "IMAGE",
"link": 231
},
{
"name": "mask",
"shape": 7,
"type": "CONDITIONING",
"link": 55
"type": "MASK",
"link": null
}
],
"outputs": [
{
"name": "text_embeds",
"type": "WANVIDEOTEXTEMBEDS",
"links": null
"name": "samples",
"type": "LATENT",
"links": [
174
]
}
],
"properties": {
"cnr_id": "ComfyUI-WanVideoWrapper",
"ver": "d9b1f4d1a5aea91d101ae97a54714a5861af3f50",
"Node name for S&R": "WanVideoTextEmbedBridge"
"ver": "06863fe2d283e89ba2386260ad2700557dda1897",
"Node name for S&R": "WanVideoEncode"
},
"widgets_values": []
"widgets_values": [
false,
272,
272,
144,
128,
0,
1
]
},
{
"id": 130,
"type": "FaceProcessorLoader",
"pos": [
-299.8837890625,
128.56805419921875
],
"size": [
319.3335876464844,
58
],
"flags": {},
"order": 16,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "face_processor",
"type": "FACE_PROCESSOR",
"links": [
230
]
}
],
"properties": {
"Node name for S&R": "FaceProcessorLoader"
},
"widgets_values": [
"model.pt"
]
},
{
"id": 128,
"type": "ApplyFaceProcessor",
"pos": [
-297.2541198730469,
-77.13932037353516
-258.21417236328125,
-111.67808532714844
],
"size": [
270,
126
174
],
"flags": {},
"order": 21,
@@ -1335,7 +1482,7 @@
{
"name": "face_processor",
"type": "FACE_PROCESSOR",
"link": 223
"link": 230
},
{
"name": "image",
@@ -1349,8 +1496,8 @@
"type": "IMAGE",
"links": [
227,
228,
229
229,
231
]
}
],
@@ -1360,155 +1507,10 @@
"widgets_values": [
512,
10,
1.5
1.5,
0.5,
false
]
},
{
"id": 127,
"type": "FaceProcessorLoader",
"pos": [
-294.2811279296875,
107.27786254882812
],
"size": [
270,
58
],
"flags": {},
"order": 13,
"mode": 0,
"inputs": [],
"outputs": [
{
"name": "face_processor",
"type": "FACE_PROCESSOR",
"links": [
223
]
}
],
"properties": {
"Node name for S&R": "FaceProcessorLoader"
},
"widgets_values": [
"models/insightface"
]
},
{
"id": 126,
"type": "MarkdownNote",
"pos": [
-653.9163818359375,
-382.01556396484375
],
"size": [
362.6117858886719,
143.0945281982422
],
"flags": {},
"order": 14,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {},
"widgets_values": [
"LoRA link:\n\n[https://huggingface.co/BowenXue/Stand-In](https://huggingface.co/BowenXue/Stand-In)\n\nThis LoRA is not the traditional kind and it HAS TO connect to the model loader directly."
],
"color": "#432",
"bgcolor": "#653"
},
{
"id": 121,
"type": "PreviewImage",
"pos": [
37.458839416503906,
-72.97832489013672
],
"size": [
140,
246
],
"flags": {},
"order": 25,
"mode": 0,
"inputs": [
{
"name": "images",
"type": "IMAGE",
"link": 227
}
],
"outputs": [],
"properties": {
"cnr_id": "comfy-core",
"ver": "0.3.49",
"Node name for S&R": "PreviewImage"
},
"widgets_values": []
},
{
"id": 58,
"type": "LoadImage",
"pos": [
-737.1319580078125,
-174.04302978515625
],
"size": [
413.10479736328125,
498.3180847167969
],
"flags": {},
"order": 15,
"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": [
"clipspace/clipspace-mask-379138.7999999998.png [input]",
"image"
],
"color": "#2a363b",
"bgcolor": "#3f5159"
},
{
"id": 129,
"type": "MarkdownNote",
"pos": [
791.3861694335938,
-356.8863830566406
],
"size": [
362.6117858886719,
143.0945281982422
],
"flags": {},
"order": 16,
"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"
}
],
"links": [
@@ -1704,14 +1706,6 @@
3,
"INT"
],
[
223,
127,
0,
128,
0,
"FACE_PROCESSOR"
],
[
226,
58,
@@ -1728,14 +1722,6 @@
0,
"IMAGE"
],
[
228,
128,
0,
104,
1,
"IMAGE"
],
[
229,
128,
@@ -1743,6 +1729,22 @@
122,
1,
"IMAGE"
],
[
230,
130,
0,
128,
0,
"FACE_PROCESSOR"
],
[
231,
128,
0,
104,
1,
"IMAGE"
]
],
"groups": [
@@ -1763,10 +1765,10 @@
"config": {},
"extra": {
"ds": {
"scale": 0.6727499949326107,
"scale": 0.7400249944258753,
"offset": [
1220.5620388990717,
479.6860694347906
1050.1092033816878,
678.2426041646066
]
},
"frontendVersion": "1.24.4",