Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86d7f73981 | ||
|
|
f428182ddf | ||
|
|
a43dae373e | ||
|
|
1087f2ee06 | ||
|
|
841a245cd4 | ||
|
|
aecc925630 | ||
|
|
b5abf19a1b | ||
|
|
9775a98f03 | ||
|
|
ac288bbcb9 |
@@ -7,6 +7,7 @@ This custom node helps to conveniently enhance images through Detector, Detailer
|
|||||||
|
|
||||||
|
|
||||||
## NOTICE
|
## NOTICE
|
||||||
|
* V7.6: Automatic installation is no longer supported. Please install using ComfyUI-Manager, or manually install requirements.txt and run install.py to complete the installation.
|
||||||
* V7.0: Supports Switch based on Execution Model Inversion.
|
* V7.0: Supports Switch based on Execution Model Inversion.
|
||||||
* V6.0: Supports FLUX.1 model in Impact KSampler, Detailers, PreviewBridgeLatent
|
* V6.0: Supports FLUX.1 model in Impact KSampler, Detailers, PreviewBridgeLatent
|
||||||
* V5.0: It is no longer compatible with versions of ComfyUI before 2024.04.08.
|
* V5.0: It is no longer compatible with versions of ComfyUI before 2024.04.08.
|
||||||
@@ -89,6 +90,7 @@ This custom node helps to conveniently enhance images through Detector, Detailer
|
|||||||
* `MaskDetailer (pipe)` - This is a simple inpaint node that applies the Detailer to the mask area.
|
* `MaskDetailer (pipe)` - This is a simple inpaint node that applies the Detailer to the mask area.
|
||||||
|
|
||||||
* `FromDetailer (SDXL/pipe)`, `BasicPipe -> DetailerPipe (SDXL)`, `Edit DetailerPipe (SDXL)` - These are pipe functions used in Detailer for utilizing the refiner model of SDXL.
|
* `FromDetailer (SDXL/pipe)`, `BasicPipe -> DetailerPipe (SDXL)`, `Edit DetailerPipe (SDXL)` - These are pipe functions used in Detailer for utilizing the refiner model of SDXL.
|
||||||
|
* `Any PIPE -> BasicPipe` - Convert the PIPE Value of other custom nodes that are not BASIC_PIPE but internally have the same structure as BASIC_PIPE to BASIC_PIPE. If an incompatible type is applied, it may cause runtime errors.
|
||||||
|
|
||||||
### SEGS Manipulation nodes
|
### SEGS Manipulation nodes
|
||||||
* `SEGSDetailer` - Performs detailed work on SEGS without pasting it back onto the original image.
|
* `SEGSDetailer` - Performs detailed work on SEGS without pasting it back onto the original image.
|
||||||
@@ -236,7 +238,7 @@ This custom node helps to conveniently enhance images through Detector, Detailer
|
|||||||
- The input of images can be scaled up as needed
|
- The input of images can be scaled up as needed
|
||||||
* `Masks to Mask List`, `Mask List to Masks`, `Make Mask List`, `Make Mask Batch` - It has the same functionality as the nodes above, but uses mask as input instead of image.
|
* `Masks to Mask List`, `Mask List to Masks`, `Make Mask List`, `Make Mask Batch` - It has the same functionality as the nodes above, but uses mask as input instead of image.
|
||||||
* `Flatten Mask Batch` - Flattens a Mask Batch into a single Mask. Normal operation is not guaranteed for non-binary masks.
|
* `Flatten Mask Batch` - Flattens a Mask Batch into a single Mask. Normal operation is not guaranteed for non-binary masks.
|
||||||
|
* `Make List (Any)` - Create a list with arbitrary values.
|
||||||
|
|
||||||
### Logics (experimental)
|
### Logics (experimental)
|
||||||
* These nodes are experimental nodes designed to implement the logic for loops and dynamic switching.
|
* These nodes are experimental nodes designed to implement the logic for loops and dynamic switching.
|
||||||
@@ -309,7 +311,8 @@ This custom node helps to conveniently enhance images through Detector, Detailer
|
|||||||
|
|
||||||
|
|
||||||
## Ultralytics models
|
## Ultralytics models
|
||||||
* huggingface.co/Bingsu/[adetailer](https://github.com/ultralytics/assets/releases/) - You can download face, people detection models, and clothing detection models.
|
* When using ultralytics models, save them separately in `models/ultralytics/bbox` and `models/ultralytics/segm` depending on the type of model. Many models can be downloaded by searching for `ultralytics` in the Model Manager of ComfyUI-Manager.
|
||||||
|
* huggingface.co/Bingsu/[adetailer](https://huggingface.co/Bingsu/adetailer/tree/main) - You can download face, people detection models, and clothing detection models.
|
||||||
* ultralytics/[assets](https://github.com/ultralytics/assets/releases/) - You can download various types of detection models other than faces or people.
|
* ultralytics/[assets](https://github.com/ultralytics/assets/releases/) - You can download various types of detection models other than faces or people.
|
||||||
* civitai/[adetailer](https://civitai.com/search/models?sortBy=models_v5&query=adetailer) - You can download various types detection models....Many models are associated with NSFW content.
|
* civitai/[adetailer](https://civitai.com/search/models?sortBy=models_v5&query=adetailer) - You can download various types detection models....Many models are associated with NSFW content.
|
||||||
|
|
||||||
@@ -331,6 +334,10 @@ mmdet_skip = False
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
### Install via ComfyUI-Manager (Recommended)
|
||||||
|
* Search `ComfyUI Impact Pack` in ComfyUI-Manager and click `Install` button.
|
||||||
|
|
||||||
|
### Manual Install (Not Recommended)
|
||||||
1. `cd custom_nodes`
|
1. `cd custom_nodes`
|
||||||
2. `git clone https://github.com/ltdrdata/ComfyUI-Impact-Pack.git`
|
2. `git clone https://github.com/ltdrdata/ComfyUI-Impact-Pack.git`
|
||||||
3. `cd ComfyUI-Impact-Pack`
|
3. `cd ComfyUI-Impact-Pack`
|
||||||
@@ -339,24 +346,29 @@ mmdet_skip = False
|
|||||||
5. (optional) `python install.py`
|
5. (optional) `python install.py`
|
||||||
* Impact Pack will automatically install its dependencies during its initial launch.
|
* Impact Pack will automatically install its dependencies during its initial launch.
|
||||||
* For the portable version, you should execute the command `..\..\..\python_embeded\python.exe install.py` to run the installation script.
|
* For the portable version, you should execute the command `..\..\..\python_embeded\python.exe install.py` to run the installation script.
|
||||||
|
|
||||||
|
|
||||||
6. Restart ComfyUI
|
6. Restart ComfyUI
|
||||||
|
|
||||||
* NOTE1: If an error occurs during the installation process, please refer to [Troubleshooting Page](troubleshooting/TROUBLESHOOTING.md) for assistance.
|
* NOTE1: If an error occurs during the installation process, please refer to [Troubleshooting Page](troubleshooting/TROUBLESHOOTING.md) for assistance.
|
||||||
* NOTE2: You can use this colab notebook [colab notebook](https://colab.research.google.com/github/ltdrdata/ComfyUI-Impact-Pack/blob/Main/notebook/comfyui_colab_impact_pack.ipynb) to launch it. This notebook automatically downloads the impact pack to the custom_nodes directory, installs the tested dependencies, and runs it.
|
* NOTE2: You can use this colab notebook [colab notebook](https://colab.research.google.com/github/ltdrdata/ComfyUI-Impact-Pack/blob/Main/notebook/comfyui_colab_impact_pack.ipynb) to launch it. This notebook automatically downloads the impact pack to the custom_nodes directory, installs the tested dependencies, and runs it.
|
||||||
* NOTE3: If you create an empty file named `skip_download_model` in the `ComfyUI/custom_nodes/` directory, it will skip the model download step during the installation of the impact pack.
|
* NOTE3: If you create an empty file named `skip_download_model` in the `ComfyUI/custom_nodes/` directory, it will skip the model download step during the installation of the impact pack.
|
||||||
|
|
||||||
|
|
||||||
## Package Dependencies (If you need to manual setup.)
|
## Package Dependencies (If you need to manual setup.)
|
||||||
|
|
||||||
* pip install
|
* pip install
|
||||||
* openmim
|
|
||||||
* segment-anything
|
* segment-anything
|
||||||
* ultralytics
|
* ultralytics
|
||||||
* scikit-image
|
* scikit-image
|
||||||
* piexif
|
* piexif
|
||||||
* (optional) pycocotools
|
* opencv-python
|
||||||
|
* GitPython
|
||||||
|
* scipy
|
||||||
|
* numpy<2
|
||||||
|
* dill
|
||||||
|
* matplotlib
|
||||||
* (optional) onnxruntime
|
* (optional) onnxruntime
|
||||||
|
* (deprecated) openmim # for mim
|
||||||
|
* (deprecated) pycocotools # for mim
|
||||||
|
|
||||||
* mim install (deprecated)
|
* mim install (deprecated)
|
||||||
* mmcv==2.0.0, mmdet==3.0.0, mmengine==0.7.2
|
* mmcv==2.0.0, mmdet==3.0.0, mmengine==0.7.2
|
||||||
|
|||||||
+8
-20
@@ -23,22 +23,6 @@ import impact.sample_error_enhancer
|
|||||||
print(f"### Loading: ComfyUI-Impact-Pack ({impact.config.version})")
|
print(f"### Loading: ComfyUI-Impact-Pack ({impact.config.version})")
|
||||||
|
|
||||||
|
|
||||||
def do_install():
|
|
||||||
import importlib
|
|
||||||
spec = importlib.util.spec_from_file_location('impact_install', os.path.join(os.path.dirname(__file__), 'install.py'))
|
|
||||||
impact_install = importlib.util.module_from_spec(spec)
|
|
||||||
spec.loader.exec_module(impact_install)
|
|
||||||
|
|
||||||
|
|
||||||
# ensure dependency
|
|
||||||
if not os.path.exists(os.path.join(subpack_path, ".git")) and os.path.exists(subpack_path):
|
|
||||||
print(f"### CompfyUI-Impact-Pack: corrupted subpack detected.")
|
|
||||||
shutil.rmtree(subpack_path)
|
|
||||||
|
|
||||||
if impact.config.get_config()['dependency_version'] < impact.config.dependency_version or not os.path.exists(subpack_path):
|
|
||||||
print(f"### ComfyUI-Impact-Pack: Updating dependencies [{impact.config.get_config()['dependency_version']} -> {impact.config.dependency_version}]")
|
|
||||||
do_install()
|
|
||||||
|
|
||||||
sys.path.append(subpack_path)
|
sys.path.append(subpack_path)
|
||||||
|
|
||||||
# Core
|
# Core
|
||||||
@@ -63,10 +47,10 @@ try:
|
|||||||
import mmcv
|
import mmcv
|
||||||
from mmdet.apis import (inference_detector, init_detector)
|
from mmdet.apis import (inference_detector, init_detector)
|
||||||
from mmdet.evaluation import get_classes
|
from mmdet.evaluation import get_classes
|
||||||
except:
|
except Exception as e:
|
||||||
import importlib
|
import logging
|
||||||
print("### ComfyUI-Impact-Pack: Reinstall dependencies (several dependencies are missing.)")
|
logging.error("[Impact Pack] Failed to import due to several dependencies are missing!!!!")
|
||||||
do_install()
|
raise e
|
||||||
|
|
||||||
|
|
||||||
import impact.impact_server # to load server api
|
import impact.impact_server # to load server api
|
||||||
@@ -116,6 +100,7 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
"FromDetailerPipe": FromDetailerPipe,
|
"FromDetailerPipe": FromDetailerPipe,
|
||||||
"FromDetailerPipe_v2": FromDetailerPipe_v2,
|
"FromDetailerPipe_v2": FromDetailerPipe_v2,
|
||||||
"FromDetailerPipeSDXL": FromDetailerPipe_SDXL,
|
"FromDetailerPipeSDXL": FromDetailerPipe_SDXL,
|
||||||
|
"AnyPipeToBasic": AnyPipeToBasic,
|
||||||
"ToBasicPipe": ToBasicPipe,
|
"ToBasicPipe": ToBasicPipe,
|
||||||
"FromBasicPipe": FromBasicPipe,
|
"FromBasicPipe": FromBasicPipe,
|
||||||
"FromBasicPipe_v2": FromBasicPipe_v2,
|
"FromBasicPipe_v2": FromBasicPipe_v2,
|
||||||
@@ -250,6 +235,7 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
"ImpactImageBatchToImageList": ImageBatchToImageList,
|
"ImpactImageBatchToImageList": ImageBatchToImageList,
|
||||||
"ImpactMakeImageList": MakeImageList,
|
"ImpactMakeImageList": MakeImageList,
|
||||||
"ImpactMakeImageBatch": MakeImageBatch,
|
"ImpactMakeImageBatch": MakeImageBatch,
|
||||||
|
"ImpactMakeAnyList": MakeAnyList,
|
||||||
"ImpactMakeMaskList": MakeMaskList,
|
"ImpactMakeMaskList": MakeMaskList,
|
||||||
"ImpactMakeMaskBatch": MakeMaskBatch,
|
"ImpactMakeMaskBatch": MakeMaskBatch,
|
||||||
|
|
||||||
@@ -358,6 +344,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
|||||||
"DetailerPipeToBasicPipe": "DetailerPipe -> BasicPipe",
|
"DetailerPipeToBasicPipe": "DetailerPipe -> BasicPipe",
|
||||||
"EditBasicPipe": "Edit BasicPipe",
|
"EditBasicPipe": "Edit BasicPipe",
|
||||||
"EditDetailerPipe": "Edit DetailerPipe",
|
"EditDetailerPipe": "Edit DetailerPipe",
|
||||||
|
"AnyPipeToBasic": "Any PIPE -> BasicPipe",
|
||||||
|
|
||||||
"LatentPixelScale": "Latent Scale (on Pixel Space)",
|
"LatentPixelScale": "Latent Scale (on Pixel Space)",
|
||||||
"IterativeLatentUpscale": "Iterative Upscale (Latent/on Pixel Space)",
|
"IterativeLatentUpscale": "Iterative Upscale (Latent/on Pixel Space)",
|
||||||
@@ -413,6 +400,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
|||||||
"ImpactMakeImageBatch": "Make Image Batch",
|
"ImpactMakeImageBatch": "Make Image Batch",
|
||||||
"ImpactMakeMaskList": "Make Mask List",
|
"ImpactMakeMaskList": "Make Mask List",
|
||||||
"ImpactMakeMaskBatch": "Make Mask Batch",
|
"ImpactMakeMaskBatch": "Make Mask Batch",
|
||||||
|
"ImpactMakeAnyList": "Make List (Any)",
|
||||||
|
|
||||||
"ImpactStringSelector": "String Selector",
|
"ImpactStringSelector": "String Selector",
|
||||||
"StringListToString": "String List to String",
|
"StringListToString": "String List to String",
|
||||||
|
|||||||
+5
-163
@@ -5,7 +5,6 @@ import subprocess
|
|||||||
import threading
|
import threading
|
||||||
import locale
|
import locale
|
||||||
import traceback
|
import traceback
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
if sys.argv[0] == 'install.py':
|
if sys.argv[0] == 'install.py':
|
||||||
@@ -13,7 +12,6 @@ if sys.argv[0] == 'install.py':
|
|||||||
|
|
||||||
|
|
||||||
impact_path = os.path.join(os.path.dirname(__file__), "modules")
|
impact_path = os.path.join(os.path.dirname(__file__), "modules")
|
||||||
old_subpack_path = os.path.join(os.path.dirname(__file__), "subpack")
|
|
||||||
subpack_path = os.path.join(os.path.dirname(__file__), "impact_subpack")
|
subpack_path = os.path.join(os.path.dirname(__file__), "impact_subpack")
|
||||||
subpack_repo = "https://github.com/ltdrdata/ComfyUI-Impact-Subpack"
|
subpack_repo = "https://github.com/ltdrdata/ComfyUI-Impact-Subpack"
|
||||||
|
|
||||||
@@ -71,64 +69,13 @@ def process_wrap(cmd_str, cwd=None, handler=None, env=None):
|
|||||||
# ---
|
# ---
|
||||||
|
|
||||||
|
|
||||||
pip_list = None
|
|
||||||
|
|
||||||
|
|
||||||
def get_installed_packages():
|
|
||||||
global pip_list
|
|
||||||
|
|
||||||
if pip_list is None:
|
|
||||||
try:
|
|
||||||
result = subprocess.check_output([sys.executable, '-m', 'pip', 'list'], universal_newlines=True)
|
|
||||||
pip_list = set([line.split()[0].lower() for line in result.split('\n') if line.strip()])
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(f"[ComfyUI-Manager] Failed to retrieve the information of installed pip packages.")
|
|
||||||
return set()
|
|
||||||
|
|
||||||
return pip_list
|
|
||||||
|
|
||||||
|
|
||||||
def is_installed(name):
|
|
||||||
name = name.strip()
|
|
||||||
pattern = r'([^<>!=]+)([<>!=]=?)'
|
|
||||||
match = re.search(pattern, name)
|
|
||||||
|
|
||||||
if match:
|
|
||||||
name = match.group(1)
|
|
||||||
|
|
||||||
result = name.lower() in get_installed_packages()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def is_requirements_installed(file_path):
|
|
||||||
print(f"req_path: {file_path}")
|
|
||||||
if os.path.exists(file_path):
|
|
||||||
with open(file_path, 'r') as file:
|
|
||||||
lines = file.readlines()
|
|
||||||
for line in lines:
|
|
||||||
if not is_installed(line):
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import platform
|
import platform
|
||||||
|
import folder_paths
|
||||||
from torchvision.datasets.utils import download_url
|
from torchvision.datasets.utils import download_url
|
||||||
import impact.config
|
import impact.config
|
||||||
|
|
||||||
|
|
||||||
print("### ComfyUI-Impact-Pack: Check dependencies")
|
print("### ComfyUI-Impact-Pack: Check dependencies")
|
||||||
|
|
||||||
if "python_embeded" in sys.executable or "python_embedded" in sys.executable:
|
|
||||||
pip_install = [sys.executable, '-s', '-m', 'pip', 'install']
|
|
||||||
pip_upgrade = [sys.executable, '-s', '-m', 'pip', 'install', '-U']
|
|
||||||
mim_install = [sys.executable, '-s', '-m', 'mim', 'install']
|
|
||||||
else:
|
|
||||||
pip_install = [sys.executable, '-m', 'pip', 'install']
|
|
||||||
pip_upgrade = [sys.executable, '-m', 'pip', 'install', '-U']
|
|
||||||
mim_install = [sys.executable, '-m', 'mim', 'install']
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_subpack():
|
def ensure_subpack():
|
||||||
import git
|
import git
|
||||||
if os.path.exists(subpack_path):
|
if os.path.exists(subpack_path):
|
||||||
@@ -145,106 +92,11 @@ try:
|
|||||||
else:
|
else:
|
||||||
git.Repo.clone_from(subpack_repo, subpack_path)
|
git.Repo.clone_from(subpack_repo, subpack_path)
|
||||||
|
|
||||||
if os.path.exists(old_subpack_path):
|
|
||||||
shutil.rmtree(old_subpack_path)
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_pip_packages_first():
|
|
||||||
subpack_req = os.path.join(subpack_path, "requirements.txt")
|
|
||||||
if os.path.exists(subpack_req) and not is_requirements_installed(subpack_req):
|
|
||||||
process_wrap(pip_install + ['-r', 'requirements.txt'], cwd=subpack_path)
|
|
||||||
|
|
||||||
if not impact.config.get_config()['mmdet_skip']:
|
|
||||||
process_wrap(pip_install + ['openmim'])
|
|
||||||
|
|
||||||
try:
|
|
||||||
import pycocotools
|
|
||||||
except Exception:
|
|
||||||
if platform.system() not in ["Windows"] or platform.machine() not in ["AMD64", "x86_64"]:
|
|
||||||
print(f"Your system is {platform.system()}; !! You need to install 'libpython3-dev' for this step. !!")
|
|
||||||
|
|
||||||
process_wrap(pip_install + ['pycocotools'])
|
|
||||||
else:
|
|
||||||
pycocotools = {
|
|
||||||
(3, 8): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp38-cp38-win_amd64.whl",
|
|
||||||
(3, 9): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp39-cp39-win_amd64.whl",
|
|
||||||
(3, 10): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp310-cp310-win_amd64.whl",
|
|
||||||
(3, 11): "https://github.com/Bing-su/dddetailer/releases/download/pycocotools/pycocotools-2.0.6-cp311-cp311-win_amd64.whl",
|
|
||||||
}
|
|
||||||
|
|
||||||
version = sys.version_info[:2]
|
|
||||||
url = pycocotools[version]
|
|
||||||
process_wrap(pip_install + [url])
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_pip_packages_last():
|
|
||||||
my_path = os.path.dirname(__file__)
|
|
||||||
requirements_path = os.path.join(my_path, "requirements.txt")
|
|
||||||
|
|
||||||
if not is_requirements_installed(requirements_path):
|
|
||||||
process_wrap(pip_install + ['-r', requirements_path])
|
|
||||||
|
|
||||||
# fallback
|
|
||||||
try:
|
|
||||||
import segment_anything
|
|
||||||
from skimage.measure import label, regionprops
|
|
||||||
import piexif
|
|
||||||
except Exception:
|
|
||||||
process_wrap(pip_install + ['-r', requirements_path])
|
|
||||||
|
|
||||||
# !! cv2 importing test must be very last !!
|
|
||||||
try:
|
|
||||||
from cv2 import setNumThreads
|
|
||||||
except Exception:
|
|
||||||
try:
|
|
||||||
is_open_cv_installed = False
|
|
||||||
|
|
||||||
# upgrade if opencv is installed already
|
|
||||||
if is_installed('opencv-python'):
|
|
||||||
process_wrap(pip_upgrade + ['opencv-python'])
|
|
||||||
is_open_cv_installed = True
|
|
||||||
|
|
||||||
if is_installed('opencv-python-headless'):
|
|
||||||
process_wrap(pip_upgrade + ['opencv-python-headless'])
|
|
||||||
is_open_cv_installed = True
|
|
||||||
|
|
||||||
if is_installed('opencv-contrib-python'):
|
|
||||||
process_wrap(pip_upgrade + ['opencv-contrib-python'])
|
|
||||||
is_open_cv_installed = True
|
|
||||||
|
|
||||||
if is_installed('opencv-contrib-python-headless'):
|
|
||||||
process_wrap(pip_upgrade + ['opencv-contrib-python-headless'])
|
|
||||||
is_open_cv_installed = True
|
|
||||||
|
|
||||||
# if opencv is not installed install `opencv-python-headless`
|
|
||||||
if not is_open_cv_installed:
|
|
||||||
process_wrap(pip_install + ['opencv-python-headless'])
|
|
||||||
except:
|
|
||||||
print(f"[ERROR] ComfyUI-Impact-Pack: failed to install 'opencv-python'. Please, install manually.")
|
|
||||||
|
|
||||||
def ensure_mmdet_package():
|
|
||||||
try:
|
|
||||||
import mmcv
|
|
||||||
import mmdet
|
|
||||||
from mmdet.evaluation import get_classes
|
|
||||||
except Exception:
|
|
||||||
process_wrap(pip_install + ['opendatalab==0.0.9'])
|
|
||||||
process_wrap(pip_install + ['-U', 'openmim'])
|
|
||||||
process_wrap(mim_install + ['mmcv>=2.0.0rc4, <2.1.0'])
|
|
||||||
process_wrap(mim_install + ['mmdet==3.0.0'])
|
|
||||||
process_wrap(mim_install + ['mmengine==0.7.4'])
|
|
||||||
|
|
||||||
|
|
||||||
def install():
|
def install():
|
||||||
subpack_install_script = os.path.join(subpack_path, "install.py")
|
subpack_install_script = os.path.join(subpack_path, "install.py")
|
||||||
|
|
||||||
print(f"### ComfyUI-Impact-Pack: Updating subpack")
|
print(f"### ComfyUI-Impact-Pack: Updating subpack")
|
||||||
try:
|
|
||||||
import git
|
|
||||||
except Exception:
|
|
||||||
if not is_installed('GitPython'):
|
|
||||||
process_wrap(pip_install + ['GitPython'])
|
|
||||||
|
|
||||||
ensure_subpack() # The installation of the subpack must take place before ensure_pip. cv2 triggers a permission error.
|
ensure_subpack() # The installation of the subpack must take place before ensure_pip. cv2 triggers a permission error.
|
||||||
|
|
||||||
new_env = os.environ.copy()
|
new_env = os.environ.copy()
|
||||||
@@ -253,29 +105,20 @@ try:
|
|||||||
|
|
||||||
if os.path.exists(subpack_install_script):
|
if os.path.exists(subpack_install_script):
|
||||||
process_wrap([sys.executable, 'install.py'], cwd=subpack_path, env=new_env)
|
process_wrap([sys.executable, 'install.py'], cwd=subpack_path, env=new_env)
|
||||||
if not is_requirements_installed(os.path.join(subpack_path, 'requirements.txt')):
|
|
||||||
process_wrap(pip_install + ['-r', 'requirements.txt'], cwd=subpack_path)
|
|
||||||
else:
|
else:
|
||||||
print(f"### ComfyUI-Impact-Pack: (Install Failed) Subpack\nFile not found: `{subpack_install_script}`")
|
print(f"### ComfyUI-Impact-Pack: (Install Failed) Subpack\nFile not found: `{subpack_install_script}`")
|
||||||
|
|
||||||
ensure_pip_packages_first()
|
|
||||||
|
|
||||||
if not impact.config.get_config()['mmdet_skip']:
|
|
||||||
ensure_mmdet_package()
|
|
||||||
|
|
||||||
ensure_pip_packages_last()
|
|
||||||
|
|
||||||
# Download model
|
# Download model
|
||||||
print("### ComfyUI-Impact-Pack: Check basic models")
|
print("### ComfyUI-Impact-Pack: Check basic models")
|
||||||
bbox_path = os.path.join(model_path, "mmdets", "bbox")
|
|
||||||
sam_path = os.path.join(model_path, "sams")
|
sam_path = os.path.join(model_path, "sams")
|
||||||
onnx_path = os.path.join(model_path, "onnx")
|
onnx_path = os.path.join(model_path, "onnx")
|
||||||
|
|
||||||
if not os.path.exists(os.path.join(os.path.dirname(__file__), '..', 'skip_download_model')):
|
if not os.path.exists(os.path.join(os.path.dirname(__file__), '..', 'skip_download_model')):
|
||||||
if not os.path.exists(bbox_path):
|
|
||||||
os.makedirs(bbox_path)
|
|
||||||
|
|
||||||
if not impact.config.get_config()['mmdet_skip']:
|
if not impact.config.get_config()['mmdet_skip']:
|
||||||
|
bbox_path = os.path.join(model_path, "mmdets", "bbox")
|
||||||
|
if not os.path.exists(bbox_path):
|
||||||
|
os.makedirs(bbox_path)
|
||||||
|
|
||||||
if not os.path.exists(os.path.join(bbox_path, "mmdet_anime-face_yolov3.pth")):
|
if not os.path.exists(os.path.join(bbox_path, "mmdet_anime-face_yolov3.pth")):
|
||||||
download_url("https://huggingface.co/dustysys/ddetailer/resolve/main/mmdet/bbox/mmdet_anime-face_yolov3.pth", bbox_path)
|
download_url("https://huggingface.co/dustysys/ddetailer/resolve/main/mmdet/bbox/mmdet_anime-face_yolov3.pth", bbox_path)
|
||||||
|
|
||||||
@@ -291,7 +134,6 @@ try:
|
|||||||
|
|
||||||
impact.config.write_config()
|
impact.config.write_config()
|
||||||
|
|
||||||
|
|
||||||
install()
|
install()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
+5
-1
@@ -394,7 +394,7 @@ app.registerExtension({
|
|||||||
|
|
||||||
if (nodeData.name === 'ImpactMakeImageList' || nodeData.name === 'ImpactMakeImageBatch' ||
|
if (nodeData.name === 'ImpactMakeImageList' || nodeData.name === 'ImpactMakeImageBatch' ||
|
||||||
nodeData.name === 'ImpactMakeMaskList' || nodeData.name === 'ImpactMakeMaskBatch' ||
|
nodeData.name === 'ImpactMakeMaskList' || nodeData.name === 'ImpactMakeMaskBatch' ||
|
||||||
nodeData.name === 'CombineRegionalPrompts' ||
|
nodeData.name === 'ImpactMakeAnyList' || nodeData.name === 'CombineRegionalPrompts' ||
|
||||||
nodeData.name === 'ImpactCombineConditionings' || nodeData.name === 'ImpactConcatConditionings' ||
|
nodeData.name === 'ImpactCombineConditionings' || nodeData.name === 'ImpactConcatConditionings' ||
|
||||||
nodeData.name === 'ImpactSEGSConcat' ||
|
nodeData.name === 'ImpactSEGSConcat' ||
|
||||||
nodeData.name === 'ImpactSwitch' || nodeData.name === 'LatentSwitch' || nodeData.name == 'SEGSSwitch') {
|
nodeData.name === 'ImpactSwitch' || nodeData.name === 'LatentSwitch' || nodeData.name == 'SEGSSwitch') {
|
||||||
@@ -411,6 +411,10 @@ app.registerExtension({
|
|||||||
input_name = "mask";
|
input_name = "mask";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'ImpactMakeAnyList':
|
||||||
|
input_name = "value";
|
||||||
|
break;
|
||||||
|
|
||||||
case 'ImpactSEGSConcat':
|
case 'ImpactSEGSConcat':
|
||||||
input_name = "segs";
|
input_name = "segs";
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import configparser
|
import configparser
|
||||||
import os
|
import os
|
||||||
|
|
||||||
version_code = [7, 5, 2]
|
version_code = [7, 7]
|
||||||
version = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
version = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
||||||
|
|
||||||
dependency_version = 22
|
dependency_version = 22
|
||||||
|
|||||||
@@ -1680,6 +1680,9 @@ class PixelKSampleUpscaler:
|
|||||||
self.hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative,
|
self.hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative,
|
||||||
upscaled_latent, denoise)
|
upscaled_latent, denoise)
|
||||||
|
|
||||||
|
if 'noise_mask' in samples:
|
||||||
|
upscaled_latent['noise_mask'] = samples['noise_mask']
|
||||||
|
|
||||||
refined_latent = self.sample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise, upscaled_images)
|
refined_latent = self.sample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise, upscaled_images)
|
||||||
return refined_latent
|
return refined_latent
|
||||||
|
|
||||||
@@ -1709,6 +1712,9 @@ class PixelKSampleUpscaler:
|
|||||||
self.hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative,
|
self.hook.pre_ksample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative,
|
||||||
upscaled_latent, denoise)
|
upscaled_latent, denoise)
|
||||||
|
|
||||||
|
if 'noise_mask' in samples:
|
||||||
|
upscaled_latent['noise_mask'] = samples['noise_mask']
|
||||||
|
|
||||||
refined_latent = self.sample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise, upscaled_images)
|
refined_latent = self.sample(model, seed, steps, cfg, sampler_name, scheduler, positive, negative, upscaled_latent, denoise, upscaled_images)
|
||||||
return refined_latent
|
return refined_latent
|
||||||
|
|
||||||
|
|||||||
@@ -319,6 +319,7 @@ class DetailerForEach:
|
|||||||
if wildcard_item and wildcard_item.strip() == '[STOP]':
|
if wildcard_item and wildcard_item.strip() == '[STOP]':
|
||||||
break
|
break
|
||||||
|
|
||||||
|
orig_cropped_image = cropped_image.clone()
|
||||||
enhanced_image, cnet_pils = core.enhance_detail(cropped_image, model, clip, vae, guide_size, guide_size_for_bbox, max_size,
|
enhanced_image, cnet_pils = core.enhance_detail(cropped_image, model, clip, vae, guide_size, guide_size_for_bbox, max_size,
|
||||||
seg.bbox, seg_seed, steps, cfg, sampler_name, scheduler,
|
seg.bbox, seg_seed, steps, cfg, sampler_name, scheduler,
|
||||||
cropped_positive, cropped_negative, denoise, cropped_mask, force_inpaint,
|
cropped_positive, cropped_negative, denoise, cropped_mask, force_inpaint,
|
||||||
@@ -338,7 +339,7 @@ class DetailerForEach:
|
|||||||
# use image paste
|
# use image paste
|
||||||
image = image.cpu()
|
image = image.cpu()
|
||||||
enhanced_image = enhanced_image.cpu()
|
enhanced_image = enhanced_image.cpu()
|
||||||
tensor_paste(image, enhanced_image, (seg.crop_region[0], seg.crop_region[1]), mask)
|
tensor_paste(image, enhanced_image, (seg.crop_region[0], seg.crop_region[1]), mask) # this code affecting to `cropped_image`.
|
||||||
enhanced_list.append(enhanced_image)
|
enhanced_list.append(enhanced_image)
|
||||||
|
|
||||||
if detailer_hook is not None:
|
if detailer_hook is not None:
|
||||||
@@ -356,7 +357,7 @@ class DetailerForEach:
|
|||||||
else:
|
else:
|
||||||
new_seg_image = None
|
new_seg_image = None
|
||||||
|
|
||||||
cropped_list.append(cropped_image)
|
cropped_list.append(orig_cropped_image) # NOTE: Don't use `cropped_image`
|
||||||
|
|
||||||
new_seg = SEG(new_seg_image, seg.cropped_mask, seg.confidence, seg.crop_region, seg.bbox, seg.label, seg.control_net_wrapper)
|
new_seg = SEG(new_seg_image, seg.cropped_mask, seg.confidence, seg.crop_region, seg.bbox, seg.label, seg.control_net_wrapper)
|
||||||
new_segs.append(new_seg)
|
new_segs.append(new_seg)
|
||||||
@@ -1249,6 +1250,7 @@ class IterativeLatentUpscale:
|
|||||||
upscale_factor_unit = max(0, (upscale_factor - 1.0) / steps)
|
upscale_factor_unit = max(0, (upscale_factor - 1.0) / steps)
|
||||||
|
|
||||||
current_latent = samples
|
current_latent = samples
|
||||||
|
noise_mask = current_latent.get('noise_mask')
|
||||||
scale = 1
|
scale = 1
|
||||||
|
|
||||||
for i in range(steps-1):
|
for i in range(steps-1):
|
||||||
@@ -1263,6 +1265,8 @@ class IterativeLatentUpscale:
|
|||||||
print(f"IterativeLatentUpscale[{i+1}/{steps}]: {new_w:.1f}x{new_h:.1f} (scale:{scale:.2f}) ")
|
print(f"IterativeLatentUpscale[{i+1}/{steps}]: {new_w:.1f}x{new_h:.1f} (scale:{scale:.2f}) ")
|
||||||
step_info = i, steps
|
step_info = i, steps
|
||||||
current_latent = upscaler.upscale_shape(step_info, current_latent, new_w, new_h, temp_prefix)
|
current_latent = upscaler.upscale_shape(step_info, current_latent, new_w, new_h, temp_prefix)
|
||||||
|
if noise_mask is not None:
|
||||||
|
current_latent['noise_mask'] = noise_mask
|
||||||
|
|
||||||
if scale < upscale_factor:
|
if scale < upscale_factor:
|
||||||
new_w = w*upscale_factor
|
new_w = w*upscale_factor
|
||||||
@@ -1274,7 +1278,7 @@ class IterativeLatentUpscale:
|
|||||||
|
|
||||||
core.update_node_status(unique_id, "", None)
|
core.update_node_status(unique_id, "", None)
|
||||||
|
|
||||||
return (current_latent, upscaler.vae)
|
return current_latent, upscaler.vae
|
||||||
|
|
||||||
|
|
||||||
class IterativeImageUpscale:
|
class IterativeImageUpscale:
|
||||||
|
|||||||
@@ -24,37 +24,6 @@ import random
|
|||||||
from server import PromptServer
|
from server import PromptServer
|
||||||
|
|
||||||
|
|
||||||
@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)
|
|
||||||
|
|
||||||
|
|
||||||
sam_predictor = None
|
sam_predictor = None
|
||||||
default_sam_model_name = os.path.join(impact_pack.model_path, "sams", "sam_vit_b_01ec64.pth")
|
default_sam_model_name = os.path.join(impact_pack.model_path, "sams", "sam_vit_b_01ec64.pth")
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import folder_paths
|
import folder_paths
|
||||||
import impact.wildcards
|
import impact.wildcards
|
||||||
|
from impact.utils import any_typ
|
||||||
|
|
||||||
|
|
||||||
class ToDetailerPipe:
|
class ToDetailerPipe:
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -108,6 +110,23 @@ class FromDetailerPipe_SDXL:
|
|||||||
return detailer_pipe, model, clip, vae, positive, negative, bbox_detector, sam_model_opt, segm_detector_opt, detailer_hook, refiner_model, refiner_clip, refiner_positive, refiner_negative
|
return detailer_pipe, model, clip, vae, positive, negative, bbox_detector, sam_model_opt, segm_detector_opt, detailer_hook, refiner_model, refiner_clip, refiner_positive, refiner_negative
|
||||||
|
|
||||||
|
|
||||||
|
class AnyPipeToBasic:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {
|
||||||
|
"required": {"any_pipe": (any_typ,)},
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("BASIC_PIPE", )
|
||||||
|
RETURN_NAMES = ("basic_pipe", )
|
||||||
|
FUNCTION = "doit"
|
||||||
|
|
||||||
|
CATEGORY = "ImpactPack/Pipe"
|
||||||
|
|
||||||
|
def doit(self, any_pipe):
|
||||||
|
return (any_pipe[:5], )
|
||||||
|
|
||||||
|
|
||||||
class ToBasicPipe:
|
class ToBasicPipe:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
|
|||||||
@@ -392,6 +392,30 @@ class ImageBatchToImageList:
|
|||||||
return (images, )
|
return (images, )
|
||||||
|
|
||||||
|
|
||||||
|
class MakeAnyList:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {
|
||||||
|
"required": {},
|
||||||
|
"optional": {"value1": (any_typ,), }
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = (any_typ,)
|
||||||
|
OUTPUT_IS_LIST = (True,)
|
||||||
|
FUNCTION = "doit"
|
||||||
|
|
||||||
|
CATEGORY = "ImpactPack/Util"
|
||||||
|
|
||||||
|
def doit(self, **kwargs):
|
||||||
|
values = []
|
||||||
|
|
||||||
|
for k, v in kwargs.items():
|
||||||
|
if v is not None:
|
||||||
|
values.append(v)
|
||||||
|
|
||||||
|
return (values, )
|
||||||
|
|
||||||
|
|
||||||
class MakeMaskList:
|
class MakeMaskList:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from impact import config
|
|||||||
|
|
||||||
wildcards_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "wildcards"))
|
wildcards_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "wildcards"))
|
||||||
|
|
||||||
RE_WildCardQuantifier = re.compile(r"(?P<quantifier>\d+)#__(?P<keyword>[\w.\-+/*\\]+)__", re.IGNORECASE)
|
RE_WildCardQuantifier = re.compile(r"(?P<quantifier>\d+)#__(?P<keyword>[\w.\-+/*\\]+?)__", re.IGNORECASE)
|
||||||
wildcard_lock = threading.Lock()
|
wildcard_lock = threading.Lock()
|
||||||
wildcard_dict = {}
|
wildcard_dict = {}
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ def process(text, seed=None):
|
|||||||
select_sep = ' '
|
select_sep = ' '
|
||||||
range_pattern = r'(\d+)(-(\d+))?'
|
range_pattern = r'(\d+)(-(\d+))?'
|
||||||
range_pattern2 = r'-(\d+)'
|
range_pattern2 = r'-(\d+)'
|
||||||
wildcard_pattern = r"__([\w.\-+/*\\]+)__"
|
wildcard_pattern = r"__([\w.\-+/*\\]+?)__"
|
||||||
|
|
||||||
if len(multi_select_pattern) > 1:
|
if len(multi_select_pattern) > 1:
|
||||||
r = re.match(range_pattern, options[0])
|
r = re.match(range_pattern, options[0])
|
||||||
@@ -200,7 +200,7 @@ def process(text, seed=None):
|
|||||||
return replaced_string, replacements_found
|
return replaced_string, replacements_found
|
||||||
|
|
||||||
def replace_wildcard(string):
|
def replace_wildcard(string):
|
||||||
pattern = r"__([\w.\-+/*\\]+)__"
|
pattern = r"__([\w.\-+/*\\]+?)__"
|
||||||
matches = re.findall(pattern, string)
|
matches = re.findall(pattern, string)
|
||||||
|
|
||||||
replacements_found = False
|
replacements_found = False
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "comfyui-impact-pack"
|
name = "comfyui-impact-pack"
|
||||||
description = "This extension offers various detector nodes and detailer nodes that allow you to configure a workflow that automatically enhances facial details. And provide iterative upscaler."
|
description = "This extension offers various detector nodes and detailer nodes that allow you to configure a workflow that automatically enhances facial details. And provide iterative upscaler."
|
||||||
version = "7.5.2"
|
version = "7.7"
|
||||||
license = { file = "LICENSE.txt" }
|
license = { file = "LICENSE.txt" }
|
||||||
dependencies = ["segment-anything", "scikit-image", "piexif", "transformers", "opencv-python-headless", "GitPython", "scipy>=1.11.4"]
|
dependencies = ["segment-anything", "scikit-image", "piexif", "transformers", "opencv-python-headless", "GitPython", "scipy>=1.11.4"]
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -6,4 +6,5 @@ opencv-python-headless
|
|||||||
GitPython
|
GitPython
|
||||||
scipy>=1.11.4
|
scipy>=1.11.4
|
||||||
numpy<2
|
numpy<2
|
||||||
dill
|
dill
|
||||||
|
matplotlib
|
||||||
Reference in New Issue
Block a user