Merge branch 'feature/tosegs' into Main
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
* BitwiseAndMaskForEach - Perform 'bitwise and' operations between 2 SEGS.
|
||||
* BitwiseAndMaskForEach - Perform subtract operations between 2 SEGS.
|
||||
* Segs & Masks - Perform a bitwise AND operation on SEGS and MASK.
|
||||
* MaskToSegs - This node generates SEGS based on the mask.
|
||||
* ToBinaryMask - This node separates the mask generated with alpha values between 0 and 255 into 0 and 255. The non-zero parts are always set to 255.
|
||||
|
||||
# Installation
|
||||
|
||||
@@ -52,7 +54,7 @@
|
||||
|
||||
#### 1. Basic auto face detection and refine exapmle.
|
||||

|
||||
 
|
||||
  
|
||||
* The face that has been damaged due to low resolution is restored with high resolution by generating and synthesizing it, in order to restore the details.
|
||||
* You can load models for bbox or segm using MMDetLoader. If you load a bbox model, only **BBOX_MODEL** is valid in the output, and if you load a segm model, only **SEGM_MODEL** is valid.
|
||||
* Currently, we are using the more sophisticated SAM model instead of the SEGM_MODEL for silhouette extraction.
|
||||
@@ -60,6 +62,7 @@
|
||||
* The default downloaded bbox model currently only detects the face area as a rectangle, and the segm model detects the silhouette of a person.
|
||||
* The difference between BboxDetectorCombine and BboxDetectorForEach is that the former outputs a single mask by combining all detected bboxes, and the latter outputs SEGS consisting of various information, including the cropped image, mask pattern, crop position, and confidence, for each detection. SEGS can be used in other ...ForEach nodes.
|
||||
|
||||
* The "noise_mask" option determines whether to add noise only to the masked area when generating an image using "KSampler". If enabled, denoising will not be applied outside the masked area, which can result in a safer generation with stronger denoising, but it may not always produce good results. The middle image shows the result when the "noise_mask" option is disabled, and the image on the right shows the result when the "noise_mask" option is enabled.
|
||||
|
||||
* Detector Node
|
||||
* threshold: Detect only those object whose recognized confidence is above this set value.
|
||||
@@ -88,6 +91,19 @@
|
||||
|
||||

|
||||
|
||||
* SEGS generated by the ...Detector nodes can also be converted to a MASK using nodes such as SegsCombineMask and used accordingly.
|
||||
|
||||
#### SAMDetection Application
|
||||
|
||||

|
||||
  
|
||||
|
||||
* By using the segmentation feature of SAM, it is possible to automatically generate the optimal mask and apply it to areas other than the face. The image on the left is the original image, the middle image is the result of applying a mask to the alpha channel, and the image on the right is the final result.
|
||||
|
||||
* The "detection_hint" in "SAMDetectorCombined" is a specifier that indicates which points should be included in the segmentation when performing segmentation. "center-1" specifies one point in the center of the mask, "horizontal-2" specifies two points on the center horizontal line, "vertical-2" specifies two points on the center vertical line, "rectangle-4" specifies four points in a rectangular shape inside the mask, and "diamond-4" specifies four points in a diamond shape centered around the center point.
|
||||
|
||||
* Unlike in face detection, for non-rigid objects, the center point may not always be the segmentation area, so be careful not to assume that the center point is always the segmentation area.
|
||||
|
||||
|
||||
# Credits
|
||||
|
||||
@@ -103,4 +119,4 @@ hysts/[anime-face-detector](https://github.com/hysts/anime-face-detector) - Crea
|
||||
|
||||
open-mmlab/[mmdetection](https://github.com/open-mmlab/mmdetection) - Object detection toolset. `dd-person_mask2former` was trained via transfer learning using their [R-50 Mask2Former instance segmentation model](https://github.com/open-mmlab/mmdetection/tree/master/configs/mask2former#instance-segmentation) as a base.
|
||||
|
||||
WASasquatch/[was-node-suite-comfyui](https://github.com/WASasquatch/was-node-suite-comfyui) - A powerful custom node extensions of ComfyUI.
|
||||
WASasquatch/[was-node-suite-comfyui](https://github.com/WASasquatch/was-node-suite-comfyui) - A powerful custom node extensions of ComfyUI.
|
||||
|
||||
+248
-91
@@ -6,51 +6,56 @@ import platform
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy"))
|
||||
sys.path.append('../ComfyUI')
|
||||
|
||||
def packages_pip():
|
||||
import sys, subprocess
|
||||
return [r.decode().split('==')[0] for r in subprocess.check_output([sys.executable, '-m', 'pip', 'freeze']).split()]
|
||||
|
||||
def packages_mim():
|
||||
import sys, subprocess
|
||||
return [r.decode().split('==')[0] for r in subprocess.check_output([sys.executable, '-m', 'mim', 'list']).split()]
|
||||
|
||||
# INSTALL
|
||||
print("Loading: ComfyUI-Impact-Pack")
|
||||
print("### ComfyUI-Impact-Pack: Check dependencies")
|
||||
installed_pip = packages_pip()
|
||||
|
||||
if "openmim" not in installed_pip:
|
||||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-U', 'openmim'])
|
||||
|
||||
if "segment-anything" not in installed_pip:
|
||||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'segment-anything'])
|
||||
def ensure_pip_packages():
|
||||
try:
|
||||
import segment_anything
|
||||
except Exception:
|
||||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'segment-anything'])
|
||||
|
||||
# INSTALL pycocotools
|
||||
if "pycocotools" not in installed_pip:
|
||||
if platform.system() not in ["Windows"] or platform.machine() not in ["AMD64", "x86_64"]:
|
||||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'pycocotools'])
|
||||
else:
|
||||
pycocotools = {
|
||||
(3, 8): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp38-cp38-win_amd64.whl",
|
||||
(3, 9): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp39-cp39-win_amd64.whl",
|
||||
(3, 10): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp310-cp310-win_amd64.whl",
|
||||
(3, 11): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp311-cp311-win_amd64.whl",
|
||||
}
|
||||
try:
|
||||
from skimage.measure import label, regionprops
|
||||
except Exception:
|
||||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'scikit-image'])
|
||||
|
||||
version = sys.version_info[:2]
|
||||
url = pycocotools[version]
|
||||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', url])
|
||||
try:
|
||||
import pycocotools
|
||||
except Exception:
|
||||
if platform.system() not in ["Windows"] or platform.machine() not in ["AMD64", "x86_64"]:
|
||||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'pycocotools'])
|
||||
else:
|
||||
pycocotools = {
|
||||
(3, 8): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp38-cp38-win_amd64.whl",
|
||||
(3, 9): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp39-cp39-win_amd64.whl",
|
||||
(3, 10): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp310-cp310-win_amd64.whl",
|
||||
(3, 11): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp311-cp311-win_amd64.whl",
|
||||
}
|
||||
|
||||
installed_mim = packages_mim()
|
||||
version = sys.version_info[:2]
|
||||
url = pycocotools[version]
|
||||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', url])
|
||||
|
||||
if "mmcv" not in installed_mim:
|
||||
subprocess.check_call([sys.executable, '-m', 'mim', 'install', 'mmcv==2.0.0'])
|
||||
|
||||
if "mmdet" not in installed_mim:
|
||||
subprocess.check_call([sys.executable, '-m', 'mim', 'install', 'mmdet==3.0.0'])
|
||||
def ensure_mmdet_package():
|
||||
try:
|
||||
import mmcv
|
||||
import mmdet
|
||||
from mmdet.evaluation import get_classes
|
||||
except Exception:
|
||||
subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-U', 'openmim'])
|
||||
subprocess.check_call([sys.executable, '-m', 'mim', 'install', 'mmcv==2.0.0'])
|
||||
subprocess.check_call([sys.executable, '-m', 'mim', 'install', 'mmdet==3.0.0'])
|
||||
subprocess.check_call([sys.executable, '-m', 'mim', 'install', 'mmengine==0.7.2'])
|
||||
|
||||
|
||||
ensure_pip_packages()
|
||||
ensure_mmdet_package()
|
||||
|
||||
if "mmengine" not in installed_mim:
|
||||
subprocess.check_call([sys.executable, '-m', 'mim', 'install', 'mmengine==0.7.2'])
|
||||
|
||||
# Download model
|
||||
print("### ComfyUI-Impact-Pack: Check basic models")
|
||||
@@ -85,6 +90,11 @@ import comfy.samplers
|
||||
import comfy.sd
|
||||
import nodes
|
||||
import warnings
|
||||
from PIL import Image, ImageFilter
|
||||
from mmdet.evaluation import get_classes
|
||||
from skimage.measure import label, regionprops
|
||||
|
||||
|
||||
warnings.filterwarnings('ignore', category=UserWarning, message='TypedStorage is deprecated')
|
||||
|
||||
|
||||
@@ -152,6 +162,12 @@ def bitwise_and_masks(mask1, mask2):
|
||||
return mask
|
||||
|
||||
|
||||
def to_binary_mask(mask):
|
||||
mask = mask.clone()
|
||||
mask[mask != 0] = 1.
|
||||
return mask
|
||||
|
||||
|
||||
def dilate_masks(segmasks, dilation_factor, iter=1):
|
||||
if dilation_factor == 0:
|
||||
return segmasks
|
||||
@@ -165,10 +181,6 @@ def dilate_masks(segmasks, dilation_factor, iter=1):
|
||||
return dilated_masks
|
||||
|
||||
|
||||
from PIL import Image, ImageFilter
|
||||
from mmdet.evaluation import get_classes
|
||||
|
||||
|
||||
def feather_mask(mask, thickness):
|
||||
pil_mask = Image.fromarray(np.uint8(mask * 255))
|
||||
|
||||
@@ -421,7 +433,7 @@ def scale_tensor_and_to_pil(w,h, image):
|
||||
|
||||
|
||||
def enhance_detail(image, model, vae, guide_size, bbox_size, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, denoise):
|
||||
positive, negative, denoise, noise_mask):
|
||||
|
||||
h = image.shape[1]
|
||||
w = image.shape[2]
|
||||
@@ -437,6 +449,9 @@ def enhance_detail(image, model, vae, guide_size, bbox_size, seed, steps, cfg, s
|
||||
new_w = int(((w * upscale)//64) * 64)
|
||||
new_h = int(((h * upscale)//64) * 64)
|
||||
|
||||
if upscale < 1.0:
|
||||
print(f"Detailer: segment skip")
|
||||
None
|
||||
|
||||
print(f"Detailer: segment upscale for ({bbox_size}) | crop region {w,h} x {upscale} -> {new_w,new_h}")
|
||||
|
||||
@@ -446,6 +461,16 @@ def enhance_detail(image, model, vae, guide_size, bbox_size, seed, steps, cfg, s
|
||||
# ksampler
|
||||
latent_image = to_latent_image(upscaled_image, vae)
|
||||
|
||||
if noise_mask is not None:
|
||||
# upscale the mask tensor by a factor of 2 using bilinear interpolation
|
||||
noise_mask = torch.from_numpy(noise_mask)
|
||||
upscaled_mask = torch.nn.functional.interpolate(noise_mask.unsqueeze(0).unsqueeze(0), size=(new_h, new_w),
|
||||
mode='bilinear', align_corners=False)
|
||||
|
||||
# remove the extra dimensions added by unsqueeze
|
||||
upscaled_mask = upscaled_mask.squeeze().squeeze()
|
||||
latent_image['noise_mask'] = upscaled_mask
|
||||
|
||||
sampler = nodes.KSampler()
|
||||
refined_latent = sampler.sample(model, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, latent_image, denoise)
|
||||
@@ -475,6 +500,7 @@ def composite_to(dest_latent, crop_region, src_latent):
|
||||
|
||||
return orig_image[0]
|
||||
|
||||
|
||||
class DetailerForEach:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
@@ -494,6 +520,7 @@ class DetailerForEach:
|
||||
"negative": ("CONDITIONING",),
|
||||
"denoise": ("FLOAT", {"default": 0.5, "min": 0.0001, "max": 1.0, "step": 0.01}),
|
||||
"feather": ("INT", {"default": 5, "min": 0, "max": 100, "step": 1}),
|
||||
"noise_mask": (["enabled", "disabled"], )
|
||||
},
|
||||
"optional": { "external_seed": ("SEED", ), }
|
||||
}
|
||||
@@ -503,8 +530,8 @@ class DetailerForEach:
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
|
||||
def doit(self, image, segs, model, vae, guide_size, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, denoise, feather, external_seed=None):
|
||||
def do_detail(self, image, segs, model, vae, guide_size, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, denoise, feather, noise_mask, external_seed=None):
|
||||
|
||||
if external_seed is not None:
|
||||
seed = external_seed['seed']
|
||||
@@ -512,49 +539,24 @@ class DetailerForEach:
|
||||
image_pil = tensor2pil(image).convert('RGBA')
|
||||
|
||||
for x in segs:
|
||||
cropped_image = x[0]
|
||||
crop_region = x[3]
|
||||
cropped_image = x[0] if x[0] is not None else crop_ndarray4(image.numpy(), crop_region)
|
||||
|
||||
mask_pil = feather_mask(x[1], feather)
|
||||
confidence = x[2]
|
||||
crop_region = x[3]
|
||||
bbox_size = x[4]
|
||||
|
||||
enhanced_pil = enhance_detail(cropped_image, model, vae, guide_size, bbox_size,
|
||||
seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise)
|
||||
|
||||
if not (enhanced_pil is None):
|
||||
# don't latent composite &
|
||||
# use image paste
|
||||
image_pil.paste(enhanced_pil, (crop_region[0], crop_region[1]), mask_pil)
|
||||
|
||||
return (pil2tensor(image_pil.convert('RGB')), )
|
||||
|
||||
|
||||
class DetailerForEachTest(DetailerForEach):
|
||||
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Test"
|
||||
|
||||
def doit(self, image, segs, model, vae, guide_size, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, denoise, feather, external_seed=None):
|
||||
|
||||
if external_seed is not None:
|
||||
seed = external_seed['seed']
|
||||
|
||||
image_pil = tensor2pil(image).convert('RGBA')
|
||||
|
||||
for x in segs:
|
||||
cropped_image = x[0]
|
||||
mask_pil = feather_mask(x[1], feather)
|
||||
confidence = x[2]
|
||||
crop_region = x[3]
|
||||
bbox_size = x[4]
|
||||
if noise_mask == "enabled":
|
||||
cropped_mask = x[1]
|
||||
else:
|
||||
cropped_mask = None
|
||||
|
||||
enhanced_pil = enhance_detail(cropped_image, model, vae, guide_size, bbox_size,
|
||||
seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise)
|
||||
seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, denoise, cropped_mask)
|
||||
|
||||
if not (enhanced_pil is None):
|
||||
# don't latent composite &
|
||||
# don't latent composite-> converting to latent caused poor quality
|
||||
# use image paste
|
||||
image_pil.paste(enhanced_pil, (crop_region[0], crop_region[1]), mask_pil)
|
||||
|
||||
@@ -563,7 +565,35 @@ class DetailerForEachTest(DetailerForEach):
|
||||
if len(segs) > 0:
|
||||
return image_tensor, torch.from_numpy(cropped_image), pil2tensor(enhanced_pil),
|
||||
else:
|
||||
return image_tensor, image_tensor, image_tensor,
|
||||
return image_tensor, None, None,
|
||||
|
||||
def doit(self, image, segs, model, vae, guide_size, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, denoise, feather, noise_mask, external_seed=None):
|
||||
|
||||
enhanced_img, cropped, cropped_enhanced = \
|
||||
self.do_detail(image, segs, model, vae, guide_size, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, denoise, feather, noise_mask, external_seed)
|
||||
|
||||
return (enhanced_img, )
|
||||
|
||||
|
||||
class DetailerForEachTest(DetailerForEach):
|
||||
RETURN_TYPES = ("IMAGE", "IMAGE", "IMAGE", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
|
||||
def doit(self, image, segs, model, vae, guide_size, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, denoise, feather, noise_mask, external_seed=None):
|
||||
|
||||
enhanced_img, cropped, cropped_enhanced = \
|
||||
self.do_detail(image, segs, model, vae, guide_size, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, denoise, feather, noise_mask, external_seed)
|
||||
|
||||
if cropped is None:
|
||||
return enhanced_img, enhanced_img, enhanced_img,
|
||||
else:
|
||||
return enhanced_img, cropped, cropped_enhanced,
|
||||
|
||||
|
||||
class SegsMaskCombine:
|
||||
@@ -579,7 +609,7 @@ class SegsMaskCombine:
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
CATEGORY = "ImpactPack/Operation"
|
||||
|
||||
def doit(self, segs, image):
|
||||
h = image.shape[1]
|
||||
@@ -603,6 +633,7 @@ class SAMDetectorCombined:
|
||||
"sam_model": ("SAM_MODEL", ),
|
||||
"segs": ("SEGS", ),
|
||||
"image": ("IMAGE", ),
|
||||
"detection_hint": (["center-1", "horizontal-2", "vertical-2", "rect-4", "diamond-4", "none"],),
|
||||
"dilation": ("INT", {"default": 0, "min": 0, "max": 1000, "step": 1}),
|
||||
"threshold": ("FLOAT", {"default": 0.93, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
}
|
||||
@@ -611,9 +642,9 @@ class SAMDetectorCombined:
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
CATEGORY = "ImpactPack/Detector"
|
||||
|
||||
def doit(self, sam_model, segs, image, dilation, threshold):
|
||||
def doit(self, sam_model, segs, image, detection_hint, dilation, threshold):
|
||||
predictor = SamPredictor(sam_model)
|
||||
image = np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8)
|
||||
|
||||
@@ -632,7 +663,46 @@ class SAMDetectorCombined:
|
||||
|
||||
dilated_bbox = [x1, y1, x2, y2]
|
||||
|
||||
cur_masks, scores, _ = predictor.predict(point_coords=np.array([center]), point_labels=np.array([1]),
|
||||
points = []
|
||||
plabs = []
|
||||
if detection_hint == "center-1":
|
||||
points.append(center)
|
||||
plabs = [1] # 1 = foreground point, 0 = background point
|
||||
|
||||
elif detection_hint == "horizontal-2":
|
||||
gap = (x2 - x1) / 3
|
||||
points.append((x1 + gap, center[1]))
|
||||
points.append((x1 + gap*2, center[1]))
|
||||
plabs = [1, 1]
|
||||
|
||||
elif detection_hint == "vertical-2":
|
||||
gap = (y2 - y1) / 3
|
||||
points.append((center[0], y1 + gap))
|
||||
points.append((center[0], y1 + gap*2))
|
||||
plabs = [1, 1]
|
||||
|
||||
elif detection_hint == "rect-4":
|
||||
x_gap = (x2 - x1) / 3
|
||||
y_gap = (y2 - y1) / 3
|
||||
points.append((x1 + x_gap, center[1]))
|
||||
points.append((x1 + x_gap*2, center[1]))
|
||||
points.append((center[0], y1 + y_gap))
|
||||
points.append((center[0], y1 + y_gap*2))
|
||||
plabs = [1, 1, 1, 1]
|
||||
|
||||
elif detection_hint == "diamond-4":
|
||||
x_gap = (x2 - x1) / 3
|
||||
y_gap = (y2 - y1) / 3
|
||||
points.append((x1 + x_gap, y1 + y_gap))
|
||||
points.append((x1 + x_gap*2, y1 + y_gap))
|
||||
points.append((x1 + x_gap, y1 + y_gap*2))
|
||||
points.append((x1 + x_gap*2, y1 + y_gap*2))
|
||||
plabs = [1, 1, 1, 1]
|
||||
|
||||
point_coords = None if not points else np.array(points)
|
||||
point_labels = None if not plabs else np.array(plabs)
|
||||
|
||||
cur_masks, scores, _ = predictor.predict(point_coords=point_coords, point_labels=point_labels,
|
||||
box=np.array([dilated_bbox]))
|
||||
|
||||
selected = False
|
||||
@@ -673,7 +743,7 @@ class BboxDetectorForEach:
|
||||
RETURN_TYPES = ("SEGS", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
CATEGORY = "ImpactPack/Detector"
|
||||
|
||||
def doit(self, bbox_model, image, threshold, dilation, crop_factor):
|
||||
mmdet_results = inference_bbox(bbox_model, image, threshold)
|
||||
@@ -716,7 +786,7 @@ class SegmDetectorForEach:
|
||||
RETURN_TYPES = ("SEGS", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
CATEGORY = "ImpactPack/Detector"
|
||||
|
||||
def doit(self, segm_model, image, threshold, dilation, crop_factor):
|
||||
mmdet_results = inference_segm(segm_model, image, threshold)
|
||||
@@ -736,9 +806,8 @@ class SegmDetectorForEach:
|
||||
cropped_image = crop_image(image, crop_region)
|
||||
cropped_mask = crop_ndarray2(item_mask, crop_region)
|
||||
confidence = x[2]
|
||||
bbox_size = (item_bbox[2]-item_bbox[0],item_bbox[3]-item_bbox[1]) # (w,h)
|
||||
|
||||
item = (cropped_image, cropped_mask, confidence, crop_region, bbox_size)
|
||||
item = (cropped_image, cropped_mask, confidence, crop_region, item_bbox)
|
||||
items.append(item)
|
||||
|
||||
return (items, )
|
||||
@@ -756,15 +825,19 @@ class SegsBitwiseAndMask:
|
||||
RETURN_TYPES = ("SEGS",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
CATEGORY = "ImpactPack/Operation"
|
||||
|
||||
def doit(self, segs, mask):
|
||||
if mask is None:
|
||||
print("[SegsBitwiseAndMask] Cannot operate: MASK is empty.")
|
||||
return ([], )
|
||||
|
||||
items = []
|
||||
|
||||
mask = (mask.numpy() * 255).astype(np.uint8)
|
||||
|
||||
for x in segs:
|
||||
cropped_mask = (x[1].copy() * 255).astype(np.uint8)
|
||||
cropped_mask = (x[1] * 255).astype(np.uint8)
|
||||
crop_region = x[3]
|
||||
|
||||
cropped_mask2 = mask[crop_region[1]:crop_region[3], crop_region[0]:crop_region[2]]
|
||||
@@ -791,7 +864,7 @@ class BitwiseAndMaskForEach:
|
||||
RETURN_TYPES = ("SEGS",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
CATEGORY = "ImpactPack/Operation"
|
||||
|
||||
def doit(self, base_segs, mask_segs):
|
||||
|
||||
@@ -846,7 +919,7 @@ class SubtractMaskForEach:
|
||||
RETURN_TYPES = ("SEGS",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
CATEGORY = "ImpactPack/Operation"
|
||||
|
||||
def doit(self, base_segs, mask_segs):
|
||||
|
||||
@@ -889,6 +962,66 @@ class SubtractMaskForEach:
|
||||
return (result,)
|
||||
|
||||
|
||||
class MaskToSEGS:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"mask": ("MASK",),
|
||||
"combined": (["False", "True"], ),
|
||||
"crop_factor": ("FLOAT", {"default": 3.0, "min": 1.5, "max": 10, "step": 1}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("SEGS",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Operation"
|
||||
|
||||
def doit(self, mask, combined, crop_factor):
|
||||
if mask is None:
|
||||
print("[MaskToSEGS] Cannot operate: MASK is empty.")
|
||||
return ([], )
|
||||
|
||||
mask = mask.numpy()
|
||||
|
||||
result = []
|
||||
if combined == "True":
|
||||
# Find the indices of the non-zero elements
|
||||
indices = np.nonzero(mask)
|
||||
|
||||
if len(indices[0]) > 0 and len(indices[1]) > 0:
|
||||
# Determine the bounding box of the non-zero elements
|
||||
bbox = np.min(indices[1]), np.min(indices[0]), np.max(indices[1]), np.max(indices[0])
|
||||
crop_region = make_crop_region(mask.shape[1], mask.shape[0], bbox, crop_factor)
|
||||
x1, y1, x2, y2 = crop_region
|
||||
|
||||
if x2 - x1 > 0 and y2 - y1 > 0:
|
||||
cropped_mask = mask[y1:y2, x1:x2]
|
||||
result.append((None, cropped_mask, 1.0, crop_region, bbox))
|
||||
|
||||
else:
|
||||
# label the connected components
|
||||
labelled_mask = label(mask)
|
||||
|
||||
# get the region properties for each connected component
|
||||
regions = regionprops(labelled_mask)
|
||||
|
||||
# iterate over the regions and print their bounding boxes
|
||||
for region in regions:
|
||||
y1, x1, y2, x2 = region.bbox
|
||||
bbox = x1, x2, y1, y2
|
||||
crop_region = make_crop_region(mask.shape[1], mask.shape[0], bbox, crop_factor)
|
||||
|
||||
if x2 - x1 > 0 and y2 - y1 > 0:
|
||||
cropped_mask = mask[y1:y2, x1:x2]
|
||||
result.append((None, cropped_mask, 1.0, crop_region, bbox))
|
||||
|
||||
if not result:
|
||||
print(f"[MaskToSEGS] Empty mask.")
|
||||
|
||||
return (result, )
|
||||
|
||||
|
||||
class SegmDetectorCombined:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
@@ -904,7 +1037,7 @@ class SegmDetectorCombined:
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
CATEGORY = "ImpactPack/Detector"
|
||||
|
||||
def doit(self, segm_model, image, threshold, dilation):
|
||||
mmdet_results = inference_segm(segm_model, image, threshold)
|
||||
@@ -938,6 +1071,25 @@ class BboxDetectorCombined(SegmDetectorCombined):
|
||||
return (mask,)
|
||||
|
||||
|
||||
class ToBinaryMask:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required":
|
||||
{
|
||||
"mask": ("MASK",),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Operation"
|
||||
|
||||
def doit(self, mask,):
|
||||
mask = to_binary_mask(mask)
|
||||
return (mask,)
|
||||
|
||||
|
||||
class BitwiseAndMask:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
@@ -951,12 +1103,13 @@ class BitwiseAndMask:
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
CATEGORY = "ImpactPack/Operation"
|
||||
|
||||
def doit(self, mask1, mask2):
|
||||
mask = bitwise_and_masks(mask1, mask2)
|
||||
return (mask,)
|
||||
|
||||
|
||||
class SubtractMask:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
@@ -970,12 +1123,13 @@ class SubtractMask:
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack"
|
||||
CATEGORY = "ImpactPack/Operation"
|
||||
|
||||
def doit(self, mask1, mask2):
|
||||
mask = subtract_masks(mask1, mask2)
|
||||
return (mask,)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"MMDetLoader": MMDetLoader,
|
||||
"SAMLoader": SAMLoader,
|
||||
@@ -995,4 +1149,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"SubtractMask": SubtractMask,
|
||||
"Segs & Mask": SegsBitwiseAndMask,
|
||||
"SegsMaskCombine": SegsMaskCombine,
|
||||
|
||||
"MaskToSEGS": MaskToSEGS,
|
||||
"ToBinaryMask": ToBinaryMask,
|
||||
}
|
||||
|
||||
+304
-290
@@ -44,116 +44,6 @@
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 107,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
752,
|
||||
620
|
||||
],
|
||||
"size": {
|
||||
"0": 703.5068359375,
|
||||
"1": 549.9654541015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 17,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 273
|
||||
}
|
||||
],
|
||||
"title": "Prompt",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"original"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 108,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
360,
|
||||
1123
|
||||
],
|
||||
"size": {
|
||||
"0": 381.7952880859375,
|
||||
"1": 46.58692932128906
|
||||
},
|
||||
"flags": {},
|
||||
"order": 14,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 272
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 267
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
273,
|
||||
274,
|
||||
346
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 110,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
362,
|
||||
866
|
||||
],
|
||||
"size": {
|
||||
"0": 381.7952880859375,
|
||||
"1": 213.58692932128906
|
||||
},
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 304
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
265,
|
||||
351,
|
||||
371
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"title": "Negative Prompt",
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"nsfw, (worst quality:1.4), (low quality:1.4), (blurry:1.22), (greyscale:1.1), (monochrome:1.1), cropped, lowres, text, jpeg artifacts, signature, watermark, username, blurry, artist name, trademark, title, (tan:1.1), muscular, petite, infant, toddlers, (sd character:1.1), Reference sheet, bad_prompt, comic, lowres low resolution, (bad anatomy:1.1), low quality anatomy, (bad hands:1.22), bad nails, bad legs, (bad fingers:1.22), bad toes, extra digit, (extra hands:1.22), (extra fingers:1.22), extra arms, extra legs, fewer digit, low quality face, low quality eyes, (cropped hands:1.22), cropped legs, cropped arms, (cropped fingers:1.22), (fused fingers:1.22), (too many fingers:1.22), tattoo, (missing fingers:1.22), ugly, text, (thai:1.1), thai girl, thai style, thai face, thai makeup), (american girl:1.1), american, american style, american face, american makeup), (chinese girl:1.1), chinese, chinese style, chinese face, chinese makeup), more than one person in focus, (more than two arm per body:1.48), (more than two leg per body:1.41), (more than five fingers on one hand:1.41), multi arms, multi legs, bad arm anatomy, bad leg anatomy, (bad hand anatomy:1.1), (bad finger anatomy:1.1), bad detailed background, unclear architectural outline, elf-ears, obesity, fat, (mutated hands and fingers:1.1), disfigured, fused, cloned, duplicate, flag, mole, strabismus, (highleg panties:1.1), hat, fishnet, (no pants), topless, bottomless, low-cut_armhole, high-waist_sideboob, sideless_outfit, breast_slip, cleavage_cutout, center_opening, breastless_clothes, sideboob, backboob, underboob, underboob_cutout, nipple_slip, areola_slip, revealing_clothes, see-through clothes, crotch_cutout, hip_vent, ass_cutout, side_slit, zettai_ryouiki, butt_crack, naked, nude, clothes_grab, untying, open_clothes, untied, undressing, unzipped, clothes_down, bikini, pink hair, letters, characters, wing, sunglasses, nipple"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 109,
|
||||
"type": "CLIPTextEncode",
|
||||
@@ -229,66 +119,6 @@
|
||||
"horizontal": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 112,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
21,
|
||||
1065
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
266
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
512,
|
||||
832,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 115,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1498,
|
||||
618
|
||||
],
|
||||
"size": {
|
||||
"0": 708.5068359375,
|
||||
"1": 555.9654541015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 24,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 352
|
||||
}
|
||||
],
|
||||
"title": "Refined",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"refined"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 124,
|
||||
"type": "CLIPTextEncode",
|
||||
@@ -623,7 +453,7 @@
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 350
|
||||
"1": 394
|
||||
},
|
||||
"flags": {},
|
||||
"order": 23,
|
||||
@@ -658,6 +488,11 @@
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 351
|
||||
},
|
||||
{
|
||||
"name": "external_seed",
|
||||
"type": "SEED",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
@@ -699,7 +534,8 @@
|
||||
"euler",
|
||||
"karras",
|
||||
0.6,
|
||||
5
|
||||
5,
|
||||
"enabled"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -806,65 +642,6 @@
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 111,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
20,
|
||||
762
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 262
|
||||
},
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 315
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 264
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 265
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 266
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
272
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
762773680021613,
|
||||
false,
|
||||
30,
|
||||
7,
|
||||
"euler",
|
||||
"karras",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 133,
|
||||
"type": "Reroute",
|
||||
@@ -1060,45 +837,6 @@
|
||||
"horizontal": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 138,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
1503,
|
||||
1746
|
||||
],
|
||||
"size": [
|
||||
955.8740349121085,
|
||||
273.6712827148433
|
||||
],
|
||||
"flags": {},
|
||||
"order": 16,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 376
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
375
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"title": "Face Prompt",
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"adorable face, widening eyes, disgust, closeup portrait, looking away, detailed eyes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 136,
|
||||
"type": "SaveImage",
|
||||
@@ -1106,10 +844,10 @@
|
||||
756,
|
||||
1341
|
||||
],
|
||||
"size": [
|
||||
704.027668457031,
|
||||
678.629770507812
|
||||
],
|
||||
"size": {
|
||||
"0": 704.0276489257812,
|
||||
"1": 678.6297607421875
|
||||
},
|
||||
"flags": {},
|
||||
"order": 32,
|
||||
"mode": 0,
|
||||
@@ -1135,7 +873,7 @@
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 350
|
||||
"1": 394
|
||||
},
|
||||
"flags": {},
|
||||
"order": 31,
|
||||
@@ -1172,6 +910,11 @@
|
||||
"type": "CONDITIONING",
|
||||
"link": 371,
|
||||
"slot_index": 5
|
||||
},
|
||||
{
|
||||
"name": "external_seed",
|
||||
"type": "SEED",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
@@ -1196,7 +939,8 @@
|
||||
"euler",
|
||||
"karras",
|
||||
0.5,
|
||||
5
|
||||
5,
|
||||
"enabled"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1206,10 +950,10 @@
|
||||
2195,
|
||||
1554
|
||||
],
|
||||
"size": [
|
||||
260.3999938964844,
|
||||
126
|
||||
],
|
||||
"size": {
|
||||
"0": 260.3999938964844,
|
||||
"1": 126
|
||||
},
|
||||
"flags": {},
|
||||
"order": 28,
|
||||
"mode": 0,
|
||||
@@ -1248,6 +992,45 @@
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
},
|
||||
{
|
||||
"id": 138,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
1498,
|
||||
1775
|
||||
],
|
||||
"size": [
|
||||
954.989501953125,
|
||||
243.09625799005676
|
||||
],
|
||||
"flags": {},
|
||||
"order": 16,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 376
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
375
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"title": "Face Prompt",
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"adorable face, widening eyes, disgust, closeup portrait, looking away, detailed eyes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 90,
|
||||
"type": "BboxDetectorForEach",
|
||||
@@ -1301,12 +1084,12 @@
|
||||
"id": 127,
|
||||
"type": "SAMDetectorCombined",
|
||||
"pos": [
|
||||
1111,
|
||||
316
|
||||
1112,
|
||||
306
|
||||
],
|
||||
"size": {
|
||||
"0": 243.7554168701172,
|
||||
"1": 122
|
||||
"1": 146
|
||||
},
|
||||
"flags": {},
|
||||
"order": 21,
|
||||
@@ -1342,7 +1125,8 @@
|
||||
"Node name for S&R": "SAMDetectorCombined"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"center-1",
|
||||
1,
|
||||
0.93
|
||||
],
|
||||
"color": "#232",
|
||||
@@ -1355,10 +1139,10 @@
|
||||
2192,
|
||||
1353
|
||||
],
|
||||
"size": [
|
||||
259.5433422851563,
|
||||
148.8305297851564
|
||||
],
|
||||
"size": {
|
||||
"0": 259.5433349609375,
|
||||
"1": 148.83053588867188
|
||||
},
|
||||
"flags": {},
|
||||
"order": 29,
|
||||
"mode": 2,
|
||||
@@ -1393,11 +1177,241 @@
|
||||
"Node name for S&R": "SAMDetectorCombined"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"center-1",
|
||||
0.93,
|
||||
0.93
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 115,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1498,
|
||||
618
|
||||
],
|
||||
"size": [
|
||||
714.0886352539064,
|
||||
594.8502563476563
|
||||
],
|
||||
"flags": {},
|
||||
"order": 24,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 352
|
||||
}
|
||||
],
|
||||
"title": "Refined",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"refined"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 107,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
753,
|
||||
620
|
||||
],
|
||||
"size": [
|
||||
700.0886352539064,
|
||||
588.4502563476562
|
||||
],
|
||||
"flags": {},
|
||||
"order": 17,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 273
|
||||
}
|
||||
],
|
||||
"title": "Prompt",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"original"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 108,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
361,
|
||||
1155
|
||||
],
|
||||
"size": {
|
||||
"0": 381.7952880859375,
|
||||
"1": 46.58692932128906
|
||||
},
|
||||
"flags": {},
|
||||
"order": 14,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 272
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 267
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
273,
|
||||
274,
|
||||
346
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 110,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
359,
|
||||
881
|
||||
],
|
||||
"size": {
|
||||
"0": 381.7952880859375,
|
||||
"1": 213.58692932128906
|
||||
},
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 304
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
265,
|
||||
351,
|
||||
371
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"title": "Negative Prompt",
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"nsfw, (worst quality:1.4), (low quality:1.4), (blurry:1.22), (greyscale:1.1), (monochrome:1.1), cropped, lowres, text, jpeg artifacts, signature, watermark, username, blurry, artist name, trademark, title, (tan:1.1), muscular, petite, infant, toddlers, (sd character:1.1), Reference sheet, bad_prompt, comic, lowres low resolution, (bad anatomy:1.1), low quality anatomy, (bad hands:1.22), bad nails, bad legs, (bad fingers:1.22), bad toes, extra digit, (extra hands:1.22), (extra fingers:1.22), extra arms, extra legs, fewer digit, low quality face, low quality eyes, (cropped hands:1.22), cropped legs, cropped arms, (cropped fingers:1.22), (fused fingers:1.22), (too many fingers:1.22), tattoo, (missing fingers:1.22), ugly, text, (thai:1.1), thai girl, thai style, thai face, thai makeup), (american girl:1.1), american, american style, american face, american makeup), (chinese girl:1.1), chinese, chinese style, chinese face, chinese makeup), more than one person in focus, (more than two arm per body:1.48), (more than two leg per body:1.41), (more than five fingers on one hand:1.41), multi arms, multi legs, bad arm anatomy, bad leg anatomy, (bad hand anatomy:1.1), (bad finger anatomy:1.1), bad detailed background, unclear architectural outline, elf-ears, obesity, fat, (mutated hands and fingers:1.1), disfigured, fused, cloned, duplicate, flag, mole, strabismus, (highleg panties:1.1), hat, fishnet, (no pants), topless, bottomless, low-cut_armhole, high-waist_sideboob, sideless_outfit, breast_slip, cleavage_cutout, center_opening, breastless_clothes, sideboob, backboob, underboob, underboob_cutout, nipple_slip, areola_slip, revealing_clothes, see-through clothes, crotch_cutout, hip_vent, ass_cutout, side_slit, zettai_ryouiki, butt_crack, naked, nude, clothes_grab, untying, open_clothes, untied, undressing, unzipped, clothes_down, bikini, pink hair, letters, characters, wing, sunglasses, nipple"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 112,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
23,
|
||||
1095
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
266
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
512,
|
||||
832,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 111,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
21,
|
||||
771
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 262
|
||||
},
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 315
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 264
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 265
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 266
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
272
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
762773680021613,
|
||||
false,
|
||||
30,
|
||||
7,
|
||||
"euler",
|
||||
"karras",
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
@@ -1881,4 +1895,4 @@
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
}
|
||||
|
||||
+69
-62
@@ -494,10 +494,10 @@
|
||||
752,
|
||||
620
|
||||
],
|
||||
"size": [
|
||||
703.5068359375,
|
||||
549.9654846191406
|
||||
],
|
||||
"size": {
|
||||
"0": 703.5068359375,
|
||||
"1": 549.9654541015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
@@ -521,10 +521,10 @@
|
||||
1484,
|
||||
615
|
||||
],
|
||||
"size": [
|
||||
708.5068359375,
|
||||
555.9654846191406
|
||||
],
|
||||
"size": {
|
||||
"0": 708.5068359375,
|
||||
"1": 555.9654541015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 16,
|
||||
"mode": 0,
|
||||
@@ -550,7 +550,7 @@
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 350
|
||||
"1": 394
|
||||
},
|
||||
"flags": {},
|
||||
"order": 15,
|
||||
@@ -585,6 +585,11 @@
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 280
|
||||
},
|
||||
{
|
||||
"name": "external_seed",
|
||||
"type": "SEED",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
@@ -609,60 +614,10 @@
|
||||
"euler",
|
||||
"karras",
|
||||
0.5,
|
||||
5
|
||||
5,
|
||||
"enabled"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 91,
|
||||
"type": "SAMDetectorCombined",
|
||||
"pos": [
|
||||
1112.0510126953125,
|
||||
289
|
||||
],
|
||||
"size": {
|
||||
"0": 234.59999084472656,
|
||||
"1": 125.6999740600586
|
||||
},
|
||||
"flags": {},
|
||||
"order": 12,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "sam_model",
|
||||
"type": "SAM_MODEL",
|
||||
"link": 282
|
||||
},
|
||||
{
|
||||
"name": "segs",
|
||||
"type": "SEGS",
|
||||
"link": 208
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 219
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
247
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SAMDetectorCombined"
|
||||
},
|
||||
"widgets_values": [
|
||||
1,
|
||||
0.93
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 90,
|
||||
"type": "BboxDetectorForEach",
|
||||
@@ -710,6 +665,58 @@
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
},
|
||||
{
|
||||
"id": 91,
|
||||
"type": "SAMDetectorCombined",
|
||||
"pos": [
|
||||
1112.0510126953125,
|
||||
289
|
||||
],
|
||||
"size": {
|
||||
"0": 234.59999084472656,
|
||||
"1": 146
|
||||
},
|
||||
"flags": {},
|
||||
"order": 12,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "sam_model",
|
||||
"type": "SAM_MODEL",
|
||||
"link": 282
|
||||
},
|
||||
{
|
||||
"name": "segs",
|
||||
"type": "SEGS",
|
||||
"link": 208
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 219
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
247
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SAMDetectorCombined"
|
||||
},
|
||||
"widgets_values": [
|
||||
"center-1",
|
||||
0.93,
|
||||
0.93
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
@@ -957,4 +964,4 @@
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 177 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 154 KiB |
+1149
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
+185
-179
@@ -9,10 +9,10 @@
|
||||
953.1426500976561,
|
||||
275.82098431396537
|
||||
],
|
||||
"size": [
|
||||
297.050703568892,
|
||||
124.40960415926838
|
||||
],
|
||||
"size": {
|
||||
"0": 297.0506896972656,
|
||||
"1": 124.40960693359375
|
||||
},
|
||||
"flags": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -39,48 +39,6 @@
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 37,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
596.1426500976559,
|
||||
651.8209843139646
|
||||
],
|
||||
"size": [
|
||||
296.778076171875,
|
||||
141.13685954700816
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 62
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
71,
|
||||
158,
|
||||
160
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"low quality, worst quality, bad anatomy"
|
||||
],
|
||||
"color": "#233",
|
||||
"bgcolor": "#355"
|
||||
},
|
||||
{
|
||||
"id": 31,
|
||||
"type": "CLIPTextEncode",
|
||||
@@ -88,10 +46,10 @@
|
||||
600.1426500976557,
|
||||
459.8209843139653
|
||||
],
|
||||
"size": [
|
||||
290.05080344460225,
|
||||
136.4095868197354
|
||||
],
|
||||
"size": {
|
||||
"0": 290.0508117675781,
|
||||
"1": 136.4095916748047
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
@@ -128,10 +86,10 @@
|
||||
602.1426500976557,
|
||||
274.82098431396537
|
||||
],
|
||||
"size": [
|
||||
289.505273992365,
|
||||
122
|
||||
],
|
||||
"size": {
|
||||
"0": 289.5052795410156,
|
||||
"1": 122
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
@@ -174,35 +132,6 @@
|
||||
"color": "#233",
|
||||
"bgcolor": "#355"
|
||||
},
|
||||
{
|
||||
"id": 71,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1639,
|
||||
407
|
||||
],
|
||||
"size": [
|
||||
304.26312866210947,
|
||||
384.7335550308228
|
||||
],
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 161
|
||||
}
|
||||
],
|
||||
"title": "Refined Image",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"refined"
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 67,
|
||||
"type": "BboxDetectorForEach",
|
||||
@@ -210,10 +139,10 @@
|
||||
1991,
|
||||
225
|
||||
],
|
||||
"size": [
|
||||
290.32338506525207,
|
||||
126.13687549937845
|
||||
],
|
||||
"size": {
|
||||
"0": 290.3233947753906,
|
||||
"1": 126.13687896728516
|
||||
},
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
@@ -250,34 +179,6 @@
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 41,
|
||||
"type": "PreviewImage",
|
||||
"pos": [
|
||||
1307,
|
||||
409
|
||||
],
|
||||
"size": [
|
||||
300.6870242032137,
|
||||
383.227705522017
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 110
|
||||
}
|
||||
],
|
||||
"title": "Prompt Image",
|
||||
"properties": {
|
||||
"Node name for S&R": "PreviewImage"
|
||||
},
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 40,
|
||||
"type": "VAEDecode",
|
||||
@@ -331,10 +232,10 @@
|
||||
1584,
|
||||
106
|
||||
],
|
||||
"size": [
|
||||
361.56315917968755,
|
||||
93.23355712890628
|
||||
],
|
||||
"size": {
|
||||
"0": 361.56317138671875,
|
||||
"1": 93.23355865478516
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
@@ -363,88 +264,72 @@
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 70,
|
||||
"type": "DetailerForEach",
|
||||
"id": 71,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1991,
|
||||
1639,
|
||||
407
|
||||
],
|
||||
"size": [
|
||||
293.2631591796876,
|
||||
381.4335571289063
|
||||
302.85585160688856,
|
||||
394.98975060202815
|
||||
],
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 155
|
||||
},
|
||||
{
|
||||
"name": "segs",
|
||||
"type": "SEGS",
|
||||
"link": 152
|
||||
},
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 153
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 156
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 158
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 160
|
||||
"link": 161
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
161
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "DetailerForEach"
|
||||
},
|
||||
"title": "Refined Image",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
256,
|
||||
588407384967333,
|
||||
true,
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"karras",
|
||||
0.6,
|
||||
5
|
||||
"refined"
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 41,
|
||||
"type": "PreviewImage",
|
||||
"pos": [
|
||||
1307,
|
||||
409
|
||||
],
|
||||
"size": [
|
||||
297.5831243341613,
|
||||
395.7170233293009
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 110
|
||||
}
|
||||
],
|
||||
"title": "Prompt Image",
|
||||
"properties": {
|
||||
"Node name for S&R": "PreviewImage"
|
||||
},
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 42,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
955.1426500976561,
|
||||
458.8209843139653
|
||||
955,
|
||||
459
|
||||
],
|
||||
"size": [
|
||||
298.6870672052555,
|
||||
336.8641496138139
|
||||
295.9467606977978,
|
||||
347.53520514748277
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
@@ -495,6 +380,127 @@
|
||||
],
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 37,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
595,
|
||||
662
|
||||
],
|
||||
"size": {
|
||||
"0": 296.778076171875,
|
||||
"1": 141.13685607910156
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 62
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
71,
|
||||
158,
|
||||
160
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"low quality, worst quality, bad anatomy"
|
||||
],
|
||||
"color": "#233",
|
||||
"bgcolor": "#355"
|
||||
},
|
||||
{
|
||||
"id": 70,
|
||||
"type": "DetailerForEach",
|
||||
"pos": [
|
||||
1991,
|
||||
407
|
||||
],
|
||||
"size": {
|
||||
"0": 293.2631530761719,
|
||||
"1": 394
|
||||
},
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 155
|
||||
},
|
||||
{
|
||||
"name": "segs",
|
||||
"type": "SEGS",
|
||||
"link": 152
|
||||
},
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 153
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 156
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 158
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 160
|
||||
},
|
||||
{
|
||||
"name": "external_seed",
|
||||
"type": "SEED",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
161
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "DetailerForEach"
|
||||
},
|
||||
"widgets_values": [
|
||||
192,
|
||||
771642664002280,
|
||||
true,
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"karras",
|
||||
0.6,
|
||||
5,
|
||||
"disabled"
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
@@ -647,4 +653,4 @@
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Destortion on Detailer
|
||||
|
||||
* Currently, there is an issue with ComfyUI where upscaling to a specific resolution results in a black image. If you encounter this problem, please try adjusting the guide_size parameter.
|
||||
* Please also note that this issue may be caused by a bug in xformers 0.0.18. If you encounter this problem, please try adjusting the guide_size parameter.
|
||||
|
||||

|
||||
|
||||
|
||||
Reference in New Issue
Block a user