c1a010c78919f8efef07b18490f90b54ce38605a218a48907aa972358dd0fbc1
Browse files- extensions/adetailer/controlnet_ext/restore.py +49 -0
- extensions/adetailer/install.py +80 -0
- extensions/adetailer/preload.py +9 -0
- extensions/adetailer/pyproject.toml +26 -0
- extensions/adetailer/scripts/!adetailer.py +634 -0
- extensions/adetailer/scripts/__pycache__/!adetailer.cpython-310.pyc +0 -0
- extensions/adetailer/sd_webui/__init__.py +0 -0
- extensions/adetailer/sd_webui/__pycache__/__init__.cpython-310.pyc +0 -0
- extensions/adetailer/sd_webui/__pycache__/images.cpython-310.pyc +0 -0
- extensions/adetailer/sd_webui/__pycache__/paths.cpython-310.pyc +0 -0
- extensions/adetailer/sd_webui/__pycache__/processing.cpython-310.pyc +0 -0
- extensions/adetailer/sd_webui/__pycache__/safe.cpython-310.pyc +0 -0
- extensions/adetailer/sd_webui/__pycache__/script_callbacks.cpython-310.pyc +0 -0
- extensions/adetailer/sd_webui/__pycache__/scripts.cpython-310.pyc +0 -0
- extensions/adetailer/sd_webui/__pycache__/shared.cpython-310.pyc +0 -0
- extensions/adetailer/sd_webui/images.py +62 -0
- extensions/adetailer/sd_webui/paths.py +14 -0
- extensions/adetailer/sd_webui/processing.py +172 -0
- extensions/adetailer/sd_webui/safe.py +10 -0
- extensions/adetailer/sd_webui/script_callbacks.py +15 -0
- extensions/adetailer/sd_webui/scripts.py +83 -0
- extensions/adetailer/sd_webui/shared.py +66 -0
- extensions/microsoftexcel-controlnet/.github/ISSUE_TEMPLATE/bug_report.yml +91 -0
- extensions/microsoftexcel-controlnet/.github/ISSUE_TEMPLATE/config.yml +1 -0
- extensions/microsoftexcel-controlnet/.github/workflows/tests.yml +37 -0
- extensions/microsoftexcel-controlnet/.gitignore +171 -0
- extensions/microsoftexcel-controlnet/LICENSE +21 -0
- extensions/microsoftexcel-controlnet/README.md +246 -0
- extensions/microsoftexcel-controlnet/__pycache__/preload.cpython-310.pyc +0 -0
- extensions/microsoftexcel-controlnet/annotator/__pycache__/annotator_path.cpython-310.pyc +0 -0
- extensions/microsoftexcel-controlnet/annotator/__pycache__/util.cpython-310.pyc +0 -0
- extensions/microsoftexcel-controlnet/annotator/annotator_path.py +22 -0
- extensions/microsoftexcel-controlnet/annotator/binary/__init__.py +14 -0
- extensions/microsoftexcel-controlnet/annotator/canny/__init__.py +5 -0
- extensions/microsoftexcel-controlnet/annotator/clip/__init__.py +39 -0
- extensions/microsoftexcel-controlnet/annotator/clip_vision/config.json +171 -0
- extensions/microsoftexcel-controlnet/annotator/clip_vision/merges.txt +0 -0
- extensions/microsoftexcel-controlnet/annotator/clip_vision/preprocessor_config.json +19 -0
- extensions/microsoftexcel-controlnet/annotator/clip_vision/tokenizer.json +0 -0
- extensions/microsoftexcel-controlnet/annotator/clip_vision/tokenizer_config.json +34 -0
- extensions/microsoftexcel-controlnet/annotator/clip_vision/vocab.json +0 -0
- extensions/microsoftexcel-controlnet/annotator/color/__init__.py +20 -0
- extensions/microsoftexcel-controlnet/annotator/downloads/openpose/body_pose_model.pth +3 -0
- extensions/microsoftexcel-controlnet/annotator/downloads/openpose/facenet.pth +3 -0
- extensions/microsoftexcel-controlnet/annotator/downloads/openpose/hand_pose_model.pth +3 -0
- extensions/microsoftexcel-controlnet/annotator/hed/__init__.py +98 -0
- extensions/microsoftexcel-controlnet/annotator/keypose/__init__.py +212 -0
- extensions/microsoftexcel-controlnet/annotator/keypose/faster_rcnn_r50_fpn_coco.py +182 -0
- extensions/microsoftexcel-controlnet/annotator/keypose/hrnet_w48_coco_256x192.py +169 -0
- extensions/microsoftexcel-controlnet/annotator/leres/__init__.py +113 -0
extensions/adetailer/controlnet_ext/restore.py
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from contextlib import contextmanager
|
4 |
+
|
5 |
+
from modules import img2img, processing, shared
|
6 |
+
|
7 |
+
|
8 |
+
def cn_restore_unet_hook(p, cn_latest_network):
|
9 |
+
if cn_latest_network is not None:
|
10 |
+
unet = p.sd_model.model.diffusion_model
|
11 |
+
cn_latest_network.restore(unet)
|
12 |
+
|
13 |
+
|
14 |
+
class CNHijackRestore:
|
15 |
+
def __init__(self):
|
16 |
+
self.process = hasattr(processing, "__controlnet_original_process_images_inner")
|
17 |
+
self.img2img = hasattr(img2img, "__controlnet_original_process_batch")
|
18 |
+
|
19 |
+
def __enter__(self):
|
20 |
+
if self.process:
|
21 |
+
self.orig_process = processing.process_images_inner
|
22 |
+
processing.process_images_inner = getattr(
|
23 |
+
processing, "__controlnet_original_process_images_inner"
|
24 |
+
)
|
25 |
+
if self.img2img:
|
26 |
+
self.orig_img2img = img2img.process_batch
|
27 |
+
img2img.process_batch = getattr(
|
28 |
+
img2img, "__controlnet_original_process_batch"
|
29 |
+
)
|
30 |
+
|
31 |
+
def __exit__(self, *args, **kwargs):
|
32 |
+
if self.process:
|
33 |
+
processing.process_images_inner = self.orig_process
|
34 |
+
if self.img2img:
|
35 |
+
img2img.process_batch = self.orig_img2img
|
36 |
+
|
37 |
+
|
38 |
+
@contextmanager
|
39 |
+
def cn_allow_script_control():
|
40 |
+
orig = False
|
41 |
+
if "control_net_allow_script_control" in shared.opts.data:
|
42 |
+
try:
|
43 |
+
orig = shared.opts.data["control_net_allow_script_control"]
|
44 |
+
shared.opts.data["control_net_allow_script_control"] = True
|
45 |
+
yield
|
46 |
+
finally:
|
47 |
+
shared.opts.data["control_net_allow_script_control"] = orig
|
48 |
+
else:
|
49 |
+
yield
|
extensions/adetailer/install.py
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import importlib.util
|
4 |
+
import subprocess
|
5 |
+
import sys
|
6 |
+
from importlib.metadata import version # python >= 3.8
|
7 |
+
|
8 |
+
from packaging.version import parse
|
9 |
+
|
10 |
+
|
11 |
+
def is_installed(
|
12 |
+
package: str, min_version: str | None = None, max_version: str | None = None
|
13 |
+
):
|
14 |
+
try:
|
15 |
+
spec = importlib.util.find_spec(package)
|
16 |
+
except ModuleNotFoundError:
|
17 |
+
return False
|
18 |
+
|
19 |
+
if spec is None:
|
20 |
+
return False
|
21 |
+
|
22 |
+
if not min_version and not max_version:
|
23 |
+
return True
|
24 |
+
|
25 |
+
if not min_version:
|
26 |
+
min_version = "0.0.0"
|
27 |
+
if not max_version:
|
28 |
+
max_version = "99999999.99999999.99999999"
|
29 |
+
|
30 |
+
if package == "google.protobuf":
|
31 |
+
package = "protobuf"
|
32 |
+
|
33 |
+
try:
|
34 |
+
pkg_version = version(package)
|
35 |
+
return parse(min_version) <= parse(pkg_version) <= parse(max_version)
|
36 |
+
except Exception:
|
37 |
+
return False
|
38 |
+
|
39 |
+
|
40 |
+
def run_pip(*args):
|
41 |
+
subprocess.run([sys.executable, "-m", "pip", "install", *args])
|
42 |
+
|
43 |
+
|
44 |
+
def install():
|
45 |
+
deps = [
|
46 |
+
# requirements
|
47 |
+
("ultralytics", "8.0.97", None),
|
48 |
+
("mediapipe", "0.10.0", None),
|
49 |
+
("huggingface_hub", None, None),
|
50 |
+
("pydantic", None, None),
|
51 |
+
# mediapipe
|
52 |
+
("protobuf", "3.20.0", "3.20.9999"),
|
53 |
+
]
|
54 |
+
|
55 |
+
for pkg, low, high in deps:
|
56 |
+
# https://github.com/protocolbuffers/protobuf/tree/main/python
|
57 |
+
name = "google.protobuf" if pkg == "protobuf" else pkg
|
58 |
+
|
59 |
+
if not is_installed(name, low, high):
|
60 |
+
if low and high:
|
61 |
+
cmd = f"{pkg}>={low},<={high}"
|
62 |
+
elif low:
|
63 |
+
cmd = f"{pkg}>={low}"
|
64 |
+
elif high:
|
65 |
+
cmd = f"{pkg}<={high}"
|
66 |
+
else:
|
67 |
+
cmd = pkg
|
68 |
+
|
69 |
+
run_pip("-U", cmd)
|
70 |
+
|
71 |
+
|
72 |
+
try:
|
73 |
+
import launch
|
74 |
+
|
75 |
+
skip_install = launch.args.skip_install
|
76 |
+
except Exception:
|
77 |
+
skip_install = False
|
78 |
+
|
79 |
+
if not skip_install:
|
80 |
+
install()
|
extensions/adetailer/preload.py
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import argparse
|
2 |
+
|
3 |
+
|
4 |
+
def preload(parser: argparse.ArgumentParser):
|
5 |
+
parser.add_argument(
|
6 |
+
"--ad-no-huggingface",
|
7 |
+
action="store_true",
|
8 |
+
help="Don't use adetailer models from huggingface",
|
9 |
+
)
|
extensions/adetailer/pyproject.toml
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[project]
|
2 |
+
name = "adetailer"
|
3 |
+
description = "An object detection and auto-mask extension for stable diffusion webui."
|
4 |
+
authors = [
|
5 |
+
{name = "dowon", email = "ks2515@naver.com"},
|
6 |
+
]
|
7 |
+
requires-python = ">=3.8,<3.12"
|
8 |
+
readme = "README.md"
|
9 |
+
license = {text = "AGPL-3.0"}
|
10 |
+
|
11 |
+
[project.urls]
|
12 |
+
repository = "https://github.com/Bing-su/adetailer"
|
13 |
+
|
14 |
+
[tool.isort]
|
15 |
+
profile = "black"
|
16 |
+
known_first_party = ["launch", "modules"]
|
17 |
+
|
18 |
+
[tool.ruff]
|
19 |
+
select = ["A", "B", "C4", "E", "F", "I001", "ISC", "N", "PIE", "PT", "RET", "SIM", "UP", "W"]
|
20 |
+
ignore = ["B008", "B905", "E501", "F401", "UP007"]
|
21 |
+
|
22 |
+
[tool.ruff.isort]
|
23 |
+
known-first-party = ["launch", "modules"]
|
24 |
+
|
25 |
+
[tool.ruff.per-file-ignores]
|
26 |
+
"sd_webui/*.py" = ["B027", "F403"]
|
extensions/adetailer/scripts/!adetailer.py
ADDED
@@ -0,0 +1,634 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import os
|
4 |
+
import platform
|
5 |
+
import re
|
6 |
+
import sys
|
7 |
+
import traceback
|
8 |
+
from contextlib import contextmanager, suppress
|
9 |
+
from copy import copy, deepcopy
|
10 |
+
from pathlib import Path
|
11 |
+
from textwrap import dedent
|
12 |
+
from typing import Any
|
13 |
+
|
14 |
+
import gradio as gr
|
15 |
+
import torch
|
16 |
+
|
17 |
+
import modules # noqa: F401
|
18 |
+
from adetailer import (
|
19 |
+
AFTER_DETAILER,
|
20 |
+
__version__,
|
21 |
+
get_models,
|
22 |
+
mediapipe_predict,
|
23 |
+
ultralytics_predict,
|
24 |
+
)
|
25 |
+
from adetailer.args import ALL_ARGS, BBOX_SORTBY, ADetailerArgs, EnableChecker
|
26 |
+
from adetailer.common import PredictOutput
|
27 |
+
from adetailer.mask import filter_by_ratio, mask_preprocess, sort_bboxes
|
28 |
+
from adetailer.ui import adui, ordinal, suffix
|
29 |
+
from controlnet_ext import ControlNetExt, controlnet_exists
|
30 |
+
from controlnet_ext.restore import (
|
31 |
+
CNHijackRestore,
|
32 |
+
cn_allow_script_control,
|
33 |
+
cn_restore_unet_hook,
|
34 |
+
)
|
35 |
+
from sd_webui import images, safe, script_callbacks, scripts, shared
|
36 |
+
from sd_webui.paths import data_path, models_path
|
37 |
+
from sd_webui.processing import (
|
38 |
+
StableDiffusionProcessingImg2Img,
|
39 |
+
create_infotext,
|
40 |
+
process_images,
|
41 |
+
)
|
42 |
+
from sd_webui.shared import cmd_opts, opts, state
|
43 |
+
|
44 |
+
with suppress(ImportError):
|
45 |
+
from rich import print
|
46 |
+
|
47 |
+
|
48 |
+
no_huggingface = getattr(cmd_opts, "ad_no_huggingface", False)
|
49 |
+
adetailer_dir = Path(models_path, "adetailer")
|
50 |
+
model_mapping = get_models(adetailer_dir, huggingface=not no_huggingface)
|
51 |
+
txt2img_submit_button = img2img_submit_button = None
|
52 |
+
SCRIPT_DEFAULT = "dynamic_prompting,dynamic_thresholding,wildcard_recursive,wildcards"
|
53 |
+
|
54 |
+
if (
|
55 |
+
not adetailer_dir.exists()
|
56 |
+
and adetailer_dir.parent.exists()
|
57 |
+
and os.access(adetailer_dir.parent, os.W_OK)
|
58 |
+
):
|
59 |
+
adetailer_dir.mkdir()
|
60 |
+
|
61 |
+
print(
|
62 |
+
f"[-] ADetailer initialized. version: {__version__}, num models: {len(model_mapping)}"
|
63 |
+
)
|
64 |
+
|
65 |
+
|
66 |
+
@contextmanager
|
67 |
+
def change_torch_load():
|
68 |
+
orig = torch.load
|
69 |
+
try:
|
70 |
+
torch.load = safe.unsafe_torch_load
|
71 |
+
yield
|
72 |
+
finally:
|
73 |
+
torch.load = orig
|
74 |
+
|
75 |
+
|
76 |
+
@contextmanager
|
77 |
+
def pause_total_tqdm():
|
78 |
+
orig = opts.data.get("multiple_tqdm", True)
|
79 |
+
try:
|
80 |
+
opts.data["multiple_tqdm"] = False
|
81 |
+
yield
|
82 |
+
finally:
|
83 |
+
opts.data["multiple_tqdm"] = orig
|
84 |
+
|
85 |
+
|
86 |
+
class AfterDetailerScript(scripts.Script):
|
87 |
+
def __init__(self):
|
88 |
+
super().__init__()
|
89 |
+
self.ultralytics_device = self.get_ultralytics_device()
|
90 |
+
|
91 |
+
self.controlnet_ext = None
|
92 |
+
self.cn_script = None
|
93 |
+
self.cn_latest_network = None
|
94 |
+
|
95 |
+
def title(self):
|
96 |
+
return AFTER_DETAILER
|
97 |
+
|
98 |
+
def show(self, is_img2img):
|
99 |
+
return scripts.AlwaysVisible
|
100 |
+
|
101 |
+
def ui(self, is_img2img):
|
102 |
+
num_models = opts.data.get("ad_max_models", 2)
|
103 |
+
model_list = list(model_mapping.keys())
|
104 |
+
|
105 |
+
components, infotext_fields = adui(
|
106 |
+
num_models,
|
107 |
+
is_img2img,
|
108 |
+
model_list,
|
109 |
+
txt2img_submit_button,
|
110 |
+
img2img_submit_button,
|
111 |
+
)
|
112 |
+
|
113 |
+
self.infotext_fields = infotext_fields
|
114 |
+
return components
|
115 |
+
|
116 |
+
def init_controlnet_ext(self) -> None:
|
117 |
+
if self.controlnet_ext is not None:
|
118 |
+
return
|
119 |
+
self.controlnet_ext = ControlNetExt()
|
120 |
+
|
121 |
+
if controlnet_exists:
|
122 |
+
try:
|
123 |
+
self.controlnet_ext.init_controlnet()
|
124 |
+
except ImportError:
|
125 |
+
error = traceback.format_exc()
|
126 |
+
print(
|
127 |
+
f"[-] ADetailer: ControlNetExt init failed:\n{error}",
|
128 |
+
file=sys.stderr,
|
129 |
+
)
|
130 |
+
|
131 |
+
def update_controlnet_args(self, p, args: ADetailerArgs) -> None:
|
132 |
+
if self.controlnet_ext is None:
|
133 |
+
self.init_controlnet_ext()
|
134 |
+
|
135 |
+
if (
|
136 |
+
self.controlnet_ext is not None
|
137 |
+
and self.controlnet_ext.cn_available
|
138 |
+
and args.ad_controlnet_model != "None"
|
139 |
+
):
|
140 |
+
self.controlnet_ext.update_scripts_args(
|
141 |
+
p,
|
142 |
+
model=args.ad_controlnet_model,
|
143 |
+
weight=args.ad_controlnet_weight,
|
144 |
+
guidance_start=args.ad_controlnet_guidance_start,
|
145 |
+
guidance_end=args.ad_controlnet_guidance_end,
|
146 |
+
)
|
147 |
+
|
148 |
+
def is_ad_enabled(self, *args_) -> bool:
|
149 |
+
if len(args_) == 0 or (len(args_) == 1 and isinstance(args_[0], bool)):
|
150 |
+
message = f"""
|
151 |
+
[-] ADetailer: Not enough arguments passed to ADetailer.
|
152 |
+
input: {args_!r}
|
153 |
+
"""
|
154 |
+
raise ValueError(dedent(message))
|
155 |
+
a0 = args_[0]
|
156 |
+
a1 = args_[1] if len(args_) > 1 else None
|
157 |
+
checker = EnableChecker(a0=a0, a1=a1)
|
158 |
+
return checker.is_enabled()
|
159 |
+
|
160 |
+
def get_args(self, *args_) -> list[ADetailerArgs]:
|
161 |
+
"""
|
162 |
+
`args_` is at least 1 in length by `is_ad_enabled` immediately above
|
163 |
+
"""
|
164 |
+
args = [arg for arg in args_ if isinstance(arg, dict)]
|
165 |
+
|
166 |
+
if not args:
|
167 |
+
message = f"[-] ADetailer: Invalid arguments passed to ADetailer: {args_!r}"
|
168 |
+
raise ValueError(message)
|
169 |
+
|
170 |
+
all_inputs = []
|
171 |
+
|
172 |
+
for n, arg_dict in enumerate(args, 1):
|
173 |
+
try:
|
174 |
+
inp = ADetailerArgs(**arg_dict)
|
175 |
+
except ValueError as e:
|
176 |
+
msgs = [
|
177 |
+
f"[-] ADetailer: ValidationError when validating {ordinal(n)} arguments: {e}\n"
|
178 |
+
]
|
179 |
+
for attr in ALL_ARGS.attrs:
|
180 |
+
arg = arg_dict.get(attr)
|
181 |
+
dtype = type(arg)
|
182 |
+
arg = "DEFAULT" if arg is None else repr(arg)
|
183 |
+
msgs.append(f" {attr}: {arg} ({dtype})")
|
184 |
+
raise ValueError("\n".join(msgs)) from e
|
185 |
+
|
186 |
+
all_inputs.append(inp)
|
187 |
+
|
188 |
+
return all_inputs
|
189 |
+
|
190 |
+
def extra_params(self, arg_list: list[ADetailerArgs]) -> dict:
|
191 |
+
params = {}
|
192 |
+
for n, args in enumerate(arg_list):
|
193 |
+
params.update(args.extra_params(suffix=suffix(n)))
|
194 |
+
params["ADetailer version"] = __version__
|
195 |
+
return params
|
196 |
+
|
197 |
+
@staticmethod
|
198 |
+
def get_ultralytics_device() -> str:
|
199 |
+
'`device = ""` means autodetect'
|
200 |
+
device = ""
|
201 |
+
if platform.system() == "Darwin":
|
202 |
+
return device
|
203 |
+
|
204 |
+
if any(getattr(cmd_opts, vram, False) for vram in ["lowvram", "medvram"]):
|
205 |
+
device = "cpu"
|
206 |
+
|
207 |
+
return device
|
208 |
+
|
209 |
+
def prompt_blank_replacement(
|
210 |
+
self, all_prompts: list[str], i: int, default: str
|
211 |
+
) -> str:
|
212 |
+
if not all_prompts:
|
213 |
+
return default
|
214 |
+
if i < len(all_prompts):
|
215 |
+
return all_prompts[i]
|
216 |
+
j = i % len(all_prompts)
|
217 |
+
return all_prompts[j]
|
218 |
+
|
219 |
+
def _get_prompt(
|
220 |
+
self, ad_prompt: str, all_prompts: list[str], i: int, default: str
|
221 |
+
) -> list[str]:
|
222 |
+
prompts = re.split(r"\s*\[SEP\]\s*", ad_prompt)
|
223 |
+
blank_replacement = self.prompt_blank_replacement(all_prompts, i, default)
|
224 |
+
for n in range(len(prompts)):
|
225 |
+
if not prompts[n]:
|
226 |
+
prompts[n] = blank_replacement
|
227 |
+
return prompts
|
228 |
+
|
229 |
+
def get_prompt(self, p, args: ADetailerArgs) -> tuple[list[str], list[str]]:
|
230 |
+
i = p._idx
|
231 |
+
|
232 |
+
prompt = self._get_prompt(args.ad_prompt, p.all_prompts, i, p.prompt)
|
233 |
+
negative_prompt = self._get_prompt(
|
234 |
+
args.ad_negative_prompt, p.all_negative_prompts, i, p.negative_prompt
|
235 |
+
)
|
236 |
+
|
237 |
+
return prompt, negative_prompt
|
238 |
+
|
239 |
+
def get_seed(self, p) -> tuple[int, int]:
|
240 |
+
i = p._idx
|
241 |
+
|
242 |
+
if not p.all_seeds:
|
243 |
+
seed = p.seed
|
244 |
+
elif i < len(p.all_seeds):
|
245 |
+
seed = p.all_seeds[i]
|
246 |
+
else:
|
247 |
+
j = i % len(p.all_seeds)
|
248 |
+
seed = p.all_seeds[j]
|
249 |
+
|
250 |
+
if not p.all_subseeds:
|
251 |
+
subseed = p.subseed
|
252 |
+
elif i < len(p.all_subseeds):
|
253 |
+
subseed = p.all_subseeds[i]
|
254 |
+
else:
|
255 |
+
j = i % len(p.all_subseeds)
|
256 |
+
subseed = p.all_subseeds[j]
|
257 |
+
|
258 |
+
return seed, subseed
|
259 |
+
|
260 |
+
def get_width_height(self, p, args: ADetailerArgs) -> tuple[int, int]:
|
261 |
+
if args.ad_use_inpaint_width_height:
|
262 |
+
width = args.ad_inpaint_width
|
263 |
+
height = args.ad_inpaint_height
|
264 |
+
else:
|
265 |
+
width = p.width
|
266 |
+
height = p.height
|
267 |
+
|
268 |
+
return width, height
|
269 |
+
|
270 |
+
def get_steps(self, p, args: ADetailerArgs) -> int:
|
271 |
+
if args.ad_use_steps:
|
272 |
+
return args.ad_steps
|
273 |
+
return p.steps
|
274 |
+
|
275 |
+
def get_cfg_scale(self, p, args: ADetailerArgs) -> float:
|
276 |
+
if args.ad_use_cfg_scale:
|
277 |
+
return args.ad_cfg_scale
|
278 |
+
return p.cfg_scale
|
279 |
+
|
280 |
+
def infotext(self, p) -> str:
|
281 |
+
return create_infotext(
|
282 |
+
p, p.all_prompts, p.all_seeds, p.all_subseeds, None, 0, 0
|
283 |
+
)
|
284 |
+
|
285 |
+
def write_params_txt(self, p) -> None:
|
286 |
+
infotext = self.infotext(p)
|
287 |
+
params_txt = Path(data_path, "params.txt")
|
288 |
+
params_txt.write_text(infotext, encoding="utf-8")
|
289 |
+
|
290 |
+
def script_filter(self, p, args: ADetailerArgs):
|
291 |
+
script_runner = copy(p.scripts)
|
292 |
+
script_args = deepcopy(p.script_args)
|
293 |
+
self.disable_controlnet_units(script_args)
|
294 |
+
|
295 |
+
ad_only_seleted_scripts = opts.data.get("ad_only_seleted_scripts", True)
|
296 |
+
if not ad_only_seleted_scripts:
|
297 |
+
return script_runner, script_args
|
298 |
+
|
299 |
+
ad_script_names = opts.data.get("ad_script_names", SCRIPT_DEFAULT)
|
300 |
+
script_names_set = {
|
301 |
+
name
|
302 |
+
for script_name in ad_script_names.split(",")
|
303 |
+
for name in (script_name, script_name.strip())
|
304 |
+
}
|
305 |
+
|
306 |
+
if args.ad_controlnet_model != "None":
|
307 |
+
script_names_set.add("controlnet")
|
308 |
+
|
309 |
+
filtered_alwayson = []
|
310 |
+
for script_object in script_runner.alwayson_scripts:
|
311 |
+
filepath = script_object.filename
|
312 |
+
filename = Path(filepath).stem
|
313 |
+
if filename in script_names_set:
|
314 |
+
filtered_alwayson.append(script_object)
|
315 |
+
if filename == "controlnet":
|
316 |
+
self.cn_script = script_object
|
317 |
+
self.cn_latest_network = script_object.latest_network
|
318 |
+
|
319 |
+
script_runner.alwayson_scripts = filtered_alwayson
|
320 |
+
return script_runner, script_args
|
321 |
+
|
322 |
+
def disable_controlnet_units(self, script_args: list[Any]) -> None:
|
323 |
+
for obj in script_args:
|
324 |
+
if "controlnet" in obj.__class__.__name__.lower():
|
325 |
+
if hasattr(obj, "enabled"):
|
326 |
+
obj.enabled = False
|
327 |
+
if hasattr(obj, "input_mode"):
|
328 |
+
obj.input_mode = getattr(obj.input_mode, "SIMPLE", "simple")
|
329 |
+
|
330 |
+
elif isinstance(obj, dict) and "module" in obj:
|
331 |
+
obj["enabled"] = False
|
332 |
+
|
333 |
+
def get_i2i_p(self, p, args: ADetailerArgs, image):
|
334 |
+
seed, subseed = self.get_seed(p)
|
335 |
+
width, height = self.get_width_height(p, args)
|
336 |
+
steps = self.get_steps(p, args)
|
337 |
+
cfg_scale = self.get_cfg_scale(p, args)
|
338 |
+
|
339 |
+
sampler_name = p.sampler_name
|
340 |
+
if sampler_name in ["PLMS", "UniPC"]:
|
341 |
+
sampler_name = "Euler"
|
342 |
+
|
343 |
+
i2i = StableDiffusionProcessingImg2Img(
|
344 |
+
init_images=[image],
|
345 |
+
resize_mode=0,
|
346 |
+
denoising_strength=args.ad_denoising_strength,
|
347 |
+
mask=None,
|
348 |
+
mask_blur=args.ad_mask_blur,
|
349 |
+
inpainting_fill=1,
|
350 |
+
inpaint_full_res=args.ad_inpaint_only_masked,
|
351 |
+
inpaint_full_res_padding=args.ad_inpaint_only_masked_padding,
|
352 |
+
inpainting_mask_invert=0,
|
353 |
+
sd_model=p.sd_model,
|
354 |
+
outpath_samples=p.outpath_samples,
|
355 |
+
outpath_grids=p.outpath_grids,
|
356 |
+
prompt="", # replace later
|
357 |
+
negative_prompt="",
|
358 |
+
styles=p.styles,
|
359 |
+
seed=seed,
|
360 |
+
subseed=subseed,
|
361 |
+
subseed_strength=p.subseed_strength,
|
362 |
+
seed_resize_from_h=p.seed_resize_from_h,
|
363 |
+
seed_resize_from_w=p.seed_resize_from_w,
|
364 |
+
sampler_name=sampler_name,
|
365 |
+
batch_size=1,
|
366 |
+
n_iter=1,
|
367 |
+
steps=steps,
|
368 |
+
cfg_scale=cfg_scale,
|
369 |
+
width=width,
|
370 |
+
height=height,
|
371 |
+
restore_faces=args.ad_restore_face,
|
372 |
+
tiling=p.tiling,
|
373 |
+
extra_generation_params=p.extra_generation_params,
|
374 |
+
do_not_save_samples=True,
|
375 |
+
do_not_save_grid=True,
|
376 |
+
)
|
377 |
+
|
378 |
+
i2i.scripts, i2i.script_args = self.script_filter(p, args)
|
379 |
+
i2i._disable_adetailer = True
|
380 |
+
|
381 |
+
if args.ad_controlnet_model != "None":
|
382 |
+
self.update_controlnet_args(i2i, args)
|
383 |
+
else:
|
384 |
+
i2i.control_net_enabled = False
|
385 |
+
|
386 |
+
return i2i
|
387 |
+
|
388 |
+
def save_image(self, p, image, *, condition: str, suffix: str) -> None:
|
389 |
+
i = p._idx
|
390 |
+
seed, _ = self.get_seed(p)
|
391 |
+
|
392 |
+
if opts.data.get(condition, False):
|
393 |
+
images.save_image(
|
394 |
+
image=image,
|
395 |
+
path=p.outpath_samples,
|
396 |
+
basename="",
|
397 |
+
seed=seed,
|
398 |
+
prompt=p.all_prompts[i] if i < len(p.all_prompts) else p.prompt,
|
399 |
+
extension=opts.samples_format,
|
400 |
+
info=self.infotext(p),
|
401 |
+
p=p,
|
402 |
+
suffix=suffix,
|
403 |
+
)
|
404 |
+
|
405 |
+
def get_ad_model(self, name: str):
|
406 |
+
if name not in model_mapping:
|
407 |
+
msg = f"[-] ADetailer: Model {name!r} not found. Available models: {list(model_mapping.keys())}"
|
408 |
+
raise ValueError(msg)
|
409 |
+
return model_mapping[name]
|
410 |
+
|
411 |
+
def sort_bboxes(self, pred: PredictOutput) -> PredictOutput:
|
412 |
+
sortby = opts.data.get("ad_bbox_sortby", BBOX_SORTBY[0])
|
413 |
+
sortby_idx = BBOX_SORTBY.index(sortby)
|
414 |
+
pred = sort_bboxes(pred, sortby_idx)
|
415 |
+
return pred
|
416 |
+
|
417 |
+
def pred_preprocessing(self, pred: PredictOutput, args: ADetailerArgs):
|
418 |
+
pred = filter_by_ratio(
|
419 |
+
pred, low=args.ad_mask_min_ratio, high=args.ad_mask_max_ratio
|
420 |
+
)
|
421 |
+
pred = self.sort_bboxes(pred)
|
422 |
+
return mask_preprocess(
|
423 |
+
pred.masks,
|
424 |
+
kernel=args.ad_dilate_erode,
|
425 |
+
x_offset=args.ad_x_offset,
|
426 |
+
y_offset=args.ad_y_offset,
|
427 |
+
merge_invert=args.ad_mask_merge_invert,
|
428 |
+
)
|
429 |
+
|
430 |
+
def i2i_prompts_replace(
|
431 |
+
self, i2i, prompts: list[str], negative_prompts: list[str], j: int
|
432 |
+
) -> None:
|
433 |
+
i1 = min(j, len(prompts) - 1)
|
434 |
+
i2 = min(j, len(negative_prompts) - 1)
|
435 |
+
prompt = prompts[i1]
|
436 |
+
negative_prompt = negative_prompts[i2]
|
437 |
+
i2i.prompt = prompt
|
438 |
+
i2i.negative_prompt = negative_prompt
|
439 |
+
|
440 |
+
def is_need_call_process(self, p) -> bool:
|
441 |
+
i = p._idx
|
442 |
+
n_iter = p.iteration
|
443 |
+
bs = p.batch_size
|
444 |
+
return (i == (n_iter + 1) * bs - 1) and (i != len(p.all_prompts) - 1)
|
445 |
+
|
446 |
+
def process(self, p, *args_):
|
447 |
+
if getattr(p, "_disable_adetailer", False):
|
448 |
+
return
|
449 |
+
|
450 |
+
if self.is_ad_enabled(*args_):
|
451 |
+
arg_list = self.get_args(*args_)
|
452 |
+
extra_params = self.extra_params(arg_list)
|
453 |
+
p.extra_generation_params.update(extra_params)
|
454 |
+
|
455 |
+
p._idx = -1
|
456 |
+
|
457 |
+
def _postprocess_image(self, p, pp, args: ADetailerArgs, *, n: int = 0) -> bool:
|
458 |
+
"""
|
459 |
+
Returns
|
460 |
+
-------
|
461 |
+
bool
|
462 |
+
|
463 |
+
`True` if image was processed, `False` otherwise.
|
464 |
+
"""
|
465 |
+
if state.interrupted:
|
466 |
+
return False
|
467 |
+
|
468 |
+
i = p._idx
|
469 |
+
|
470 |
+
i2i = self.get_i2i_p(p, args, pp.image)
|
471 |
+
seed, subseed = self.get_seed(p)
|
472 |
+
ad_prompts, ad_negatives = self.get_prompt(p, args)
|
473 |
+
|
474 |
+
is_mediapipe = args.ad_model.lower().startswith("mediapipe")
|
475 |
+
|
476 |
+
kwargs = {}
|
477 |
+
if is_mediapipe:
|
478 |
+
predictor = mediapipe_predict
|
479 |
+
ad_model = args.ad_model
|
480 |
+
else:
|
481 |
+
predictor = ultralytics_predict
|
482 |
+
ad_model = self.get_ad_model(args.ad_model)
|
483 |
+
kwargs["device"] = self.ultralytics_device
|
484 |
+
|
485 |
+
with change_torch_load():
|
486 |
+
pred = predictor(ad_model, pp.image, args.ad_confidence, **kwargs)
|
487 |
+
|
488 |
+
masks = self.pred_preprocessing(pred, args)
|
489 |
+
|
490 |
+
if not masks:
|
491 |
+
print(
|
492 |
+
f"[-] ADetailer: nothing detected on image {i + 1} with {ordinal(n + 1)} settings."
|
493 |
+
)
|
494 |
+
return False
|
495 |
+
|
496 |
+
self.save_image(
|
497 |
+
p,
|
498 |
+
pred.preview,
|
499 |
+
condition="ad_save_previews",
|
500 |
+
suffix="-ad-preview" + suffix(n, "-"),
|
501 |
+
)
|
502 |
+
|
503 |
+
steps = len(masks)
|
504 |
+
processed = None
|
505 |
+
state.job_count += steps
|
506 |
+
|
507 |
+
if is_mediapipe:
|
508 |
+
print(f"mediapipe: {steps} detected.")
|
509 |
+
|
510 |
+
p2 = copy(i2i)
|
511 |
+
for j in range(steps):
|
512 |
+
p2.image_mask = masks[j]
|
513 |
+
self.i2i_prompts_replace(p2, ad_prompts, ad_negatives, j)
|
514 |
+
|
515 |
+
if not re.match(r"^\s*\[SKIP\]\s*$", p2.prompt):
|
516 |
+
if args.ad_controlnet_model == "None":
|
517 |
+
cn_restore_unet_hook(p2, self.cn_latest_network)
|
518 |
+
processed = process_images(p2)
|
519 |
+
|
520 |
+
p2 = copy(i2i)
|
521 |
+
p2.init_images = [processed.images[0]]
|
522 |
+
|
523 |
+
p2.seed = seed + j + 1
|
524 |
+
p2.subseed = subseed + j + 1
|
525 |
+
|
526 |
+
if processed is not None:
|
527 |
+
pp.image = processed.images[0]
|
528 |
+
return True
|
529 |
+
|
530 |
+
return False
|
531 |
+
|
532 |
+
def postprocess_image(self, p, pp, *args_):
|
533 |
+
if getattr(p, "_disable_adetailer", False):
|
534 |
+
return
|
535 |
+
|
536 |
+
if not self.is_ad_enabled(*args_):
|
537 |
+
return
|
538 |
+
|
539 |
+
p._idx = getattr(p, "_idx", -1) + 1
|
540 |
+
init_image = copy(pp.image)
|
541 |
+
arg_list = self.get_args(*args_)
|
542 |
+
|
543 |
+
is_processed = False
|
544 |
+
with CNHijackRestore(), pause_total_tqdm(), cn_allow_script_control():
|
545 |
+
for n, args in enumerate(arg_list):
|
546 |
+
if args.ad_model == "None":
|
547 |
+
continue
|
548 |
+
is_processed |= self._postprocess_image(p, pp, args, n=n)
|
549 |
+
|
550 |
+
if is_processed:
|
551 |
+
self.save_image(
|
552 |
+
p, init_image, condition="ad_save_images_before", suffix="-ad-before"
|
553 |
+
)
|
554 |
+
|
555 |
+
if self.cn_script is not None and self.is_need_call_process(p):
|
556 |
+
self.cn_script.process(p)
|
557 |
+
|
558 |
+
try:
|
559 |
+
if p._idx == len(p.all_prompts) - 1:
|
560 |
+
self.write_params_txt(p)
|
561 |
+
except Exception:
|
562 |
+
pass
|
563 |
+
|
564 |
+
|
565 |
+
def on_after_component(component, **_kwargs):
|
566 |
+
global txt2img_submit_button, img2img_submit_button
|
567 |
+
if getattr(component, "elem_id", None) == "txt2img_generate":
|
568 |
+
txt2img_submit_button = component
|
569 |
+
return
|
570 |
+
|
571 |
+
if getattr(component, "elem_id", None) == "img2img_generate":
|
572 |
+
img2img_submit_button = component
|
573 |
+
|
574 |
+
|
575 |
+
def on_ui_settings():
|
576 |
+
section = ("ADetailer", AFTER_DETAILER)
|
577 |
+
shared.opts.add_option(
|
578 |
+
"ad_max_models",
|
579 |
+
shared.OptionInfo(
|
580 |
+
default=2,
|
581 |
+
label="Max models",
|
582 |
+
component=gr.Slider,
|
583 |
+
component_args={"minimum": 1, "maximum": 5, "step": 1},
|
584 |
+
section=section,
|
585 |
+
),
|
586 |
+
)
|
587 |
+
|
588 |
+
shared.opts.add_option(
|
589 |
+
"ad_save_previews",
|
590 |
+
shared.OptionInfo(False, "Save mask previews", section=section),
|
591 |
+
)
|
592 |
+
|
593 |
+
shared.opts.add_option(
|
594 |
+
"ad_save_images_before",
|
595 |
+
shared.OptionInfo(False, "Save images before ADetailer", section=section),
|
596 |
+
)
|
597 |
+
|
598 |
+
shared.opts.add_option(
|
599 |
+
"ad_only_seleted_scripts",
|
600 |
+
shared.OptionInfo(
|
601 |
+
True, "Apply only selected scripts to ADetailer", section=section
|
602 |
+
),
|
603 |
+
)
|
604 |
+
|
605 |
+
textbox_args = {
|
606 |
+
"placeholder": "comma-separated list of script names",
|
607 |
+
"interactive": True,
|
608 |
+
}
|
609 |
+
|
610 |
+
shared.opts.add_option(
|
611 |
+
"ad_script_names",
|
612 |
+
shared.OptionInfo(
|
613 |
+
default=SCRIPT_DEFAULT,
|
614 |
+
label="Script names to apply to ADetailer (separated by comma)",
|
615 |
+
component=gr.Textbox,
|
616 |
+
component_args=textbox_args,
|
617 |
+
section=section,
|
618 |
+
),
|
619 |
+
)
|
620 |
+
|
621 |
+
shared.opts.add_option(
|
622 |
+
"ad_bbox_sortby",
|
623 |
+
shared.OptionInfo(
|
624 |
+
default="None",
|
625 |
+
label="Sort bounding boxes by",
|
626 |
+
component=gr.Radio,
|
627 |
+
component_args={"choices": BBOX_SORTBY},
|
628 |
+
section=section,
|
629 |
+
),
|
630 |
+
)
|
631 |
+
|
632 |
+
|
633 |
+
script_callbacks.on_ui_settings(on_ui_settings)
|
634 |
+
script_callbacks.on_after_component(on_after_component)
|
extensions/adetailer/scripts/__pycache__/!adetailer.cpython-310.pyc
ADDED
Binary file (18.2 kB). View file
|
|
extensions/adetailer/sd_webui/__init__.py
ADDED
File without changes
|
extensions/adetailer/sd_webui/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (158 Bytes). View file
|
|
extensions/adetailer/sd_webui/__pycache__/images.cpython-310.pyc
ADDED
Binary file (2.64 kB). View file
|
|
extensions/adetailer/sd_webui/__pycache__/paths.cpython-310.pyc
ADDED
Binary file (566 Bytes). View file
|
|
extensions/adetailer/sd_webui/__pycache__/processing.cpython-310.pyc
ADDED
Binary file (6.56 kB). View file
|
|
extensions/adetailer/sd_webui/__pycache__/safe.cpython-310.pyc
ADDED
Binary file (339 Bytes). View file
|
|
extensions/adetailer/sd_webui/__pycache__/script_callbacks.cpython-310.pyc
ADDED
Binary file (604 Bytes). View file
|
|
extensions/adetailer/sd_webui/__pycache__/scripts.cpython-310.pyc
ADDED
Binary file (3.23 kB). View file
|
|
extensions/adetailer/sd_webui/__pycache__/shared.cpython-310.pyc
ADDED
Binary file (2.63 kB). View file
|
|
extensions/adetailer/sd_webui/images.py
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from typing import TYPE_CHECKING
|
4 |
+
|
5 |
+
if TYPE_CHECKING:
|
6 |
+
from PIL import Image, PngImagePlugin
|
7 |
+
|
8 |
+
from sd_webui.processing import StableDiffusionProcessing
|
9 |
+
|
10 |
+
def save_image(
|
11 |
+
image: Image.Image,
|
12 |
+
path: str,
|
13 |
+
basename: str,
|
14 |
+
seed: int | None = None,
|
15 |
+
prompt: str = "",
|
16 |
+
extension: str = "png",
|
17 |
+
info: str | PngImagePlugin.iTXt = "",
|
18 |
+
short_filename: bool = False,
|
19 |
+
no_prompt: bool = False,
|
20 |
+
grid: bool = False,
|
21 |
+
pnginfo_section_name: str = "parameters",
|
22 |
+
p: StableDiffusionProcessing | None = None,
|
23 |
+
existing_info: dict | None = None,
|
24 |
+
forced_filename: str | None = None,
|
25 |
+
suffix: str = "",
|
26 |
+
save_to_dirs: bool = False,
|
27 |
+
) -> tuple[str, str | None]:
|
28 |
+
"""Save an image.
|
29 |
+
|
30 |
+
Args:
|
31 |
+
image (`PIL.Image`):
|
32 |
+
The image to be saved.
|
33 |
+
path (`str`):
|
34 |
+
The directory to save the image. Note, the option `save_to_dirs` will make the image to be saved into a sub directory.
|
35 |
+
basename (`str`):
|
36 |
+
The base filename which will be applied to `filename pattern`.
|
37 |
+
seed, prompt, short_filename,
|
38 |
+
extension (`str`):
|
39 |
+
Image file extension, default is `png`.
|
40 |
+
pngsectionname (`str`):
|
41 |
+
Specify the name of the section which `info` will be saved in.
|
42 |
+
info (`str` or `PngImagePlugin.iTXt`):
|
43 |
+
PNG info chunks.
|
44 |
+
existing_info (`dict`):
|
45 |
+
Additional PNG info. `existing_info == {pngsectionname: info, ...}`
|
46 |
+
no_prompt:
|
47 |
+
TODO I don't know its meaning.
|
48 |
+
p (`StableDiffusionProcessing`)
|
49 |
+
forced_filename (`str`):
|
50 |
+
If specified, `basename` and filename pattern will be ignored.
|
51 |
+
save_to_dirs (bool):
|
52 |
+
If true, the image will be saved into a subdirectory of `path`.
|
53 |
+
|
54 |
+
Returns: (fullfn, txt_fullfn)
|
55 |
+
fullfn (`str`):
|
56 |
+
The full path of the saved imaged.
|
57 |
+
txt_fullfn (`str` or None):
|
58 |
+
If a text file is saved for this image, this will be its full path. Otherwise None.
|
59 |
+
"""
|
60 |
+
|
61 |
+
else:
|
62 |
+
from modules.images import save_image
|
extensions/adetailer/sd_webui/paths.py
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from typing import TYPE_CHECKING
|
4 |
+
|
5 |
+
if TYPE_CHECKING:
|
6 |
+
import os
|
7 |
+
|
8 |
+
models_path = os.path.join(os.path.dirname(__file__), "1")
|
9 |
+
script_path = os.path.join(os.path.dirname(__file__), "2")
|
10 |
+
data_path = os.path.join(os.path.dirname(__file__), "3")
|
11 |
+
extensions_dir = os.path.join(os.path.dirname(__file__), "4")
|
12 |
+
extensions_builtin_dir = os.path.join(os.path.dirname(__file__), "5")
|
13 |
+
else:
|
14 |
+
from modules.paths import data_path, models_path, script_path
|
extensions/adetailer/sd_webui/processing.py
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from typing import TYPE_CHECKING
|
4 |
+
|
5 |
+
if TYPE_CHECKING:
|
6 |
+
from dataclasses import dataclass, field
|
7 |
+
from typing import Any, Callable
|
8 |
+
|
9 |
+
import numpy as np
|
10 |
+
import torch
|
11 |
+
from PIL import Image
|
12 |
+
|
13 |
+
def _image():
|
14 |
+
return Image.new("L", (512, 512))
|
15 |
+
|
16 |
+
@dataclass
|
17 |
+
class StableDiffusionProcessing:
|
18 |
+
sd_model: torch.nn.Module = field(default_factory=lambda: torch.nn.Linear(1, 1))
|
19 |
+
outpath_samples: str = ""
|
20 |
+
outpath_grids: str = ""
|
21 |
+
prompt: str = ""
|
22 |
+
prompt_for_display: str = ""
|
23 |
+
negative_prompt: str = ""
|
24 |
+
styles: list[str] = field(default_factory=list)
|
25 |
+
seed: int = -1
|
26 |
+
subseed: int = -1
|
27 |
+
subseed_strength: float = 0.0
|
28 |
+
seed_resize_from_h: int = -1
|
29 |
+
seed_resize_from_w: int = -1
|
30 |
+
sampler_name: str | None = None
|
31 |
+
batch_size: int = 1
|
32 |
+
n_iter: int = 1
|
33 |
+
steps: int = 50
|
34 |
+
cfg_scale: float = 7.0
|
35 |
+
width: int = 512
|
36 |
+
height: int = 512
|
37 |
+
restore_faces: bool = False
|
38 |
+
tiling: bool = False
|
39 |
+
do_not_save_samples: bool = False
|
40 |
+
do_not_save_grid: bool = False
|
41 |
+
extra_generation_params: dict[str, Any] = field(default_factory=dict)
|
42 |
+
overlay_images: list[Image.Image] = field(default_factory=list)
|
43 |
+
eta: float = 0.0
|
44 |
+
do_not_reload_embeddings: bool = False
|
45 |
+
paste_to: tuple[int | float, ...] = (0, 0, 0, 0)
|
46 |
+
color_corrections: list[np.ndarray] = field(default_factory=list)
|
47 |
+
denoising_strength: float = 0.0
|
48 |
+
sampler_noise_scheduler_override: Callable | None = None
|
49 |
+
ddim_discretize: str = ""
|
50 |
+
s_min_uncond: float = 0.0
|
51 |
+
s_churn: float = 0.0
|
52 |
+
s_tmin: float = 0.0
|
53 |
+
s_tmax: float = 0.0
|
54 |
+
s_noise: float = 0.0
|
55 |
+
override_settings: dict[str, Any] = field(default_factory=dict)
|
56 |
+
override_settings_restore_afterwards: bool = False
|
57 |
+
is_using_inpainting_conditioning: bool = False
|
58 |
+
disable_extra_networks: bool = False
|
59 |
+
scripts: Any = None
|
60 |
+
script_args: list[Any] = field(default_factory=list)
|
61 |
+
all_prompts: list[str] = field(default_factory=list)
|
62 |
+
all_negative_prompts: list[str] = field(default_factory=list)
|
63 |
+
all_seeds: list[int] = field(default_factory=list)
|
64 |
+
all_subseeds: list[int] = field(default_factory=list)
|
65 |
+
iteration: int = 1
|
66 |
+
is_hr_pass: bool = False
|
67 |
+
|
68 |
+
@dataclass
|
69 |
+
class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
70 |
+
sampler: Callable | None = None
|
71 |
+
enable_hr: bool = False
|
72 |
+
denoising_strength: float = 0.75
|
73 |
+
hr_scale: float = 2.0
|
74 |
+
hr_upscaler: str = ""
|
75 |
+
hr_second_pass_steps: int = 0
|
76 |
+
hr_resize_x: int = 0
|
77 |
+
hr_resize_y: int = 0
|
78 |
+
hr_upscale_to_x: int = 0
|
79 |
+
hr_upscale_to_y: int = 0
|
80 |
+
width: int = 512
|
81 |
+
height: int = 512
|
82 |
+
truncate_x: int = 512
|
83 |
+
truncate_y: int = 512
|
84 |
+
applied_old_hires_behavior_to: tuple[int, int] = (512, 512)
|
85 |
+
|
86 |
+
@dataclass
|
87 |
+
class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
88 |
+
sampler: Callable | None = None
|
89 |
+
init_images: list[Image.Image] = field(default_factory=list)
|
90 |
+
resize_mode: int = 0
|
91 |
+
denoising_strength: float = 0.75
|
92 |
+
image_cfg_scale: float | None = None
|
93 |
+
init_latent: torch.Tensor | None = None
|
94 |
+
image_mask: Image.Image = field(default_factory=_image)
|
95 |
+
latent_mask: Image.Image = field(default_factory=_image)
|
96 |
+
mask_for_overlay: Image.Image = field(default_factory=_image)
|
97 |
+
mask_blur: int = 4
|
98 |
+
inpainting_fill: int = 0
|
99 |
+
inpaint_full_res: bool = True
|
100 |
+
inpaint_full_res_padding: int = 0
|
101 |
+
inpainting_mask_invert: int | bool = 0
|
102 |
+
initial_noise_multiplier: float = 1.0
|
103 |
+
mask: torch.Tensor | None = None
|
104 |
+
nmask: torch.Tensor | None = None
|
105 |
+
image_conditioning: torch.Tensor | None = None
|
106 |
+
|
107 |
+
@dataclass
|
108 |
+
class Processed:
|
109 |
+
images: list[Image.Image] = field(default_factory=list)
|
110 |
+
prompt: list[str] = field(default_factory=list)
|
111 |
+
negative_prompt: list[str] = field(default_factory=list)
|
112 |
+
seed: list[int] = field(default_factory=list)
|
113 |
+
subseed: list[int] = field(default_factory=list)
|
114 |
+
subseed_strength: float = 0.0
|
115 |
+
info: str = ""
|
116 |
+
comments: str = ""
|
117 |
+
width: int = 512
|
118 |
+
height: int = 512
|
119 |
+
sampler_name: str = ""
|
120 |
+
cfg_scale: float = 7.0
|
121 |
+
image_cfg_scale: float | None = None
|
122 |
+
steps: int = 50
|
123 |
+
batch_size: int = 1
|
124 |
+
restore_faces: bool = False
|
125 |
+
face_restoration_model: str | None = None
|
126 |
+
sd_model_hash: str = ""
|
127 |
+
seed_resize_from_w: int = -1
|
128 |
+
seed_resize_from_h: int = -1
|
129 |
+
denoising_strength: float = 0.0
|
130 |
+
extra_generation_params: dict[str, Any] = field(default_factory=dict)
|
131 |
+
index_of_first_image: int = 0
|
132 |
+
styles: list[str] = field(default_factory=list)
|
133 |
+
job_timestamp: str = ""
|
134 |
+
clip_skip: int = 1
|
135 |
+
eta: float = 0.0
|
136 |
+
ddim_discretize: str = ""
|
137 |
+
s_churn: float = 0.0
|
138 |
+
s_tmin: float = 0.0
|
139 |
+
s_tmax: float = 0.0
|
140 |
+
s_noise: float = 0.0
|
141 |
+
sampler_noise_scheduler_override: Callable | None = None
|
142 |
+
is_using_inpainting_conditioning: bool = False
|
143 |
+
all_prompts: list[str] = field(default_factory=list)
|
144 |
+
all_negative_prompts: list[str] = field(default_factory=list)
|
145 |
+
all_seeds: list[int] = field(default_factory=list)
|
146 |
+
all_subseeds: list[int] = field(default_factory=list)
|
147 |
+
infotexts: list[str] = field(default_factory=list)
|
148 |
+
|
149 |
+
def create_infotext(
|
150 |
+
p: StableDiffusionProcessingTxt2Img | StableDiffusionProcessingImg2Img,
|
151 |
+
all_prompts: list[str],
|
152 |
+
all_seeds: list[int],
|
153 |
+
all_subseeds: list[int],
|
154 |
+
comments: Any,
|
155 |
+
iteration: int = 0,
|
156 |
+
position_in_batch: int = 0,
|
157 |
+
) -> str:
|
158 |
+
pass
|
159 |
+
|
160 |
+
def process_images(
|
161 |
+
p: StableDiffusionProcessingTxt2Img | StableDiffusionProcessingImg2Img,
|
162 |
+
) -> Processed:
|
163 |
+
pass
|
164 |
+
|
165 |
+
else:
|
166 |
+
from modules.processing import (
|
167 |
+
StableDiffusionProcessing,
|
168 |
+
StableDiffusionProcessingImg2Img,
|
169 |
+
StableDiffusionProcessingTxt2Img,
|
170 |
+
create_infotext,
|
171 |
+
process_images,
|
172 |
+
)
|
extensions/adetailer/sd_webui/safe.py
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from typing import TYPE_CHECKING
|
4 |
+
|
5 |
+
if TYPE_CHECKING:
|
6 |
+
import torch
|
7 |
+
|
8 |
+
unsafe_torch_load = torch.load
|
9 |
+
else:
|
10 |
+
from modules.safe import unsafe_torch_load
|
extensions/adetailer/sd_webui/script_callbacks.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from typing import TYPE_CHECKING
|
4 |
+
|
5 |
+
if TYPE_CHECKING:
|
6 |
+
from typing import Callable
|
7 |
+
|
8 |
+
def on_ui_settings(callback: Callable):
|
9 |
+
pass
|
10 |
+
|
11 |
+
def on_after_component(callback: Callable):
|
12 |
+
pass
|
13 |
+
|
14 |
+
else:
|
15 |
+
from modules.script_callbacks import on_after_component, on_ui_settings
|
extensions/adetailer/sd_webui/scripts.py
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from typing import TYPE_CHECKING
|
4 |
+
|
5 |
+
if TYPE_CHECKING:
|
6 |
+
from abc import ABC, abstractmethod
|
7 |
+
from dataclasses import dataclass
|
8 |
+
from typing import Any
|
9 |
+
|
10 |
+
import gradio as gr
|
11 |
+
from PIL import Image
|
12 |
+
|
13 |
+
from sd_webui.processing import (
|
14 |
+
Processed,
|
15 |
+
StableDiffusionProcessingImg2Img,
|
16 |
+
StableDiffusionProcessingTxt2Img,
|
17 |
+
)
|
18 |
+
|
19 |
+
SDPType = StableDiffusionProcessingImg2Img | StableDiffusionProcessingTxt2Img
|
20 |
+
AlwaysVisible = object()
|
21 |
+
|
22 |
+
@dataclass
|
23 |
+
class PostprocessImageArgs:
|
24 |
+
image: Image.Image
|
25 |
+
|
26 |
+
class Script(ABC):
|
27 |
+
filename: str
|
28 |
+
args_from: int
|
29 |
+
args_to: int
|
30 |
+
alwayson: bool
|
31 |
+
|
32 |
+
is_txt2img: bool
|
33 |
+
is_img2img: bool
|
34 |
+
|
35 |
+
group: gr.Group
|
36 |
+
infotext_fields: list[tuple[str, str]]
|
37 |
+
paste_field_names: list[str]
|
38 |
+
|
39 |
+
@abstractmethod
|
40 |
+
def title(self):
|
41 |
+
raise NotImplementedError
|
42 |
+
|
43 |
+
def ui(self, is_img2img: bool):
|
44 |
+
pass
|
45 |
+
|
46 |
+
def show(self, is_img2img: bool):
|
47 |
+
return True
|
48 |
+
|
49 |
+
def run(self, p: SDPType, *args):
|
50 |
+
pass
|
51 |
+
|
52 |
+
def process(self, p: SDPType, *args):
|
53 |
+
pass
|
54 |
+
|
55 |
+
def before_process_batch(self, p: SDPType, *args, **kwargs):
|
56 |
+
pass
|
57 |
+
|
58 |
+
def process_batch(self, p: SDPType, *args, **kwargs):
|
59 |
+
pass
|
60 |
+
|
61 |
+
def postprocess_batch(self, p: SDPType, *args, **kwargs):
|
62 |
+
pass
|
63 |
+
|
64 |
+
def postprocess_image(self, p: SDPType, pp: PostprocessImageArgs, *args):
|
65 |
+
pass
|
66 |
+
|
67 |
+
def postprocess(self, p: SDPType, processed: Processed, *args):
|
68 |
+
pass
|
69 |
+
|
70 |
+
def before_component(self, component, **kwargs):
|
71 |
+
pass
|
72 |
+
|
73 |
+
def after_component(self, component, **kwargs):
|
74 |
+
pass
|
75 |
+
|
76 |
+
def describe(self):
|
77 |
+
return ""
|
78 |
+
|
79 |
+
def elem_id(self, item_id: Any) -> str:
|
80 |
+
pass
|
81 |
+
|
82 |
+
else:
|
83 |
+
from modules.scripts import AlwaysVisible, PostprocessImageArgs, Script
|
extensions/adetailer/sd_webui/shared.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from typing import TYPE_CHECKING
|
4 |
+
|
5 |
+
if TYPE_CHECKING:
|
6 |
+
import argparse
|
7 |
+
from dataclasses import dataclass
|
8 |
+
from typing import Any, Callable
|
9 |
+
|
10 |
+
import torch
|
11 |
+
from PIL import Image
|
12 |
+
|
13 |
+
@dataclass
|
14 |
+
class State:
|
15 |
+
skipped: bool = False
|
16 |
+
interrupted: bool = False
|
17 |
+
job: str = ""
|
18 |
+
job_no: int = 0
|
19 |
+
job_count: int = 0
|
20 |
+
processing_has_refined_job_count: bool = False
|
21 |
+
job_timestamp: str = "0"
|
22 |
+
sampling_step: int = 0
|
23 |
+
sampling_steps: int = 0
|
24 |
+
current_latent: torch.Tensor | None = None
|
25 |
+
current_image: Image.Image | None = None
|
26 |
+
current_image_sampling_step: int = 0
|
27 |
+
id_live_preview: int = 0
|
28 |
+
textinfo: str | None = None
|
29 |
+
time_start: float | None = None
|
30 |
+
need_restart: bool = False
|
31 |
+
server_start: float | None = None
|
32 |
+
|
33 |
+
@dataclass
|
34 |
+
class OptionInfo:
|
35 |
+
default: Any = None
|
36 |
+
label: str = ""
|
37 |
+
component: Any = None
|
38 |
+
component_args: Callable[[], dict] | dict[str, Any] | None = None
|
39 |
+
onchange: Callable[[], None] | None = None
|
40 |
+
section: tuple[str, str] | None = None
|
41 |
+
refresh: Callable[[], None] | None = None
|
42 |
+
|
43 |
+
class Option:
|
44 |
+
data_labels: dict[str, OptionInfo]
|
45 |
+
|
46 |
+
def __init__(self):
|
47 |
+
self.data: dict[str, Any] = {}
|
48 |
+
|
49 |
+
def add_option(self, key: str, info: OptionInfo):
|
50 |
+
pass
|
51 |
+
|
52 |
+
def __getattr__(self, item: str):
|
53 |
+
if self.data is not None and item in self.data:
|
54 |
+
return self.data[item]
|
55 |
+
|
56 |
+
if item in self.data_labels:
|
57 |
+
return self.data_labels[item].default
|
58 |
+
|
59 |
+
return super().__getattribute__(item)
|
60 |
+
|
61 |
+
opts = Option()
|
62 |
+
cmd_opts = argparse.Namespace()
|
63 |
+
state = State()
|
64 |
+
|
65 |
+
else:
|
66 |
+
from modules.shared import OptionInfo, cmd_opts, opts, state
|
extensions/microsoftexcel-controlnet/.github/ISSUE_TEMPLATE/bug_report.yml
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Bug Report
|
2 |
+
description: Create a report
|
3 |
+
title: "[Bug]: "
|
4 |
+
labels: ["bug-report"]
|
5 |
+
|
6 |
+
body:
|
7 |
+
- type: checkboxes
|
8 |
+
attributes:
|
9 |
+
label: Is there an existing issue for this?
|
10 |
+
description: Please search to see if an issue already exists for the bug you encountered, and that it hasn't been fixed in a recent build/commit.
|
11 |
+
options:
|
12 |
+
- label: I have searched the existing issues and checked the recent builds/commits of both this extension and the webui
|
13 |
+
required: true
|
14 |
+
- type: markdown
|
15 |
+
attributes:
|
16 |
+
value: |
|
17 |
+
*Please fill this form with as much information as possible, don't forget to fill "What OS..." and "What browsers" and *provide screenshots if possible**
|
18 |
+
- type: textarea
|
19 |
+
id: what-did
|
20 |
+
attributes:
|
21 |
+
label: What happened?
|
22 |
+
description: Tell us what happened in a very clear and simple way
|
23 |
+
validations:
|
24 |
+
required: true
|
25 |
+
- type: textarea
|
26 |
+
id: steps
|
27 |
+
attributes:
|
28 |
+
label: Steps to reproduce the problem
|
29 |
+
description: Please provide us with precise step by step information on how to reproduce the bug
|
30 |
+
value: |
|
31 |
+
1. Go to ....
|
32 |
+
2. Press ....
|
33 |
+
3. ...
|
34 |
+
validations:
|
35 |
+
required: true
|
36 |
+
- type: textarea
|
37 |
+
id: what-should
|
38 |
+
attributes:
|
39 |
+
label: What should have happened?
|
40 |
+
description: Tell what you think the normal behavior should be
|
41 |
+
validations:
|
42 |
+
required: true
|
43 |
+
- type: textarea
|
44 |
+
id: commits
|
45 |
+
attributes:
|
46 |
+
label: Commit where the problem happens
|
47 |
+
description: Which commit of the extension are you running on? Please include the commit of both the extension and the webui (Do not write *Latest version/repo/commit*, as this means nothing and will have changed by the time we read your issue. Rather, copy the **Commit** link at the bottom of the UI, or from the cmd/terminal if you can't launch it.)
|
48 |
+
value: |
|
49 |
+
webui:
|
50 |
+
controlnet:
|
51 |
+
validations:
|
52 |
+
required: true
|
53 |
+
- type: dropdown
|
54 |
+
id: browsers
|
55 |
+
attributes:
|
56 |
+
label: What browsers do you use to access the UI ?
|
57 |
+
multiple: true
|
58 |
+
options:
|
59 |
+
- Mozilla Firefox
|
60 |
+
- Google Chrome
|
61 |
+
- Brave
|
62 |
+
- Apple Safari
|
63 |
+
- Microsoft Edge
|
64 |
+
- type: textarea
|
65 |
+
id: cmdargs
|
66 |
+
attributes:
|
67 |
+
label: Command Line Arguments
|
68 |
+
description: Are you using any launching parameters/command line arguments (modified webui-user .bat/.sh) ? If yes, please write them below. Write "No" otherwise.
|
69 |
+
render: Shell
|
70 |
+
validations:
|
71 |
+
required: true
|
72 |
+
- type: textarea
|
73 |
+
id: extensions
|
74 |
+
attributes:
|
75 |
+
label: List of enabled extensions
|
76 |
+
description: Please provide a full list of enabled extensions or screenshots of your "Extensions" tab.
|
77 |
+
validations:
|
78 |
+
required: true
|
79 |
+
- type: textarea
|
80 |
+
id: logs
|
81 |
+
attributes:
|
82 |
+
label: Console logs
|
83 |
+
description: Please provide full cmd/terminal logs from the moment you started UI to the end of it, after your bug happened. If it's very long, provide a link to pastebin or similar service.
|
84 |
+
render: Shell
|
85 |
+
validations:
|
86 |
+
required: true
|
87 |
+
- type: textarea
|
88 |
+
id: misc
|
89 |
+
attributes:
|
90 |
+
label: Additional information
|
91 |
+
description: Please provide us with any relevant additional info or context.
|
extensions/microsoftexcel-controlnet/.github/ISSUE_TEMPLATE/config.yml
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
blank_issues_enabled: true
|
extensions/microsoftexcel-controlnet/.github/workflows/tests.yml
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Run basic features tests on CPU
|
2 |
+
|
3 |
+
on:
|
4 |
+
- push
|
5 |
+
- pull_request
|
6 |
+
|
7 |
+
jobs:
|
8 |
+
build:
|
9 |
+
runs-on: ubuntu-latest
|
10 |
+
steps:
|
11 |
+
- name: Checkout Code
|
12 |
+
uses: actions/checkout@v3
|
13 |
+
with:
|
14 |
+
repository: 'AUTOMATIC1111/stable-diffusion-webui'
|
15 |
+
path: 'stable-diffusion-webui'
|
16 |
+
ref: '5ab7f213bec2f816f9c5644becb32eb72c8ffb89'
|
17 |
+
|
18 |
+
- name: Checkout Code
|
19 |
+
uses: actions/checkout@v3
|
20 |
+
with:
|
21 |
+
repository: 'Mikubill/sd-webui-controlnet'
|
22 |
+
path: 'stable-diffusion-webui/extensions/sd-webui-controlnet'
|
23 |
+
|
24 |
+
- name: Set up Python 3.10
|
25 |
+
uses: actions/setup-python@v4
|
26 |
+
with:
|
27 |
+
python-version: 3.10.6
|
28 |
+
cache: pip
|
29 |
+
cache-dependency-path: |
|
30 |
+
**/requirements*txt
|
31 |
+
stable-diffusion-webui/requirements*txt
|
32 |
+
|
33 |
+
- run: |
|
34 |
+
pip install torch torchvision
|
35 |
+
curl -Lo stable-diffusion-webui/extensions/sd-webui-controlnet/models/control_canny-fp16.safetensors https://huggingface.co/webui/ControlNet-modules-safetensors/resolve/main/control_canny-fp16.safetensors
|
36 |
+
cd stable-diffusion-webui && python launch.py --no-half --disable-opt-split-attention --use-cpu all --skip-torch-cuda-test --api --tests ./extensions/sd-webui-controlnet/tests
|
37 |
+
rm -fr stable-diffusion-webui/extensions/sd-webui-controlnet/models/control_canny-fp16.safetensors
|
extensions/microsoftexcel-controlnet/.gitignore
ADDED
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Byte-compiled / optimized / DLL files
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
|
6 |
+
# C extensions
|
7 |
+
*.so
|
8 |
+
|
9 |
+
# Distribution / packaging
|
10 |
+
.Python
|
11 |
+
build/
|
12 |
+
develop-eggs/
|
13 |
+
dist/
|
14 |
+
downloads/
|
15 |
+
eggs/
|
16 |
+
.eggs/
|
17 |
+
lib/
|
18 |
+
lib64/
|
19 |
+
parts/
|
20 |
+
sdist/
|
21 |
+
var/
|
22 |
+
wheels/
|
23 |
+
share/python-wheels/
|
24 |
+
*.egg-info/
|
25 |
+
.installed.cfg
|
26 |
+
*.egg
|
27 |
+
MANIFEST
|
28 |
+
|
29 |
+
# PyInstaller
|
30 |
+
# Usually these files are written by a python script from a template
|
31 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
32 |
+
*.manifest
|
33 |
+
*.spec
|
34 |
+
|
35 |
+
# Installer logs
|
36 |
+
pip-log.txt
|
37 |
+
pip-delete-this-directory.txt
|
38 |
+
|
39 |
+
# Unit test / coverage reports
|
40 |
+
htmlcov/
|
41 |
+
.tox/
|
42 |
+
.nox/
|
43 |
+
.coverage
|
44 |
+
.coverage.*
|
45 |
+
.cache
|
46 |
+
nosetests.xml
|
47 |
+
coverage.xml
|
48 |
+
*.cover
|
49 |
+
*.py,cover
|
50 |
+
.hypothesis/
|
51 |
+
.pytest_cache/
|
52 |
+
cover/
|
53 |
+
|
54 |
+
# Translations
|
55 |
+
*.mo
|
56 |
+
*.pot
|
57 |
+
|
58 |
+
# Django stuff:
|
59 |
+
*.log
|
60 |
+
local_settings.py
|
61 |
+
db.sqlite3
|
62 |
+
db.sqlite3-journal
|
63 |
+
|
64 |
+
# Flask stuff:
|
65 |
+
instance/
|
66 |
+
.webassets-cache
|
67 |
+
|
68 |
+
# Scrapy stuff:
|
69 |
+
.scrapy
|
70 |
+
|
71 |
+
# Sphinx documentation
|
72 |
+
docs/_build/
|
73 |
+
|
74 |
+
# PyBuilder
|
75 |
+
.pybuilder/
|
76 |
+
target/
|
77 |
+
|
78 |
+
# Jupyter Notebook
|
79 |
+
.ipynb_checkpoints
|
80 |
+
|
81 |
+
# IPython
|
82 |
+
profile_default/
|
83 |
+
ipython_config.py
|
84 |
+
|
85 |
+
# pyenv
|
86 |
+
# For a library or package, you might want to ignore these files since the code is
|
87 |
+
# intended to run in multiple environments; otherwise, check them in:
|
88 |
+
# .python-version
|
89 |
+
|
90 |
+
# pipenv
|
91 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
92 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
93 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
94 |
+
# install all needed dependencies.
|
95 |
+
#Pipfile.lock
|
96 |
+
|
97 |
+
# poetry
|
98 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
99 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
100 |
+
# commonly ignored for libraries.
|
101 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
102 |
+
#poetry.lock
|
103 |
+
|
104 |
+
# pdm
|
105 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
106 |
+
#pdm.lock
|
107 |
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
108 |
+
# in version control.
|
109 |
+
# https://pdm.fming.dev/#use-with-ide
|
110 |
+
.pdm.toml
|
111 |
+
|
112 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
113 |
+
__pypackages__/
|
114 |
+
|
115 |
+
# Celery stuff
|
116 |
+
celerybeat-schedule
|
117 |
+
celerybeat.pid
|
118 |
+
|
119 |
+
# SageMath parsed files
|
120 |
+
*.sage.py
|
121 |
+
|
122 |
+
# Environments
|
123 |
+
.env
|
124 |
+
.venv
|
125 |
+
env/
|
126 |
+
venv/
|
127 |
+
ENV/
|
128 |
+
env.bak/
|
129 |
+
venv.bak/
|
130 |
+
|
131 |
+
# Spyder project settings
|
132 |
+
.spyderproject
|
133 |
+
.spyproject
|
134 |
+
|
135 |
+
# Rope project settings
|
136 |
+
.ropeproject
|
137 |
+
|
138 |
+
# mkdocs documentation
|
139 |
+
/site
|
140 |
+
|
141 |
+
# mypy
|
142 |
+
.mypy_cache/
|
143 |
+
.dmypy.json
|
144 |
+
dmypy.json
|
145 |
+
|
146 |
+
# Pyre type checker
|
147 |
+
.pyre/
|
148 |
+
|
149 |
+
# pytype static type analyzer
|
150 |
+
.pytype/
|
151 |
+
|
152 |
+
# Cython debug symbols
|
153 |
+
cython_debug/
|
154 |
+
|
155 |
+
# PyCharm
|
156 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
157 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
158 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
159 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
160 |
+
#.idea
|
161 |
+
*.pt
|
162 |
+
*.pth
|
163 |
+
*.ckpt
|
164 |
+
*.bin
|
165 |
+
*.safetensors
|
166 |
+
|
167 |
+
# Editor setting metadata
|
168 |
+
.idea/
|
169 |
+
.vscode/
|
170 |
+
detected_maps/
|
171 |
+
annotator/downloads/
|
extensions/microsoftexcel-controlnet/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2023 Kakigōri Maker
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
extensions/microsoftexcel-controlnet/README.md
ADDED
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# ControlNet for Stable Diffusion WebUI
|
2 |
+
|
3 |
+
The WebUI extension for ControlNet and other injection-based SD controls.
|
4 |
+
|
5 |
+
![image](https://user-images.githubusercontent.com/19834515/235606305-229b3d1e-5bfc-467f-9d55-0976eab71652.png)
|
6 |
+
|
7 |
+
This extension is for AUTOMATIC1111's [Stable Diffusion web UI](https://github.com/AUTOMATIC1111/stable-diffusion-webui), allows the Web UI to add [ControlNet](https://github.com/lllyasviel/ControlNet) to the original Stable Diffusion model to generate images. The addition is on-the-fly, the merging is not required.
|
8 |
+
|
9 |
+
# Installation
|
10 |
+
|
11 |
+
1. Open "Extensions" tab.
|
12 |
+
2. Open "Install from URL" tab in the tab.
|
13 |
+
3. Enter `https://github.com/Mikubill/sd-webui-controlnet.git` to "URL for extension's git repository".
|
14 |
+
4. Press "Install" button.
|
15 |
+
5. Wait for 5 seconds, and you will see the message "Installed into stable-diffusion-webui\extensions\sd-webui-controlnet. Use Installed tab to restart".
|
16 |
+
6. Go to "Installed" tab, click "Check for updates", and then click "Apply and restart UI". (The next time you can also use these buttons to update ControlNet.)
|
17 |
+
7. Completely restart A1111 webui including your terminal. (If you do not know what is a "terminal", you can reboot your computer to achieve the same effect.)
|
18 |
+
8. Download models (see below).
|
19 |
+
9. After you put models in the correct folder, you may need to refresh to see the models. The refresh button is right to your "Model" dropdown.
|
20 |
+
|
21 |
+
|
22 |
+
**Update from ControlNet 1.0 to 1.1:**
|
23 |
+
|
24 |
+
* If you are not sure, you can back up and remove the folder "stable-diffusion-webui\extensions\sd-webui-controlnet", and then start from the step 1 in the above Installation section.
|
25 |
+
|
26 |
+
* Or you can start from the step 6 in the above Install section.
|
27 |
+
|
28 |
+
# Download Models
|
29 |
+
|
30 |
+
Right now all the 14 models of ControlNet 1.1 are in the beta test.
|
31 |
+
|
32 |
+
Download the models from ControlNet 1.1: https://huggingface.co/lllyasviel/ControlNet-v1-1/tree/main
|
33 |
+
|
34 |
+
You need to download model files ending with ".pth" .
|
35 |
+
|
36 |
+
Put models in your "stable-diffusion-webui\extensions\sd-webui-controlnet\models". Now we have already included all "yaml" files. You only need to download "pth" files.
|
37 |
+
|
38 |
+
Do not right-click the filenames in HuggingFace website to download. Some users right-clicked those HuggingFace HTML websites and saved those HTML pages as PTH/YAML files. They are not downloading correct files. Instead, please click the small download arrow “↓” icon in HuggingFace to download.
|
39 |
+
|
40 |
+
Note: If you download models elsewhere, please make sure that yaml file names and model files names are same. Please manually rename all yaml files if you download from other sources. (Some models like "shuffle" needs the yaml file so that we know the outputs of ControlNet should pass a global average pooling before injecting to SD U-Nets.)
|
41 |
+
|
42 |
+
# New Features in ControlNet 1.1
|
43 |
+
|
44 |
+
### Perfect Support for All ControlNet 1.0/1.1 and T2I Adapter Models.
|
45 |
+
|
46 |
+
Now we have perfect support all available models and preprocessors, including perfect support for T2I style adapter and ControlNet 1.1 Shuffle. (Make sure that your YAML file names and model file names are same, see also YAML files in "stable-diffusion-webui\extensions\sd-webui-controlnet\models".)
|
47 |
+
|
48 |
+
### Perfect Support for A1111 High-Res. Fix
|
49 |
+
|
50 |
+
Now if you turn on High-Res Fix in A1111, each controlnet will output two different control images: a small one and a large one. The small one is for your basic generating, and the big one is for your High-Res Fix generating. The two control images are computed by a smart algorithm called "super high-quality control image resampling". This is turned on by default, and you do not need to change any setting.
|
51 |
+
|
52 |
+
### Perfect Support for All A1111 Img2Img or Inpaint Settings and All Mask Types
|
53 |
+
|
54 |
+
Now ControlNet is extensively tested with A1111's different types of masks, including "Inpaint masked"/"Inpaint not masked", and "Whole picture"/"Only masked", and "Only masked padding"&"Mask blur". The resizing perfectly matches A1111's "Just resize"/"Crop and resize"/"Resize and fill". This means you can use ControlNet in nearly everywhere in your A1111 UI without difficulty!
|
55 |
+
|
56 |
+
### The New "Pixel-Perfect" Mode
|
57 |
+
|
58 |
+
Now if you turn on pixel-perfect mode, you do not need to set preprocessor (annotator) resolutions manually. The ControlNet will automatically compute the best annotator resolution for you so that each pixel perfectly matches Stable Diffusion.
|
59 |
+
|
60 |
+
### User-Friendly GUI and Preprocessor Preview
|
61 |
+
|
62 |
+
We reorganized some previously confusing UI like "canvas width/height for new canvas" and it is in the 📝 button now. Now the preview GUI is controlled by the "allow preview" option and the trigger button 💥. The preview image size is better than before, and you do not need to scroll up and down - your a1111 GUI will not be messed up anymore!
|
63 |
+
|
64 |
+
### Support for Almost All Upscaling Scripts
|
65 |
+
|
66 |
+
Now ControlNet 1.1 can support almost all Upscaling/Tile methods. ControlNet 1.1 support the script "Ultimate SD upscale" and almost all other tile-based extensions. Please do not confuse ["Ultimate SD upscale"](https://github.com/Coyote-A/ultimate-upscale-for-automatic1111) with "SD upscale" - they are different scripts. Note that the most recommended upscaling method is ["Tiled VAE/Diffusion"](https://github.com/pkuliyi2015/multidiffusion-upscaler-for-automatic1111) but we test as many methods/extensions as possible. Note that "SD upscale" is supported since 1.1.117, and if you use it, you need to leave all ControlNet images as blank (We do not recommend "SD upscale" since it is somewhat buggy and cannot be maintained - use the "Ultimate SD upscale" instead).
|
67 |
+
|
68 |
+
### More Control Modes (previously called Guess Mode)
|
69 |
+
|
70 |
+
We have fixed many bugs in previous 1.0’s Guess Mode and now it is called Control Mode
|
71 |
+
|
72 |
+
![image](https://user-images.githubusercontent.com/19834515/236641759-6c44ddf6-c7ad-4bda-92be-e90a52911d75.png)
|
73 |
+
|
74 |
+
Now you can control which aspect is more important (your prompt or your ControlNet):
|
75 |
+
|
76 |
+
* "Balanced": ControlNet on both sides of CFG scale, same as turning off "Guess Mode" in ControlNet 1.0
|
77 |
+
|
78 |
+
* "My prompt is more important": ControlNet on both sides of CFG scale, with progressively reduced SD U-Net injections (layer_weight*=0.825**I, where 0<=I <13, and the 13 means ControlNet injected SD 13 times). In this way, you can make sure that your prompts are perfectly displayed in your generated images.
|
79 |
+
|
80 |
+
* "ControlNet is more important": ControlNet only on the Conditional Side of CFG scale (the cond in A1111's batch-cond-uncond). This means the ControlNet will be X times stronger if your cfg-scale is X. For example, if your cfg-scale is 7, then ControlNet is 7 times stronger. Note that here the X times stronger is different from "Control Weights" since your weights are not modified. This "stronger" effect usually has less artifact and give ControlNet more room to guess what is missing from your prompts (and in the previous 1.0, it is called "Guess Mode").
|
81 |
+
|
82 |
+
<table width="100%">
|
83 |
+
<tr>
|
84 |
+
<td width="25%" style="text-align: center">Input (depth+canny+hed)</td>
|
85 |
+
<td width="25%" style="text-align: center">"Balanced"</td>
|
86 |
+
<td width="25%" style="text-align: center">"My prompt is more important"</td>
|
87 |
+
<td width="25%" style="text-align: center">"ControlNet is more important"</td>
|
88 |
+
</tr>
|
89 |
+
<tr>
|
90 |
+
<td width="25%" style="text-align: center"><img src="samples/cm1.png"></td>
|
91 |
+
<td width="25%" style="text-align: center"><img src="samples/cm2.png"></td>
|
92 |
+
<td width="25%" style="text-align: center"><img src="samples/cm3.png"></td>
|
93 |
+
<td width="25%" style="text-align: center"><img src="samples/cm4.png"></td>
|
94 |
+
</tr>
|
95 |
+
</table>
|
96 |
+
|
97 |
+
### Reference-Only Control
|
98 |
+
|
99 |
+
Now we have a `reference-only` preprocessor that does not require any control models. It can guide the diffusion directly using images as references.
|
100 |
+
|
101 |
+
(Prompt "a dog running on grassland, best quality, ...")
|
102 |
+
|
103 |
+
![image](samples/ref.png)
|
104 |
+
|
105 |
+
This method is similar to inpaint-based reference but it does not make your image disordered.
|
106 |
+
|
107 |
+
Many professional A1111 users know a trick to diffuse image with references by inpaint. For example, if you have a 512x512 image of a dog, and want to generate another 512x512 image with the same dog, some users will connect the 512x512 dog image and a 512x512 blank image into a 1024x512 image, send to inpaint, and mask out the blank 512x512 part to diffuse a dog with similar appearance. However, that method is usually not very satisfying since images are connected and many distortions will appear.
|
108 |
+
|
109 |
+
This `reference-only` ControlNet can directly link the attention layers of your SD to any independent images, so that your SD will read arbitary images for reference. You need at least ControlNet 1.1.153 to use it.
|
110 |
+
|
111 |
+
To use, just select `reference-only` as preprocessor and put an image. Your SD will just use the image as reference.
|
112 |
+
|
113 |
+
*Note that this method is as "non-opinioned" as possible. It only contains very basic connection codes, without any personal preferences, to connect the attention layers with your reference images. However, even if we tried best to not include any opinioned codes, we still need to write some subjective implementations to deal with weighting, cfg-scale, etc - tech report is on the way.*
|
114 |
+
|
115 |
+
More examples [here](https://github.com/Mikubill/sd-webui-controlnet/discussions/1236).
|
116 |
+
|
117 |
+
# Technical Documents
|
118 |
+
|
119 |
+
See also the documents of ControlNet 1.1:
|
120 |
+
|
121 |
+
https://github.com/lllyasviel/ControlNet-v1-1-nightly#model-specification
|
122 |
+
|
123 |
+
# Default Setting
|
124 |
+
|
125 |
+
This is my setting. If you run into any problem, you can use this setting as a sanity check
|
126 |
+
|
127 |
+
![image](https://user-images.githubusercontent.com/19834515/235620638-17937171-8ac1-45bc-a3cb-3aebf605b4ef.png)
|
128 |
+
|
129 |
+
# Use Previous Models
|
130 |
+
|
131 |
+
### Use ControlNet 1.0 Models
|
132 |
+
|
133 |
+
https://huggingface.co/lllyasviel/ControlNet/tree/main/models
|
134 |
+
|
135 |
+
You can still use all previous models in the previous ControlNet 1.0. Now, the previous "depth" is now called "depth_midas", the previous "normal" is called "normal_midas", the previous "hed" is called "softedge_hed". And starting from 1.1, all line maps, edge maps, lineart maps, boundary maps will have black background and white lines.
|
136 |
+
|
137 |
+
### Use T2I-Adapter Models
|
138 |
+
|
139 |
+
(From TencentARC/T2I-Adapter)
|
140 |
+
|
141 |
+
To use T2I-Adapter models:
|
142 |
+
|
143 |
+
1. Download files from https://huggingface.co/TencentARC/T2I-Adapter/tree/main/models
|
144 |
+
2. Put them in "stable-diffusion-webui\extensions\sd-webui-controlnet\models".
|
145 |
+
3. Make sure that the file names of pth files and yaml files are consistent.
|
146 |
+
|
147 |
+
*Note that "CoAdapter" is not implemented yet.*
|
148 |
+
|
149 |
+
# Gallery
|
150 |
+
|
151 |
+
The below results are from ControlNet 1.0.
|
152 |
+
|
153 |
+
| Source | Input | Output |
|
154 |
+
|:-------------------------:|:-------------------------:|:-------------------------:|
|
155 |
+
| (no preprocessor) | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/bal-source.png?raw=true"> | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/bal-gen.png?raw=true"> |
|
156 |
+
| (no preprocessor) | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/dog_rel.jpg?raw=true"> | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/dog_rel.png?raw=true"> |
|
157 |
+
|<img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/mahiro_input.png?raw=true"> | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/mahiro_canny.png?raw=true"> | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/mahiro-out.png?raw=true"> |
|
158 |
+
|<img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/evt_source.jpg?raw=true"> | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/evt_hed.png?raw=true"> | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/evt_gen.png?raw=true"> |
|
159 |
+
|<img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/an-source.jpg?raw=true"> | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/an-pose.png?raw=true"> | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/an-gen.png?raw=true"> |
|
160 |
+
|<img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/sk-b-src.png?raw=true"> | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/sk-b-dep.png?raw=true"> | <img width="256" alt="" src="https://github.com/Mikubill/sd-webui-controlnet/blob/main/samples/sk-b-out.png?raw=true"> |
|
161 |
+
|
162 |
+
The below examples are from T2I-Adapter.
|
163 |
+
|
164 |
+
From `t2iadapter_color_sd14v1.pth` :
|
165 |
+
|
166 |
+
| Source | Input | Output |
|
167 |
+
|:-------------------------:|:-------------------------:|:-------------------------:|
|
168 |
+
| <img width="256" alt="" src="https://user-images.githubusercontent.com/31246794/222947416-ec9e52a4-a1d0-48d8-bb81-736bf636145e.jpeg"> | <img width="256" alt="" src="https://user-images.githubusercontent.com/31246794/222947435-1164e7d8-d857-42f9-ab10-2d4a4b25f33a.png"> | <img width="256" alt="" src="https://user-images.githubusercontent.com/31246794/222947557-5520d5f8-88b4-474d-a576-5c9cd3acac3a.png"> |
|
169 |
+
|
170 |
+
From `t2iadapter_style_sd14v1.pth` :
|
171 |
+
|
172 |
+
| Source | Input | Output |
|
173 |
+
|:-------------------------:|:-------------------------:|:-------------------------:|
|
174 |
+
| <img width="256" alt="" src="https://user-images.githubusercontent.com/31246794/222947416-ec9e52a4-a1d0-48d8-bb81-736bf636145e.jpeg"> | (clip, non-image) | <img width="256" alt="" src="https://user-images.githubusercontent.com/31246794/222965711-7b884c9e-7095-45cb-a91c-e50d296ba3a2.png"> |
|
175 |
+
|
176 |
+
# Minimum Requirements
|
177 |
+
|
178 |
+
* (Windows) (NVIDIA: Ampere) 4gb - with `--xformers` enabled, and `Low VRAM` mode ticked in the UI, goes up to 768x832
|
179 |
+
|
180 |
+
# Multi-ControlNet
|
181 |
+
|
182 |
+
This option allows multiple ControlNet inputs for a single generation. To enable this option, change `Multi ControlNet: Max models amount (requires restart)` in the settings. Note that you will need to restart the WebUI for changes to take effect.
|
183 |
+
|
184 |
+
<table width="100%">
|
185 |
+
<tr>
|
186 |
+
<td width="25%" style="text-align: center">Source A</td>
|
187 |
+
<td width="25%" style="text-align: center">Source B</td>
|
188 |
+
<td width="25%" style="text-align: center">Output</td>
|
189 |
+
</tr>
|
190 |
+
<tr>
|
191 |
+
<td width="25%" style="text-align: center"><img src="https://user-images.githubusercontent.com/31246794/220448620-cd3ede92-8d3f-43d5-b771-32dd8417618f.png"></td>
|
192 |
+
<td width="25%" style="text-align: center"><img src="https://user-images.githubusercontent.com/31246794/220448619-beed9bdb-f6bb-41c2-a7df-aa3ef1f653c5.png"></td>
|
193 |
+
<td width="25%" style="text-align: center"><img src="https://user-images.githubusercontent.com/31246794/220448613-c99a9e04-0450-40fd-bc73-a9122cefaa2c.png"></td>
|
194 |
+
</tr>
|
195 |
+
</table>
|
196 |
+
|
197 |
+
# Control Weight/Start/End
|
198 |
+
|
199 |
+
Weight is the weight of the controlnet "influence". It's analogous to prompt attention/emphasis. E.g. (myprompt: 1.2). Technically, it's the factor by which to multiply the ControlNet outputs before merging them with original SD Unet.
|
200 |
+
|
201 |
+
Guidance Start/End is the percentage of total steps the controlnet applies (guidance strength = guidance end). It's analogous to prompt editing/shifting. E.g. \[myprompt::0.8\] (It applies from the beginning until 80% of total steps)
|
202 |
+
|
203 |
+
# Batch Mode
|
204 |
+
|
205 |
+
Put any unit into batch mode to activate batch mode for all units. Specify a batch directory for each unit, or use the new textbox in the img2img batch tab as a fallback. Although the textbox is located in the img2img batch tab, you can use it to generate images in the txt2img tab as well.
|
206 |
+
|
207 |
+
Note that this feature is only available in the gradio user interface. Call the APIs as many times as you want for custom batch scheduling.
|
208 |
+
|
209 |
+
# API and Script Access
|
210 |
+
|
211 |
+
This extension can accept txt2img or img2img tasks via API or external extension call. Note that you may need to enable `Allow other scripts to control this extension` in settings for external calls.
|
212 |
+
|
213 |
+
To use the API: start WebUI with argument `--api` and go to `http://webui-address/docs` for documents or checkout [examples](https://github.com/Mikubill/sd-webui-controlnet/blob/main/example/api_txt2img.ipynb).
|
214 |
+
|
215 |
+
To use external call: Checkout [Wiki](https://github.com/Mikubill/sd-webui-controlnet/wiki/API)
|
216 |
+
|
217 |
+
# Command Line Arguments
|
218 |
+
|
219 |
+
This extension adds these command line arguments to the webui:
|
220 |
+
|
221 |
+
```
|
222 |
+
--controlnet-dir <path to directory with controlnet models> ADD a controlnet models directory
|
223 |
+
--controlnet-annotator-models-path <path to directory with annotator model directories> SET the directory for annotator models
|
224 |
+
--no-half-controlnet load controlnet models in full precision
|
225 |
+
--controlnet-preprocessor-cache-size Cache size for controlnet preprocessor results
|
226 |
+
```
|
227 |
+
|
228 |
+
# MacOS Support
|
229 |
+
|
230 |
+
Tested with pytorch nightly: https://github.com/Mikubill/sd-webui-controlnet/pull/143#issuecomment-1435058285
|
231 |
+
|
232 |
+
To use this extension with mps and normal pytorch, currently you may need to start WebUI with `--no-half`.
|
233 |
+
|
234 |
+
# Archive of Deprecated Versions
|
235 |
+
|
236 |
+
The previous version (sd-webui-controlnet 1.0) is archived in
|
237 |
+
|
238 |
+
https://github.com/lllyasviel/webui-controlnet-v1-archived
|
239 |
+
|
240 |
+
Using this version is not a temporary stop of updates. You will stop all updates forever.
|
241 |
+
|
242 |
+
Please consider this version if you work with professional studios that requires 100% reproducing of all previous results pixel by pixel.
|
243 |
+
|
244 |
+
# Thanks
|
245 |
+
|
246 |
+
This implementation is inspired by kohya-ss/sd-webui-additional-networks
|
extensions/microsoftexcel-controlnet/__pycache__/preload.cpython-310.pyc
ADDED
Binary file (777 Bytes). View file
|
|
extensions/microsoftexcel-controlnet/annotator/__pycache__/annotator_path.cpython-310.pyc
ADDED
Binary file (706 Bytes). View file
|
|
extensions/microsoftexcel-controlnet/annotator/__pycache__/util.cpython-310.pyc
ADDED
Binary file (2.59 kB). View file
|
|
extensions/microsoftexcel-controlnet/annotator/annotator_path.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from modules import shared
|
3 |
+
|
4 |
+
models_path = shared.opts.data.get('control_net_modules_path', None)
|
5 |
+
if not models_path:
|
6 |
+
models_path = getattr(shared.cmd_opts, 'controlnet_annotator_models_path', None)
|
7 |
+
if not models_path:
|
8 |
+
models_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'downloads')
|
9 |
+
|
10 |
+
if not os.path.isabs(models_path):
|
11 |
+
models_path = os.path.join(shared.data_path, models_path)
|
12 |
+
|
13 |
+
clip_vision_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'clip_vision')
|
14 |
+
# clip vision is always inside controlnet "extensions\sd-webui-controlnet"
|
15 |
+
# and any problem can be solved by removing controlnet and reinstall
|
16 |
+
|
17 |
+
models_path = os.path.realpath(models_path)
|
18 |
+
os.makedirs(models_path, exist_ok=True)
|
19 |
+
print(f'ControlNet preprocessor location: {models_path}')
|
20 |
+
# Make sure that the default location is inside controlnet "extensions\sd-webui-controlnet"
|
21 |
+
# so that any problem can be solved by removing controlnet and reinstall
|
22 |
+
# if users do not change configs on their own (otherwise users will know what is wrong)
|
extensions/microsoftexcel-controlnet/annotator/binary/__init__.py
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
|
3 |
+
|
4 |
+
def apply_binary(img, bin_threshold):
|
5 |
+
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
|
6 |
+
|
7 |
+
if bin_threshold == 0 or bin_threshold == 255:
|
8 |
+
# Otsu's threshold
|
9 |
+
otsu_threshold, img_bin = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
|
10 |
+
print("Otsu threshold:", otsu_threshold)
|
11 |
+
else:
|
12 |
+
_, img_bin = cv2.threshold(img_gray, bin_threshold, 255, cv2.THRESH_BINARY_INV)
|
13 |
+
|
14 |
+
return cv2.cvtColor(img_bin, cv2.COLOR_GRAY2RGB)
|
extensions/microsoftexcel-controlnet/annotator/canny/__init__.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
|
3 |
+
|
4 |
+
def apply_canny(img, low_threshold, high_threshold):
|
5 |
+
return cv2.Canny(img, low_threshold, high_threshold)
|
extensions/microsoftexcel-controlnet/annotator/clip/__init__.py
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from transformers import CLIPProcessor, CLIPVisionModel
|
3 |
+
from modules import devices
|
4 |
+
import os
|
5 |
+
from annotator.annotator_path import clip_vision_path
|
6 |
+
|
7 |
+
|
8 |
+
remote_model_path = "https://huggingface.co/openai/clip-vit-large-patch14/resolve/main/pytorch_model.bin"
|
9 |
+
clip_path = clip_vision_path
|
10 |
+
print(f'ControlNet ClipVision location: {clip_path}')
|
11 |
+
|
12 |
+
clip_proc = None
|
13 |
+
clip_vision_model = None
|
14 |
+
|
15 |
+
|
16 |
+
def apply_clip(img):
|
17 |
+
global clip_proc, clip_vision_model
|
18 |
+
|
19 |
+
if clip_vision_model is None:
|
20 |
+
modelpath = os.path.join(clip_path, 'pytorch_model.bin')
|
21 |
+
if not os.path.exists(modelpath):
|
22 |
+
from basicsr.utils.download_util import load_file_from_url
|
23 |
+
load_file_from_url(remote_model_path, model_dir=clip_path)
|
24 |
+
|
25 |
+
clip_proc = CLIPProcessor.from_pretrained(clip_path)
|
26 |
+
clip_vision_model = CLIPVisionModel.from_pretrained(clip_path)
|
27 |
+
|
28 |
+
with torch.no_grad():
|
29 |
+
clip_vision_model = clip_vision_model.to(devices.get_device_for("controlnet"))
|
30 |
+
style_for_clip = clip_proc(images=img, return_tensors="pt")['pixel_values']
|
31 |
+
style_feat = clip_vision_model(style_for_clip.to(devices.get_device_for("controlnet")))['last_hidden_state']
|
32 |
+
|
33 |
+
return style_feat
|
34 |
+
|
35 |
+
|
36 |
+
def unload_clip_model():
|
37 |
+
global clip_proc, clip_vision_model
|
38 |
+
if clip_vision_model is not None:
|
39 |
+
clip_vision_model.cpu()
|
extensions/microsoftexcel-controlnet/annotator/clip_vision/config.json
ADDED
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"_name_or_path": "clip-vit-large-patch14/",
|
3 |
+
"architectures": [
|
4 |
+
"CLIPModel"
|
5 |
+
],
|
6 |
+
"initializer_factor": 1.0,
|
7 |
+
"logit_scale_init_value": 2.6592,
|
8 |
+
"model_type": "clip",
|
9 |
+
"projection_dim": 768,
|
10 |
+
"text_config": {
|
11 |
+
"_name_or_path": "",
|
12 |
+
"add_cross_attention": false,
|
13 |
+
"architectures": null,
|
14 |
+
"attention_dropout": 0.0,
|
15 |
+
"bad_words_ids": null,
|
16 |
+
"bos_token_id": 0,
|
17 |
+
"chunk_size_feed_forward": 0,
|
18 |
+
"cross_attention_hidden_size": null,
|
19 |
+
"decoder_start_token_id": null,
|
20 |
+
"diversity_penalty": 0.0,
|
21 |
+
"do_sample": false,
|
22 |
+
"dropout": 0.0,
|
23 |
+
"early_stopping": false,
|
24 |
+
"encoder_no_repeat_ngram_size": 0,
|
25 |
+
"eos_token_id": 2,
|
26 |
+
"finetuning_task": null,
|
27 |
+
"forced_bos_token_id": null,
|
28 |
+
"forced_eos_token_id": null,
|
29 |
+
"hidden_act": "quick_gelu",
|
30 |
+
"hidden_size": 768,
|
31 |
+
"id2label": {
|
32 |
+
"0": "LABEL_0",
|
33 |
+
"1": "LABEL_1"
|
34 |
+
},
|
35 |
+
"initializer_factor": 1.0,
|
36 |
+
"initializer_range": 0.02,
|
37 |
+
"intermediate_size": 3072,
|
38 |
+
"is_decoder": false,
|
39 |
+
"is_encoder_decoder": false,
|
40 |
+
"label2id": {
|
41 |
+
"LABEL_0": 0,
|
42 |
+
"LABEL_1": 1
|
43 |
+
},
|
44 |
+
"layer_norm_eps": 1e-05,
|
45 |
+
"length_penalty": 1.0,
|
46 |
+
"max_length": 20,
|
47 |
+
"max_position_embeddings": 77,
|
48 |
+
"min_length": 0,
|
49 |
+
"model_type": "clip_text_model",
|
50 |
+
"no_repeat_ngram_size": 0,
|
51 |
+
"num_attention_heads": 12,
|
52 |
+
"num_beam_groups": 1,
|
53 |
+
"num_beams": 1,
|
54 |
+
"num_hidden_layers": 12,
|
55 |
+
"num_return_sequences": 1,
|
56 |
+
"output_attentions": false,
|
57 |
+
"output_hidden_states": false,
|
58 |
+
"output_scores": false,
|
59 |
+
"pad_token_id": 1,
|
60 |
+
"prefix": null,
|
61 |
+
"problem_type": null,
|
62 |
+
"projection_dim" : 768,
|
63 |
+
"pruned_heads": {},
|
64 |
+
"remove_invalid_values": false,
|
65 |
+
"repetition_penalty": 1.0,
|
66 |
+
"return_dict": true,
|
67 |
+
"return_dict_in_generate": false,
|
68 |
+
"sep_token_id": null,
|
69 |
+
"task_specific_params": null,
|
70 |
+
"temperature": 1.0,
|
71 |
+
"tie_encoder_decoder": false,
|
72 |
+
"tie_word_embeddings": true,
|
73 |
+
"tokenizer_class": null,
|
74 |
+
"top_k": 50,
|
75 |
+
"top_p": 1.0,
|
76 |
+
"torch_dtype": null,
|
77 |
+
"torchscript": false,
|
78 |
+
"transformers_version": "4.16.0.dev0",
|
79 |
+
"use_bfloat16": false,
|
80 |
+
"vocab_size": 49408
|
81 |
+
},
|
82 |
+
"text_config_dict": {
|
83 |
+
"hidden_size": 768,
|
84 |
+
"intermediate_size": 3072,
|
85 |
+
"num_attention_heads": 12,
|
86 |
+
"num_hidden_layers": 12,
|
87 |
+
"projection_dim": 768
|
88 |
+
},
|
89 |
+
"torch_dtype": "float32",
|
90 |
+
"transformers_version": null,
|
91 |
+
"vision_config": {
|
92 |
+
"_name_or_path": "",
|
93 |
+
"add_cross_attention": false,
|
94 |
+
"architectures": null,
|
95 |
+
"attention_dropout": 0.0,
|
96 |
+
"bad_words_ids": null,
|
97 |
+
"bos_token_id": null,
|
98 |
+
"chunk_size_feed_forward": 0,
|
99 |
+
"cross_attention_hidden_size": null,
|
100 |
+
"decoder_start_token_id": null,
|
101 |
+
"diversity_penalty": 0.0,
|
102 |
+
"do_sample": false,
|
103 |
+
"dropout": 0.0,
|
104 |
+
"early_stopping": false,
|
105 |
+
"encoder_no_repeat_ngram_size": 0,
|
106 |
+
"eos_token_id": null,
|
107 |
+
"finetuning_task": null,
|
108 |
+
"forced_bos_token_id": null,
|
109 |
+
"forced_eos_token_id": null,
|
110 |
+
"hidden_act": "quick_gelu",
|
111 |
+
"hidden_size": 1024,
|
112 |
+
"id2label": {
|
113 |
+
"0": "LABEL_0",
|
114 |
+
"1": "LABEL_1"
|
115 |
+
},
|
116 |
+
"image_size": 224,
|
117 |
+
"initializer_factor": 1.0,
|
118 |
+
"initializer_range": 0.02,
|
119 |
+
"intermediate_size": 4096,
|
120 |
+
"is_decoder": false,
|
121 |
+
"is_encoder_decoder": false,
|
122 |
+
"label2id": {
|
123 |
+
"LABEL_0": 0,
|
124 |
+
"LABEL_1": 1
|
125 |
+
},
|
126 |
+
"layer_norm_eps": 1e-05,
|
127 |
+
"length_penalty": 1.0,
|
128 |
+
"max_length": 20,
|
129 |
+
"min_length": 0,
|
130 |
+
"model_type": "clip_vision_model",
|
131 |
+
"no_repeat_ngram_size": 0,
|
132 |
+
"num_attention_heads": 16,
|
133 |
+
"num_beam_groups": 1,
|
134 |
+
"num_beams": 1,
|
135 |
+
"num_hidden_layers": 24,
|
136 |
+
"num_return_sequences": 1,
|
137 |
+
"output_attentions": false,
|
138 |
+
"output_hidden_states": false,
|
139 |
+
"output_scores": false,
|
140 |
+
"pad_token_id": null,
|
141 |
+
"patch_size": 14,
|
142 |
+
"prefix": null,
|
143 |
+
"problem_type": null,
|
144 |
+
"projection_dim" : 768,
|
145 |
+
"pruned_heads": {},
|
146 |
+
"remove_invalid_values": false,
|
147 |
+
"repetition_penalty": 1.0,
|
148 |
+
"return_dict": true,
|
149 |
+
"return_dict_in_generate": false,
|
150 |
+
"sep_token_id": null,
|
151 |
+
"task_specific_params": null,
|
152 |
+
"temperature": 1.0,
|
153 |
+
"tie_encoder_decoder": false,
|
154 |
+
"tie_word_embeddings": true,
|
155 |
+
"tokenizer_class": null,
|
156 |
+
"top_k": 50,
|
157 |
+
"top_p": 1.0,
|
158 |
+
"torch_dtype": null,
|
159 |
+
"torchscript": false,
|
160 |
+
"transformers_version": "4.16.0.dev0",
|
161 |
+
"use_bfloat16": false
|
162 |
+
},
|
163 |
+
"vision_config_dict": {
|
164 |
+
"hidden_size": 1024,
|
165 |
+
"intermediate_size": 4096,
|
166 |
+
"num_attention_heads": 16,
|
167 |
+
"num_hidden_layers": 24,
|
168 |
+
"patch_size": 14,
|
169 |
+
"projection_dim": 768
|
170 |
+
}
|
171 |
+
}
|
extensions/microsoftexcel-controlnet/annotator/clip_vision/merges.txt
ADDED
The diff for this file is too large to render.
See raw diff
|
|
extensions/microsoftexcel-controlnet/annotator/clip_vision/preprocessor_config.json
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"crop_size": 224,
|
3 |
+
"do_center_crop": true,
|
4 |
+
"do_normalize": true,
|
5 |
+
"do_resize": true,
|
6 |
+
"feature_extractor_type": "CLIPFeatureExtractor",
|
7 |
+
"image_mean": [
|
8 |
+
0.48145466,
|
9 |
+
0.4578275,
|
10 |
+
0.40821073
|
11 |
+
],
|
12 |
+
"image_std": [
|
13 |
+
0.26862954,
|
14 |
+
0.26130258,
|
15 |
+
0.27577711
|
16 |
+
],
|
17 |
+
"resample": 3,
|
18 |
+
"size": 224
|
19 |
+
}
|
extensions/microsoftexcel-controlnet/annotator/clip_vision/tokenizer.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
extensions/microsoftexcel-controlnet/annotator/clip_vision/tokenizer_config.json
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"unk_token": {
|
3 |
+
"content": "<|endoftext|>",
|
4 |
+
"single_word": false,
|
5 |
+
"lstrip": false,
|
6 |
+
"rstrip": false,
|
7 |
+
"normalized": true,
|
8 |
+
"__type": "AddedToken"
|
9 |
+
},
|
10 |
+
"bos_token": {
|
11 |
+
"content": "<|startoftext|>",
|
12 |
+
"single_word": false,
|
13 |
+
"lstrip": false,
|
14 |
+
"rstrip": false,
|
15 |
+
"normalized": true,
|
16 |
+
"__type": "AddedToken"
|
17 |
+
},
|
18 |
+
"eos_token": {
|
19 |
+
"content": "<|endoftext|>",
|
20 |
+
"single_word": false,
|
21 |
+
"lstrip": false,
|
22 |
+
"rstrip": false,
|
23 |
+
"normalized": true,
|
24 |
+
"__type": "AddedToken"
|
25 |
+
},
|
26 |
+
"pad_token": "<|endoftext|>",
|
27 |
+
"add_prefix_space": false,
|
28 |
+
"errors": "replace",
|
29 |
+
"do_lower_case": true,
|
30 |
+
"name_or_path": "openai/clip-vit-base-patch32",
|
31 |
+
"model_max_length": 77,
|
32 |
+
"special_tokens_map_file": "./special_tokens_map.json",
|
33 |
+
"tokenizer_class": "CLIPTokenizer"
|
34 |
+
}
|
extensions/microsoftexcel-controlnet/annotator/clip_vision/vocab.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
extensions/microsoftexcel-controlnet/annotator/color/__init__.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
|
3 |
+
def cv2_resize_shortest_edge(image, size):
|
4 |
+
h, w = image.shape[:2]
|
5 |
+
if h < w:
|
6 |
+
new_h = size
|
7 |
+
new_w = int(round(w / h * size))
|
8 |
+
else:
|
9 |
+
new_w = size
|
10 |
+
new_h = int(round(h / w * size))
|
11 |
+
resized_image = cv2.resize(image, (new_w, new_h), interpolation=cv2.INTER_AREA)
|
12 |
+
return resized_image
|
13 |
+
|
14 |
+
def apply_color(img, res=512):
|
15 |
+
img = cv2_resize_shortest_edge(img, res)
|
16 |
+
h, w = img.shape[:2]
|
17 |
+
|
18 |
+
input_img_color = cv2.resize(img, (w//64, h//64), interpolation=cv2.INTER_CUBIC)
|
19 |
+
input_img_color = cv2.resize(input_img_color, (w, h), interpolation=cv2.INTER_NEAREST)
|
20 |
+
return input_img_color
|
extensions/microsoftexcel-controlnet/annotator/downloads/openpose/body_pose_model.pth
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:25a948c16078b0f08e236bda51a385d855ef4c153598947c28c0d47ed94bb746
|
3 |
+
size 209267595
|
extensions/microsoftexcel-controlnet/annotator/downloads/openpose/facenet.pth
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:8beb52e548624ffcc4aed12af7aee7dcbfaeea420c75609fee999fe7add79d43
|
3 |
+
size 153718792
|
extensions/microsoftexcel-controlnet/annotator/downloads/openpose/hand_pose_model.pth
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:b76b00d1750901abd07b9f9d8c98cc3385b8fe834a26d4b4f0aad439e75fc600
|
3 |
+
size 147341049
|
extensions/microsoftexcel-controlnet/annotator/hed/__init__.py
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# This is an improved version and model of HED edge detection with Apache License, Version 2.0.
|
2 |
+
# Please use this implementation in your products
|
3 |
+
# This implementation may produce slightly different results from Saining Xie's official implementations,
|
4 |
+
# but it generates smoother edges and is more suitable for ControlNet as well as other image-to-image translations.
|
5 |
+
# Different from official models and other implementations, this is an RGB-input model (rather than BGR)
|
6 |
+
# and in this way it works better for gradio's RGB protocol
|
7 |
+
|
8 |
+
import os
|
9 |
+
import cv2
|
10 |
+
import torch
|
11 |
+
import numpy as np
|
12 |
+
|
13 |
+
from einops import rearrange
|
14 |
+
import os
|
15 |
+
from modules import devices
|
16 |
+
from annotator.annotator_path import models_path
|
17 |
+
from annotator.util import safe_step, nms
|
18 |
+
|
19 |
+
|
20 |
+
class DoubleConvBlock(torch.nn.Module):
|
21 |
+
def __init__(self, input_channel, output_channel, layer_number):
|
22 |
+
super().__init__()
|
23 |
+
self.convs = torch.nn.Sequential()
|
24 |
+
self.convs.append(torch.nn.Conv2d(in_channels=input_channel, out_channels=output_channel, kernel_size=(3, 3), stride=(1, 1), padding=1))
|
25 |
+
for i in range(1, layer_number):
|
26 |
+
self.convs.append(torch.nn.Conv2d(in_channels=output_channel, out_channels=output_channel, kernel_size=(3, 3), stride=(1, 1), padding=1))
|
27 |
+
self.projection = torch.nn.Conv2d(in_channels=output_channel, out_channels=1, kernel_size=(1, 1), stride=(1, 1), padding=0)
|
28 |
+
|
29 |
+
def __call__(self, x, down_sampling=False):
|
30 |
+
h = x
|
31 |
+
if down_sampling:
|
32 |
+
h = torch.nn.functional.max_pool2d(h, kernel_size=(2, 2), stride=(2, 2))
|
33 |
+
for conv in self.convs:
|
34 |
+
h = conv(h)
|
35 |
+
h = torch.nn.functional.relu(h)
|
36 |
+
return h, self.projection(h)
|
37 |
+
|
38 |
+
|
39 |
+
class ControlNetHED_Apache2(torch.nn.Module):
|
40 |
+
def __init__(self):
|
41 |
+
super().__init__()
|
42 |
+
self.norm = torch.nn.Parameter(torch.zeros(size=(1, 3, 1, 1)))
|
43 |
+
self.block1 = DoubleConvBlock(input_channel=3, output_channel=64, layer_number=2)
|
44 |
+
self.block2 = DoubleConvBlock(input_channel=64, output_channel=128, layer_number=2)
|
45 |
+
self.block3 = DoubleConvBlock(input_channel=128, output_channel=256, layer_number=3)
|
46 |
+
self.block4 = DoubleConvBlock(input_channel=256, output_channel=512, layer_number=3)
|
47 |
+
self.block5 = DoubleConvBlock(input_channel=512, output_channel=512, layer_number=3)
|
48 |
+
|
49 |
+
def __call__(self, x):
|
50 |
+
h = x - self.norm
|
51 |
+
h, projection1 = self.block1(h)
|
52 |
+
h, projection2 = self.block2(h, down_sampling=True)
|
53 |
+
h, projection3 = self.block3(h, down_sampling=True)
|
54 |
+
h, projection4 = self.block4(h, down_sampling=True)
|
55 |
+
h, projection5 = self.block5(h, down_sampling=True)
|
56 |
+
return projection1, projection2, projection3, projection4, projection5
|
57 |
+
|
58 |
+
|
59 |
+
netNetwork = None
|
60 |
+
remote_model_path = "https://huggingface.co/lllyasviel/Annotators/resolve/main/ControlNetHED.pth"
|
61 |
+
modeldir = os.path.join(models_path, "hed")
|
62 |
+
old_modeldir = os.path.dirname(os.path.realpath(__file__))
|
63 |
+
|
64 |
+
|
65 |
+
def apply_hed(input_image, is_safe=False):
|
66 |
+
global netNetwork
|
67 |
+
if netNetwork is None:
|
68 |
+
modelpath = os.path.join(modeldir, "ControlNetHED.pth")
|
69 |
+
old_modelpath = os.path.join(old_modeldir, "ControlNetHED.pth")
|
70 |
+
if os.path.exists(old_modelpath):
|
71 |
+
modelpath = old_modelpath
|
72 |
+
elif not os.path.exists(modelpath):
|
73 |
+
from basicsr.utils.download_util import load_file_from_url
|
74 |
+
load_file_from_url(remote_model_path, model_dir=modeldir)
|
75 |
+
netNetwork = ControlNetHED_Apache2().to(devices.get_device_for("controlnet"))
|
76 |
+
netNetwork.load_state_dict(torch.load(modelpath, map_location='cpu'))
|
77 |
+
netNetwork.to(devices.get_device_for("controlnet")).float().eval()
|
78 |
+
|
79 |
+
assert input_image.ndim == 3
|
80 |
+
H, W, C = input_image.shape
|
81 |
+
with torch.no_grad():
|
82 |
+
image_hed = torch.from_numpy(input_image.copy()).float().to(devices.get_device_for("controlnet"))
|
83 |
+
image_hed = rearrange(image_hed, 'h w c -> 1 c h w')
|
84 |
+
edges = netNetwork(image_hed)
|
85 |
+
edges = [e.detach().cpu().numpy().astype(np.float32)[0, 0] for e in edges]
|
86 |
+
edges = [cv2.resize(e, (W, H), interpolation=cv2.INTER_LINEAR) for e in edges]
|
87 |
+
edges = np.stack(edges, axis=2)
|
88 |
+
edge = 1 / (1 + np.exp(-np.mean(edges, axis=2).astype(np.float64)))
|
89 |
+
if is_safe:
|
90 |
+
edge = safe_step(edge)
|
91 |
+
edge = (edge * 255.0).clip(0, 255).astype(np.uint8)
|
92 |
+
return edge
|
93 |
+
|
94 |
+
|
95 |
+
def unload_hed_model():
|
96 |
+
global netNetwork
|
97 |
+
if netNetwork is not None:
|
98 |
+
netNetwork.cpu()
|
extensions/microsoftexcel-controlnet/annotator/keypose/__init__.py
ADDED
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
import torch
|
4 |
+
|
5 |
+
import os
|
6 |
+
from modules import devices
|
7 |
+
from annotator.annotator_path import models_path
|
8 |
+
|
9 |
+
import mmcv
|
10 |
+
from mmdet.apis import inference_detector, init_detector
|
11 |
+
from mmpose.apis import inference_top_down_pose_model
|
12 |
+
from mmpose.apis import init_pose_model, process_mmdet_results, vis_pose_result
|
13 |
+
|
14 |
+
|
15 |
+
def preprocessing(image, device):
|
16 |
+
# Resize
|
17 |
+
scale = 640 / max(image.shape[:2])
|
18 |
+
image = cv2.resize(image, dsize=None, fx=scale, fy=scale)
|
19 |
+
raw_image = image.astype(np.uint8)
|
20 |
+
|
21 |
+
# Subtract mean values
|
22 |
+
image = image.astype(np.float32)
|
23 |
+
image -= np.array(
|
24 |
+
[
|
25 |
+
float(104.008),
|
26 |
+
float(116.669),
|
27 |
+
float(122.675),
|
28 |
+
]
|
29 |
+
)
|
30 |
+
|
31 |
+
# Convert to torch.Tensor and add "batch" axis
|
32 |
+
image = torch.from_numpy(image.transpose(2, 0, 1)).float().unsqueeze(0)
|
33 |
+
image = image.to(device)
|
34 |
+
|
35 |
+
return image, raw_image
|
36 |
+
|
37 |
+
|
38 |
+
def imshow_keypoints(img,
|
39 |
+
pose_result,
|
40 |
+
skeleton=None,
|
41 |
+
kpt_score_thr=0.1,
|
42 |
+
pose_kpt_color=None,
|
43 |
+
pose_link_color=None,
|
44 |
+
radius=4,
|
45 |
+
thickness=1):
|
46 |
+
"""Draw keypoints and links on an image.
|
47 |
+
Args:
|
48 |
+
img (ndarry): The image to draw poses on.
|
49 |
+
pose_result (list[kpts]): The poses to draw. Each element kpts is
|
50 |
+
a set of K keypoints as an Kx3 numpy.ndarray, where each
|
51 |
+
keypoint is represented as x, y, score.
|
52 |
+
kpt_score_thr (float, optional): Minimum score of keypoints
|
53 |
+
to be shown. Default: 0.3.
|
54 |
+
pose_kpt_color (np.array[Nx3]`): Color of N keypoints. If None,
|
55 |
+
the keypoint will not be drawn.
|
56 |
+
pose_link_color (np.array[Mx3]): Color of M links. If None, the
|
57 |
+
links will not be drawn.
|
58 |
+
thickness (int): Thickness of lines.
|
59 |
+
"""
|
60 |
+
|
61 |
+
img_h, img_w, _ = img.shape
|
62 |
+
img = np.zeros(img.shape)
|
63 |
+
|
64 |
+
for idx, kpts in enumerate(pose_result):
|
65 |
+
if idx > 1:
|
66 |
+
continue
|
67 |
+
kpts = kpts['keypoints']
|
68 |
+
# print(kpts)
|
69 |
+
kpts = np.array(kpts, copy=False)
|
70 |
+
|
71 |
+
# draw each point on image
|
72 |
+
if pose_kpt_color is not None:
|
73 |
+
assert len(pose_kpt_color) == len(kpts)
|
74 |
+
|
75 |
+
for kid, kpt in enumerate(kpts):
|
76 |
+
x_coord, y_coord, kpt_score = int(kpt[0]), int(kpt[1]), kpt[2]
|
77 |
+
|
78 |
+
if kpt_score < kpt_score_thr or pose_kpt_color[kid] is None:
|
79 |
+
# skip the point that should not be drawn
|
80 |
+
continue
|
81 |
+
|
82 |
+
color = tuple(int(c) for c in pose_kpt_color[kid])
|
83 |
+
cv2.circle(img, (int(x_coord), int(y_coord)),
|
84 |
+
radius, color, -1)
|
85 |
+
|
86 |
+
# draw links
|
87 |
+
if skeleton is not None and pose_link_color is not None:
|
88 |
+
assert len(pose_link_color) == len(skeleton)
|
89 |
+
|
90 |
+
for sk_id, sk in enumerate(skeleton):
|
91 |
+
pos1 = (int(kpts[sk[0], 0]), int(kpts[sk[0], 1]))
|
92 |
+
pos2 = (int(kpts[sk[1], 0]), int(kpts[sk[1], 1]))
|
93 |
+
|
94 |
+
if (pos1[0] <= 0 or pos1[0] >= img_w or pos1[1] <= 0 or pos1[1] >= img_h or pos2[0] <= 0
|
95 |
+
or pos2[0] >= img_w or pos2[1] <= 0 or pos2[1] >= img_h or kpts[sk[0], 2] < kpt_score_thr
|
96 |
+
or kpts[sk[1], 2] < kpt_score_thr or pose_link_color[sk_id] is None):
|
97 |
+
# skip the link that should not be drawn
|
98 |
+
continue
|
99 |
+
color = tuple(int(c) for c in pose_link_color[sk_id])
|
100 |
+
cv2.line(img, pos1, pos2, color, thickness=thickness)
|
101 |
+
|
102 |
+
return img
|
103 |
+
|
104 |
+
|
105 |
+
human_det, pose_model = None, None
|
106 |
+
det_model_path = "https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth"
|
107 |
+
pose_model_path = "https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w48_coco_256x192-b9e0b3ab_20200708.pth"
|
108 |
+
|
109 |
+
modeldir = os.path.join(models_path, "keypose")
|
110 |
+
old_modeldir = os.path.dirname(os.path.realpath(__file__))
|
111 |
+
|
112 |
+
det_config = 'faster_rcnn_r50_fpn_coco.py'
|
113 |
+
pose_config = 'hrnet_w48_coco_256x192.py'
|
114 |
+
|
115 |
+
det_checkpoint = 'faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'
|
116 |
+
pose_checkpoint = 'hrnet_w48_coco_256x192-b9e0b3ab_20200708.pth'
|
117 |
+
det_cat_id = 1
|
118 |
+
bbox_thr = 0.2
|
119 |
+
|
120 |
+
skeleton = [
|
121 |
+
[15, 13], [13, 11], [16, 14], [14, 12], [11, 12], [5, 11], [6, 12], [5, 6], [5, 7], [6, 8],
|
122 |
+
[7, 9], [8, 10],
|
123 |
+
[1, 2], [0, 1], [0, 2], [1, 3], [2, 4], [3, 5], [4, 6]
|
124 |
+
]
|
125 |
+
|
126 |
+
pose_kpt_color = [
|
127 |
+
[51, 153, 255], [51, 153, 255], [51, 153, 255], [51, 153, 255], [51, 153, 255],
|
128 |
+
[0, 255, 0],
|
129 |
+
[255, 128, 0], [0, 255, 0], [255, 128, 0], [0, 255, 0], [255, 128, 0], [0, 255, 0],
|
130 |
+
[255, 128, 0],
|
131 |
+
[0, 255, 0], [255, 128, 0], [0, 255, 0], [255, 128, 0]
|
132 |
+
]
|
133 |
+
|
134 |
+
pose_link_color = [
|
135 |
+
[0, 255, 0], [0, 255, 0], [255, 128, 0], [255, 128, 0],
|
136 |
+
[51, 153, 255], [51, 153, 255], [51, 153, 255], [51, 153, 255], [0, 255, 0],
|
137 |
+
[255, 128, 0],
|
138 |
+
[0, 255, 0], [255, 128, 0], [51, 153, 255], [51, 153, 255], [51, 153, 255],
|
139 |
+
[51, 153, 255],
|
140 |
+
[51, 153, 255], [51, 153, 255], [51, 153, 255]
|
141 |
+
]
|
142 |
+
|
143 |
+
def find_download_model(checkpoint, remote_path):
|
144 |
+
modelpath = os.path.join(modeldir, checkpoint)
|
145 |
+
old_modelpath = os.path.join(old_modeldir, checkpoint)
|
146 |
+
|
147 |
+
if os.path.exists(old_modelpath):
|
148 |
+
modelpath = old_modelpath
|
149 |
+
elif not os.path.exists(modelpath):
|
150 |
+
from basicsr.utils.download_util import load_file_from_url
|
151 |
+
load_file_from_url(remote_path, model_dir=modeldir)
|
152 |
+
|
153 |
+
return modelpath
|
154 |
+
|
155 |
+
def apply_keypose(input_image):
|
156 |
+
global human_det, pose_model
|
157 |
+
if netNetwork is None:
|
158 |
+
det_model_local = find_download_model(det_checkpoint, det_model_path)
|
159 |
+
hrnet_model_local = find_download_model(pose_checkpoint, pose_model_path)
|
160 |
+
det_config_mmcv = mmcv.Config.fromfile(det_config)
|
161 |
+
pose_config_mmcv = mmcv.Config.fromfile(pose_config)
|
162 |
+
human_det = init_detector(det_config_mmcv, det_model_local, device=devices.get_device_for("controlnet"))
|
163 |
+
pose_model = init_pose_model(pose_config_mmcv, hrnet_model_local, device=devices.get_device_for("controlnet"))
|
164 |
+
|
165 |
+
assert input_image.ndim == 3
|
166 |
+
input_image = input_image.copy()
|
167 |
+
with torch.no_grad():
|
168 |
+
image = torch.from_numpy(input_image).float().to(devices.get_device_for("controlnet"))
|
169 |
+
image = image / 255.0
|
170 |
+
mmdet_results = inference_detector(human_det, image)
|
171 |
+
|
172 |
+
# keep the person class bounding boxes.
|
173 |
+
person_results = process_mmdet_results(mmdet_results, det_cat_id)
|
174 |
+
|
175 |
+
return_heatmap = False
|
176 |
+
dataset = pose_model.cfg.data['test']['type']
|
177 |
+
|
178 |
+
# e.g. use ('backbone', ) to return backbone feature
|
179 |
+
output_layer_names = None
|
180 |
+
pose_results, _ = inference_top_down_pose_model(
|
181 |
+
pose_model,
|
182 |
+
image,
|
183 |
+
person_results,
|
184 |
+
bbox_thr=bbox_thr,
|
185 |
+
format='xyxy',
|
186 |
+
dataset=dataset,
|
187 |
+
dataset_info=None,
|
188 |
+
return_heatmap=return_heatmap,
|
189 |
+
outputs=output_layer_names
|
190 |
+
)
|
191 |
+
|
192 |
+
im_keypose_out = imshow_keypoints(
|
193 |
+
image,
|
194 |
+
pose_results,
|
195 |
+
skeleton=skeleton,
|
196 |
+
pose_kpt_color=pose_kpt_color,
|
197 |
+
pose_link_color=pose_link_color,
|
198 |
+
radius=2,
|
199 |
+
thickness=2
|
200 |
+
)
|
201 |
+
im_keypose_out = im_keypose_out.astype(np.uint8)
|
202 |
+
|
203 |
+
# image_hed = rearrange(image_hed, 'h w c -> 1 c h w')
|
204 |
+
# edge = netNetwork(image_hed)[0]
|
205 |
+
# edge = (edge.cpu().numpy() * 255.0).clip(0, 255).astype(np.uint8)
|
206 |
+
return im_keypose_out
|
207 |
+
|
208 |
+
|
209 |
+
def unload_hed_model():
|
210 |
+
global netNetwork
|
211 |
+
if netNetwork is not None:
|
212 |
+
netNetwork.cpu()
|
extensions/microsoftexcel-controlnet/annotator/keypose/faster_rcnn_r50_fpn_coco.py
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
checkpoint_config = dict(interval=1)
|
2 |
+
# yapf:disable
|
3 |
+
log_config = dict(
|
4 |
+
interval=50,
|
5 |
+
hooks=[
|
6 |
+
dict(type='TextLoggerHook'),
|
7 |
+
# dict(type='TensorboardLoggerHook')
|
8 |
+
])
|
9 |
+
# yapf:enable
|
10 |
+
dist_params = dict(backend='nccl')
|
11 |
+
log_level = 'INFO'
|
12 |
+
load_from = None
|
13 |
+
resume_from = None
|
14 |
+
workflow = [('train', 1)]
|
15 |
+
# optimizer
|
16 |
+
optimizer = dict(type='SGD', lr=0.02, momentum=0.9, weight_decay=0.0001)
|
17 |
+
optimizer_config = dict(grad_clip=None)
|
18 |
+
# learning policy
|
19 |
+
lr_config = dict(
|
20 |
+
policy='step',
|
21 |
+
warmup='linear',
|
22 |
+
warmup_iters=500,
|
23 |
+
warmup_ratio=0.001,
|
24 |
+
step=[8, 11])
|
25 |
+
total_epochs = 12
|
26 |
+
|
27 |
+
model = dict(
|
28 |
+
type='FasterRCNN',
|
29 |
+
pretrained='torchvision://resnet50',
|
30 |
+
backbone=dict(
|
31 |
+
type='ResNet',
|
32 |
+
depth=50,
|
33 |
+
num_stages=4,
|
34 |
+
out_indices=(0, 1, 2, 3),
|
35 |
+
frozen_stages=1,
|
36 |
+
norm_cfg=dict(type='BN', requires_grad=True),
|
37 |
+
norm_eval=True,
|
38 |
+
style='pytorch'),
|
39 |
+
neck=dict(
|
40 |
+
type='FPN',
|
41 |
+
in_channels=[256, 512, 1024, 2048],
|
42 |
+
out_channels=256,
|
43 |
+
num_outs=5),
|
44 |
+
rpn_head=dict(
|
45 |
+
type='RPNHead',
|
46 |
+
in_channels=256,
|
47 |
+
feat_channels=256,
|
48 |
+
anchor_generator=dict(
|
49 |
+
type='AnchorGenerator',
|
50 |
+
scales=[8],
|
51 |
+
ratios=[0.5, 1.0, 2.0],
|
52 |
+
strides=[4, 8, 16, 32, 64]),
|
53 |
+
bbox_coder=dict(
|
54 |
+
type='DeltaXYWHBBoxCoder',
|
55 |
+
target_means=[.0, .0, .0, .0],
|
56 |
+
target_stds=[1.0, 1.0, 1.0, 1.0]),
|
57 |
+
loss_cls=dict(
|
58 |
+
type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
|
59 |
+
loss_bbox=dict(type='L1Loss', loss_weight=1.0)),
|
60 |
+
roi_head=dict(
|
61 |
+
type='StandardRoIHead',
|
62 |
+
bbox_roi_extractor=dict(
|
63 |
+
type='SingleRoIExtractor',
|
64 |
+
roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0),
|
65 |
+
out_channels=256,
|
66 |
+
featmap_strides=[4, 8, 16, 32]),
|
67 |
+
bbox_head=dict(
|
68 |
+
type='Shared2FCBBoxHead',
|
69 |
+
in_channels=256,
|
70 |
+
fc_out_channels=1024,
|
71 |
+
roi_feat_size=7,
|
72 |
+
num_classes=80,
|
73 |
+
bbox_coder=dict(
|
74 |
+
type='DeltaXYWHBBoxCoder',
|
75 |
+
target_means=[0., 0., 0., 0.],
|
76 |
+
target_stds=[0.1, 0.1, 0.2, 0.2]),
|
77 |
+
reg_class_agnostic=False,
|
78 |
+
loss_cls=dict(
|
79 |
+
type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0),
|
80 |
+
loss_bbox=dict(type='L1Loss', loss_weight=1.0))),
|
81 |
+
# model training and testing settings
|
82 |
+
train_cfg=dict(
|
83 |
+
rpn=dict(
|
84 |
+
assigner=dict(
|
85 |
+
type='MaxIoUAssigner',
|
86 |
+
pos_iou_thr=0.7,
|
87 |
+
neg_iou_thr=0.3,
|
88 |
+
min_pos_iou=0.3,
|
89 |
+
match_low_quality=True,
|
90 |
+
ignore_iof_thr=-1),
|
91 |
+
sampler=dict(
|
92 |
+
type='RandomSampler',
|
93 |
+
num=256,
|
94 |
+
pos_fraction=0.5,
|
95 |
+
neg_pos_ub=-1,
|
96 |
+
add_gt_as_proposals=False),
|
97 |
+
allowed_border=-1,
|
98 |
+
pos_weight=-1,
|
99 |
+
debug=False),
|
100 |
+
rpn_proposal=dict(
|
101 |
+
nms_pre=2000,
|
102 |
+
max_per_img=1000,
|
103 |
+
nms=dict(type='nms', iou_threshold=0.7),
|
104 |
+
min_bbox_size=0),
|
105 |
+
rcnn=dict(
|
106 |
+
assigner=dict(
|
107 |
+
type='MaxIoUAssigner',
|
108 |
+
pos_iou_thr=0.5,
|
109 |
+
neg_iou_thr=0.5,
|
110 |
+
min_pos_iou=0.5,
|
111 |
+
match_low_quality=False,
|
112 |
+
ignore_iof_thr=-1),
|
113 |
+
sampler=dict(
|
114 |
+
type='RandomSampler',
|
115 |
+
num=512,
|
116 |
+
pos_fraction=0.25,
|
117 |
+
neg_pos_ub=-1,
|
118 |
+
add_gt_as_proposals=True),
|
119 |
+
pos_weight=-1,
|
120 |
+
debug=False)),
|
121 |
+
test_cfg=dict(
|
122 |
+
rpn=dict(
|
123 |
+
nms_pre=1000,
|
124 |
+
max_per_img=1000,
|
125 |
+
nms=dict(type='nms', iou_threshold=0.7),
|
126 |
+
min_bbox_size=0),
|
127 |
+
rcnn=dict(
|
128 |
+
score_thr=0.05,
|
129 |
+
nms=dict(type='nms', iou_threshold=0.5),
|
130 |
+
max_per_img=100)
|
131 |
+
# soft-nms is also supported for rcnn testing
|
132 |
+
# e.g., nms=dict(type='soft_nms', iou_threshold=0.5, min_score=0.05)
|
133 |
+
))
|
134 |
+
|
135 |
+
dataset_type = 'CocoDataset'
|
136 |
+
data_root = 'data/coco'
|
137 |
+
img_norm_cfg = dict(
|
138 |
+
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
|
139 |
+
train_pipeline = [
|
140 |
+
dict(type='LoadImageFromFile'),
|
141 |
+
dict(type='LoadAnnotations', with_bbox=True),
|
142 |
+
dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
|
143 |
+
dict(type='RandomFlip', flip_ratio=0.5),
|
144 |
+
dict(type='Normalize', **img_norm_cfg),
|
145 |
+
dict(type='Pad', size_divisor=32),
|
146 |
+
dict(type='DefaultFormatBundle'),
|
147 |
+
dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']),
|
148 |
+
]
|
149 |
+
test_pipeline = [
|
150 |
+
dict(type='LoadImageFromFile'),
|
151 |
+
dict(
|
152 |
+
type='MultiScaleFlipAug',
|
153 |
+
img_scale=(1333, 800),
|
154 |
+
flip=False,
|
155 |
+
transforms=[
|
156 |
+
dict(type='Resize', keep_ratio=True),
|
157 |
+
dict(type='RandomFlip'),
|
158 |
+
dict(type='Normalize', **img_norm_cfg),
|
159 |
+
dict(type='Pad', size_divisor=32),
|
160 |
+
dict(type='DefaultFormatBundle'),
|
161 |
+
dict(type='Collect', keys=['img']),
|
162 |
+
])
|
163 |
+
]
|
164 |
+
data = dict(
|
165 |
+
samples_per_gpu=2,
|
166 |
+
workers_per_gpu=2,
|
167 |
+
train=dict(
|
168 |
+
type=dataset_type,
|
169 |
+
ann_file=f'{data_root}/annotations/instances_train2017.json',
|
170 |
+
img_prefix=f'{data_root}/train2017/',
|
171 |
+
pipeline=train_pipeline),
|
172 |
+
val=dict(
|
173 |
+
type=dataset_type,
|
174 |
+
ann_file=f'{data_root}/annotations/instances_val2017.json',
|
175 |
+
img_prefix=f'{data_root}/val2017/',
|
176 |
+
pipeline=test_pipeline),
|
177 |
+
test=dict(
|
178 |
+
type=dataset_type,
|
179 |
+
ann_file=f'{data_root}/annotations/instances_val2017.json',
|
180 |
+
img_prefix=f'{data_root}/val2017/',
|
181 |
+
pipeline=test_pipeline))
|
182 |
+
evaluation = dict(interval=1, metric='bbox')
|
extensions/microsoftexcel-controlnet/annotator/keypose/hrnet_w48_coco_256x192.py
ADDED
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# _base_ = [
|
2 |
+
# '../../../../_base_/default_runtime.py',
|
3 |
+
# '../../../../_base_/datasets/coco.py'
|
4 |
+
# ]
|
5 |
+
evaluation = dict(interval=10, metric='mAP', save_best='AP')
|
6 |
+
|
7 |
+
optimizer = dict(
|
8 |
+
type='Adam',
|
9 |
+
lr=5e-4,
|
10 |
+
)
|
11 |
+
optimizer_config = dict(grad_clip=None)
|
12 |
+
# learning policy
|
13 |
+
lr_config = dict(
|
14 |
+
policy='step',
|
15 |
+
warmup='linear',
|
16 |
+
warmup_iters=500,
|
17 |
+
warmup_ratio=0.001,
|
18 |
+
step=[170, 200])
|
19 |
+
total_epochs = 210
|
20 |
+
channel_cfg = dict(
|
21 |
+
num_output_channels=17,
|
22 |
+
dataset_joints=17,
|
23 |
+
dataset_channel=[
|
24 |
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
|
25 |
+
],
|
26 |
+
inference_channel=[
|
27 |
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
|
28 |
+
])
|
29 |
+
|
30 |
+
# model settings
|
31 |
+
model = dict(
|
32 |
+
type='TopDown',
|
33 |
+
pretrained='https://download.openmmlab.com/mmpose/'
|
34 |
+
'pretrain_models/hrnet_w48-8ef0771d.pth',
|
35 |
+
backbone=dict(
|
36 |
+
type='HRNet',
|
37 |
+
in_channels=3,
|
38 |
+
extra=dict(
|
39 |
+
stage1=dict(
|
40 |
+
num_modules=1,
|
41 |
+
num_branches=1,
|
42 |
+
block='BOTTLENECK',
|
43 |
+
num_blocks=(4, ),
|
44 |
+
num_channels=(64, )),
|
45 |
+
stage2=dict(
|
46 |
+
num_modules=1,
|
47 |
+
num_branches=2,
|
48 |
+
block='BASIC',
|
49 |
+
num_blocks=(4, 4),
|
50 |
+
num_channels=(48, 96)),
|
51 |
+
stage3=dict(
|
52 |
+
num_modules=4,
|
53 |
+
num_branches=3,
|
54 |
+
block='BASIC',
|
55 |
+
num_blocks=(4, 4, 4),
|
56 |
+
num_channels=(48, 96, 192)),
|
57 |
+
stage4=dict(
|
58 |
+
num_modules=3,
|
59 |
+
num_branches=4,
|
60 |
+
block='BASIC',
|
61 |
+
num_blocks=(4, 4, 4, 4),
|
62 |
+
num_channels=(48, 96, 192, 384))),
|
63 |
+
),
|
64 |
+
keypoint_head=dict(
|
65 |
+
type='TopdownHeatmapSimpleHead',
|
66 |
+
in_channels=48,
|
67 |
+
out_channels=channel_cfg['num_output_channels'],
|
68 |
+
num_deconv_layers=0,
|
69 |
+
extra=dict(final_conv_kernel=1, ),
|
70 |
+
loss_keypoint=dict(type='JointsMSELoss', use_target_weight=True)),
|
71 |
+
train_cfg=dict(),
|
72 |
+
test_cfg=dict(
|
73 |
+
flip_test=True,
|
74 |
+
post_process='default',
|
75 |
+
shift_heatmap=True,
|
76 |
+
modulate_kernel=11))
|
77 |
+
|
78 |
+
data_cfg = dict(
|
79 |
+
image_size=[192, 256],
|
80 |
+
heatmap_size=[48, 64],
|
81 |
+
num_output_channels=channel_cfg['num_output_channels'],
|
82 |
+
num_joints=channel_cfg['dataset_joints'],
|
83 |
+
dataset_channel=channel_cfg['dataset_channel'],
|
84 |
+
inference_channel=channel_cfg['inference_channel'],
|
85 |
+
soft_nms=False,
|
86 |
+
nms_thr=1.0,
|
87 |
+
oks_thr=0.9,
|
88 |
+
vis_thr=0.2,
|
89 |
+
use_gt_bbox=False,
|
90 |
+
det_bbox_thr=0.0,
|
91 |
+
bbox_file='data/coco/person_detection_results/'
|
92 |
+
'COCO_val2017_detections_AP_H_56_person.json',
|
93 |
+
)
|
94 |
+
|
95 |
+
train_pipeline = [
|
96 |
+
dict(type='LoadImageFromFile'),
|
97 |
+
dict(type='TopDownGetBboxCenterScale', padding=1.25),
|
98 |
+
dict(type='TopDownRandomShiftBboxCenter', shift_factor=0.16, prob=0.3),
|
99 |
+
dict(type='TopDownRandomFlip', flip_prob=0.5),
|
100 |
+
dict(
|
101 |
+
type='TopDownHalfBodyTransform',
|
102 |
+
num_joints_half_body=8,
|
103 |
+
prob_half_body=0.3),
|
104 |
+
dict(
|
105 |
+
type='TopDownGetRandomScaleRotation', rot_factor=40, scale_factor=0.5),
|
106 |
+
dict(type='TopDownAffine'),
|
107 |
+
dict(type='ToTensor'),
|
108 |
+
dict(
|
109 |
+
type='NormalizeTensor',
|
110 |
+
mean=[0.485, 0.456, 0.406],
|
111 |
+
std=[0.229, 0.224, 0.225]),
|
112 |
+
dict(type='TopDownGenerateTarget', sigma=2),
|
113 |
+
dict(
|
114 |
+
type='Collect',
|
115 |
+
keys=['img', 'target', 'target_weight'],
|
116 |
+
meta_keys=[
|
117 |
+
'image_file', 'joints_3d', 'joints_3d_visible', 'center', 'scale',
|
118 |
+
'rotation', 'bbox_score', 'flip_pairs'
|
119 |
+
]),
|
120 |
+
]
|
121 |
+
|
122 |
+
val_pipeline = [
|
123 |
+
dict(type='LoadImageFromFile'),
|
124 |
+
dict(type='TopDownGetBboxCenterScale', padding=1.25),
|
125 |
+
dict(type='TopDownAffine'),
|
126 |
+
dict(type='ToTensor'),
|
127 |
+
dict(
|
128 |
+
type='NormalizeTensor',
|
129 |
+
mean=[0.485, 0.456, 0.406],
|
130 |
+
std=[0.229, 0.224, 0.225]),
|
131 |
+
dict(
|
132 |
+
type='Collect',
|
133 |
+
keys=['img'],
|
134 |
+
meta_keys=[
|
135 |
+
'image_file', 'center', 'scale', 'rotation', 'bbox_score',
|
136 |
+
'flip_pairs'
|
137 |
+
]),
|
138 |
+
]
|
139 |
+
|
140 |
+
test_pipeline = val_pipeline
|
141 |
+
|
142 |
+
data_root = 'data/coco'
|
143 |
+
data = dict(
|
144 |
+
samples_per_gpu=32,
|
145 |
+
workers_per_gpu=2,
|
146 |
+
val_dataloader=dict(samples_per_gpu=32),
|
147 |
+
test_dataloader=dict(samples_per_gpu=32),
|
148 |
+
train=dict(
|
149 |
+
type='TopDownCocoDataset',
|
150 |
+
ann_file=f'{data_root}/annotations/person_keypoints_train2017.json',
|
151 |
+
img_prefix=f'{data_root}/train2017/',
|
152 |
+
data_cfg=data_cfg,
|
153 |
+
pipeline=train_pipeline,
|
154 |
+
dataset_info={{_base_.dataset_info}}),
|
155 |
+
val=dict(
|
156 |
+
type='TopDownCocoDataset',
|
157 |
+
ann_file=f'{data_root}/annotations/person_keypoints_val2017.json',
|
158 |
+
img_prefix=f'{data_root}/val2017/',
|
159 |
+
data_cfg=data_cfg,
|
160 |
+
pipeline=val_pipeline,
|
161 |
+
dataset_info={{_base_.dataset_info}}),
|
162 |
+
test=dict(
|
163 |
+
type='TopDownCocoDataset',
|
164 |
+
ann_file=f'{data_root}/annotations/person_keypoints_val2017.json',
|
165 |
+
img_prefix=f'{data_root}/val2017/',
|
166 |
+
data_cfg=data_cfg,
|
167 |
+
pipeline=test_pipeline,
|
168 |
+
dataset_info={{_base_.dataset_info}}),
|
169 |
+
)
|
extensions/microsoftexcel-controlnet/annotator/leres/__init__.py
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import numpy as np
|
3 |
+
import torch
|
4 |
+
import os
|
5 |
+
from modules import devices, shared
|
6 |
+
from annotator.annotator_path import models_path
|
7 |
+
from torchvision.transforms import transforms
|
8 |
+
|
9 |
+
# AdelaiDepth/LeReS imports
|
10 |
+
from .leres.depthmap import estimateleres, estimateboost
|
11 |
+
from .leres.multi_depth_model_woauxi import RelDepthModel
|
12 |
+
from .leres.net_tools import strip_prefix_if_present
|
13 |
+
|
14 |
+
# pix2pix/merge net imports
|
15 |
+
from .pix2pix.options.test_options import TestOptions
|
16 |
+
from .pix2pix.models.pix2pix4depth_model import Pix2Pix4DepthModel
|
17 |
+
|
18 |
+
base_model_path = os.path.join(models_path, "leres")
|
19 |
+
old_modeldir = os.path.dirname(os.path.realpath(__file__))
|
20 |
+
|
21 |
+
remote_model_path_leres = "https://huggingface.co/lllyasviel/Annotators/resolve/main/res101.pth"
|
22 |
+
remote_model_path_pix2pix = "https://huggingface.co/lllyasviel/Annotators/resolve/main/latest_net_G.pth"
|
23 |
+
|
24 |
+
model = None
|
25 |
+
pix2pixmodel = None
|
26 |
+
|
27 |
+
def unload_leres_model():
|
28 |
+
global model, pix2pixmodel
|
29 |
+
if model is not None:
|
30 |
+
model = model.cpu()
|
31 |
+
if pix2pixmodel is not None:
|
32 |
+
pix2pixmodel = pix2pixmodel.unload_network('G')
|
33 |
+
|
34 |
+
|
35 |
+
def apply_leres(input_image, thr_a, thr_b, boost=False):
|
36 |
+
global model, pix2pixmodel
|
37 |
+
if model is None:
|
38 |
+
model_path = os.path.join(base_model_path, "res101.pth")
|
39 |
+
old_model_path = os.path.join(old_modeldir, "res101.pth")
|
40 |
+
|
41 |
+
if os.path.exists(old_model_path):
|
42 |
+
model_path = old_model_path
|
43 |
+
elif not os.path.exists(model_path):
|
44 |
+
from basicsr.utils.download_util import load_file_from_url
|
45 |
+
load_file_from_url(remote_model_path_leres, model_dir=base_model_path)
|
46 |
+
|
47 |
+
if torch.cuda.is_available():
|
48 |
+
checkpoint = torch.load(model_path)
|
49 |
+
else:
|
50 |
+
checkpoint = torch.load(model_path, map_location=torch.device('cpu'))
|
51 |
+
|
52 |
+
model = RelDepthModel(backbone='resnext101')
|
53 |
+
model.load_state_dict(strip_prefix_if_present(checkpoint['depth_model'], "module."), strict=True)
|
54 |
+
del checkpoint
|
55 |
+
|
56 |
+
if boost and pix2pixmodel is None:
|
57 |
+
pix2pixmodel_path = os.path.join(base_model_path, "latest_net_G.pth")
|
58 |
+
if not os.path.exists(pix2pixmodel_path):
|
59 |
+
from basicsr.utils.download_util import load_file_from_url
|
60 |
+
load_file_from_url(remote_model_path_pix2pix, model_dir=base_model_path)
|
61 |
+
|
62 |
+
opt = TestOptions().parse()
|
63 |
+
if not torch.cuda.is_available():
|
64 |
+
opt.gpu_ids = [] # cpu mode
|
65 |
+
pix2pixmodel = Pix2Pix4DepthModel(opt)
|
66 |
+
pix2pixmodel.save_dir = base_model_path
|
67 |
+
pix2pixmodel.load_networks('latest')
|
68 |
+
pix2pixmodel.eval()
|
69 |
+
|
70 |
+
if devices.get_device_for("controlnet").type != 'mps':
|
71 |
+
model = model.to(devices.get_device_for("controlnet"))
|
72 |
+
|
73 |
+
assert input_image.ndim == 3
|
74 |
+
height, width, dim = input_image.shape
|
75 |
+
|
76 |
+
with torch.no_grad():
|
77 |
+
|
78 |
+
if boost:
|
79 |
+
depth = estimateboost(input_image, model, 0, pix2pixmodel, max(width, height))
|
80 |
+
else:
|
81 |
+
depth = estimateleres(input_image, model, width, height)
|
82 |
+
|
83 |
+
numbytes=2
|
84 |
+
depth_min = depth.min()
|
85 |
+
depth_max = depth.max()
|
86 |
+
max_val = (2**(8*numbytes))-1
|
87 |
+
|
88 |
+
# check output before normalizing and mapping to 16 bit
|
89 |
+
if depth_max - depth_min > np.finfo("float").eps:
|
90 |
+
out = max_val * (depth - depth_min) / (depth_max - depth_min)
|
91 |
+
else:
|
92 |
+
out = np.zeros(depth.shape)
|
93 |
+
|
94 |
+
# single channel, 16 bit image
|
95 |
+
depth_image = out.astype("uint16")
|
96 |
+
|
97 |
+
# convert to uint8
|
98 |
+
depth_image = cv2.convertScaleAbs(depth_image, alpha=(255.0/65535.0))
|
99 |
+
|
100 |
+
# remove near
|
101 |
+
if thr_a != 0:
|
102 |
+
thr_a = ((thr_a/100)*255)
|
103 |
+
depth_image = cv2.threshold(depth_image, thr_a, 255, cv2.THRESH_TOZERO)[1]
|
104 |
+
|
105 |
+
# invert image
|
106 |
+
depth_image = cv2.bitwise_not(depth_image)
|
107 |
+
|
108 |
+
# remove bg
|
109 |
+
if thr_b != 0:
|
110 |
+
thr_b = ((thr_b/100)*255)
|
111 |
+
depth_image = cv2.threshold(depth_image, thr_b, 255, cv2.THRESH_TOZERO)[1]
|
112 |
+
|
113 |
+
return depth_image
|