Upgrade to V2.0
Overhaul node structure.
@@ -1,30 +1,56 @@
|
||||
# ComfyUI-Impact-Pack
|
||||
|
||||
This custom node helps to conveniently enhance images through Detector, Detailer, Upscaler, Pipe, and more.
|
||||
|
||||
## Custom nodes pack for ComfyUI
|
||||
|
||||
# Features
|
||||
* MMDetLoader - Load MMDet model
|
||||
* SAMLoader - Load SAM model
|
||||
* ONNXLoader - Load ONNX model
|
||||
* SegmDetectorCombined - Detect segmentation and return mask from input image.
|
||||
* BboxDetectorCombined - Detect bbox(bounding box) and return mask from input image.
|
||||
* SamDetectorCombined - Using the technology of SAM, extract the segment at the location indicated by the input SEGS on the input image, and output it as a unified mask.
|
||||
* BitwiseAndMask - Perform 'bitwise and' operations between 2 masks
|
||||
* SubtractMask - Perform subtract operations between 2 masks
|
||||
* SegmDetectorForEach - Detect segmentation and return SEGS from input image.
|
||||
* BboxDetectorForEach - Detect bbox(bounding box) and return SEGS from input image.
|
||||
* ONNXDetectorForeach - Using the ONNX model, identify the bbox and retrieve the SEGS from the input image
|
||||
* DetailerForEach - Refine image rely on SEGS.
|
||||
* DetailerForEachDebug - Refine image rely on SEGS. Additionally, you can monitor cropped image and refined image of cropped image.
|
||||
* MMDetDetectorProvider - Load MMDet model to provide BBOX_DETECTOR, SEGM_DETECTOR
|
||||
* ONNXDetectorProvider - Load ONNX model to provide SEGM_DETECTOR
|
||||
* CLIPSegDetectorProvider - CLIPSeg wrapper to provide BBOX_DETECTOR
|
||||
* SEGM Detector (combined) - Detect segmentation and return mask from input image.
|
||||
* BBOX Detector (combined) - Detect bbox(bounding box) and return mask from input image.
|
||||
* SAMDetector (combined) - Using the technology of SAM, extract the segment at the location indicated by the input SEGS on the input image, and output it as a unified mask.
|
||||
* Bitwise(SEGS & SEGS) - Perform 'bitwise and' operations between 2 SEGS.
|
||||
* Bitwise(SEGS - SEGS) - Perform subtract operations between 2 SEGS.
|
||||
* Bitwise(SEGS & MASK) - Perform a bitwise AND operation on SEGS and MASK.
|
||||
* Bitwise(MASK & MASK) - Perform 'bitwise and' operations between 2 masks
|
||||
* Bitwise(MASK - MASK) - Perform subtract operations between 2 masks
|
||||
* SEGM Detector (SEGS) - Detect segmentation and return SEGS from input image.
|
||||
* BBOX Detector (SEGS) - Detect bbox(bounding box) and return SEGS from input image.
|
||||
* ONNX Detector (SEGS) - Using the ONNX model, identify the bbox and retrieve the SEGS from the input image
|
||||
* Detailer (SEGS) - Refine image rely on SEGS.
|
||||
* DetailerDebug (SEGS) - Refine image rely on SEGS. Additionally, you can monitor cropped image and refined image of cropped image.
|
||||
* The 'DetailerForEach' and 'DetailerForEachDebug' now support an 'external_seed' that is obtained from the Seed node on the [WAS suite](https://github.com/WASasquatch/was-node-suite-comfyui)
|
||||
* To prevent the regeneration caused by the seed that does not change every time when using 'external_seed', please disable the 'seed random generate' option in the 'Detailer...' node
|
||||
* 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.
|
||||
* MASK to SEGS - 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.
|
||||
* EmptySEGS - This node provides a empty SEGS.
|
||||
* MaskPainter - This node provides a feature to draw masks.
|
||||
* FaceDetailer - This is a node that can easily detect faces and improve them.
|
||||
* FaceDetailer (pipe) - This is a node that can easily detect faces and improve them. (for multipass)
|
||||
* Pipe nodes
|
||||
* ToDetailerPipe, FromDetailerPipe - These nodes are used to bundle multiple inputs used in the detailer, such as models and vae, ..., into a single DETAILER_PIPE or extract the elements that are bundled in the DETAILER_PIPE.
|
||||
* ToBasicPipe, FromBasicPipe - These nodes are used to bundle model, clip, vae, positive conditioning, and negative conditioning into a single BASIC_PIPE, or extract each element from the BASIC_PIPE.
|
||||
* EditBasicPipe, EditDetailerPipe - These nodes are used to replace some elements in BASIC_PIPE or DETAILER_PIPE.
|
||||
* Latent Scale (on Pixel Space) - This node converts latent to pixel space, upscales it, and then converts it back to latent.
|
||||
* If upscale_model_opt is provided, it uses the model to upscale the pixel and then downscales it using the interpolation method provided in scale_method to the target resolution.
|
||||
* PixelKSampleUpscalerProvider - An upscaler is provided that converts latent to pixels using VAEDecode, performs upscaling, converts back to latent using VAEEncode, and then performs k-sampling. This upscaler can be attached to nodes such as 'Iterative Upscale' for use.
|
||||
* Similar to 'Latent Scale (on Pixel Space)', if upscale_model_opt is provided, it performs pixel upscaling using the model.
|
||||
* Iterative Upscale (Latent) - The upscaler takes the input upscaler and splits the scale_factor into steps, then iteratively performs upscaling.
|
||||
This takes latent as input and outputs latent as the result.
|
||||
* Iterative Upscale (Image) - The upscaler takes the input upscaler and splits the scale_factor into steps, then iteratively performs upscaling. This takes image as input and outputs image as the result.
|
||||
* Internally, this node uses 'Iterative Upscale (Latent)'.
|
||||
|
||||
# Depercated
|
||||
* The following nodes have been kept only for compatibility with existing workflows, and are no longer supported. Please replace them with new nodes.
|
||||
* MMDetLoader -> MMDetDetectorProvider
|
||||
* SegsMaskCombine -> SEGS to MASK (combined)
|
||||
* BboxDetectorForEach -> BBOX Detector (SEGS)
|
||||
* SegmDetectorForEach -> SEGM Detector (SEGS)
|
||||
* BboxDetectorCombined -> BBOX Detector (combined)
|
||||
* SegmDetectorCombined -> SEGM Detector (combined)
|
||||
|
||||
# Installation
|
||||
|
||||
@@ -61,65 +87,52 @@
|
||||
# How to use (DDetailer feature)
|
||||
|
||||
#### 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.
|
||||
* The FaceDetailer node is a combination of a Detector node for face detection and a Detailer node for image enhancement. See the [Advanced Tutorial](tutorial/advanced.md) for a more detailed explanation.
|
||||
* The FaceDetailer node is a combination of a Detector node for face detection and a Detailer node for image enhancement. See the [Advanced Tutorial](https://github.com/ltdrdata/ComfyUI-extension-tutorials/raw/Main/ComfyUI-Impact-Pack/tutorial/advanced.md) for a more detailed explanation.
|
||||
* Pass the MMDetLoader 's bbox model and the detection model loaded by SAMLoader to FaceDetailer . Since it performs the function of KSampler for image enhancement, it overlaps with KSampler's options.
|
||||
* The MASK output of FaceDetailer provides a visualization of where the detected and enhanced areas are.
|
||||
|
||||
 
|
||||
 
|
||||
* You can see that the face in the image on the left has increased detail as in the image on the right.
|
||||
|
||||
#### 2. 2Pass refine (restore a severely damaged face)
|
||||

|
||||

|
||||
* Although two FaceDetailers can be attached together for a 2-pass configuration, various common inputs used in KSampler can be passed through DETAILER_PIPE, so FaceDetailerPipe can be used to configure easily.
|
||||
* In 1pass, only rough outline recovery is required, so restore with a reasonable resolution and low options. However, if you increase the dilation at this time, not only the face but also the surrounding parts are included in the recovery range, so it is useful when you need to reshape the face other than the facial part.
|
||||
|
||||
  
|
||||
  
|
||||
* In the first stage, the severely damaged face is restored to some extent, and in the second stage, the details are restored
|
||||
|
||||
#### 3. Face Bbox(bounding box) + Person silhouette segmantation (prevent distortion of the background.)
|
||||

|
||||
 
|
||||
#### 3. Face Bbox(bounding box) + Person silhouette segmentation (prevent distortion of the background.)
|
||||

|
||||
 
|
||||
|
||||
* Facial synthesis that emphasizes details is delicately aligned with the contours of the face, and it can be observed that it does not affect the image outside of the face.
|
||||
|
||||
* The BBoxDetectorForEach node is used to detect faces, and the SAMDetectorCombined node is used to find the segment related to the detected face. By using the Segs & Mask node with the two masks obtained in this way, an accurate mask that intersects based on segs can be generated. If this generated mask is input to the DetailerForEach node, only the target area can be created in high resolution from the image and then composited.
|
||||
|
||||
#### Mask feature
|
||||
#### 4. Iterative Upscale
|
||||

|
||||
|
||||
* The IterativeUpscale node is a node that enlarges an image/latent by a scale_factor. In this process, the upscale is carried out progressively by dividing it into steps.
|
||||
* IterativeUpscale takes an Upscaler as an input, similar to a plugin, and uses it during each iteration. PixelKSampleUpscalerProvider is an Upscaler that converts the latent representation to pixel space and applies ksampling.
|
||||
* The upscale_model_opt is an optional parameter that determines whether to use the upscale function of the model base if available. Using the upscale function of the model base can significantly reduce the number of iterative steps required. If an x2 upscaler is used, the image/latent is first upscaled by a factor of 2 and then downscaled to the target scale at each step before further processing is done.
|
||||
|
||||

|
||||
* The following image is an image of 304x512 pixels and the same image scaled up to three times its original size using IterativeUpscale.
|
||||
|
||||
* 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.
|
||||
|
||||
#### Mask Painter
|
||||
|
||||

|
||||
* Click "Edit mask" button
|
||||
* **Don't connect to 'mask_image' input**
|
||||
|
||||

|
||||
* You can draw mask on Mask Painter
|
||||
* Currently, this editor only provides basic functionalities
|
||||
|
||||
<img src="misc/maskpainter-original.png" width=352 height=512/> <img src="misc/maskpainter-result.png" width=352 height=512/>
|
||||
* When used together, SAMDetector and MaskPainter can be used to enhance specific elements of an image.
|
||||
|
||||
# Others Tutorials
|
||||
* [Advanced Tutorial](tutorial/advanced.md)
|
||||
* [Mask Pointer](tutorial/maskpointer.md)
|
||||
* [ONNX Tutorial](tutorial/ONNX.md)
|
||||
* [ComfyUI-extension-tutorials/ComfyUI-Impact-Pack](https://github.com/ltdrdata/ComfyUI-extension-tutorials/tree/Main/ComfyUI-Impact-Pack)
|
||||
* [Advanced Tutorial](https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/advanced.md)
|
||||
* [SAM Application](https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/sam.md)
|
||||
* [Mask Painter](https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/maskpainter.md)
|
||||
* [Mask Pointer](https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/maskpointer.md)
|
||||
* [ONNX Tutorial](https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/ONNX.md)
|
||||
* [CLIPSeg Tutorial](https://github.com/ltdrdata/ComfyUI-extension-tutorials/blob/Main/ComfyUI-Impact-Pack/tutorial/clipseg.md)
|
||||
|
||||
|
||||
# Credits
|
||||
@@ -136,4 +149,6 @@ 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.
|
||||
|
||||
biegert/[ComfyUI-CLIPSeg](https://github.com/biegert/ComfyUI-CLIPSeg) - This is a custom node that enables the use of CLIPSeg technology, which can find segments through prompts, in ComfyUI.
|
||||
|
||||
WASasquatch/[was-node-suite-comfyui](https://github.com/WASasquatch/was-node-suite-comfyui) - A powerful custom node extensions of ComfyUI.
|
||||
|
||||
@@ -1,21 +1,156 @@
|
||||
import shutil
|
||||
import folder_paths
|
||||
import os, sys, subprocess
|
||||
|
||||
|
||||
# ensure .js
|
||||
print("### Loading: ComfyUI-Impact-Pack")
|
||||
import os
|
||||
import sys
|
||||
|
||||
comfy_path = os.path.dirname(folder_paths.__file__)
|
||||
impact_path = os.path.dirname(__file__)
|
||||
|
||||
sys.path.append(impact_path)
|
||||
|
||||
import impact_config
|
||||
print(f"### Loading: ComfyUI-Impact-Pack ({impact_config.version})")
|
||||
|
||||
# ensure dependency
|
||||
if impact_config.read_config()[1] < impact_config.dependency_version:
|
||||
import install # to install dependencies
|
||||
# Core
|
||||
# recheck dependencies for colab
|
||||
try:
|
||||
import folder_paths
|
||||
import torch
|
||||
import cv2
|
||||
import mmcv
|
||||
import numpy as np
|
||||
from mmdet.apis import (inference_detector, init_detector)
|
||||
import comfy.samplers
|
||||
import comfy.sd
|
||||
import warnings
|
||||
from PIL import Image, ImageFilter
|
||||
from mmdet.evaluation import get_classes
|
||||
from skimage.measure import label, regionprops
|
||||
from collections import namedtuple
|
||||
except:
|
||||
print("### ComfyUI-Impact-Pack: Reinstall dependencies (several dependencies are missing.)")
|
||||
import install
|
||||
|
||||
import impact_server # to load server api
|
||||
|
||||
def setup_js():
|
||||
impact_path = os.path.dirname(__file__)
|
||||
js_dest_path = os.path.join(comfy_path, "web", "extensions", "core")
|
||||
# remove garbage
|
||||
old_js_path = os.path.join(comfy_path, "web", "extensions", "core", "impact-pack.js")
|
||||
if os.path.exists(old_js_path):
|
||||
os.remove(old_js_path)
|
||||
|
||||
# setup js
|
||||
js_dest_path = os.path.join(comfy_path, "web", "extensions", "impact-pack")
|
||||
if not os.path.exists(js_dest_path):
|
||||
os.makedirs(js_dest_path)
|
||||
js_src_path = os.path.join(impact_path, "js", "impact-pack.js")
|
||||
shutil.copy(js_src_path, js_dest_path)
|
||||
|
||||
setup_js()
|
||||
|
||||
from .impact_pack import NODE_CLASS_MAPPINGS
|
||||
import legacy_nodes
|
||||
from impact_pack import *
|
||||
from detectors import *
|
||||
from impact_pipe import *
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS']
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"SAMLoader": SAMLoader,
|
||||
"MMDetDetectorProvider": MMDetDetectorProvider,
|
||||
"CLIPSegDetectorProvider": CLIPSegDetectorProvider,
|
||||
"ONNXDetectorProvider": ONNXDetectorProvider,
|
||||
|
||||
"BitwiseAndMaskForEach": BitwiseAndMaskForEach,
|
||||
"SubtractMaskForEach": SubtractMaskForEach,
|
||||
|
||||
"DetailerForEach": DetailerForEach,
|
||||
"DetailerForEachDebug": DetailerForEachTest,
|
||||
"DetailerForEachPipe": DetailerForEachPipe,
|
||||
"DetailerForEachDebugPipe": DetailerForEachTestPipe,
|
||||
|
||||
"SAMDetectorCombined": SAMDetectorCombined,
|
||||
|
||||
"FaceDetailer": FaceDetailer,
|
||||
"FaceDetailerPipe": FaceDetailerPipe,
|
||||
|
||||
"ToDetailerPipe": ToDetailerPipe ,
|
||||
"FromDetailerPipe": FromDetailerPipe,
|
||||
"ToBasicPipe": ToBasicPipe,
|
||||
"FromBasicPipe": FromBasicPipe,
|
||||
"BasicPipeToDetailerPipe": BasicPipeToDetailerPipe,
|
||||
"DetailerPipeToBasicPipe": DetailerPipeToBasicPipe,
|
||||
"EditBasicPipe": EditBasicPipe,
|
||||
"EditDetailerPipe": EditDetailerPipe,
|
||||
|
||||
"LatentPixelScale": LatentPixelScale,
|
||||
"PixelKSampleUpscalerProvider": PixelKSampleUpscalerProvider,
|
||||
"PixelKSampleUpscalerProviderPipe": PixelKSampleUpscalerProviderPipe,
|
||||
"IterativeLatentUpscale": IterativeLatentUpscale,
|
||||
"IterativeImageUpscale": IterativeImageUpscale,
|
||||
|
||||
"BitwiseAndMask": BitwiseAndMask,
|
||||
"SubtractMask": SubtractMask,
|
||||
"Segs & Mask": SegsBitwiseAndMask,
|
||||
"EmptySegs": EmptySEGS,
|
||||
|
||||
"MaskToSEGS": MaskToSEGS,
|
||||
"ToBinaryMask": ToBinaryMask,
|
||||
|
||||
"MaskPainter": MaskPainter,
|
||||
|
||||
"BboxDetectorSEGS": BboxDetectorForEach,
|
||||
"SegmDetectorSEGS": SegmDetectorForEach,
|
||||
"ONNXDetectorSEGS": ONNXDetectorForEach,
|
||||
|
||||
"BboxDetectorCombined": BboxDetectorCombined,
|
||||
"SegmDetectorCombined": SegmDetectorCombined,
|
||||
"SegsToCombinedMask": SegsToCombinedMask,
|
||||
|
||||
"MMDetLoader": legacy_nodes.MMDetLoader,
|
||||
"SegsMaskCombine": legacy_nodes.SegsMaskCombine,
|
||||
"BboxDetectorForEach": legacy_nodes.BboxDetectorForEach,
|
||||
"SegmDetectorForEach": legacy_nodes.SegmDetectorForEach,
|
||||
"BboxDetectorCombined": legacy_nodes.BboxDetectorCombined,
|
||||
"SegmDetectorCombined": legacy_nodes.SegmDetectorCombined,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"BboxDetectorSEGS": "BBOX Detector (SEGS)",
|
||||
"SegmDetectorSEGS": "SEGM Detector (SEGS)",
|
||||
"ONNXDetectorSEGS": "ONNX Detector (SEGS)",
|
||||
"BboxDetectorCombined": "BBOX Detector (combined)",
|
||||
"SegmDetectorCombined": "SEGM Detector (combined)",
|
||||
"SegsToCombinedMask": "SEGS to MASK (combined)",
|
||||
"MaskToSEGS": "MASK to SEGS",
|
||||
"BitwiseAndMaskForEach": "Bitwise(SEGS & SEGS)",
|
||||
"SubtractMaskForEach": "Bitwise(SEGS - SEGS)",
|
||||
"Segs & Mask": "Bitwise(SEGS & MASK)",
|
||||
"BitwiseAndMask": "Bitwise(MASK & MASK)",
|
||||
"SubtractMask": "Bitwise(MASK - MASK)",
|
||||
"DetailerForEach": "Detailer (SEGS)",
|
||||
"DetailerForEachPipe": "Detailer (SEGS/pipe)",
|
||||
"DetailerForEachDebug": "DetailerDebug (SEGS)",
|
||||
"DetailerForEachDebugPipe": "DetailerDebug (SEGS/pipe)",
|
||||
"SAMDetectorCombined": "SAMDetector (combined)",
|
||||
"FaceDetailerPipe": "FaceDetailer (pipe)",
|
||||
|
||||
"BasicPipeToDetailerPipe": "BasicPipe -> DetailerPipe",
|
||||
"DetailerPipeToBasicPipe": "DetailerPipe -> BasicPipe",
|
||||
"EditBasicPipe": "Edit BasicPipe",
|
||||
"EditDetailerPipe": "Edit DetailerPipe",
|
||||
|
||||
"LatentPixelScale": "Latent Scale (on Pixel Space)",
|
||||
"IterativeLatentUpscale": "Iterative Upscale (Latent)",
|
||||
"IterativeImageUpscale": "Iterative Upscale (Image)",
|
||||
|
||||
"MMDetLoader": "MMDetLoader (Legacy)",
|
||||
"SegsMaskCombine": "SegsMaskCombine (Legacy)",
|
||||
"BboxDetectorForEach": "BboxDetectorForEach (Legacy)",
|
||||
"SegmDetectorForEach": "SegmDetectorForEach (Legacy)",
|
||||
"BboxDetectorCombined": "BboxDetectorCombined (Legacy)",
|
||||
"SegmDetectorCombined": "SegmDetectorCombined (Legacy)",
|
||||
}
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import impact_core as core
|
||||
|
||||
|
||||
class SAMDetectorCombined:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"sam_model": ("SAM_MODEL", ),
|
||||
"segs": ("SEGS", ),
|
||||
"image": ("IMAGE", ),
|
||||
"detection_hint": (["center-1", "horizontal-2", "vertical-2", "rect-4", "diamond-4", "mask-area",
|
||||
"mask-points", "mask-point-bbox", "none"],),
|
||||
"dilation": ("INT", {"default": 0, "min": 0, "max": 255, "step": 1}),
|
||||
"threshold": ("FLOAT", {"default": 0.93, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"bbox_expansion": ("INT", {"default": 0, "min": 0, "max": 1000, "step": 1}),
|
||||
"mask_hint_threshold": ("FLOAT", {"default": 0.7, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"mask_hint_use_negative": (["False", "Small", "Outter"], )
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Detector"
|
||||
|
||||
def doit(self, sam_model, segs, image, detection_hint, dilation,
|
||||
threshold, bbox_expansion, mask_hint_threshold, mask_hint_use_negative):
|
||||
return (core.make_sam_mask(sam_model, segs, image, detection_hint, dilation,
|
||||
threshold, bbox_expansion, mask_hint_threshold, mask_hint_use_negative), )
|
||||
|
||||
class BboxDetectorForEach:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"bbox_detector": ("BBOX_DETECTOR", ),
|
||||
"image": ("IMAGE", ),
|
||||
"threshold": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"dilation": ("INT", {"default": 10, "min": 0, "max": 255, "step": 1}),
|
||||
"crop_factor": ("FLOAT", {"default": 3.0, "min": 1.0, "max": 10, "step": 0.1}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("SEGS", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Detector"
|
||||
|
||||
def doit(self, bbox_detector, image, threshold, dilation, crop_factor):
|
||||
segs = bbox_detector.detect(image, threshold, dilation, crop_factor)
|
||||
return (segs, )
|
||||
|
||||
|
||||
class SegmDetectorForEach:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"segm_detector": ("SEGM_DETECTOR", ),
|
||||
"image": ("IMAGE", ),
|
||||
"threshold": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"dilation": ("INT", {"default": 10, "min": 0, "max": 255, "step": 1}),
|
||||
"crop_factor": ("FLOAT", {"default": 3.0, "min": 1.0, "max": 10, "step": 0.1}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("SEGS", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Detector"
|
||||
|
||||
def doit(self, segm_detector, image, threshold, dilation, crop_factor):
|
||||
segs = segm_detector.detect(image, threshold, dilation, crop_factor)
|
||||
return (segs, )
|
||||
|
||||
|
||||
class SegmDetectorCombined:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"segm_detector": ("SEGM_DETECTOR", ),
|
||||
"image": ("IMAGE", ),
|
||||
"threshold": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"dilation": ("INT", {"default": 0, "min": 0, "max": 255, "step": 1}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Detector"
|
||||
|
||||
def doit(self, segm_detector, image, threshold, dilation):
|
||||
mask = segm_detector.detect_combined(image, threshold, dilation)
|
||||
return (mask,)
|
||||
|
||||
|
||||
class BboxDetectorCombined(SegmDetectorCombined):
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"bbox_detector": ("BBOX_DETECTOR", ),
|
||||
"image": ("IMAGE", ),
|
||||
"threshold": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"dilation": ("INT", {"default": 4, "min": 0, "max": 255, "step": 1}),
|
||||
}
|
||||
}
|
||||
|
||||
def doit(self, bbox_detector, image, threshold, dilation):
|
||||
mask = bbox_detector.detect_combined(image, threshold, dilation)
|
||||
return (mask,)
|
||||
@@ -1,6 +1,8 @@
|
||||
import configparser
|
||||
import os
|
||||
|
||||
version = "V2.0"
|
||||
|
||||
dependency_version = 1
|
||||
|
||||
my_path = os.path.dirname(__file__)
|
||||
|
||||
@@ -0,0 +1,748 @@
|
||||
import os
|
||||
import sys
|
||||
import mmcv
|
||||
from mmdet.apis import (inference_detector, init_detector)
|
||||
from mmdet.evaluation import get_classes
|
||||
from segment_anything import SamPredictor
|
||||
import cv2
|
||||
|
||||
from impact_utils import *
|
||||
from collections import namedtuple
|
||||
import numpy as np
|
||||
from skimage.measure import label, regionprops
|
||||
|
||||
main_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
sys.path.append(main_dir)
|
||||
|
||||
import nodes
|
||||
import onnx
|
||||
import comfy_extras.nodes_upscale_model as model_upscale
|
||||
|
||||
SEG = namedtuple("SEG", ['cropped_image', 'cropped_mask', 'confidence', 'crop_region', 'bbox', 'label'],
|
||||
defaults=[None])
|
||||
|
||||
|
||||
class NO_BBOX_DETECTOR:
|
||||
pass
|
||||
|
||||
|
||||
class NO_SEGM_DETECTOR:
|
||||
pass
|
||||
|
||||
|
||||
def load_mmdet(model_path):
|
||||
model_config = os.path.splitext(model_path)[0] + ".py"
|
||||
model = init_detector(model_config, model_path, device="cpu")
|
||||
return model
|
||||
|
||||
|
||||
def create_segmasks(results):
|
||||
bboxs = results[1]
|
||||
segms = results[2]
|
||||
confidence = results[3]
|
||||
|
||||
results = []
|
||||
for i in range(len(segms)):
|
||||
item = (bboxs[i], segms[i].astype(np.float32), confidence[i])
|
||||
results.append(item)
|
||||
return results
|
||||
|
||||
|
||||
def inference_segm_old(model, image, conf_threshold):
|
||||
image = image.numpy()[0] * 255
|
||||
mmdet_results = inference_detector(model, image)
|
||||
|
||||
bbox_results, segm_results = mmdet_results
|
||||
label = "A"
|
||||
|
||||
classes = get_classes("coco")
|
||||
labels = [
|
||||
np.full(bbox.shape[0], i, dtype=np.int32)
|
||||
for i, bbox in enumerate(bbox_results)
|
||||
]
|
||||
n, m = bbox_results[0].shape
|
||||
if n == 0:
|
||||
return [[], [], []]
|
||||
labels = np.concatenate(labels)
|
||||
bboxes = np.vstack(bbox_results)
|
||||
segms = mmcv.concat_list(segm_results)
|
||||
filter_idxs = np.where(bboxes[:, -1] > conf_threshold)[0]
|
||||
results = [[], [], []]
|
||||
for i in filter_idxs:
|
||||
results[0].append(label + "-" + classes[labels[i]])
|
||||
results[1].append(bboxes[i])
|
||||
results[2].append(segms[i])
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def inference_segm(image, modelname, conf_thres, lab="A"):
|
||||
image = image.numpy()[0] * 255
|
||||
mmdet_results = inference_detector(modelname, image).pred_instances
|
||||
bboxes = mmdet_results.bboxes.numpy()
|
||||
segms = mmdet_results.masks.numpy()
|
||||
scores = mmdet_results.scores.numpy()
|
||||
|
||||
classes = get_classes("coco")
|
||||
|
||||
n, m = bboxes.shape
|
||||
if n == 0:
|
||||
return [[], [], [], []]
|
||||
labels = mmdet_results.labels
|
||||
filter_inds = np.where(mmdet_results.scores > conf_thres)[0]
|
||||
results = [[], [], [], []]
|
||||
for i in filter_inds:
|
||||
results[0].append(lab + "-" + classes[labels[i]])
|
||||
results[1].append(bboxes[i])
|
||||
results[2].append(segms[i])
|
||||
results[3].append(scores[i])
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def inference_bbox(modelname, image, conf_threshold):
|
||||
image = image.numpy()[0] * 255
|
||||
label = "A"
|
||||
output = inference_detector(modelname, image).pred_instances
|
||||
cv2_image = np.array(image)
|
||||
cv2_image = cv2_image[:, :, ::-1].copy()
|
||||
cv2_gray = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2GRAY)
|
||||
|
||||
segms = []
|
||||
for x0, y0, x1, y1 in output.bboxes:
|
||||
cv2_mask = np.zeros(cv2_gray.shape, np.uint8)
|
||||
cv2.rectangle(cv2_mask, (int(x0), int(y0)), (int(x1), int(y1)), 255, -1)
|
||||
cv2_mask_bool = cv2_mask.astype(bool)
|
||||
segms.append(cv2_mask_bool)
|
||||
|
||||
n, m = output.bboxes.shape
|
||||
if n == 0:
|
||||
return [[], [], [], []]
|
||||
|
||||
bboxes = output.bboxes.numpy()
|
||||
scores = output.scores.numpy()
|
||||
filter_idxs = np.where(scores > conf_threshold)[0]
|
||||
results = [[], [], [], []]
|
||||
for i in filter_idxs:
|
||||
results[0].append(label)
|
||||
results[1].append(bboxes[i])
|
||||
results[2].append(segms[i])
|
||||
results[3].append(scores[i])
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def gen_detection_hints_from_mask_area(x, y, mask, threshold, use_negative):
|
||||
points = []
|
||||
plabs = []
|
||||
|
||||
# minimum sampling step >= 3
|
||||
y_step = max(3, int(mask.shape[0]/20))
|
||||
x_step = max(3, int(mask.shape[1]/20))
|
||||
|
||||
for i in range(0, len(mask), y_step):
|
||||
for j in range(0, len(mask[i]), x_step):
|
||||
if mask[i][j] > threshold:
|
||||
points.append((x+j, y+i))
|
||||
plabs.append(1)
|
||||
elif use_negative and mask[i][j] == 0:
|
||||
points.append((x+j, y+i))
|
||||
plabs.append(0)
|
||||
|
||||
return points, plabs
|
||||
|
||||
|
||||
def gen_negative_hints(w, h, x1, y1, x2, y2):
|
||||
npoints = []
|
||||
nplabs = []
|
||||
|
||||
# minimum sampling step >= 3
|
||||
y_step = max(3, int(w/20))
|
||||
x_step = max(3, int(h/20))
|
||||
|
||||
for i in range(10, h-10, y_step):
|
||||
for j in range(10, w-10, x_step):
|
||||
if not (x1-10 <= j and j <= x2+10 and y1-10 <= i and i <= y2+10):
|
||||
npoints.append((j, i))
|
||||
nplabs.append(0)
|
||||
|
||||
return npoints, nplabs
|
||||
|
||||
|
||||
def enhance_detail(image, model, vae, guide_size, guide_size_for, bbox, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, denoise, noise_mask, force_inpaint):
|
||||
h = image.shape[1]
|
||||
w = image.shape[2]
|
||||
|
||||
bbox_h = bbox[3] - bbox[1]
|
||||
bbox_w = bbox[2] - bbox[0]
|
||||
|
||||
# Skip processing if the detected bbox is already larger than the guide_size
|
||||
if bbox_h >= guide_size and bbox_w >= guide_size:
|
||||
print(f"Detailer: segment skip")
|
||||
None
|
||||
|
||||
if guide_size_for == "bbox":
|
||||
# Scale up based on the smaller dimension between width and height.
|
||||
upscale = guide_size / min(bbox_w, bbox_h)
|
||||
else:
|
||||
# for cropped_size
|
||||
upscale = guide_size / min(w, h)
|
||||
|
||||
new_w = int(((w * upscale) // 8) * 8)
|
||||
new_h = int(((h * upscale) // 8) * 8)
|
||||
|
||||
if not force_inpaint:
|
||||
if upscale <= 1.0:
|
||||
print(f"Detailer: segment skip [determined upscale factor={upscale}]")
|
||||
return None
|
||||
|
||||
if new_w == 0 or new_h == 0:
|
||||
print(f"Detailer: segment skip [zero size={new_w, new_h}]")
|
||||
return None
|
||||
else:
|
||||
if upscale <= 1.0 or new_w == 0 or new_h == 0:
|
||||
print(f"Detailer: force inpaint")
|
||||
upscale = 1.0
|
||||
new_w = w
|
||||
new_h = h
|
||||
|
||||
print(f"Detailer: segment upscale for ({bbox_w, bbox_h}) | crop region {w, h} x {upscale} -> {new_w, new_h}")
|
||||
|
||||
# upscale
|
||||
upscaled_image = scale_tensor(new_w, new_h, torch.from_numpy(image))
|
||||
|
||||
# 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)
|
||||
refined_latent = refined_latent[0]
|
||||
|
||||
# non-latent downscale - latent downscale cause bad quality
|
||||
refined_image = vae.decode(refined_latent['samples'])
|
||||
|
||||
# downscale
|
||||
refined_image = scale_tensor_and_to_pil(w, h, refined_image)
|
||||
|
||||
# don't convert to latent - latent break image
|
||||
# preserving pil is much better
|
||||
return refined_image
|
||||
|
||||
|
||||
def composite_to(dest_latent, crop_region, src_latent):
|
||||
x1 = crop_region[0]
|
||||
y1 = crop_region[1]
|
||||
|
||||
# composite to original latent
|
||||
lc = nodes.LatentComposite()
|
||||
|
||||
# 현재 mask 를 고려한 composite 가 없음... 이거 처리 필요.
|
||||
|
||||
orig_image = lc.composite(dest_latent, src_latent, x1, y1)
|
||||
|
||||
return orig_image[0]
|
||||
|
||||
|
||||
def sam_predict(predictor, points, plabs, bbox, threshold):
|
||||
point_coords = None if not points else np.array(points)
|
||||
point_labels = None if not plabs else np.array(plabs)
|
||||
|
||||
box = np.array([bbox]) if bbox is not None else None
|
||||
|
||||
cur_masks, scores, _ = predictor.predict(point_coords=point_coords, point_labels=point_labels, box=box)
|
||||
|
||||
total_masks = []
|
||||
|
||||
selected = False
|
||||
max_score = 0
|
||||
for idx in range(len(scores)):
|
||||
if scores[idx] > max_score:
|
||||
max_score = scores[idx]
|
||||
max_mask = cur_masks[idx]
|
||||
|
||||
if scores[idx] >= threshold:
|
||||
selected = True
|
||||
total_masks.append(cur_masks[idx])
|
||||
else:
|
||||
pass
|
||||
|
||||
if not selected:
|
||||
total_masks.append(max_mask)
|
||||
|
||||
return total_masks
|
||||
|
||||
|
||||
def make_sam_mask(sam_model, segs, image, detection_hint, dilation,
|
||||
threshold, bbox_expansion, mask_hint_threshold, mask_hint_use_negative):
|
||||
predictor = SamPredictor(sam_model)
|
||||
image = np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8)
|
||||
|
||||
predictor.set_image(image, "RGB")
|
||||
|
||||
total_masks = []
|
||||
|
||||
use_small_negative = mask_hint_use_negative == "Small"
|
||||
|
||||
# seg_shape = segs[0]
|
||||
segs = segs[1]
|
||||
if detection_hint == "mask-points":
|
||||
points = []
|
||||
plabs = []
|
||||
|
||||
for i in range(len(segs)):
|
||||
bbox = segs[i].bbox
|
||||
center = center_of_bbox(segs[i].bbox)
|
||||
points.append(center)
|
||||
|
||||
# small point is background, big point is foreground
|
||||
if use_small_negative and bbox[2] - bbox[0] < 10:
|
||||
plabs.append(0)
|
||||
else:
|
||||
plabs.append(1)
|
||||
|
||||
detected_masks = sam_predict(predictor, points, plabs, None, threshold)
|
||||
total_masks += detected_masks
|
||||
|
||||
else:
|
||||
for i in range(len(segs)):
|
||||
bbox = segs[i].bbox
|
||||
center = center_of_bbox(bbox)
|
||||
|
||||
x1 = max(bbox[0] - bbox_expansion, 0)
|
||||
y1 = max(bbox[1] - bbox_expansion, 0)
|
||||
x2 = min(bbox[2] + bbox_expansion, image.shape[1])
|
||||
y2 = min(bbox[3] + bbox_expansion, image.shape[0])
|
||||
|
||||
dilated_bbox = [x1, y1, x2, y2]
|
||||
|
||||
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]
|
||||
|
||||
elif detection_hint == "mask-point-bbox":
|
||||
center = center_of_bbox(segs[i].bbox)
|
||||
points.append(center)
|
||||
plabs = [1]
|
||||
|
||||
elif detection_hint == "mask-area":
|
||||
points, plabs = gen_detection_hints_from_mask_area(segs[i].crop_region[0], segs[i].crop_region[1],
|
||||
segs[i].cropped_mask,
|
||||
mask_hint_threshold, use_small_negative)
|
||||
|
||||
if mask_hint_use_negative == "Outter":
|
||||
npoints, nplabs = gen_negative_hints(image.shape[0], image.shape[1],
|
||||
segs[i].crop_region[0], segs[i].crop_region[1],
|
||||
segs[i].crop_region[2], segs[i].crop_region[3])
|
||||
|
||||
points += npoints
|
||||
plabs += nplabs
|
||||
|
||||
detected_masks = sam_predict(predictor, points, plabs, dilated_bbox, threshold)
|
||||
total_masks += detected_masks
|
||||
|
||||
# merge every collected masks
|
||||
mask = combine_masks2(total_masks)
|
||||
|
||||
if mask is not None:
|
||||
mask = mask.float()
|
||||
mask = dilate_mask(mask.numpy(), dilation)
|
||||
mask = torch.from_numpy(mask)
|
||||
else:
|
||||
mask = torch.zeros((8, 8), dtype=torch.float32, device="cpu") # empty mask
|
||||
|
||||
return mask
|
||||
|
||||
|
||||
def segs_bitwise_and_mask(segs, mask):
|
||||
if mask is None:
|
||||
print("[SegsBitwiseAndMask] Cannot operate: MASK is empty.")
|
||||
return ([], )
|
||||
|
||||
items = []
|
||||
|
||||
mask = (mask.numpy() * 255).astype(np.uint8)
|
||||
|
||||
for seg in segs[1]:
|
||||
cropped_mask = (seg.cropped_mask * 255).astype(np.uint8)
|
||||
crop_region = seg.crop_region
|
||||
|
||||
cropped_mask2 = mask[crop_region[1]:crop_region[3], crop_region[0]:crop_region[2]]
|
||||
|
||||
new_mask = np.bitwise_and(cropped_mask.astype(np.uint8), cropped_mask2)
|
||||
new_mask = new_mask.astype(np.float32) / 255.0
|
||||
|
||||
item = SEG(seg.cropped_image, new_mask, seg.confidence, seg.crop_region, seg.bbox, seg.label)
|
||||
items.append(item)
|
||||
|
||||
return segs[0], items
|
||||
|
||||
|
||||
class BBoxDetector:
|
||||
bbox_model = None
|
||||
|
||||
def __init__(self, bbox_model):
|
||||
self.bbox_model = bbox_model
|
||||
|
||||
def detect(self, image, threshold, dilation, crop_factor):
|
||||
mmdet_results = inference_bbox(self.bbox_model, image, threshold)
|
||||
segmasks = create_segmasks(mmdet_results)
|
||||
|
||||
if dilation > 0:
|
||||
segmasks = dilate_masks(segmasks, dilation)
|
||||
|
||||
items = []
|
||||
h = image.shape[1]
|
||||
w = image.shape[2]
|
||||
for x in segmasks:
|
||||
item_bbox = x[0]
|
||||
item_mask = x[1]
|
||||
|
||||
crop_region = make_crop_region(w, h, item_bbox, crop_factor)
|
||||
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 = SEG(cropped_image, cropped_mask, confidence, crop_region, item_bbox)
|
||||
items.append(item)
|
||||
|
||||
shape = image.shape[1],image.shape[2]
|
||||
return shape, items
|
||||
|
||||
def detect_combined(self, image, threshold, dilation):
|
||||
mmdet_results = inference_bbox(self.bbox_model, image, threshold)
|
||||
segmasks = create_segmasks(mmdet_results)
|
||||
if dilation > 0:
|
||||
segmasks = dilate_masks(segmasks, dilation)
|
||||
|
||||
return combine_masks(segmasks)
|
||||
|
||||
def setAux(self, x):
|
||||
pass
|
||||
|
||||
|
||||
class ONNXDetector(BBoxDetector):
|
||||
onnx_model = None
|
||||
|
||||
def __init__(self, onnx_model):
|
||||
self.onnx_model = onnx_model
|
||||
|
||||
def detect(self, image, threshold, dilation, crop_factor):
|
||||
h = image.shape[1]
|
||||
w = image.shape[2]
|
||||
|
||||
labels, scores, boxes = onnx.onnx_inference(image, self.onnx_model)
|
||||
|
||||
# collect feasible item
|
||||
result = []
|
||||
|
||||
for i in range(len(labels)):
|
||||
if scores[i] > threshold:
|
||||
item_bbox = boxes[i]
|
||||
x1, y1, x2, y2 = item_bbox
|
||||
|
||||
crop_region = make_crop_region(w, h, item_bbox, crop_factor)
|
||||
crop_x1, crop_y1, crop_x2, crop_y2, = crop_region
|
||||
|
||||
# prepare cropped mask
|
||||
cropped_mask = np.zeros((crop_y2-crop_y1,crop_x2-crop_x1))
|
||||
inner_mask = np.ones((y2-y1,x2-x1))
|
||||
cropped_mask[y1-crop_y1:y2-crop_y1, x1-crop_x1:x2-crop_x1] = inner_mask
|
||||
|
||||
# make items
|
||||
item = SEG(None, cropped_mask, scores[i], crop_region, item_bbox)
|
||||
result.append(item)
|
||||
|
||||
shape = h, w
|
||||
return shape, result
|
||||
|
||||
def detect_combined(self, image, threshold, dilation):
|
||||
return segs_to_combined_mask(self.detect(image, threshold, dilation, 1))
|
||||
|
||||
def setAux(self, x):
|
||||
pass
|
||||
|
||||
|
||||
class SegmDetector(BBoxDetector):
|
||||
segm_model = None
|
||||
|
||||
def __init__(self, segm_model):
|
||||
self.segm_model = segm_model
|
||||
|
||||
def detect(self, image, threshold, dilation, crop_factor):
|
||||
mmdet_results = inference_segm(image, self.segm_model, threshold)
|
||||
segmasks = create_segmasks(mmdet_results)
|
||||
|
||||
if dilation > 0:
|
||||
segmasks = dilate_masks(segmasks, dilation)
|
||||
|
||||
items = []
|
||||
h = image.shape[1]
|
||||
w = image.shape[2]
|
||||
for x in segmasks:
|
||||
item_bbox = x[0]
|
||||
item_mask = x[1]
|
||||
|
||||
crop_region = make_crop_region(w, h, item_bbox, crop_factor)
|
||||
cropped_image = crop_image(image, crop_region)
|
||||
cropped_mask = crop_ndarray2(item_mask, crop_region)
|
||||
confidence = x[2]
|
||||
|
||||
item = SEG(cropped_image, cropped_mask, confidence, crop_region, item_bbox)
|
||||
items.append(item)
|
||||
|
||||
return image.shape, items
|
||||
|
||||
def detect_combined(self, image, threshold, dilation):
|
||||
mmdet_results = inference_bbox(self.bbox_model, image, threshold)
|
||||
segmasks = create_segmasks(mmdet_results)
|
||||
if dilation > 0:
|
||||
segmasks = dilate_masks(segmasks, dilation)
|
||||
|
||||
return combine_masks(segmasks)
|
||||
|
||||
def setAux(self, x):
|
||||
pass
|
||||
|
||||
|
||||
def mask_to_segs(mask, combined, crop_factor, bbox_fill):
|
||||
if mask is None:
|
||||
print("[mask_to_segs] 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]
|
||||
item = SEG(None, cropped_mask, 1.0, crop_region, bbox, 'A')
|
||||
result.append(item)
|
||||
|
||||
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, y1, x2, 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 = np.array(mask[crop_region[1]:crop_region[3], crop_region[0]:crop_region[2]])
|
||||
|
||||
if bbox_fill:
|
||||
cropped_mask.fill(1.0)
|
||||
|
||||
item = SEG(None, cropped_mask, 1.0, crop_region, bbox, 'A')
|
||||
|
||||
result.append(item)
|
||||
|
||||
if not result:
|
||||
print(f"[mask_to_segs] Empty mask.")
|
||||
|
||||
print(f"# of Detected SEGS: {len(result)}")
|
||||
# for r in result:
|
||||
# print(f"\tbbox={r.bbox}, crop={r.crop_region}, label={r.label}")
|
||||
|
||||
return mask.shape, result
|
||||
|
||||
|
||||
def segs_to_combined_mask(segs):
|
||||
shape = segs[0]
|
||||
h = shape[0]
|
||||
w = shape[1]
|
||||
|
||||
mask = np.zeros((h, w), dtype=np.uint8)
|
||||
|
||||
for seg in segs[1]:
|
||||
cropped_mask = seg.cropped_mask
|
||||
crop_region = seg.crop_region
|
||||
mask[crop_region[1]:crop_region[3], crop_region[0]:crop_region[2]] |= (cropped_mask * 255).astype(np.uint8)
|
||||
|
||||
return torch.from_numpy(mask.astype(np.float32) / 255.0)
|
||||
|
||||
|
||||
def latent_upscale_on_pixel_space_shape(samples, scale_method, w, h, vae):
|
||||
pixels = nodes.VAEDecode().decode(vae, samples)[0]
|
||||
new_w = max(8, (w//8)*8)
|
||||
new_h = max(8, (h//8)*8)
|
||||
pixels = nodes.ImageScale().upscale(pixels, scale_method, int(new_w), int(new_h), False)
|
||||
return nodes.VAEEncode().encode(vae, pixels[0])[0]
|
||||
|
||||
|
||||
def latent_upscale_on_pixel_space(samples, scale_method, scale_factor, vae):
|
||||
pixels = nodes.VAEDecode().decode(vae, samples)[0]
|
||||
w = pixels.shape[2] * scale_factor
|
||||
h = pixels.shape[1] * scale_factor
|
||||
pixels = nodes.ImageScale().upscale(pixels, scale_method, int(w), int(h), False)
|
||||
return nodes.VAEEncode().encode(vae, pixels[0])[0]
|
||||
|
||||
|
||||
def latent_upscale_on_pixel_space_with_model_shape(samples, scale_method, upscale_model, new_w, new_h, vae):
|
||||
pixels = nodes.VAEDecode().decode(vae, samples)[0]
|
||||
w = pixels.shape[2]
|
||||
|
||||
# upscale by model upscaler
|
||||
current_w = w
|
||||
while current_w < new_w:
|
||||
pixels = model_upscale.ImageUpscaleWithModel().upscale(upscale_model, pixels)[0]
|
||||
current_w = pixels.shape[2]
|
||||
|
||||
# downscale to target scale
|
||||
pixels = nodes.ImageScale().upscale(pixels, scale_method, int(new_w), int(new_h), False)
|
||||
return nodes.VAEEncode().encode(vae, pixels[0])[0]
|
||||
|
||||
|
||||
def latent_upscale_on_pixel_space_with_model(samples, scale_method, upscale_model, scale_factor, vae):
|
||||
pixels = nodes.VAEDecode().decode(vae, samples)[0]
|
||||
w = pixels.shape[2]
|
||||
h = pixels.shape[1]
|
||||
|
||||
new_w = w * scale_factor
|
||||
new_h = h * scale_factor
|
||||
|
||||
# upscale by model upscaler
|
||||
current_w = w
|
||||
while current_w < new_w:
|
||||
pixels = model_upscale.ImageUpscaleWithModel().upscale(upscale_model, pixels)[0]
|
||||
current_w = pixels.shape[2]
|
||||
|
||||
# downscale to target scale
|
||||
pixels = nodes.ImageScale().upscale(pixels, scale_method, int(new_w), int(new_h), False)
|
||||
return nodes.VAEEncode().encode(vae, pixels[0])[0]
|
||||
|
||||
|
||||
class PixelKSampleUpscaler:
|
||||
params = None
|
||||
upscale_model = None
|
||||
|
||||
def __init__(self, scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise, upscale_model_opt=None):
|
||||
self.params = scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise
|
||||
self.upscale_model = upscale_model_opt
|
||||
|
||||
def upscale(self, samples, upscale_factor):
|
||||
scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise = self.params
|
||||
|
||||
if self.upscale_model is None:
|
||||
upscaled_latent = latent_upscale_on_pixel_space(samples, scale_method, upscale_factor, vae)
|
||||
else:
|
||||
upscaled_latent = latent_upscale_on_pixel_space_with_model(samples, scale_method, self.upscale_model, upscale_factor, vae)
|
||||
|
||||
refined_latent = nodes.KSampler().sample(model, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, upscaled_latent, denoise)
|
||||
return refined_latent
|
||||
|
||||
def upscale_shape(self, samples, w, h):
|
||||
scale_method, model, vae, seed, steps, cfg, sampler_name, scheduler, positive, negative, denoise = self.params
|
||||
|
||||
if self.upscale_model is None:
|
||||
upscaled_latent = latent_upscale_on_pixel_space_shape(samples, scale_method, w, h, vae)
|
||||
else:
|
||||
upscaled_latent = latent_upscale_on_pixel_space_with_model_shape(samples, scale_method, self.upscale_model, w, h, vae)
|
||||
|
||||
refined_latent = nodes.KSampler().sample(model, seed, steps, cfg, sampler_name, scheduler,
|
||||
positive, negative, upscaled_latent, denoise)
|
||||
return refined_latent[0]
|
||||
|
||||
try:
|
||||
class BBoxDetectorBasedOnCLIPSeg(BBoxDetector):
|
||||
prompt = None
|
||||
blur = None
|
||||
threshold = None
|
||||
dilation_factor = None
|
||||
aux = None
|
||||
|
||||
def __init__(self, prompt, blur, threshold, dilation_factor):
|
||||
self.prompt = prompt
|
||||
self.blur = blur
|
||||
self.threshold = threshold
|
||||
self.dilation_factor = dilation_factor
|
||||
|
||||
def detect(self, image, bbox_threshold, bbox_dilation, bbox_crop_factor):
|
||||
mask = self.detect_combined(image, bbox_threshold, bbox_dilation)
|
||||
segs = mask_to_segs(mask, False, bbox_crop_factor, True)
|
||||
return segs
|
||||
|
||||
def detect_combined(self, image, bbox_threshold, bbox_dilation):
|
||||
from custom_nodes.clipseg import CLIPSeg
|
||||
|
||||
if self.threshold is None:
|
||||
threshold = bbox_threshold
|
||||
else:
|
||||
threshold = self.threshold
|
||||
|
||||
if self.dilation_factor is None:
|
||||
dilation_factor = bbox_dilation
|
||||
else:
|
||||
dilation_factor = self.dilation_factor
|
||||
|
||||
prompt = self.aux if self.prompt == '' and self.aux is not None else self.prompt
|
||||
|
||||
mask, _, _ = CLIPSeg().segment_image(image, prompt, self.blur, threshold, dilation_factor)
|
||||
mask = to_binary_mask(mask)
|
||||
return mask
|
||||
|
||||
def setAux(self, x):
|
||||
self.aux = x
|
||||
|
||||
except:
|
||||
pass
|
||||
@@ -0,0 +1,205 @@
|
||||
class ToDetailerPipe:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"model": ("MODEL",),
|
||||
"vae": ("VAE",),
|
||||
"positive": ("CONDITIONING",),
|
||||
"negative": ("CONDITIONING",),
|
||||
"bbox_detector": ("BBOX_DETECTOR", ),
|
||||
},
|
||||
"optional": {
|
||||
"sam_model_opt": ("SAM_MODEL", ),
|
||||
}}
|
||||
|
||||
RETURN_TYPES = ("DETAILER_PIPE", )
|
||||
RETURN_NAMES = ("detailer_pipe", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Pipe"
|
||||
|
||||
def doit(self, model, vae, positive, negative, bbox_detector, sam_model_opt=None):
|
||||
pipe = (model, vae, positive, negative, bbox_detector, sam_model_opt)
|
||||
return (pipe, )
|
||||
|
||||
|
||||
class FromDetailerPipe:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {"detailer_pipe": ("DETAILER_PIPE",), }, }
|
||||
|
||||
RETURN_TYPES = ("MODEL", "VAE", "CONDITIONING", "CONDITIONING", "BBOX_DETECTOR", "SAM_MODEL")
|
||||
RETURN_NAMES = ("model", "vae", "positive", "negative", "bbox_detector", "sam_model_opt")
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Pipe"
|
||||
|
||||
def doit(self, detailer_pipe):
|
||||
model, vae, positive, negative, bbox_detector, sam_model_opt = detailer_pipe
|
||||
return model, vae, positive, negative, bbox_detector, sam_model_opt
|
||||
|
||||
|
||||
class ToBasicPipe:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"model": ("MODEL",),
|
||||
"clip": ("CLIP",),
|
||||
"vae": ("VAE",),
|
||||
"positive": ("CONDITIONING",),
|
||||
"negative": ("CONDITIONING",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BASIC_PIPE", )
|
||||
RETURN_NAMES = ("basic_pipe", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Pipe"
|
||||
|
||||
def doit(self, model, clip, vae, positive, negative):
|
||||
pipe = (model, clip, vae, positive, negative)
|
||||
return (pipe, )
|
||||
|
||||
|
||||
class FromBasicPipe:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": { "basic_pipe": ("BASIC_PIPE",), }, }
|
||||
|
||||
RETURN_TYPES = ("MODEL", "CLIP", "VAE", "CONDITIONING", "CONDITIONING")
|
||||
RETURN_NAMES = ("model", "clip", "vae", "positive", "negative")
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Pipe"
|
||||
|
||||
def doit(self, basic_pipe):
|
||||
model, clip, vae, positive, negative = basic_pipe
|
||||
return model, clip, vae, positive, negative
|
||||
|
||||
|
||||
class BasicPipeToDetailerPipe:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {"basic_pipe": ("BASIC_PIPE",),
|
||||
"bbox_detector": ("BBOX_DETECTOR", ), },
|
||||
"optional": {"sam_model_opt": ("SAM_MODEL", ), },
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("DETAILER_PIPE", )
|
||||
RETURN_NAMES = ("detailer_pipe", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Pipe"
|
||||
|
||||
def doit(self, basic_pipe, bbox_detector, sam_model_opt=None):
|
||||
model, _, vae, positive, negative = basic_pipe
|
||||
pipe = model, vae, positive, negative, bbox_detector, sam_model_opt
|
||||
return (pipe, )
|
||||
|
||||
|
||||
class DetailerPipeToBasicPipe:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {"detailer_pipe": ("DETAILER_PIPE",),
|
||||
"clip": ("CLIP",), }, }
|
||||
|
||||
RETURN_TYPES = ("BASIC_PIPE", )
|
||||
RETURN_NAMES = ("basic_pipe", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Pipe"
|
||||
|
||||
def doit(self, detailer_pipe, clip):
|
||||
model, vae, positive, negative, _, _ = detailer_pipe
|
||||
pipe = model, clip, vae, positive, negative
|
||||
return (pipe, )
|
||||
|
||||
|
||||
class EditBasicPipe:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {"basic_pipe": ("BASIC_PIPE",), },
|
||||
"optional": {
|
||||
"model": ("MODEL",),
|
||||
"clip": ("CLIP",),
|
||||
"vae": ("VAE",),
|
||||
"positive": ("CONDITIONING",),
|
||||
"negative": ("CONDITIONING",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BASIC_PIPE", )
|
||||
RETURN_NAMES = ("basic_pipe", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Pipe"
|
||||
|
||||
def doit(self, basic_pipe, model=None, clip=None, vae=None, positive=None, negative=None):
|
||||
res_model, res_clip, res_vae, res_positive, res_negative = basic_pipe
|
||||
|
||||
if model is not None:
|
||||
res_model = model
|
||||
|
||||
if clip is not None:
|
||||
res_clip = clip
|
||||
|
||||
if vae is not None:
|
||||
res_vae = vae
|
||||
|
||||
if positive is not None:
|
||||
res_positive = positive
|
||||
|
||||
if negative is not None:
|
||||
res_negative = negative
|
||||
|
||||
pipe = res_model, res_clip, res_vae, res_positive, res_negative
|
||||
|
||||
return (pipe, )
|
||||
|
||||
|
||||
class EditDetailerPipe:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {"detailer_pipe": ("DETAILER_PIPE",), },
|
||||
"optional": {
|
||||
"model": ("MODEL",),
|
||||
"vae": ("VAE",),
|
||||
"positive": ("CONDITIONING",),
|
||||
"negative": ("CONDITIONING",),
|
||||
"bbox_detector": ("BBOX_DETECTOR",),
|
||||
"sam_model": ("SAM_MODEL",), },
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BASIC_PIPE",)
|
||||
RETURN_NAMES = ("basic_pipe",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Pipe"
|
||||
|
||||
def doit(self, detailer_pipe, model=None, vae=None, positive=None, negative=None, bbox_detector=None, sam_model=None):
|
||||
res_model, res_vae, res_positive, res_negative, res_bbox_detector, res_sam_model = detailer_pipe
|
||||
|
||||
if model is not None:
|
||||
res_model = model
|
||||
|
||||
if vae is not None:
|
||||
res_vae = vae
|
||||
|
||||
if positive is not None:
|
||||
res_positive = positive
|
||||
|
||||
if negative is not None:
|
||||
res_negative = negative
|
||||
|
||||
if bbox_detector is not None:
|
||||
res_bbox_detector = bbox_detector
|
||||
|
||||
if sam_model is not None:
|
||||
res_sam_model = sam_model
|
||||
|
||||
pipe = res_model, res_vae, res_positive, res_negative, res_bbox_detector, res_sam_model
|
||||
|
||||
return (pipe, )
|
||||
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
from aiohttp import web
|
||||
import server
|
||||
import folder_paths
|
||||
|
||||
|
||||
@server.PromptServer.instance.routes.post("/upload/temp")
|
||||
async def upload_image(request):
|
||||
upload_dir = folder_paths.get_temp_directory()
|
||||
|
||||
if not os.path.exists(upload_dir):
|
||||
os.makedirs(upload_dir)
|
||||
|
||||
post = await request.post()
|
||||
image = post.get("image")
|
||||
|
||||
if image and image.file:
|
||||
filename = image.filename
|
||||
if not filename:
|
||||
return web.Response(status=400)
|
||||
|
||||
split = os.path.splitext(filename)
|
||||
i = 1
|
||||
while os.path.exists(os.path.join(upload_dir, filename)):
|
||||
filename = f"{split[0]} ({i}){split[1]}"
|
||||
i += 1
|
||||
|
||||
filepath = os.path.join(upload_dir, filename)
|
||||
|
||||
with open(filepath, "wb") as f:
|
||||
f.write(image.file.read())
|
||||
|
||||
return web.json_response({"name": filename})
|
||||
else:
|
||||
return web.Response(status=400)
|
||||
@@ -0,0 +1,189 @@
|
||||
import torch
|
||||
import cv2
|
||||
import numpy as np
|
||||
from PIL import Image, ImageFilter
|
||||
|
||||
LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.LANCZOS)
|
||||
|
||||
def pil2tensor(image):
|
||||
return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0)
|
||||
|
||||
|
||||
def tensor2pil(image):
|
||||
return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))
|
||||
|
||||
|
||||
def center_of_bbox(bbox):
|
||||
w, h = bbox[2] - bbox[0], bbox[3] - bbox[1]
|
||||
return bbox[0] + w/2, bbox[1] + h/2
|
||||
|
||||
|
||||
def combine_masks(masks):
|
||||
if len(masks) == 0:
|
||||
return None
|
||||
else:
|
||||
initial_cv2_mask = np.array(masks[0][1])
|
||||
combined_cv2_mask = initial_cv2_mask
|
||||
|
||||
for i in range(1, len(masks)):
|
||||
cv2_mask = np.array(masks[i][1])
|
||||
combined_cv2_mask = cv2.bitwise_or(combined_cv2_mask, cv2_mask)
|
||||
|
||||
mask = torch.from_numpy(combined_cv2_mask)
|
||||
return mask
|
||||
|
||||
|
||||
def combine_masks2(masks):
|
||||
if len(masks) == 0:
|
||||
return None
|
||||
else:
|
||||
initial_cv2_mask = np.array(masks[0]).astype(np.uint8)
|
||||
combined_cv2_mask = initial_cv2_mask
|
||||
|
||||
for i in range(1, len(masks)):
|
||||
cv2_mask = np.array(masks[i]).astype(np.uint8)
|
||||
combined_cv2_mask = cv2.bitwise_or(combined_cv2_mask, cv2_mask)
|
||||
|
||||
mask = torch.from_numpy(combined_cv2_mask)
|
||||
return mask
|
||||
|
||||
|
||||
def bitwise_and_masks(mask1, mask2):
|
||||
cv2_mask1 = np.array(mask1)
|
||||
cv2_mask2 = np.array(mask2)
|
||||
cv2_mask = cv2.bitwise_and(cv2_mask1, cv2_mask2)
|
||||
mask = torch.from_numpy(cv2_mask)
|
||||
return mask
|
||||
|
||||
|
||||
def to_binary_mask(mask):
|
||||
mask = mask.clone()
|
||||
mask[mask != 0] = 1.
|
||||
return mask
|
||||
|
||||
|
||||
def dilate_mask(mask, dilation_factor, iter=1):
|
||||
if dilation_factor == 0:
|
||||
return mask
|
||||
|
||||
kernel = np.ones((dilation_factor,dilation_factor), np.uint8)
|
||||
return cv2.dilate(mask, kernel, iter)
|
||||
|
||||
|
||||
def dilate_masks(segmasks, dilation_factor, iter=1):
|
||||
if dilation_factor == 0:
|
||||
return segmasks
|
||||
|
||||
dilated_masks = []
|
||||
kernel = np.ones((dilation_factor,dilation_factor), np.uint8)
|
||||
for i in range(len(segmasks)):
|
||||
cv2_mask = segmasks[i][1]
|
||||
dilated_mask = cv2.dilate(cv2_mask, kernel, iter)
|
||||
item = (segmasks[i][0], dilated_mask, segmasks[i][2])
|
||||
dilated_masks.append(item)
|
||||
return dilated_masks
|
||||
|
||||
|
||||
def feather_mask(mask, thickness):
|
||||
pil_mask = Image.fromarray(np.uint8(mask * 255))
|
||||
|
||||
# Create a feathered mask by applying a Gaussian blur to the mask
|
||||
blurred_mask = pil_mask.filter(ImageFilter.GaussianBlur(thickness))
|
||||
feathered_mask = Image.new("L", pil_mask.size, 0)
|
||||
feathered_mask.paste(blurred_mask, (0, 0), blurred_mask)
|
||||
return feathered_mask
|
||||
|
||||
|
||||
def subtract_masks(mask1, mask2):
|
||||
cv2_mask1 = np.array(mask1) * 255
|
||||
cv2_mask2 = np.array(mask2) * 255
|
||||
cv2_mask = cv2.subtract(cv2_mask1, cv2_mask2)
|
||||
mask = torch.from_numpy(cv2_mask) / 255.0
|
||||
return mask
|
||||
|
||||
|
||||
def normalize_region(limit, startp, size):
|
||||
if startp < 0:
|
||||
new_endp = min(limit, size)
|
||||
new_startp = 0
|
||||
elif startp + size > limit:
|
||||
new_startp = limit - size
|
||||
new_endp = limit
|
||||
else:
|
||||
new_startp = startp
|
||||
new_endp = min(limit, startp+size)
|
||||
|
||||
return int(new_startp), int(new_endp)
|
||||
|
||||
|
||||
def make_crop_region(w, h, bbox, crop_factor):
|
||||
x1 = bbox[0]
|
||||
y1 = bbox[1]
|
||||
x2 = bbox[2]
|
||||
y2 = bbox[3]
|
||||
|
||||
bbox_w = x2 - x1
|
||||
bbox_h = y2 - y1
|
||||
|
||||
crop_w = bbox_w * crop_factor
|
||||
crop_h = bbox_h * crop_factor
|
||||
|
||||
kernel_x = x1 + bbox_w / 2
|
||||
kernel_y = y1 + bbox_h / 2
|
||||
|
||||
new_x1 = int(kernel_x - crop_w / 2)
|
||||
new_y1 = int(kernel_y - crop_h / 2)
|
||||
|
||||
# make sure position in (w,h)
|
||||
new_x1, new_x2 = normalize_region(w, new_x1, crop_w)
|
||||
new_y1, new_y2 = normalize_region(h, new_y1, crop_h)
|
||||
|
||||
return [new_x1, new_y1, new_x2, new_y2]
|
||||
|
||||
|
||||
def crop_ndarray4(npimg, crop_region):
|
||||
x1 = crop_region[0]
|
||||
y1 = crop_region[1]
|
||||
x2 = crop_region[2]
|
||||
y2 = crop_region[3]
|
||||
|
||||
cropped = npimg[:, y1:y2, x1:x2, :]
|
||||
|
||||
return cropped
|
||||
|
||||
|
||||
def crop_ndarray2(npimg, crop_region):
|
||||
x1 = crop_region[0]
|
||||
y1 = crop_region[1]
|
||||
x2 = crop_region[2]
|
||||
y2 = crop_region[3]
|
||||
|
||||
cropped = npimg[y1:y2, x1:x2]
|
||||
|
||||
return cropped
|
||||
|
||||
|
||||
def crop_image(image, crop_region):
|
||||
return crop_ndarray4(np.array(image), crop_region)
|
||||
|
||||
|
||||
def to_latent_image(pixels, vae):
|
||||
x = (pixels.shape[1] // 8) * 8
|
||||
y = (pixels.shape[2] // 8) * 8
|
||||
if pixels.shape[1] != x or pixels.shape[2] != y:
|
||||
pixels = pixels[:, :x, :y, :]
|
||||
t = vae.encode(pixels[:, :, :, :3])
|
||||
return {"samples": t}
|
||||
|
||||
|
||||
def scale_tensor(w, h, image):
|
||||
image = tensor2pil(image)
|
||||
scaled_image = image.resize((w, h), resample=LANCZOS)
|
||||
return pil2tensor(scaled_image)
|
||||
|
||||
|
||||
def scale_tensor_and_to_pil(w,h, image):
|
||||
image = tensor2pil(image)
|
||||
return image.resize((w, h), resample=LANCZOS)
|
||||
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
import folder_paths
|
||||
import impact_core as core
|
||||
from impact_utils import *
|
||||
from impact_core import SEG
|
||||
|
||||
|
||||
class NO_BBOX_MODEL:
|
||||
pass
|
||||
|
||||
|
||||
class NO_SEGM_MODEL:
|
||||
pass
|
||||
|
||||
|
||||
class MMDetLoader:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
bboxs = ["bbox/"+x for x in folder_paths.get_filename_list("mmdets_bbox")]
|
||||
segms = ["segm/"+x for x in folder_paths.get_filename_list("mmdets_segm")]
|
||||
return {"required": {"model_name": (bboxs + segms, )}}
|
||||
RETURN_TYPES = ("BBOX_MODEL", "SEGM_MODEL")
|
||||
FUNCTION = "load_mmdet"
|
||||
|
||||
CATEGORY = "ImpactPack/Legacy"
|
||||
|
||||
def load_mmdet(self, model_name):
|
||||
mmdet_path = folder_paths.get_full_path("mmdets", model_name)
|
||||
model = core.load_mmdet(mmdet_path)
|
||||
|
||||
if model_name.startswith("bbox"):
|
||||
return model, NO_SEGM_MODEL()
|
||||
else:
|
||||
return NO_BBOX_MODEL(), model
|
||||
|
||||
|
||||
class BboxDetectorForEach:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"bbox_model": ("BBOX_MODEL", ),
|
||||
"image": ("IMAGE", ),
|
||||
"threshold": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"dilation": ("INT", {"default": 10, "min": 0, "max": 255, "step": 1}),
|
||||
"crop_factor": ("FLOAT", {"default": 3.0, "min": 1.0, "max": 10, "step": 0.1}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("SEGS", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Legacy"
|
||||
|
||||
@staticmethod
|
||||
def detect(bbox_model, image, threshold, dilation, crop_factor):
|
||||
mmdet_results = core.inference_bbox(bbox_model, image, threshold)
|
||||
segmasks = core.create_segmasks(mmdet_results)
|
||||
|
||||
if dilation > 0:
|
||||
segmasks = dilate_masks(segmasks, dilation)
|
||||
|
||||
items = []
|
||||
h = image.shape[1]
|
||||
w = image.shape[2]
|
||||
for x in segmasks:
|
||||
item_bbox = x[0]
|
||||
item_mask = x[1]
|
||||
|
||||
crop_region = make_crop_region(w, h, item_bbox, crop_factor)
|
||||
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 = SEG(cropped_image, cropped_mask, confidence, crop_region, item_bbox)
|
||||
items.append(item)
|
||||
|
||||
shape = h, w
|
||||
return shape, items
|
||||
|
||||
def doit(self, bbox_model, image, threshold, dilation, crop_factor):
|
||||
return (BboxDetectorForEach.detect(bbox_model, image, threshold, dilation, crop_factor), )
|
||||
|
||||
|
||||
class SegmDetectorCombined:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"segm_model": ("SEGM_MODEL", ),
|
||||
"image": ("IMAGE", ),
|
||||
"threshold": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"dilation": ("INT", {"default": 0, "min": 0, "max": 255, "step": 1}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Legacy"
|
||||
|
||||
def doit(self, segm_model, image, threshold, dilation):
|
||||
mmdet_results = core.inference_segm(image, segm_model, threshold)
|
||||
segmasks = core.create_segmasks(mmdet_results)
|
||||
if dilation > 0:
|
||||
segmasks = dilate_masks(segmasks, dilation)
|
||||
|
||||
mask = combine_masks(segmasks)
|
||||
return (mask,)
|
||||
|
||||
|
||||
class BboxDetectorCombined(SegmDetectorCombined):
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"bbox_model": ("BBOX_MODEL", ),
|
||||
"image": ("IMAGE", ),
|
||||
"threshold": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"dilation": ("INT", {"default": 4, "min": 0, "max": 255, "step": 1}),
|
||||
}
|
||||
}
|
||||
|
||||
def doit(self, bbox_model, image, threshold, dilation):
|
||||
mmdet_results = core.inference_bbox(bbox_model, image, threshold)
|
||||
segmasks = core.create_segmasks(mmdet_results)
|
||||
if dilation > 0:
|
||||
segmasks = dilate_masks(segmasks, dilation)
|
||||
|
||||
mask = combine_masks(segmasks)
|
||||
return (mask,)
|
||||
|
||||
|
||||
class SegmDetectorForEach:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"segm_model": ("SEGM_MODEL", ),
|
||||
"image": ("IMAGE", ),
|
||||
"threshold": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"dilation": ("INT", {"default": 10, "min": 0, "max": 255, "step": 1}),
|
||||
"crop_factor": ("FLOAT", {"default": 3.0, "min": 1.0, "max": 10, "step": 0.1}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("SEGS", )
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Legacy"
|
||||
|
||||
def doit(self, segm_model, image, threshold, dilation, crop_factor):
|
||||
mmdet_results = core.inference_segm(image, segm_model, threshold)
|
||||
segmasks = core.create_segmasks(mmdet_results)
|
||||
|
||||
if dilation > 0:
|
||||
segmasks = dilate_masks(segmasks, dilation)
|
||||
|
||||
items = []
|
||||
h = image.shape[1]
|
||||
w = image.shape[2]
|
||||
for x in segmasks:
|
||||
item_bbox = x[0]
|
||||
item_mask = x[1]
|
||||
|
||||
crop_region = make_crop_region(w, h, item_bbox, crop_factor)
|
||||
cropped_image = crop_image(image, crop_region)
|
||||
cropped_mask = crop_ndarray2(item_mask, crop_region)
|
||||
confidence = x[2]
|
||||
|
||||
item = SEG(cropped_image, cropped_mask, confidence, crop_region, item_bbox)
|
||||
items.append(item)
|
||||
|
||||
shape = h,w
|
||||
return ((shape, items), )
|
||||
|
||||
|
||||
class SegsMaskCombine:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"segs": ("SEGS", ),
|
||||
"image": ("IMAGE", ),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "doit"
|
||||
|
||||
CATEGORY = "ImpactPack/Legacy"
|
||||
|
||||
@staticmethod
|
||||
def combine(segs, image):
|
||||
h = image.shape[1]
|
||||
w = image.shape[2]
|
||||
|
||||
mask = np.zeros((h, w), dtype=np.uint8)
|
||||
|
||||
for seg in segs[1]:
|
||||
cropped_mask = seg.cropped_mask
|
||||
crop_region = seg.crop_region
|
||||
mask[crop_region[1]:crop_region[3], crop_region[0]:crop_region[2]] |= (cropped_mask * 255).astype(np.uint8)
|
||||
|
||||
return torch.from_numpy(mask.astype(np.float32) / 255.0)
|
||||
|
||||
def doit(self, segs, image):
|
||||
return (SegsMaskCombine.combine(segs, image), )
|
||||
|
Before Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 669 KiB |
|
Before Width: | Height: | Size: 150 KiB |
@@ -1,940 +0,0 @@
|
||||
{
|
||||
"last_node_id": 77,
|
||||
"last_link_id": 177,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 67,
|
||||
"type": "BboxDetectorForEach",
|
||||
"pos": [
|
||||
738.6226098144523,
|
||||
108.70101345825232
|
||||
],
|
||||
"size": {
|
||||
"0": 290.3233947753906,
|
||||
"1": 126.13687896728516
|
||||
},
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "bbox_model",
|
||||
"type": "BBOX_MODEL",
|
||||
"link": 176
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 140
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "SEGS",
|
||||
"type": "SEGS",
|
||||
"links": [
|
||||
152
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "BboxDetectorForEach"
|
||||
},
|
||||
"widgets_values": [
|
||||
0.5,
|
||||
10,
|
||||
4
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 76,
|
||||
"type": "Reroute",
|
||||
"pos": [
|
||||
961.6226098144517,
|
||||
1.701013458251873
|
||||
],
|
||||
"size": [
|
||||
124,
|
||||
26
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "*",
|
||||
"link": 174,
|
||||
"pos": [
|
||||
62,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "BBOX_MODEL",
|
||||
"type": "BBOX_MODEL",
|
||||
"links": [
|
||||
175,
|
||||
176
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"showOutputText": true,
|
||||
"horizontal": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 44,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
401.62260981445274,
|
||||
110.70101345825232
|
||||
],
|
||||
"size": {
|
||||
"0": 297.0506896972656,
|
||||
"1": 124.40960693359375
|
||||
},
|
||||
"flags": {
|
||||
"collapsed": false
|
||||
},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
73
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
256,
|
||||
320,
|
||||
1
|
||||
],
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 40,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
608.6226098144529,
|
||||
30.701013458251865
|
||||
],
|
||||
"size": {
|
||||
"0": 311,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {
|
||||
"collapsed": true
|
||||
},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 74
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 137
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
110,
|
||||
140,
|
||||
155
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 30,
|
||||
"type": "CheckpointLoader",
|
||||
"pos": [
|
||||
50.62260981445271,
|
||||
109.70101345825233
|
||||
],
|
||||
"size": {
|
||||
"0": 289.5052795410156,
|
||||
"1": 122
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
72,
|
||||
153,
|
||||
168
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
49,
|
||||
62
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
137,
|
||||
156,
|
||||
167
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"anything_v3.yaml",
|
||||
"V07_v07.safetensors"
|
||||
],
|
||||
"color": "#233",
|
||||
"bgcolor": "#355"
|
||||
},
|
||||
{
|
||||
"id": 71,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
735.4799597167967,
|
||||
759.880029144287
|
||||
],
|
||||
"size": {
|
||||
"0": 302.5051574707031,
|
||||
"1": 388.0459289550781
|
||||
},
|
||||
"flags": {},
|
||||
"order": 11,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 161
|
||||
}
|
||||
],
|
||||
"title": "Refined Image",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"refined"
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 70,
|
||||
"type": "DetailerForEach",
|
||||
"pos": [
|
||||
733.6226098144523,
|
||||
289.70101345825253
|
||||
],
|
||||
"size": {
|
||||
"0": 297.7779235839844,
|
||||
"1": 418
|
||||
},
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"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,
|
||||
172,
|
||||
173
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "DetailerForEach"
|
||||
},
|
||||
"widgets_values": [
|
||||
256,
|
||||
"bbox",
|
||||
650434405941391,
|
||||
"randomize",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"karras",
|
||||
0.6,
|
||||
5,
|
||||
"enabled"
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 75,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1069.4799597167953,
|
||||
759.880029144287
|
||||
],
|
||||
"size": {
|
||||
"0": 287.59619140625,
|
||||
"1": 388.227783203125
|
||||
},
|
||||
"flags": {},
|
||||
"order": 14,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 171
|
||||
}
|
||||
],
|
||||
"title": "2nd Refined Image",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"refined"
|
||||
],
|
||||
"color": "#223",
|
||||
"bgcolor": "#335"
|
||||
},
|
||||
{
|
||||
"id": 41,
|
||||
"type": "PreviewImage",
|
||||
"pos": [
|
||||
404.47995971679666,
|
||||
766.880029144287
|
||||
],
|
||||
"size": {
|
||||
"0": 300.68701171875,
|
||||
"1": 383.2276916503906
|
||||
},
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 110
|
||||
}
|
||||
],
|
||||
"title": "Prompt Image",
|
||||
"properties": {
|
||||
"Node name for S&R": "PreviewImage"
|
||||
},
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 37,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
45.47995971679696,
|
||||
528.880029144287
|
||||
],
|
||||
"size": {
|
||||
"0": 296.4716796875,
|
||||
"1": 176.8111572265625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 62
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
71,
|
||||
158,
|
||||
160,
|
||||
165
|
||||
],
|
||||
"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",
|
||||
"pos": [
|
||||
48.47995971679696,
|
||||
294.8800291442872
|
||||
],
|
||||
"size": {
|
||||
"0": 290.4716796875,
|
||||
"1": 180.8111572265625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 49
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
70,
|
||||
166
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"1girl, photorealistic:1.4, masterpiece, jump, full shot, jacket, jean shorts, perfect anatomy, street city background, detailed eyes, smile"
|
||||
],
|
||||
"color": "#233",
|
||||
"bgcolor": "#355"
|
||||
},
|
||||
{
|
||||
"id": 42,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
402.47995971679666,
|
||||
291.8800291442872
|
||||
],
|
||||
"size": {
|
||||
"0": 300.4716796875,
|
||||
"1": 416.8111572265625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 72
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 70
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 71
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 73
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
74
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
805157917915454,
|
||||
false,
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"karras",
|
||||
1
|
||||
],
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 73,
|
||||
"type": "BboxDetectorForEach",
|
||||
"pos": [
|
||||
1067.4799597167953,
|
||||
107.88002914428695
|
||||
],
|
||||
"size": {
|
||||
"0": 284.8689270019531,
|
||||
"1": 126
|
||||
},
|
||||
"flags": {},
|
||||
"order": 12,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "bbox_model",
|
||||
"type": "BBOX_MODEL",
|
||||
"link": 175
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 172
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "SEGS",
|
||||
"type": "SEGS",
|
||||
"links": [
|
||||
164
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "BboxDetectorForEach"
|
||||
},
|
||||
"widgets_values": [
|
||||
0.5,
|
||||
10,
|
||||
4
|
||||
],
|
||||
"color": "#223",
|
||||
"bgcolor": "#335"
|
||||
},
|
||||
{
|
||||
"id": 45,
|
||||
"type": "MMDetLoader",
|
||||
"pos": [
|
||||
1412.1400225830075,
|
||||
115.2000213623046
|
||||
],
|
||||
"size": {
|
||||
"0": 348.3031005859375,
|
||||
"1": 99.29615783691406
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "BBOX_MODEL",
|
||||
"type": "BBOX_MODEL",
|
||||
"links": [
|
||||
174
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "SEGM_MODEL",
|
||||
"type": "SEGM_MODEL",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "MMDetLoader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"bbox/mmdet_anime-face_yolov3.pth"
|
||||
],
|
||||
"color": "#222",
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 74,
|
||||
"type": "DetailerForEach",
|
||||
"pos": [
|
||||
1068,
|
||||
288
|
||||
],
|
||||
"size": [
|
||||
285.10000305175777,
|
||||
420.4000015258789
|
||||
],
|
||||
"flags": {},
|
||||
"order": 13,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 173
|
||||
},
|
||||
{
|
||||
"name": "segs",
|
||||
"type": "SEGS",
|
||||
"link": 164
|
||||
},
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 168
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 167
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 166
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 165
|
||||
},
|
||||
{
|
||||
"name": "external_seed",
|
||||
"type": "SEED",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
171
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "DetailerForEach"
|
||||
},
|
||||
"widgets_values": [
|
||||
256,
|
||||
"bbox",
|
||||
621928064748632,
|
||||
"randomize",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"karras",
|
||||
0.6,
|
||||
5,
|
||||
"enabled"
|
||||
],
|
||||
"color": "#223",
|
||||
"bgcolor": "#335"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
49,
|
||||
30,
|
||||
1,
|
||||
31,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
62,
|
||||
30,
|
||||
1,
|
||||
37,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
70,
|
||||
31,
|
||||
0,
|
||||
42,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
71,
|
||||
37,
|
||||
0,
|
||||
42,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
72,
|
||||
30,
|
||||
0,
|
||||
42,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
73,
|
||||
44,
|
||||
0,
|
||||
42,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
74,
|
||||
42,
|
||||
0,
|
||||
40,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
110,
|
||||
40,
|
||||
0,
|
||||
41,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
137,
|
||||
30,
|
||||
2,
|
||||
40,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
140,
|
||||
40,
|
||||
0,
|
||||
67,
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
152,
|
||||
67,
|
||||
0,
|
||||
70,
|
||||
1,
|
||||
"SEGS"
|
||||
],
|
||||
[
|
||||
153,
|
||||
30,
|
||||
0,
|
||||
70,
|
||||
2,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
155,
|
||||
40,
|
||||
0,
|
||||
70,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
156,
|
||||
30,
|
||||
2,
|
||||
70,
|
||||
3,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
158,
|
||||
37,
|
||||
0,
|
||||
70,
|
||||
4,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
160,
|
||||
37,
|
||||
0,
|
||||
70,
|
||||
5,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
161,
|
||||
70,
|
||||
0,
|
||||
71,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
164,
|
||||
73,
|
||||
0,
|
||||
74,
|
||||
1,
|
||||
"SEGS"
|
||||
],
|
||||
[
|
||||
165,
|
||||
37,
|
||||
0,
|
||||
74,
|
||||
5,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
166,
|
||||
31,
|
||||
0,
|
||||
74,
|
||||
4,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
167,
|
||||
30,
|
||||
2,
|
||||
74,
|
||||
3,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
168,
|
||||
30,
|
||||
0,
|
||||
74,
|
||||
2,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
171,
|
||||
74,
|
||||
0,
|
||||
75,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
172,
|
||||
70,
|
||||
0,
|
||||
73,
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
173,
|
||||
70,
|
||||
0,
|
||||
74,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
174,
|
||||
45,
|
||||
0,
|
||||
76,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
175,
|
||||
76,
|
||||
0,
|
||||
73,
|
||||
0,
|
||||
"BBOX_MODEL"
|
||||
],
|
||||
[
|
||||
176,
|
||||
76,
|
||||
0,
|
||||
67,
|
||||
0,
|
||||
"BBOX_MODEL"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
|
Before Width: | Height: | Size: 680 KiB |
@@ -1,658 +0,0 @@
|
||||
{
|
||||
"last_node_id": 77,
|
||||
"last_link_id": 179,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 30,
|
||||
"type": "CheckpointLoader",
|
||||
"pos": [
|
||||
50,
|
||||
230
|
||||
],
|
||||
"size": {
|
||||
"0": 289.5052795410156,
|
||||
"1": 122
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
72,
|
||||
153
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
49,
|
||||
62
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
137,
|
||||
156
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"anything_v3.yaml",
|
||||
"V07_v07.safetensors"
|
||||
],
|
||||
"color": "#233",
|
||||
"bgcolor": "#355"
|
||||
},
|
||||
{
|
||||
"id": 67,
|
||||
"type": "BboxDetectorForEach",
|
||||
"pos": [
|
||||
1440,
|
||||
180
|
||||
],
|
||||
"size": {
|
||||
"0": 290.3233947753906,
|
||||
"1": 126.13687896728516
|
||||
},
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "bbox_model",
|
||||
"type": "BBOX_MODEL",
|
||||
"link": 179
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 140
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "SEGS",
|
||||
"type": "SEGS",
|
||||
"links": [
|
||||
152
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "BboxDetectorForEach"
|
||||
},
|
||||
"widgets_values": [
|
||||
0.5,
|
||||
10,
|
||||
4
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 40,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
570,
|
||||
180
|
||||
],
|
||||
"size": {
|
||||
"0": 311,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {
|
||||
"collapsed": true
|
||||
},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 74
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 137
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
110,
|
||||
140,
|
||||
155
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 45,
|
||||
"type": "MMDetLoader",
|
||||
"pos": [
|
||||
1030,
|
||||
60
|
||||
],
|
||||
"size": {
|
||||
"0": 361.56317138671875,
|
||||
"1": 93.23355865478516
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "BBOX_MODEL",
|
||||
"type": "BBOX_MODEL",
|
||||
"links": [
|
||||
179
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "SEGM_MODEL",
|
||||
"type": "SEGM_MODEL",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "MMDetLoader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"bbox/mmdet_anime-face_yolov3.pth"
|
||||
],
|
||||
"color": "#222",
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 71,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1090,
|
||||
360
|
||||
],
|
||||
"size": {
|
||||
"0": 302.8558654785156,
|
||||
"1": 394.98974609375
|
||||
},
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 161
|
||||
}
|
||||
],
|
||||
"title": "Refined Image",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"refined"
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 42,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
400,
|
||||
410
|
||||
],
|
||||
"size": {
|
||||
"0": 295.9467468261719,
|
||||
"1": 347.53521728515625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 72
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 70
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 71
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 73
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
74
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
805157917915455,
|
||||
"fixed",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"karras",
|
||||
1
|
||||
],
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 41,
|
||||
"type": "PreviewImage",
|
||||
"pos": [
|
||||
760,
|
||||
360
|
||||
],
|
||||
"size": {
|
||||
"0": 297.5831298828125,
|
||||
"1": 395.7170104980469
|
||||
},
|
||||
"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": 44,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
400,
|
||||
230
|
||||
],
|
||||
"size": {
|
||||
"0": 297.0506896972656,
|
||||
"1": 124.40960693359375
|
||||
},
|
||||
"flags": {
|
||||
"collapsed": false
|
||||
},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
73
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
256,
|
||||
320,
|
||||
1
|
||||
],
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 37,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
50,
|
||||
620
|
||||
],
|
||||
"size": [
|
||||
288.77154541015625,
|
||||
139.74398040771484
|
||||
],
|
||||
"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",
|
||||
"pos": [
|
||||
50,
|
||||
420
|
||||
],
|
||||
"size": {
|
||||
"0": 290.0508117675781,
|
||||
"1": 136.4095916748047
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 49
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
70
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"1girl, photorealistic:1.4, masterpiece, holding book, full shot, black suit, perfect anatomy, office, detailed eyes, smile"
|
||||
],
|
||||
"color": "#233",
|
||||
"bgcolor": "#355"
|
||||
},
|
||||
{
|
||||
"id": 70,
|
||||
"type": "DetailerForEach",
|
||||
"pos": [
|
||||
1440,
|
||||
360
|
||||
],
|
||||
"size": {
|
||||
"0": 293.2631530761719,
|
||||
"1": 442
|
||||
},
|
||||
"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,
|
||||
"bbox",
|
||||
true,
|
||||
"fixed",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"karras",
|
||||
0.4,
|
||||
5,
|
||||
"enabled",
|
||||
"disabled"
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
49,
|
||||
30,
|
||||
1,
|
||||
31,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
62,
|
||||
30,
|
||||
1,
|
||||
37,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
70,
|
||||
31,
|
||||
0,
|
||||
42,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
71,
|
||||
37,
|
||||
0,
|
||||
42,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
72,
|
||||
30,
|
||||
0,
|
||||
42,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
73,
|
||||
44,
|
||||
0,
|
||||
42,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
74,
|
||||
42,
|
||||
0,
|
||||
40,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
110,
|
||||
40,
|
||||
0,
|
||||
41,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
137,
|
||||
30,
|
||||
2,
|
||||
40,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
140,
|
||||
40,
|
||||
0,
|
||||
67,
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
152,
|
||||
67,
|
||||
0,
|
||||
70,
|
||||
1,
|
||||
"SEGS"
|
||||
],
|
||||
[
|
||||
153,
|
||||
30,
|
||||
0,
|
||||
70,
|
||||
2,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
155,
|
||||
40,
|
||||
0,
|
||||
70,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
156,
|
||||
30,
|
||||
2,
|
||||
70,
|
||||
3,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
158,
|
||||
37,
|
||||
0,
|
||||
70,
|
||||
4,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
160,
|
||||
37,
|
||||
0,
|
||||
70,
|
||||
5,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
161,
|
||||
70,
|
||||
0,
|
||||
71,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
179,
|
||||
45,
|
||||
0,
|
||||
67,
|
||||
0,
|
||||
"BBOX_MODEL"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
|
Before Width: | Height: | Size: 514 KiB |
|
Before Width: | Height: | Size: 512 KiB |
|
Before Width: | Height: | Size: 514 KiB |
|
Before Width: | Height: | Size: 658 KiB |
|
Before Width: | Height: | Size: 664 KiB |
@@ -1,968 +0,0 @@
|
||||
{
|
||||
"last_node_id": 115,
|
||||
"last_link_id": 282,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 82,
|
||||
"type": "MMDetLoader",
|
||||
"pos": [
|
||||
712.5367020996093,
|
||||
135.30448647521965
|
||||
],
|
||||
"size": {
|
||||
"0": 374.412109375,
|
||||
"1": 93.55003356933594
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "BBOX_MODEL",
|
||||
"type": "BBOX_MODEL",
|
||||
"links": [
|
||||
204
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "SEGM_MODEL",
|
||||
"type": "SEGM_MODEL",
|
||||
"links": [],
|
||||
"slot_index": 1
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "MMDetLoader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"bbox/mmdet_anime-face_yolov3.pth"
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
},
|
||||
{
|
||||
"id": 87,
|
||||
"type": "SAMLoader",
|
||||
"pos": [
|
||||
1109.9366837890623,
|
||||
134.3044807531738
|
||||
],
|
||||
"size": {
|
||||
"0": 327.3000183105469,
|
||||
"1": 96.49998474121094
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "SAM_MODEL",
|
||||
"type": "SAM_MODEL",
|
||||
"links": [
|
||||
282
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SAMLoader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"sam_vit_b_01ec64.pth"
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 94,
|
||||
"type": "Reroute",
|
||||
"pos": [
|
||||
62,
|
||||
456
|
||||
],
|
||||
"size": [
|
||||
82,
|
||||
26
|
||||
],
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "*",
|
||||
"link": 274
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
218,
|
||||
219
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"showOutputText": true,
|
||||
"horizontal": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 103,
|
||||
"type": "Reroute",
|
||||
"pos": [
|
||||
1409.5367020996096,
|
||||
263.3044864752197
|
||||
],
|
||||
"size": [
|
||||
75,
|
||||
26
|
||||
],
|
||||
"flags": {},
|
||||
"order": 13,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "*",
|
||||
"link": 239
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "SEGS",
|
||||
"type": "SEGS",
|
||||
"links": [
|
||||
246
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"showOutputText": true,
|
||||
"horizontal": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 104,
|
||||
"type": "Segs & Mask",
|
||||
"pos": [
|
||||
1529.9366837890627,
|
||||
285.3044807531738
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 14,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "segs",
|
||||
"type": "SEGS",
|
||||
"link": 246
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 247
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "SEGS",
|
||||
"type": "SEGS",
|
||||
"links": [
|
||||
275
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Segs & Mask"
|
||||
},
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 106,
|
||||
"type": "Reroute",
|
||||
"pos": [
|
||||
872.6135858068355,
|
||||
491.7605277234375
|
||||
],
|
||||
"size": [
|
||||
75,
|
||||
26
|
||||
],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "*",
|
||||
"link": 252
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
278
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"showOutputText": true,
|
||||
"horizontal": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 105,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [
|
||||
21,
|
||||
619
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 98
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
268,
|
||||
276
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
260,
|
||||
261
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
252,
|
||||
267
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"V07_v07.safetensors"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 112,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [
|
||||
21,
|
||||
1065
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
266
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
768,
|
||||
512,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 108,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
360,
|
||||
1123
|
||||
],
|
||||
"size": {
|
||||
"0": 381.7952880859375,
|
||||
"1": 46.58692932128906
|
||||
},
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 272
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 267
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
273,
|
||||
274,
|
||||
277
|
||||
],
|
||||
"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": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 261
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
265,
|
||||
280
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"nsfw, paintings, sketches, (worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy, Deep Negative, (fat:1.2), facing away, looking away, tilted head, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, username, blurry, bad feet, cropped, poorly drawn hands, poorly drawn face, mutation, deformed, jpeg artifacts, signature, watermark, extra fingers, fewer digits, extra limbs, extra arms, extra legs, malformed limbs, fused fingers, too many fingers, long neck, cross-eyed, mutated hands, bad body, bad proportions, missing fingers, missing arms, missing legs, extra digit, badhandv4, EasyNegative, NG_DeepNegative_V1_75T, leather, ((solo))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 109,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
359,
|
||||
620
|
||||
],
|
||||
"size": {
|
||||
"0": 382,
|
||||
"1": 204
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 260
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
264,
|
||||
279
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"masterpiece, photorealistic:1.4, short break hair, (yellow check short jacket), white shirts, light pink necktie, (pink school check skirt), cute girl, sneakers, detailed eyes, realistic, 2girls, ultra detailed, beautiful girl, beautiful-detailed eyes, slender, small breast, smile, from top, luminous skin, stocking,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 107,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
752,
|
||||
620
|
||||
],
|
||||
"size": {
|
||||
"0": 703.5068359375,
|
||||
"1": 549.9654541015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 273
|
||||
}
|
||||
],
|
||||
"title": "Prompt",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"original"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 115,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1484,
|
||||
615
|
||||
],
|
||||
"size": {
|
||||
"0": 708.5068359375,
|
||||
"1": 555.9654541015625
|
||||
},
|
||||
"flags": {},
|
||||
"order": 16,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 281
|
||||
}
|
||||
],
|
||||
"title": "Refined",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"refined"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 111,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
20,
|
||||
762
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 262
|
||||
},
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 268
|
||||
},
|
||||
{
|
||||
"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": [
|
||||
832707305495685,
|
||||
"fixed",
|
||||
20,
|
||||
7,
|
||||
"euler",
|
||||
"karras",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 90,
|
||||
"type": "BboxDetectorForEach",
|
||||
"pos": [
|
||||
712.9366837890625,
|
||||
293.3044807531738
|
||||
],
|
||||
"size": {
|
||||
"0": 251.412109375,
|
||||
"1": 126
|
||||
},
|
||||
"flags": {},
|
||||
"order": 11,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "bbox_model",
|
||||
"type": "BBOX_MODEL",
|
||||
"link": 204
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 218
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "SEGS",
|
||||
"type": "SEGS",
|
||||
"links": [
|
||||
208,
|
||||
239
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "BboxDetectorForEach"
|
||||
},
|
||||
"widgets_values": [
|
||||
0.5,
|
||||
20,
|
||||
3
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
},
|
||||
{
|
||||
"id": 114,
|
||||
"type": "DetailerForEach",
|
||||
"pos": [
|
||||
2203,
|
||||
614
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 418
|
||||
},
|
||||
"flags": {},
|
||||
"order": 15,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 277
|
||||
},
|
||||
{
|
||||
"name": "segs",
|
||||
"type": "SEGS",
|
||||
"link": 275
|
||||
},
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 276
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 278
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 279
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 280
|
||||
},
|
||||
{
|
||||
"name": "external_seed",
|
||||
"type": "SEED",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
281
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "DetailerForEach"
|
||||
},
|
||||
"widgets_values": [
|
||||
256,
|
||||
"bbox",
|
||||
1041366330963730,
|
||||
"randomize",
|
||||
20,
|
||||
7,
|
||||
"euler",
|
||||
"karras",
|
||||
0.6,
|
||||
5,
|
||||
"disabled"
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": [
|
||||
"rect-4",
|
||||
10,
|
||||
0.9
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
204,
|
||||
82,
|
||||
0,
|
||||
90,
|
||||
0,
|
||||
"BBOX_MODEL"
|
||||
],
|
||||
[
|
||||
208,
|
||||
90,
|
||||
0,
|
||||
91,
|
||||
1,
|
||||
"SEGS"
|
||||
],
|
||||
[
|
||||
218,
|
||||
94,
|
||||
0,
|
||||
90,
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
219,
|
||||
94,
|
||||
0,
|
||||
91,
|
||||
2,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
239,
|
||||
90,
|
||||
0,
|
||||
103,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
246,
|
||||
103,
|
||||
0,
|
||||
104,
|
||||
0,
|
||||
"SEGS"
|
||||
],
|
||||
[
|
||||
247,
|
||||
91,
|
||||
0,
|
||||
104,
|
||||
1,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
252,
|
||||
105,
|
||||
2,
|
||||
106,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
260,
|
||||
105,
|
||||
1,
|
||||
109,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
261,
|
||||
105,
|
||||
1,
|
||||
110,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
264,
|
||||
109,
|
||||
0,
|
||||
111,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
265,
|
||||
110,
|
||||
0,
|
||||
111,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
266,
|
||||
112,
|
||||
0,
|
||||
111,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
267,
|
||||
105,
|
||||
2,
|
||||
108,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
268,
|
||||
105,
|
||||
0,
|
||||
111,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
272,
|
||||
111,
|
||||
0,
|
||||
108,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
273,
|
||||
108,
|
||||
0,
|
||||
107,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
274,
|
||||
108,
|
||||
0,
|
||||
94,
|
||||
0,
|
||||
"*"
|
||||
],
|
||||
[
|
||||
275,
|
||||
104,
|
||||
0,
|
||||
114,
|
||||
1,
|
||||
"SEGS"
|
||||
],
|
||||
[
|
||||
276,
|
||||
105,
|
||||
0,
|
||||
114,
|
||||
2,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
277,
|
||||
108,
|
||||
0,
|
||||
114,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
278,
|
||||
106,
|
||||
0,
|
||||
114,
|
||||
3,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
279,
|
||||
109,
|
||||
0,
|
||||
114,
|
||||
4,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
280,
|
||||
110,
|
||||
0,
|
||||
114,
|
||||
5,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
281,
|
||||
114,
|
||||
0,
|
||||
115,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
282,
|
||||
87,
|
||||
0,
|
||||
91,
|
||||
0,
|
||||
"SAM_MODEL"
|
||||
]
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"title": "Detection & Mask Generation",
|
||||
"bounding": [
|
||||
664,
|
||||
13,
|
||||
1190,
|
||||
447
|
||||
],
|
||||
"color": "#3f789e"
|
||||
},
|
||||
{
|
||||
"title": "Group",
|
||||
"bounding": [
|
||||
11,
|
||||
496,
|
||||
1462,
|
||||
753
|
||||
],
|
||||
"color": "#3f789e"
|
||||
},
|
||||
{
|
||||
"title": "Refine and Render",
|
||||
"bounding": [
|
||||
1476,
|
||||
495,
|
||||
1057,
|
||||
753
|
||||
],
|
||||
"color": "#3f789e"
|
||||
}
|
||||
],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 665 KiB |
|
Before Width: | Height: | Size: 658 KiB |
|
Before Width: | Height: | Size: 577 KiB |
|
Before Width: | Height: | Size: 814 KiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
@@ -1,405 +0,0 @@
|
||||
{
|
||||
"last_node_id": 13,
|
||||
"last_link_id": 15,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [
|
||||
1191,
|
||||
203
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 9
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 10
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
11
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAE Decode"
|
||||
},
|
||||
"color": "#223",
|
||||
"bgcolor": "#335"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "LoadImage",
|
||||
"pos": [
|
||||
57,
|
||||
322
|
||||
],
|
||||
"size": {
|
||||
"0": 314,
|
||||
"1": 102
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
4,
|
||||
7,
|
||||
14
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load Image"
|
||||
},
|
||||
"widgets_values": [
|
||||
"rga6845.jpeg",
|
||||
"image"
|
||||
],
|
||||
"color": "#222",
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "VAEEncodeForInpaint",
|
||||
"pos": [
|
||||
942,
|
||||
201
|
||||
],
|
||||
"size": {
|
||||
"0": 226.8000030517578,
|
||||
"1": 66
|
||||
},
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "pixels",
|
||||
"type": "IMAGE",
|
||||
"link": 7
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 8
|
||||
},
|
||||
{
|
||||
"name": "mask",
|
||||
"type": "MASK",
|
||||
"link": 6
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
9
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAE Encode (for Inpainting)"
|
||||
},
|
||||
"color": "#223",
|
||||
"bgcolor": "#335"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "VAELoader",
|
||||
"pos": [
|
||||
56,
|
||||
96
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 58
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
8,
|
||||
10
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "Load VAE"
|
||||
},
|
||||
"widgets_values": [
|
||||
"vae-ft-mse-840000-ema-pruned.safetensors"
|
||||
],
|
||||
"color": "#222",
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "SegsMaskCombine",
|
||||
"pos": [
|
||||
681,
|
||||
369
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "segs",
|
||||
"type": "SEGS",
|
||||
"link": 15
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 4
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MASK",
|
||||
"type": "MASK",
|
||||
"links": [
|
||||
6
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "SegsMaskCombine"
|
||||
},
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveImage",
|
||||
"pos": [
|
||||
1476,
|
||||
205
|
||||
],
|
||||
"size": {
|
||||
"0": 475,
|
||||
"1": 543
|
||||
},
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 11
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
],
|
||||
"color": "#223",
|
||||
"bgcolor": "#335"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"type": "ONNXDetectorForEach",
|
||||
"pos": [
|
||||
405,
|
||||
209
|
||||
],
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 102
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "onnx_model",
|
||||
"type": "ONNX_MODEL",
|
||||
"link": 13
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"type": "IMAGE",
|
||||
"link": 14
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "SEGS",
|
||||
"type": "SEGS",
|
||||
"links": [
|
||||
15
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "ONNXDetectorForEach"
|
||||
},
|
||||
"widgets_values": [
|
||||
0.5,
|
||||
2
|
||||
],
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"type": "ONNXLoader",
|
||||
"pos": [
|
||||
55,
|
||||
207
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 58
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "ONNX_MODEL",
|
||||
"type": "ONNX_MODEL",
|
||||
"links": [
|
||||
13
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "ONNXLoader"
|
||||
},
|
||||
"widgets_values": [
|
||||
"detector_v2_base_checkpoint.onnx"
|
||||
],
|
||||
"color": "#222",
|
||||
"bgcolor": "#000"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
4,
|
||||
2,
|
||||
0,
|
||||
5,
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
6,
|
||||
5,
|
||||
0,
|
||||
6,
|
||||
2,
|
||||
"MASK"
|
||||
],
|
||||
[
|
||||
7,
|
||||
2,
|
||||
0,
|
||||
6,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
8,
|
||||
7,
|
||||
0,
|
||||
6,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
9,
|
||||
6,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
10,
|
||||
7,
|
||||
0,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
11,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
13,
|
||||
1,
|
||||
0,
|
||||
13,
|
||||
0,
|
||||
"ONNX_MODEL"
|
||||
],
|
||||
[
|
||||
14,
|
||||
2,
|
||||
0,
|
||||
13,
|
||||
1,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
15,
|
||||
13,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
"SEGS"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {},
|
||||
"version": 0.4
|
||||
}
|
||||
|
Before Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 518 KiB |
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "aaaaaaaaaa"
|
||||
@@ -48,13 +49,17 @@
|
||||
" !echo \"-= Updating ComfyUI =-\"\n",
|
||||
" !git pull\n",
|
||||
" !rm \"/content/drive/MyDrive/ComfyUI/custom_nodes/comfyui-impact-pack.py\"\n",
|
||||
" !wget -O \"/content/drive/MyDrive/ComfyUI/custom_nodes/comfyui-impact-pack.py\" https://raw.githubusercontent.com/ltdrdata/ComfyUI-Impact-Pack/Main/comfyui-impact-pack.py\n",
|
||||
"\n",
|
||||
"%cd custom_nodes\n",
|
||||
"!git clone https://github.com/ltdrdata/ComfyUI-Impact-Pack\n",
|
||||
"%cd $WORKSPACE\n",
|
||||
"\n",
|
||||
"!echo -= Install dependencies =-\n",
|
||||
"!pip -q install xformers -r requirements.txt\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "kkkkkkkkkkkkkk"
|
||||
@@ -103,6 +108,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "gggggggggg"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import onnxruntime
|
||||
from impact_utils import *
|
||||
|
||||
|
||||
def onnx_inference(image, onnx_model):
|
||||
# prepare image
|
||||
pil = tensor2pil(image)
|
||||
image = np.ascontiguousarray(pil)
|
||||
image = image[:, :, ::-1] # to BGR image
|
||||
image = image.astype(np.float32)
|
||||
image -= [103.939, 116.779, 123.68] # 'caffe' mode image preprocessing
|
||||
|
||||
# do detection
|
||||
onnx_model = onnxruntime.InferenceSession(onnx_model)
|
||||
outputs = onnx_model.run(
|
||||
[s_i.name for s_i in onnx_model.get_outputs()],
|
||||
{onnx_model.get_inputs()[0].name: np.expand_dims(image, axis=0)},
|
||||
)
|
||||
|
||||
labels = [op for op in outputs if op.dtype == "int32"][0]
|
||||
scores = [op for op in outputs if isinstance(op[0][0], np.float32)][0]
|
||||
boxes = [op for op in outputs if isinstance(op[0][0], np.ndarray)][0]
|
||||
|
||||
# filter-out useless item
|
||||
idx = np.where(labels[0] == -1)[0][0]
|
||||
|
||||
labels = labels[0][:idx]
|
||||
scores = scores[0][:idx]
|
||||
boxes = boxes[0][:idx].astype(np.uint32)
|
||||
|
||||
return labels, scores, boxes
|
||||
@@ -0,0 +1,37 @@
|
||||
main_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
sys.path.append(main_dir)
|
||||
|
||||
import server
|
||||
from aiohttp import web
|
||||
|
||||
|
||||
@server.PromptServer.instance.routes.post("/upload/temp")
|
||||
async def upload_image(request):
|
||||
upload_dir = folder_paths.get_temp_directory()
|
||||
|
||||
if not os.path.exists(upload_dir):
|
||||
os.makedirs(upload_dir)
|
||||
|
||||
post = await request.post()
|
||||
image = post.get("image")
|
||||
|
||||
if image and image.file:
|
||||
filename = image.filename
|
||||
if not filename:
|
||||
return web.Response(status=400)
|
||||
|
||||
split = os.path.splitext(filename)
|
||||
i = 1
|
||||
while os.path.exists(os.path.join(upload_dir, filename)):
|
||||
filename = f"{split[0]} ({i}){split[1]}"
|
||||
i += 1
|
||||
|
||||
filepath = os.path.join(upload_dir, filename)
|
||||
|
||||
with open(filepath, "wb") as f:
|
||||
f.write(image.file.read())
|
||||
|
||||
return web.json_response({"name": filename})
|
||||
else:
|
||||
return web.Response(status=400)
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
# NudeNet
|
||||
Nudenet uses an ONNX model to detect NSFW content. This example is an application of [NudeNet](https://github.com/notAI-tech/NudeNet)'s capabilities, which detects NSFW elements in images and applies a mask as a post-processing step. This technique demonstrates the use of nudenet to detect potentially inappropriate content in order to ensure the safety of minors on certain websites
|
||||
|
||||
* [detector_v2_base_checkpoint.onnx](https://github.com/notAI-tech/NudeNet/releases/download/v0/detector_v2_base_checkpoint.onnx) is a model for nudenet. Download and placed into **ComfyUI/models/onnx**
|
||||
|
||||
* [onnx.json](../misc/onnx.json) is a workflow of this example.
|
||||
|
||||

|
||||
|
||||
|
||||
# ONNX Models
|
||||
* You can download various ONNX models from [here](https://github.com/PINTO0309/PINTO_model_zoo).
|
||||
|
Before Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 503 KiB |
@@ -1,22 +0,0 @@
|
||||
#### 1. Basic auto face detection and refine exapmle.
|
||||

|
||||
   
|
||||
* 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, Impact Pack is providing the more sophisticated SAM model instead of the SEGM_MODEL for silhouette extraction.
|
||||
|
||||
* 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.
|
||||
* dilation: Expand the detected mask area.
|
||||
* crop_factor: Determine how many times the surrounding area should be included in the detail recovery process based on the detected mask area. If this value is small, the restoration may not work well because the surrounding context cannot be known.
|
||||
|
||||
* Detailer Node
|
||||
* guide_size: This feature attempt detail recovery only when the size of the detected mask is smaller than this value. If the size is larger, this feature increase the resolution and attempt detail recovery.
|
||||
* guide_size_for: This parameter determines whether guide_size is used based on the size of the detected face (bbox) or the size of the crop area that includes the face and is broadly cropped by crop_factor.
|
||||
* feather: When compositing the recovered details onto the original image, this feature use a gradient to composite it so that the boundaries are not visible. The thickness of this gradient is determined.
|
||||
* force_inpaint: force_inpaint will try to force regeneration even if it is smaller than guide_size . This function is useful when you simply want to change to another type of prompt other than the function to save details. However, in this case, upscale is forcibly fixed to 1.
|
||||
* This feature adopt the properties of KSampler because this feature use it to recover details.
|
||||
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.2 MiB |
@@ -1,13 +0,0 @@
|
||||
|
||||
# Mask Pointer
|
||||

|
||||
* When setting the detection-hint as **mask-points** in SAMDetector, multiple mask fragments are provided as SAM prompts. If using **mask-area**, only some of the points within the float mask's inner area are provided as SAM prompts. When detection_hint_use_negative is set to True, very small dots are interpreted as negative prompts in mask-points, and some areas with a mask value of 0 are interpreted as negative prompts in **mask-area**. The **detection_hint_threshold** interprets cases where the mask value in **mask-area** is equal to or higher than the threshold as positive prompts. However, values greater than 0 but less than the **detection_hint_threshold** are not used as negative prompts.
|
||||
* When using **mask-points**, please note that you should set "combined" parameter as **False** in MaskToSegs.
|
||||
|
||||

|
||||
* When you adjust the mouse wheel up and down, you can adjust the size of the brush. When you hold down the left mouse button and drag, it will draw, and when you hold down the right mouse button and drag, it will erase.
|
||||
* When using the mask_hint_use_negative as true in conjunction with the mask-points mode, large dots are interpreted as positive prompts and small dots are interpreted as negative prompts.
|
||||
|
||||
<img src="maskpointer-original.png" width=30% height=30%> <img src="maskpointer-shirt.png" width=30% height=30%> <img src="maskpointer-hair.png" width=30% height=30%>
|
||||
|
||||
* By using **mask-points** or **mask-area**, you can select only certain parts, such as shirts or hair, to regenerate.
|
||||
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 280 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |