Merge branch 'dev' into main

This commit is contained in:
Dowon
2023-10-15 17:31:17 +09:00
7 changed files with 90 additions and 45 deletions

View File

@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]

View File

@@ -1,5 +1,11 @@
# Changelog
## 2023-10-15
- v23.10.1
- xyz grid에 prompt S/R 추가
- img2img에서 steps가 1일때 에러가 발생하는 샘플러의 처리를 위해 샘플러 이름도 변경하게 수정
## 2023-10-07
- v23.10.0

View File

@@ -1 +1 @@
__version__ = "23.10.0"
__version__ = "23.10.1"

View File

@@ -2,6 +2,7 @@ from __future__ import annotations
from functools import partial
import cv2
import numpy as np
from PIL import Image, ImageDraw
@@ -67,23 +68,6 @@ def mediapipe_face_detection(
return PredictOutput(bboxes=bboxes, masks=masks, preview=preview)
def get_convexhull(points: np.ndarray) -> list[tuple[int, int]]:
"""
Parameters
----------
points: An ndarray of shape (n, 2) containing the 2D points.
Returns
-------
list[tuple[int, int]]: Input for the draw.polygon function
"""
from scipy.spatial import ConvexHull
hull = ConvexHull(points)
vertices = hull.vertices
return list(zip(points[vertices, 0], points[vertices, 1]))
def mediapipe_face_mesh(image: Image.Image, confidence: float = 0.3) -> PredictOutput:
import mediapipe as mp
@@ -114,8 +98,8 @@ def mediapipe_face_mesh(image: Image.Image, confidence: float = 0.3) -> PredictO
connection_drawing_spec=drawing_styles.get_default_face_mesh_tesselation_style(),
)
points = np.array([(land.x * w, land.y * h) for land in landmarks.landmark])
outline = get_convexhull(points)
points = np.intp([(land.x * w, land.y * h) for land in landmarks.landmark])
outline = cv2.convexHull(points).reshape(-1).tolist()
mask = Image.new("L", image.size, "black")
draw = ImageDraw.Draw(mask)
@@ -152,11 +136,11 @@ def mediapipe_face_mesh_eyes_only(
masks = []
for landmarks in pred.multi_face_landmarks:
points = np.array([(land.x * w, land.y * h) for land in landmarks.landmark])
points = np.intp([(land.x * w, land.y * h) for land in landmarks.landmark])
left_eyes = points[left_idx]
right_eyes = points[right_idx]
left_outline = get_convexhull(left_eyes)
right_outline = get_convexhull(right_eyes)
left_outline = cv2.convexHull(left_eyes).reshape(-1).tolist()
right_outline = cv2.convexHull(right_eyes).reshape(-1).tolist()
mask = Image.new("L", image.size, "black")
draw = ImageDraw.Draw(mask)

View File

@@ -217,7 +217,7 @@ def detection(w: Widgets, n: int, is_img2img: bool):
)
w.ad_mask_k_largest = gr.Slider(
label="Mask only the top k largest (0 to disable)" + suffix(n),
minumum=0,
minimum=0,
maximum=10,
step=1,
value=0,

View File

@@ -44,8 +44,8 @@ def run_pip(*args):
def install():
deps = [
# requirements
("ultralytics", "8.0.194", None),
("mediapipe", "0.10.5", None),
("ultralytics", "8.0.198", None),
("mediapipe", "0.10.7", None),
("rich", "13.0.0", None),
# mediapipe
("protobuf", "3.20", "3.9999"),

View File

@@ -10,7 +10,7 @@ from copy import copy, deepcopy
from functools import partial
from pathlib import Path
from textwrap import dedent
from typing import Any
from typing import Any, NamedTuple
import gradio as gr
import torch
@@ -100,6 +100,22 @@ def preseve_prompts(p):
p.all_negative_prompts = all_ng
@contextmanager
def change_skip_img2img_args(p):
if not hasattr(p, "_ad_skip_img2img") or not p._ad_skip_img2img:
yield
else:
steps = p.steps
sampler_name = p.sampler_name
try:
p.steps = p._ad_orig_steps
p.sampler_name = p._ad_orig_sampler_name
yield
finally:
p.steps = steps
p.sampler_name = sampler_name
class AfterDetailerScript(scripts.Script):
def __init__(self):
super().__init__()
@@ -201,7 +217,9 @@ class AfterDetailerScript(scripts.Script):
p._ad_skip_img2img = args_[1]
if args_[1]:
p._ad_orig_steps = p.steps
p._ad_orig_sampler_name = p.sampler_name
p.steps = 1
p.sampler_name = "Euler"
else:
p._ad_skip_img2img = False
@@ -270,7 +288,12 @@ class AfterDetailerScript(scripts.Script):
return all_prompts[j]
def _get_prompt(
self, ad_prompt: str, all_prompts: list[str], i: int, default: str
self,
ad_prompt: str,
all_prompts: list[str],
i: int,
default: str,
replacements: list[PromptSR],
) -> list[str]:
prompts = re.split(r"\s*\[SEP\]\s*", ad_prompt)
blank_replacement = self.prompt_blank_replacement(all_prompts, i, default)
@@ -279,14 +302,22 @@ class AfterDetailerScript(scripts.Script):
prompts[n] = blank_replacement
elif "[PROMPT]" in prompts[n]:
prompts[n] = prompts[n].replace("[PROMPT]", f" {blank_replacement} ")
for pair in replacements:
prompts[n] = prompts[n].replace(pair.s, pair.r)
return prompts
def get_prompt(self, p, args: ADetailerArgs) -> tuple[list[str], list[str]]:
i = p._ad_idx
prompt_sr = p._ad_xyz_prompt_sr if hasattr(p, "_ad_xyz_prompt_sr") else []
prompt = self._get_prompt(args.ad_prompt, p.all_prompts, i, p.prompt)
prompt = self._get_prompt(args.ad_prompt, p.all_prompts, i, p.prompt, prompt_sr)
negative_prompt = self._get_prompt(
args.ad_negative_prompt, p.all_negative_prompts, i, p.negative_prompt
args.ad_negative_prompt,
p.all_negative_prompts,
i,
p.negative_prompt,
prompt_sr,
)
return prompt, negative_prompt
@@ -333,7 +364,11 @@ class AfterDetailerScript(scripts.Script):
return args.ad_cfg_scale if args.ad_use_cfg_scale else p.cfg_scale
def get_sampler(self, p, args: ADetailerArgs) -> str:
return args.ad_sampler if args.ad_use_sampler else p.sampler_name
if args.ad_use_sampler:
return args.ad_sampler
if hasattr(p, "_ad_orig_sampler_name"):
return p._ad_orig_sampler_name
return p.sampler_name
def get_override_settings(self, p, args: ADetailerArgs) -> dict[str, Any]:
d = {}
@@ -371,19 +406,13 @@ class AfterDetailerScript(scripts.Script):
if i % lenp != lenp - 1:
return
prev = None
if hasattr(p, "_ad_orig_steps"):
prev = p.steps
p.steps = p._ad_orig_steps
with change_skip_img2img_args(p):
infotext = self.infotext(p)
infotext = self.infotext(p)
params_txt = Path(data_path, "params.txt")
with suppress(Exception):
params_txt.write_text(infotext, encoding="utf-8")
if hasattr(p, "_ad_orig_steps"):
p.steps = prev
def script_filter(self, p, args: ADetailerArgs):
script_runner = copy(p.scripts)
script_args = deepcopy(p.script_args)
@@ -785,6 +814,27 @@ def on_ui_settings():
# xyz_grid
class PromptSR(NamedTuple):
s: str
r: str
def set_value(p, x: Any, xs: Any, *, field: str):
if not hasattr(p, "_ad_xyz"):
p._ad_xyz = {}
p._ad_xyz[field] = x
def search_and_replace_prompt(p, x: Any, xs: Any, replace_in_main_prompt: bool):
if replace_in_main_prompt:
p.prompt = p.prompt.replace(xs[0], x)
p.negative_prompt = p.negative_prompt.replace(xs[0], x)
if not hasattr(p, "_ad_xyz_prompt_sr"):
p._ad_xyz_prompt_sr = []
p._ad_xyz_prompt_sr.append(PromptSR(s=xs[0], r=x))
def make_axis_on_xyz_grid():
xyz_grid = None
for script in scripts.scripts_data:
@@ -798,11 +848,6 @@ def make_axis_on_xyz_grid():
model_list = ["None", *model_mapping.keys()]
samplers = [sampler.name for sampler in all_samplers]
def set_value(p, x, xs, *, field: str):
if not hasattr(p, "_ad_xyz"):
p._ad_xyz = {}
p._ad_xyz[field] = x
axis = [
xyz_grid.AxisOption(
"[ADetailer] ADetailer model 1st",
@@ -820,6 +865,16 @@ def make_axis_on_xyz_grid():
str,
partial(set_value, field="ad_negative_prompt"),
),
xyz_grid.AxisOption(
"[ADetailer] Prompt S/R (AD 1st)",
str,
partial(search_and_replace_prompt, replace_in_main_prompt=False),
),
xyz_grid.AxisOption(
"[ADetailer] Prompt S/R (AD 1st and main prompt)",
str,
partial(search_and_replace_prompt, replace_in_main_prompt=True),
),
xyz_grid.AxisOption(
"[ADetailer] Mask erosion / dilation 1st",
int,