diff --git a/CHANGELOG.md b/CHANGELOG.md index ff06be9..3bfde8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,20 @@ # Changelog +### 2023-05-12 + +- v23.5.11 +- `ultralytics` 알람 제거 +- 필요없는 exif 인자 더 제거함 +- `use separate steps` 옵션 추가 +- ui 배치를 조정함 + ### 2023-05-09 - v23.5.10 - 선택한 스크립트만 ADetailer에 적용하는 옵션 추가, 기본값 `True`. 설정 탭에서 지정가능. - 기본값: `dynamic_prompting,dynamic_thresholding,wildcards,wildcard_recursive` - `person_yolov8s-seg.pt` 모델 추가 +- `ultralytics`의 최소 버전을 `8.0.97`로 설정 (C:\\ 문제 해결된 버전) ### 2023-05-08 diff --git a/README.md b/README.md index 36117f7..60aab00 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,21 @@ You **DON'T** need to download any model from huggingface. ## Usage -TO DO +It's auto detecting, masking, and inpainting tool. + +So some options correspond to options on the inpaint tab. + +![image](https://i.imgur.com/f8RFI4w.png) + +Other options: + +| Option | | | +| -------------------------------------- | -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | +| ADetailer model | Determine what to detect. | `None` = disable | +| ADetailer prompt, negative prompt | Prompts and negative prompts to apply | If left blank, it will use the same as the input. | +| Detection model confidence threshold % | Only objects with a detection model confidence above this threshold are used for inpainting. | | +| Mask erosion (-) / dilation (+) | Enlarge or reduce the detected mask. | https://docs.opencv.org/4.7.0/db/df6/tutorial_erosion_dilatation.html | +| Mask x, y offset | Moves the mask horizontally and vertically by pixels. | | ## ControlNet Inpainting @@ -72,3 +86,5 @@ Datasets used for training the yolo models are: ![image](https://i.imgur.com/38RSxSO.png) ![image](https://i.imgur.com/2CYgjLx.png) + +[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/F1F1L7V2N) diff --git a/adetailer/__version__.py b/adetailer/__version__.py index 182fb40..d0eaf54 100644 --- a/adetailer/__version__.py +++ b/adetailer/__version__.py @@ -1 +1 @@ -__version__ = "23.5.10" +__version__ = "23.5.11" diff --git a/adetailer/args.py b/adetailer/args.py index 348290d..f2bb64f 100644 --- a/adetailer/args.py +++ b/adetailer/args.py @@ -33,6 +33,8 @@ _all_args = [ ("ad_use_inpaint_width_height", "ADetailer use inpaint width/height"), ("ad_inpaint_width", "ADetailer inpaint width"), ("ad_inpaint_height", "ADetailer inpaint height"), + ("ad_use_steps", "ADetailer use separate steps"), + ("ad_steps", "ADetailer steps"), ("ad_use_cfg_scale", "ADetailer use separate CFG scale"), ("ad_cfg_scale", "ADetailer CFG scale"), ("ad_controlnet_model", "ADetailer ControlNet model"), @@ -58,6 +60,8 @@ class ADetailerArgs(BaseModel, extra=Extra.forbid): ad_use_inpaint_width_height: bool = False ad_inpaint_width: PositiveInt = 512 ad_inpaint_height: PositiveInt = 512 + ad_use_steps: bool = False + ad_steps: PositiveInt = 28 ad_use_cfg_scale: bool = False ad_cfg_scale: NonNegativeFloat = 7.0 ad_controlnet_model: str = "None" @@ -87,11 +91,25 @@ class ADetailerArgs(BaseModel, extra=Extra.forbid): if not params["ADetailer negative prompt"]: params.pop("ADetailer negative prompt") + if params["ADetailer x offset"] == 0: + params.pop("ADetailer x offset") + if params["ADetailer y offset"] == 0: + params.pop("ADetailer y offset") + + if not params["ADetailer inpaint full"]: + params.pop("ADetailer inpaint padding") + if not params["ADetailer use inpaint width/height"]: + params.pop("ADetailer use inpaint width/height") params.pop("ADetailer inpaint width") params.pop("ADetailer inpaint height") + if not params["ADetailer use separate steps"]: + params.pop("ADetailer use separate steps") + params.pop("ADetailer steps") + if not params["ADetailer use separate CFG scale"]: + params.pop("ADetailer use separate CFG scale") params.pop("ADetailer CFG scale") if params["ADetailer ControlNet model"] == "None": diff --git a/adetailer/ultralytics.py b/adetailer/ultralytics.py index f55883c..fff133b 100644 --- a/adetailer/ultralytics.py +++ b/adetailer/ultralytics.py @@ -1,6 +1,5 @@ from __future__ import annotations -import platform from pathlib import Path from typing import Union @@ -10,8 +9,6 @@ from PIL import Image from adetailer import PredictOutput from adetailer.common import create_mask_from_bbox -checked = False - def ultralytics_predict( model_path: Union[str, Path], @@ -19,15 +16,12 @@ def ultralytics_predict( confidence: float = 0.3, device: str = "", ) -> PredictOutput: - if not checked: - ultralytics_check() - from ultralytics import YOLO model_path = str(model_path) model = YOLO(model_path) - pred = model(image, conf=confidence, show_labels=False, device=device) + pred = model(image, conf=confidence, device=device) bboxes = pred[0].boxes.xyxy.cpu().numpy() if bboxes.size == 0: @@ -45,19 +39,6 @@ def ultralytics_predict( return PredictOutput(bboxes=bboxes, masks=masks, preview=preview) -def ultralytics_check(): - global checked - - checked = True - if platform.system() != "Windows": - return - - p = str(Path.cwd().parent) - if p == "C:\\": - message = "[-] ADetailer: if you get stuck here, try moving the stable-diffusion-webui to a different directory, or try running as administrator." - print(message) - - def mask_to_pil(masks, shape: tuple[int, int]) -> list[Image.Image]: """ Parameters diff --git a/scripts/!adetailer.py b/scripts/!adetailer.py index d37f64f..3058bf0 100644 --- a/scripts/!adetailer.py +++ b/scripts/!adetailer.py @@ -7,6 +7,7 @@ from copy import copy, deepcopy from itertools import zip_longest from pathlib import Path from textwrap import dedent +from typing import Any import gradio as gr import torch @@ -64,7 +65,7 @@ class ChangeTorchLoad: torch.load = self.orig -def gr_show(visible=True): +def gr_show(visible: bool = True): return {"visible": visible, "__type__": "update"} @@ -119,25 +120,26 @@ class AfterDetailerScript(scripts.Script): type="value", ) - with gr.Row(elem_id="AD_toprow_prompt" + suffix(n, "_")): - w[n].ad_prompt = gr.Textbox( - label="ad_prompt" + suffix(n), - show_label=False, - lines=3, - placeholder="ADetailer prompt" + suffix(n), - elem_id="AD_prompt" + suffix(n, "_"), - ) + with gr.Group(): + with gr.Row(elem_id="AD_toprow_prompt" + suffix(n, "_")): + w[n].ad_prompt = gr.Textbox( + label="ad_prompt" + suffix(n), + show_label=False, + lines=3, + placeholder="ADetailer prompt" + suffix(n), + elem_id="AD_prompt" + suffix(n, "_"), + ) - with gr.Row( - elem_id="AD_toprow_negative_prompt" + suffix(n, "_") - ): - w[n].ad_negative_prompt = gr.Textbox( - label="ad_negative_prompt" + suffix(n), - show_label=False, - lines=2, - placeholder="ADetailer negative prompt" + suffix(n), - elem_id="AD_negative_prompt" + suffix(n, "_"), - ) + with gr.Row( + elem_id="AD_toprow_negative_prompt" + suffix(n, "_") + ): + w[n].ad_negative_prompt = gr.Textbox( + label="ad_negative_prompt" + suffix(n), + show_label=False, + lines=2, + placeholder="ADetailer negative prompt" + suffix(n), + elem_id="AD_negative_prompt" + suffix(n, "_"), + ) with gr.Group(): with gr.Row(): @@ -196,86 +198,103 @@ class AfterDetailerScript(scripts.Script): visible=True, ) + with gr.Group(): with gr.Row(): - w[n].ad_inpaint_full_res = gr.Checkbox( - label="Inpaint at full resolution " + suffix(n), - value=True, - visible=True, - ) - w[n].ad_inpaint_full_res_padding = gr.Slider( - label="Inpaint at full resolution padding, pixels " - + suffix(n), - minimum=0, - maximum=256, - step=4, - value=0, - visible=True, - ) + with gr.Column(variant="compact"): + w[n].ad_inpaint_full_res = gr.Checkbox( + label="Inpaint at full resolution " + suffix(n), + value=True, + visible=True, + ) + w[n].ad_inpaint_full_res_padding = gr.Slider( + label="Inpaint at full resolution padding, pixels " + + suffix(n), + minimum=0, + maximum=256, + step=4, + value=0, + visible=True, + ) + + with gr.Column(variant="compact"): + w[n].ad_use_inpaint_width_height = gr.Checkbox( + label="Use separate width/height" + suffix(n), + value=False, + visible=True, + ) + + w[n].ad_inpaint_width = gr.Slider( + label="inpaint width" + suffix(n), + minimum=64, + maximum=2048, + step=4, + value=512, + visible=True, + ) + + w[n].ad_inpaint_height = gr.Slider( + label="inpaint height" + suffix(n), + minimum=64, + maximum=2048, + step=4, + value=512, + visible=True, + ) with gr.Row(): - w[n].ad_use_inpaint_width_height = gr.Checkbox( - label="Use separate width/height" + suffix(n), - value=False, - visible=True, - ) + with gr.Column(variant="compact"): + w[n].ad_use_steps = gr.Checkbox( + label="Use separate steps" + suffix(n), + value=False, + visible=True, + ) - w[n].ad_inpaint_width = gr.Slider( - label="inpaint width" + suffix(n), - minimum=4, - maximum=1024, - step=4, - value=512, - visible=True, - ) + w[n].ad_steps = gr.Slider( + label="ADetailer steps" + suffix(n), + minimum=1, + maximum=150, + step=1, + value=28, + visible=True, + ) - w[n].ad_inpaint_height = gr.Slider( - label="inpaint height" + suffix(n), - minimum=4, - maximum=1024, - step=4, - value=512, - visible=True, - ) + with gr.Column(variant="compact"): + w[n].ad_use_cfg_scale = gr.Checkbox( + label="Use separate CFG scale" + suffix(n), + value=False, + visible=True, + ) - with gr.Row(): - w[n].ad_use_cfg_scale = gr.Checkbox( - label="Use separate CFG scale" + suffix(n), - value=False, - visible=True, - ) - - w[n].ad_cfg_scale = gr.Slider( - label="ADetailer CFG scale" + suffix(n), - minimum=0.0, - maximum=30.0, - step=0.5, - value=7.0, - visible=True, - ) + w[n].ad_cfg_scale = gr.Slider( + label="ADetailer CFG scale" + suffix(n), + minimum=0.0, + maximum=30.0, + step=0.5, + value=7.0, + visible=True, + ) + with gr.Group(), gr.Row(variant="panel"): cn_inpaint_models = ["None"] + get_cn_inpaint_models() - with gr.Group(): - with gr.Row(): - w[n].ad_controlnet_model = gr.Dropdown( - label="ControlNet model" + suffix(n), - choices=cn_inpaint_models, - value="None", - visible=True, - type="value", - interactive=controlnet_exists, - ) + w[n].ad_controlnet_model = gr.Dropdown( + label="ControlNet model" + suffix(n), + choices=cn_inpaint_models, + value="None", + visible=True, + type="value", + interactive=controlnet_exists, + ) - with gr.Row(): - w[n].ad_controlnet_weight = gr.Slider( - label="ControlNet weight" + suffix(n), - minimum=0.0, - maximum=1.0, - step=0.05, - value=1.0, - visible=True, - interactive=controlnet_exists, - ) + w[n].ad_controlnet_weight = gr.Slider( + label="ControlNet weight" + suffix(n), + minimum=0.0, + maximum=1.0, + step=0.05, + value=1.0, + visible=True, + interactive=controlnet_exists, + ) # Accordion end @@ -433,6 +452,11 @@ class AfterDetailerScript(scripts.Script): return width, height + def get_steps(self, p, args: ADetailerArgs) -> int: + if args.ad_use_steps: + return args.ad_steps + return p.steps + def get_cfg_scale(self, p, args: ADetailerArgs) -> float: if args.ad_use_cfg_scale: return args.ad_cfg_scale @@ -479,6 +503,7 @@ class AfterDetailerScript(scripts.Script): prompt, negative_prompt = self.get_prompt(p, args) seed, subseed = self.get_seed(p) width, height = self.get_width_height(p, args) + steps = self.get_steps(p, args) cfg_scale = self.get_cfg_scale(p, args) sampler_name = p.sampler_name @@ -509,7 +534,7 @@ class AfterDetailerScript(scripts.Script): sampler_name=sampler_name, batch_size=1, n_iter=1, - steps=p.steps, + steps=steps, cfg_scale=cfg_scale, width=width, height=height,