23 Commits

Author SHA1 Message Date
Tran Xen 42d1c75b68 Merge pull request #96 from glucauze/v1.2.7
v1.2.7 

    remove dill
    add warnings in model install and checking
    add gender selection in build
2023-09-10 16:06:47 +02:00
Tran Xen bba4845dbf add gender selection in build 2023-09-09 16:25:06 +02:00
Tran Xen c94d2aab4d v1.2.7 2023-09-09 10:51:36 +02:00
Tran Xen 0d0242e0ac Merge pull request #83 from glucauze/v1.2.6
fix inpainting in auto dev version
2023-08-31 14:46:25 +02:00
Tran Xen bf8ef5e9ec fix inpainting in auto dev version 2023-08-30 17:08:33 +02:00
Tran Xen 806086b533 Merge pull request #71 from glucauze/v1.2.5
add seed selection
2023-08-25 10:48:03 +02:00
Tran Xen 38f46d3f01 add seed selection 2023-08-24 23:56:03 +02:00
Tran Xen 9977168136 Merge pull request #68 from glucauze/v1.2.4
V1.2.4 :

Fix default settings by marking only managed field as do_not_save.

See the discussion here : #62
2023-08-24 19:35:23 +02:00
Tran Xen 2e718ee4ae fix default settings by not marking non managed fields as do_not_save 2023-08-24 19:20:31 +02:00
Tran Xen d0c56ae6ef remove override_settings in inpainting i2i_pp.py as they are not supported in some cases, i.e. sdnext for return_mask_composite and cause bugs 2023-08-24 15:47:24 +02:00
Tran Xen c4badb7894 Merge pull request #66 from glucauze/v1.2.3
fix install
2023-08-24 10:02:25 +02:00
Tran Xen 54adcc0fc6 fix install 2023-08-24 09:54:57 +02:00
Tran Xen a6ccd6fd40 Merge pull request #63 from glucauze/v1.2.3
change model link
2023-08-23 18:00:51 +02:00
Tran Xen b11037173b change model link 2023-08-23 18:00:08 +02:00
Tran Xen abdcf4a494 Merge pull request #61 from glucauze/v1.2.3
speed up ui, BREAKING : see changelog
2023-08-23 14:21:52 +02:00
Tran Xen 6ba60f6332 speed up ui, BREAKING : see changelog 2023-08-23 14:16:03 +02:00
Tran Xen 6d69f69509 speed up ui, BREAKING : see changelog 2023-08-23 14:14:21 +02:00
Tran Xen 32eeed8bd7 Merge pull request #57 from glucauze/v1.2.2a
change model url
2023-08-21 22:23:54 +02:00
Tran Xen 7830eb1da9 change model url 2023-08-21 22:21:55 +02:00
Tran Xen d1a82d520d Merge pull request #53 from glucauze/v1.2.2a
remove javascript since it's not really relevant to the extension
2023-08-17 23:51:32 +02:00
Tran Xen aba00ba381 remove javascript, use https://github.com/w-e-w/sdwebui-close-confirmation-dialogue.git instead 2023-08-17 23:46:33 +02:00
Tran Xen 272dca83b8 Merge pull request #49 from glucauze/v1.2.2a
fix bug in improved mask
2023-08-17 12:14:20 +02:00
Tran Xen 04a0a5c46c fix bug in improved mask 2023-08-17 10:41:04 +02:00
26 changed files with 284 additions and 229 deletions
+5 -5
View File
@@ -1,8 +1,4 @@
repos:
- repo: https://github.com/psf/black
rev: 23.7.0
hooks:
- id: black
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
@@ -10,4 +6,8 @@ repos:
- id: check-case-conflict
- id: check-docstring-first
- id: detect-private-key
- id: fix-byte-order-marker
- id: fix-byte-order-marker
- repo: https://github.com/psf/black
rev: 23.7.0
hooks:
- id: black
+26
View File
@@ -1,3 +1,29 @@
# 1.2.5
Allow seed selection in inpainting.
# 1.2.4
Fix default settings by marking only managed field as do_not_save.
See the discussion here : https://github.com/glucauze/sd-webui-faceswaplab/issues/62
# 1.2.3
Speed up ui : change the way default settings are manage by not storing them in ui-config.json
Migration : YOU NEED TO recreate ui-config.json (delete) or at least remove any faceswaplab reference to be able to use default settings again.
See this for explainations : https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/6109
# 1.2.2
+ Add NSFW filter option in settings (1 == disable)
+ Improve install speed
+ Install gpu requirements by default if --use-cpu is not used
+ Fix improved mask + color correction
+ Remove javascript, use https://github.com/w-e-w/sdwebui-close-confirmation-dialogue.git instead to prevent gradio from closing.
# 1.2.1 :
Add GPU support option : see https://github.com/glucauze/sd-webui-faceswaplab/pull/24
+33 -1
View File
@@ -1,6 +1,12 @@
# FaceSwapLab for a1111/Vlad
Please read the documentation here : https://glucauze.github.io/sd-webui-faceswaplab/
V1.2.3 : Breaking change for settings, please read changelog.
Please read the documentation here : https://glucauze.github.io/sd-webui-faceswaplab/
You can also read the [doc discussion section](https://github.com/glucauze/sd-webui-faceswaplab/discussions/categories/guide-doc)
See [CHANGELOG.md](CHANGELOG.md) for changes in last versions.
FaceSwapLab is an extension for Stable Diffusion that simplifies face-swapping. It has evolved from sd-webui-faceswap and some part of sd-webui-roop. However, a substantial amount of the code has been rewritten to improve performance and to better manage masks.
@@ -26,6 +32,32 @@ More on this here : https://glucauze.github.io/sd-webui-faceswaplab/
## Quick Start
Here are some gifs to explain (non cherry picked, just random pictures) :
## Simple Usage (roop like)
This use codeformer on all faces (including non swapped)
[simple.webm](https://github.com/glucauze/sd-webui-faceswaplab/assets/137925069/de00b685-d441-44f9-bae3-71cd7abef113)
## Advanced options
This is use to improve results. This use upscaling and codeformer only on swapped faces
[advanced.webm](https://github.com/glucauze/sd-webui-faceswaplab/assets/137925069/50630311-bd25-487f-871b-0a44eecd435d)
## Inpainting
This add inpainting on faces :
[inpainting.webm](https://github.com/glucauze/sd-webui-faceswaplab/assets/137925069/3d3508e9-5be4-4566-8c41-8301b2d08355)
## Build and use checkpoints :
[build.webm](https://github.com/glucauze/sd-webui-faceswaplab/assets/137925069/e84e9a3c-840d-4536-9fbb-09ed256406d7)
### Simple
1. Put a face in the reference.
+1
View File
@@ -48,6 +48,7 @@ class InpaintingOptions(BaseModel):
inpainting_model: str = Field(
description="Inpainting model", examples=["Current"], default="Current"
)
inpainting_seed: int = Field(description="Inpainting Seed", ge=-1, default=-1)
class InswappperOptions(BaseModel):
Binary file not shown.
+2
View File
@@ -5,6 +5,8 @@ permalink: /doc/
toc: true
---
You can also read the [doc discussion section](https://github.com/glucauze/sd-webui-faceswaplab/discussions/categories/guide-doc)
## TLDR: I Just Want Good Results:
1. Put a face in the reference.
+9 -4
View File
@@ -2,12 +2,11 @@ import launch
import os
import sys
import pkg_resources
from modules import shared
from packaging.version import parse
def check_install() -> None:
use_gpu = not getattr(shared.cmd_opts, "use-cpu", False)
use_gpu = True
if use_gpu and sys.platform != "darwin":
print("Faceswaplab : Use GPU requirements")
@@ -63,5 +62,11 @@ def check_install() -> None:
import timeit
check_time = timeit.timeit(check_install, number=1)
print(check_time)
try:
check_time = timeit.timeit(check_install, number=1)
print(check_time)
except Exception as e:
print("FaceswapLab install failed", e)
print(
"You can try to install dependencies manually by activating venv and installing requirements.txt or requirements-gpu.txt"
)
-4
View File
@@ -1,4 +0,0 @@
window.onbeforeunload = function() {
// Prevent the stable diffusion window from being closed by mistake
return "Are you sure ?";
};
-5
View File
@@ -8,8 +8,3 @@ def preload(parser: ArgumentParser) -> None:
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
help="Set the log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)",
)
parser.add_argument(
"--faceswaplab_gpu",
action="store_true",
help="Enable GPU if set, disable if not set",
)
-1
View File
@@ -1,5 +1,4 @@
cython
dill
ifnude
insightface==0.7.3
onnx>=1.14.0
-1
View File
@@ -1,6 +1,5 @@
protobuf>=3.20.2
cython
dill
ifnude
insightface==0.7.3
onnx>=1.14.0
+21 -16
View File
@@ -20,26 +20,31 @@ def check_configuration() -> None:
models_dir = MODELS_DIR
faces_dir = FACES_DIR
model_url = "https://huggingface.co/henryruhs/roop/resolve/main/inswapper_128.onnx"
model_url = "https://github.com/facefusion/facefusion-assets/releases/download/models/inswapper_128.onnx"
model_name = os.path.basename(model_url)
model_path = os.path.join(models_dir, model_name)
def download(url: str, path: str) -> None:
request = urllib.request.urlopen(url)
total = int(request.headers.get("Content-Length", 0))
with tqdm(
total=total,
desc="Downloading inswapper model",
unit="B",
unit_scale=True,
unit_divisor=1024,
) as progress:
urllib.request.urlretrieve(
url,
path,
reporthook=lambda count, block_size, total_size: progress.update(
block_size
),
try:
request = urllib.request.urlopen(url)
total = int(request.headers.get("Content-Length", 0))
with tqdm(
total=total,
desc="Downloading inswapper model",
unit="B",
unit_scale=True,
unit_divisor=1024,
) as progress:
urllib.request.urlretrieve(
url,
path,
reporthook=lambda count, block_size, total_size: progress.update(
block_size
),
)
except:
logger.error(
"Failed to download inswapper_128.onnx model, please download it manually and put it in the (<sdwebui>/models/faceswaplab/inswapper_128.onnx) directory"
)
os.makedirs(models_dir, exist_ok=True)
+4 -1
View File
@@ -109,7 +109,10 @@ class FaceSwapScript(scripts.Script):
components += faceswaplab_unit_ui.faceswap_unit_ui(is_img2img, i)
post_processing = faceswaplab_tab.postprocessing_ui()
# If the order is modified, the before_process should be changed accordingly.
return components + post_processing
components = components + post_processing
return components
def read_config(
self, p: StableDiffusionProcessing, *components: Tuple[Any, ...]
+1 -1
View File
@@ -16,7 +16,7 @@ REFERENCE_PATH = os.path.join(
)
# Defining the version flag for the application
VERSION_FLAG: str = "v1.2.2"
VERSION_FLAG: str = "v1.2.7"
# Defining the path for 'sd-webui-faceswaplab' inside the 'extensions' directory
EXTENSION_PATH = os.path.join("extensions", "sd-webui-faceswaplab")
@@ -12,6 +12,7 @@ class InpaintingOptions:
inpainting_steps: int = 20
inpainting_sampler: str = "Euler"
inpainting_model: str = "Current"
inpainting_seed: int = -1
@staticmethod
def from_gradio(components: List[gr.components.Component]) -> "InpaintingOptions":
@@ -38,4 +39,5 @@ class InpaintingOptions:
inpainting_steps=dto.inpainting_steps,
inpainting_sampler=dto.inpainting_sampler,
inpainting_model=dto.inpainting_model,
inpainting_seed=dto.inpainting_seed,
)
+4 -10
View File
@@ -52,6 +52,7 @@ inpainting_steps : {options.inpainting_steps}
)
i2i_kwargs = {
"init_images": [img],
"sampler_name": options.inpainting_sampler,
"do_not_save_samples": True,
"steps": options.inpainting_steps,
@@ -63,23 +64,16 @@ inpainting_steps : {options.inpainting_steps}
"prompt": prompt,
"negative_prompt": negative_prompt,
"denoising_strength": options.inpainting_denoising_strengh,
"override_settings": {
"return_mask_composite": False,
"save_images_before_face_restoration": False,
"save_images_before_highres_fix": False,
"save_images_before_color_correction": False,
"save_mask": False,
"save_mask_composite": False,
"samples_save": False,
},
"seed": options.inpainting_seed,
}
current_model_checkpoint = shared.opts.sd_model_checkpoint
if options.inpainting_model and options.inpainting_model != "Current":
# Change checkpoint
shared.opts.sd_model_checkpoint = options.inpainting_model
sd_models.select_checkpoint
sd_models.load_model()
i2i_p = StableDiffusionProcessingImg2Img([img], **i2i_kwargs)
i2i_p = StableDiffusionProcessingImg2Img(**i2i_kwargs)
i2i_processed = processing.process_images(i2i_p)
if options.inpainting_model and options.inpainting_model != "Current":
# Restore checkpoint
@@ -14,7 +14,6 @@ from scripts.faceswaplab_utils import imgutils
from scripts.faceswaplab_utils.models_utils import get_swap_models
import traceback
import dill as pickle # will be removed in future versions
from scripts.faceswaplab_swapping import swapper
from pprint import pformat
import re
@@ -40,6 +39,7 @@ def sanitize_name(name: str) -> str:
def build_face_checkpoint_and_save(
images: List[PILImage],
name: str,
gender: Gender = Gender.AUTO,
overwrite: bool = False,
path: Optional[str] = None,
) -> Optional[PILImage]:
@@ -65,7 +65,7 @@ def build_face_checkpoint_and_save(
logger.error("No source faces found")
return None
blended_face: Optional[Face] = swapper.blend_faces(faces)
blended_face: Optional[Face] = swapper.blend_faces(faces, gender=gender)
preview_path = os.path.join(
scripts.basedir(), "extensions", "sd-webui-faceswaplab", "references"
)
@@ -174,20 +174,13 @@ def load_face(name: str) -> Optional[Face]:
if filename.endswith(".pkl"):
logger.warning(
"Pkl files for faces are deprecated to enhance safety, they will be unsupported in future versions."
"Pkl files for faces are deprecated to enhance safety, you need to convert them"
)
logger.warning("The file will be converted to .safetensors")
logger.warning(
"You can also use this script https://gist.github.com/glucauze/4a3c458541f2278ad801f6625e5b9d3d"
)
with open(filename, "rb") as file:
logger.info("Load pkl")
face = Face(pickle.load(file))
logger.warning(
"Convert to safetensors, you can remove the pkl version once you have ensured that the safetensor is working"
)
save_face(face, filename.replace(".pkl", ".safetensors"))
return face
return None
elif filename.endswith(".safetensors"):
face = {}
+12 -3
View File
@@ -33,7 +33,7 @@ from scripts.faceswaplab_postprocessing.postprocessing_options import (
PostProcessingOptions,
)
from scripts.faceswaplab_utils.models_utils import get_current_swap_model
from scripts.faceswaplab_utils.typing import CV2ImgU8, PILImage, Face
from scripts.faceswaplab_utils.typing import CV2ImgU8, Gender, PILImage, Face
from scripts.faceswaplab_inpainting.i2i_pp import img2img_diffusion
from modules import shared
import onnxruntime
@@ -559,7 +559,7 @@ def get_faces_from_img_files(images: List[PILImage]) -> List[Face]:
return faces
def blend_faces(faces: List[Face]) -> Optional[Face]:
def blend_faces(faces: List[Face], gender: Gender = Gender.AUTO) -> Optional[Face]:
"""
Blends the embeddings of multiple faces into a single face.
@@ -587,10 +587,19 @@ def blend_faces(faces: List[Face]) -> Optional[Face]:
# Compute the mean of all embeddings
blended_embedding = np.mean(embeddings, axis=0)
if gender == Gender.AUTO:
int_gender: int = faces[0].gender # type: ignore
else:
int_gender: int = gender.value
assert -1 < int_gender < 2, "wrong gender"
logger.info("Int Gender : %s", int_gender)
# Create a new Face object using the properties of the first face in the list
# Assign the blended embedding to the blended Face object
blended = ISFace(
embedding=blended_embedding, gender=faces[0].gender, age=faces[0].age
embedding=blended_embedding, gender=int_gender, age=faces[0].age
)
return blended
@@ -216,18 +216,11 @@ class UpscaledINSwapper(INSwapper):
bgr_fake, inswapper_options=options, k=k
)
if options.improved_mask:
if k == 1:
logger.warning(
"Please note that improved mask does not work well without upscaling. Set upscaling to Lanczos at least if you want speed and want to use improved mask."
)
fake_diff: CV2ImgU8 = None # type: ignore
logger.info("improved_mask")
mask = get_face_mask(aimg, bgr_fake)
bgr_fake = merge_images_with_mask(aimg, bgr_fake, mask)
# compute fake_diff before sharpen and color correction (better result)
fake_diff = compute_diff(bgr_fake, aimg)
if not options.improved_mask:
# If improved mask is not used, we should compute before sharpen and color correction (better diff)
fake_diff = compute_diff(bgr_fake, aimg=aimg)
if options.sharpen:
logger.info("sharpen")
@@ -244,6 +237,24 @@ class UpscaledINSwapper(INSwapper):
)
bgr_fake = pil_to_cv2(bgr_fake_pil)
if options.improved_mask:
if k == 1:
logger.warning(
"Please note that improved mask does not work well without upscaling. Set upscaling to Lanczos at least if you want speed and want to use improved mask."
)
logger.info("improved_mask")
mask = get_face_mask(aimg, bgr_fake)
# save_img_debug(cv2_to_pil(bgr_fake), "Before Mask")
bgr_fake = merge_images_with_mask(aimg, bgr_fake, mask)
# save_img_debug(cv2_to_pil(bgr_fake), "After Mask")
fake_diff = compute_diff(bgr_fake, aimg=aimg)
assert (
fake_diff is not None
), "fake diff is None, this should not happen"
logger.info("*" * 80)
else:
@@ -266,6 +277,7 @@ class UpscaledINSwapper(INSwapper):
(target_img.shape[1], target_img.shape[0]),
borderValue=0.0,
)
fake_diff = cv2.warpAffine(
fake_diff,
IM,
@@ -4,65 +4,71 @@ from modules import sd_models, sd_samplers
from scripts.faceswaplab_utils.sd_utils import get_sd_option
def face_inpainting_ui(
name: str, id_prefix: str = "faceswaplab", description: str = ""
) -> List[gr.components.Component]:
with gr.Accordion(name, open=False):
gr.Markdown(description)
inpainting_denoising_strength = gr.Slider(
0,
def face_inpainting_ui(id_prefix: str = "faceswaplab") -> List[gr.components.Component]:
inpainting_denoising_strength = gr.Slider(
0,
1,
0,
step=0.01,
elem_id=f"{id_prefix}_pp_inpainting_denoising_strength",
label="Denoising strenght",
)
inpainting_denoising_prompt = gr.Textbox(
get_sd_option(
"faceswaplab_pp_default_inpainting_prompt", "Portrait of a [gender]"
),
elem_id=f"{id_prefix}_pp_inpainting_denoising_prompt",
label="Inpainting prompt use [gender] instead of men or woman",
)
inpainting_denoising_negative_prompt = gr.Textbox(
get_sd_option("faceswaplab_pp_default_inpainting_negative_prompt", "blurry"),
elem_id=f"{id_prefix}_pp_inpainting_denoising_neg_prompt",
label="Inpainting negative prompt use [gender] instead of men or woman",
)
with gr.Row():
samplers_names = [s.name for s in sd_samplers.all_samplers]
inpainting_sampler = gr.Dropdown(
choices=samplers_names,
value=[samplers_names[0]],
label="Inpainting Sampler",
elem_id=f"{id_prefix}_pp_inpainting_sampler",
)
inpainting_denoising_steps = gr.Slider(
1,
0,
step=0.01,
elem_id=f"{id_prefix}_pp_inpainting_denoising_strength",
label="Denoising strenght",
150,
20,
step=1,
label="Inpainting steps",
elem_id=f"{id_prefix}_pp_inpainting_steps",
)
inpainting_denoising_prompt = gr.Textbox(
get_sd_option(
"faceswaplab_pp_default_inpainting_prompt", "Portrait of a [gender]"
),
elem_id=f"{id_prefix}_pp_inpainting_denoising_prompt",
label="Inpainting prompt use [gender] instead of men or woman",
)
inpainting_denoising_negative_prompt = gr.Textbox(
get_sd_option(
"faceswaplab_pp_default_inpainting_negative_prompt", "blurry"
),
elem_id=f"{id_prefix}_pp_inpainting_denoising_neg_prompt",
label="Inpainting negative prompt use [gender] instead of men or woman",
)
with gr.Row():
samplers_names = [s.name for s in sd_samplers.all_samplers]
inpainting_sampler = gr.Dropdown(
choices=samplers_names,
value=[samplers_names[0]],
label="Inpainting Sampler",
elem_id=f"{id_prefix}_pp_inpainting_sampler",
)
inpainting_denoising_steps = gr.Slider(
1,
150,
20,
step=1,
label="Inpainting steps",
elem_id=f"{id_prefix}_pp_inpainting_steps",
)
inpaiting_model = gr.Dropdown(
choices=["Current"] + sd_models.checkpoint_tiles(),
default="Current",
label="sd model (experimental)",
elem_id=f"{id_prefix}_pp_inpainting_sd_model",
)
inpaiting_model = gr.Dropdown(
choices=["Current"] + sd_models.checkpoint_tiles(),
default="Current",
label="sd model (experimental)",
elem_id=f"{id_prefix}_pp_inpainting_sd_model",
)
inpaiting_seed = gr.Number(
label="Inpainting seed",
value=0,
minimum=0,
precision=0,
elem_id=f"{id_prefix}_pp_inpainting_seed",
)
gradio_components: List[gr.components.Component] = [
inpainting_denoising_strength,
inpainting_denoising_prompt,
inpainting_denoising_negative_prompt,
inpainting_denoising_steps,
inpainting_sampler,
inpaiting_model,
]
gradio_components: List[gr.components.Component] = [
inpainting_denoising_strength,
inpainting_denoising_prompt,
inpainting_denoising_negative_prompt,
inpainting_denoising_steps,
inpainting_sampler,
inpaiting_model,
inpaiting_seed,
]
return gradio_components
for component in gradio_components:
setattr(component, "do_not_save_to_config", True)
return gradio_components
@@ -1,9 +1,9 @@
from typing import List
import gradio as gr
import modules
from modules import shared, sd_models
from modules import shared
from scripts.faceswaplab_postprocessing.postprocessing_options import InpaintingWhen
from scripts.faceswaplab_utils.sd_utils import get_sd_option
from scripts.faceswaplab_ui.faceswaplab_inpainting_ui import face_inpainting_ui
def postprocessing_ui() -> List[gr.components.Component]:
@@ -15,18 +15,19 @@ def postprocessing_ui() -> List[gr.components.Component]:
face_restorer_name = gr.Radio(
label="Restore Face",
choices=["None"] + [x.name() for x in shared.face_restorers],
value=lambda: get_sd_option(
value=get_sd_option(
"faceswaplab_pp_default_face_restorer",
shared.face_restorers[0].name(),
),
type="value",
elem_id="faceswaplab_pp_face_restorer",
)
with gr.Column():
face_restorer_visibility = gr.Slider(
0,
1,
value=lambda: get_sd_option(
value=get_sd_option(
"faceswaplab_pp_default_face_restorer_visibility", 1
),
step=0.001,
@@ -36,7 +37,7 @@ def postprocessing_ui() -> List[gr.components.Component]:
codeformer_weight = gr.Slider(
0,
1,
value=lambda: get_sd_option(
value=get_sd_option(
"faceswaplab_pp_default_face_restorer_weight", 1
),
step=0.001,
@@ -45,7 +46,7 @@ def postprocessing_ui() -> List[gr.components.Component]:
)
upscaler_name = gr.Dropdown(
choices=[upscaler.name for upscaler in shared.sd_upscalers],
value=lambda: get_sd_option("faceswaplab_pp_default_upscaler", "None"),
value=get_sd_option("faceswaplab_pp_default_upscaler", "None"),
label="Upscaler",
elem_id="faceswaplab_pp_upscaler",
)
@@ -60,16 +61,15 @@ def postprocessing_ui() -> List[gr.components.Component]:
upscaler_visibility = gr.Slider(
0,
1,
value=lambda: get_sd_option(
"faceswaplab_pp_default_upscaler_visibility", 1
),
value=get_sd_option("faceswaplab_pp_default_upscaler_visibility", 1),
step=0.1,
label="Upscaler visibility (if scale = 1)",
elem_id="faceswaplab_pp_upscaler_visibility",
)
with gr.Accordion(f"Post Inpainting", open=True):
with gr.Accordion(label="Global-Inpainting (all faces)", open=False):
gr.Markdown(
"""Inpainting sends image to inpainting with a mask on face (once for each faces)."""
"Inpainting sends image to inpainting with a mask on face (once for each faces)."
)
inpainting_when = gr.Dropdown(
elem_id="faceswaplab_pp_inpainting_when",
@@ -77,53 +77,9 @@ def postprocessing_ui() -> List[gr.components.Component]:
value=[InpaintingWhen.BEFORE_RESTORE_FACE.value],
label="Enable/When",
)
inpainting_denoising_strength = gr.Slider(
0,
1,
0,
step=0.01,
elem_id="faceswaplab_pp_inpainting_denoising_strength",
label="Denoising strenght (will send face to img2img after processing)",
)
global_inpainting = face_inpainting_ui("faceswaplab_gpp")
inpainting_denoising_prompt = gr.Textbox(
get_sd_option(
"faceswaplab_pp_default_inpainting_prompt", "Portrait of a [gender]"
),
elem_id="faceswaplab_pp_inpainting_denoising_prompt",
label="Inpainting prompt use [gender] instead of men or woman",
)
inpainting_denoising_negative_prompt = gr.Textbox(
get_sd_option(
"faceswaplab_pp_default_inpainting_negative_prompt", "blurry"
),
elem_id="faceswaplab_pp_inpainting_denoising_neg_prompt",
label="Inpainting negative prompt use [gender] instead of men or woman",
)
with gr.Row():
samplers_names = [s.name for s in modules.sd_samplers.all_samplers] # type: ignore
inpainting_sampler = gr.Dropdown(
choices=samplers_names,
value=[samplers_names[0]],
label="Inpainting Sampler",
elem_id="faceswaplab_pp_inpainting_sampler",
)
inpainting_denoising_steps = gr.Slider(
1,
150,
20,
step=1,
label="Inpainting steps",
elem_id="faceswaplab_pp_inpainting_steps",
)
inpaiting_model = gr.Dropdown(
choices=["Current"] + sd_models.checkpoint_tiles(),
default="Current",
label="sd model (experimental)",
elem_id="faceswaplab_pp_inpainting_sd_model",
)
return [
components = [
face_restorer_name,
face_restorer_visibility,
codeformer_weight,
@@ -131,10 +87,9 @@ def postprocessing_ui() -> List[gr.components.Component]:
upscaler_scale,
upscaler_visibility,
inpainting_when,
inpainting_denoising_strength,
inpainting_denoising_prompt,
inpainting_denoising_negative_prompt,
inpainting_denoising_steps,
inpainting_sampler,
inpaiting_model,
]
] + global_inpainting
# Ask sd to not store in ui-config.json
for component in components:
setattr(component, "do_not_save_to_config", True)
return components
+13 -3
View File
@@ -137,7 +137,7 @@ def analyse_faces(image: PILImage, det_threshold: float = 0.5) -> Optional[str]:
def build_face_checkpoint_and_save(
batch_files: List[gr.File], name: str, overwrite: bool
batch_files: List[gr.File], name: str, str_gender: str, overwrite: bool
) -> PILImage:
"""
Builds a face checkpoint using the provided image files, performs face swapping,
@@ -156,10 +156,13 @@ def build_face_checkpoint_and_save(
if not batch_files:
logger.error("No face found")
return None # type: ignore (Optional not really supported by old gradio)
gender = getattr(Gender, str_gender)
logger.info("Choosen gender : %s", gender)
images: list[PILImage] = [Image.open(file.name) for file in batch_files] # type: ignore
preview_image: PILImage | None = (
face_checkpoints.build_face_checkpoint_and_save(
images=images, name=name, overwrite=overwrite
images=images, name=name, overwrite=overwrite, gender=gender
)
)
except Exception as e:
@@ -266,6 +269,13 @@ def tools_ui() -> None:
label="Name of the character",
elem_id="faceswaplab_build_character_name",
)
build_gender = gr.Dropdown(
value=Gender.AUTO.name,
choices=[e.name for e in Gender],
placeholder="Gender of the character",
label="Gender of the character",
elem_id="faceswaplab_build_character_gender",
)
build_overwrite = gr.Checkbox(
False,
placeholder="overwrite",
@@ -387,7 +397,7 @@ def tools_ui() -> None:
compare_btn.click(compare, inputs=[img1, img2], outputs=[compare_result_text])
generate_checkpoint_btn.click(
build_face_checkpoint_and_save,
inputs=[build_batch_files, build_name, build_overwrite],
inputs=[build_batch_files, build_name, build_gender, build_overwrite],
outputs=[preview],
)
extract_btn.click(
+25 -28
View File
@@ -17,7 +17,7 @@ def faceswap_unit_advanced_options(
face_restorer_name = gr.Radio(
label="Restore Face",
choices=["None"] + [x.name() for x in shared.face_restorers],
value=lambda: get_sd_option(
value=get_sd_option(
"faceswaplab_default_upscaled_swapper_face_restorer",
"None",
),
@@ -28,7 +28,7 @@ def faceswap_unit_advanced_options(
face_restorer_visibility = gr.Slider(
0,
1,
value=lambda: get_sd_option(
value=get_sd_option(
"faceswaplab_default_upscaled_swapper_face_restorer_visibility",
1.0,
),
@@ -39,7 +39,7 @@ def faceswap_unit_advanced_options(
codeformer_weight = gr.Slider(
0,
1,
value=lambda: get_sd_option(
value=get_sd_option(
"faceswaplab_default_upscaled_swapper_face_restorer_weight", 1.0
),
step=0.001,
@@ -48,33 +48,25 @@ def faceswap_unit_advanced_options(
)
upscaler_name = gr.Dropdown(
choices=[upscaler.name for upscaler in shared.sd_upscalers],
value=lambda: get_sd_option(
"faceswaplab_default_upscaled_swapper_upscaler", ""
),
value=get_sd_option("faceswaplab_default_upscaled_swapper_upscaler", ""),
label="Upscaler",
elem_id=f"{id_prefix}_face{unit_num}_upscaler",
)
improved_mask = gr.Checkbox(
lambda: get_sd_option(
"faceswaplab_default_upscaled_swapper_improved_mask", False
),
get_sd_option("faceswaplab_default_upscaled_swapper_improved_mask", False),
interactive=True,
label="Use improved segmented mask (use pastenet to mask only the face)",
elem_id=f"{id_prefix}_face{unit_num}_improved_mask",
)
color_corrections = gr.Checkbox(
lambda: get_sd_option(
"faceswaplab_default_upscaled_swapper_fixcolor", False
),
get_sd_option("faceswaplab_default_upscaled_swapper_fixcolor", False),
interactive=True,
label="Use color corrections",
elem_id=f"{id_prefix}_face{unit_num}_color_corrections",
)
sharpen_face = gr.Checkbox(
lambda: get_sd_option(
"faceswaplab_default_upscaled_swapper_sharpen", False
),
get_sd_option("faceswaplab_default_upscaled_swapper_sharpen", False),
interactive=True,
label="sharpen face",
elem_id=f"{id_prefix}_face{unit_num}_sharpen_face",
@@ -82,13 +74,13 @@ def faceswap_unit_advanced_options(
erosion_factor = gr.Slider(
0.0,
10.0,
lambda: get_sd_option("faceswaplab_default_upscaled_swapper_erosion", 1.0),
get_sd_option("faceswaplab_default_upscaled_swapper_erosion", 1.0),
step=0.01,
label="Upscaled swapper mask erosion factor, 1 = default behaviour.",
elem_id=f"{id_prefix}_face{unit_num}_erosion_factor",
)
return [
components = [
face_restorer_name,
face_restorer_visibility,
codeformer_weight,
@@ -99,6 +91,11 @@ def faceswap_unit_advanced_options(
erosion_factor,
]
for component in components:
setattr(component, "do_not_save_to_config", True)
return components
def faceswap_unit_ui(
is_img2img: bool, unit_num: int = 1, id_prefix: str = "faceswaplab"
@@ -137,7 +134,7 @@ def faceswap_unit_ui(
elem_id=f"{id_prefix}_face{unit_num}_refresh_checkpoints",
)
def refresh_fn(selected: str) -> None:
def refresh_fn(selected: str):
return gr.Dropdown.update(
value=selected, choices=get_face_checkpoints()
)
@@ -252,19 +249,19 @@ Otherwise, read the [doc](https://glucauze.github.io/sd-webui-faceswaplab/doc/)
elem_id=f"{id_prefix}_face{unit_num}_min_ref_similarity",
)
pre_inpainting = face_inpainting_ui(
name="Pre-Inpainting (Before swapping)",
id_prefix=f"{id_prefix}_face{unit_num}_preinpainting",
description="Pre-inpainting sends face to inpainting before swapping",
)
with gr.Accordion(label="Pre-Inpainting (before swapping)", open=False):
gr.Markdown("Pre-inpainting sends face to inpainting before swapping")
pre_inpainting = face_inpainting_ui(
id_prefix=f"{id_prefix}_face{unit_num}_preinpainting",
)
options = faceswap_unit_advanced_options(is_img2img, unit_num, id_prefix)
post_inpainting = face_inpainting_ui(
name="Post-Inpainting (After swapping)",
id_prefix=f"{id_prefix}_face{unit_num}_postinpainting",
description="Post-inpainting sends face to inpainting after swapping",
)
with gr.Accordion(label="Post-Inpainting (After swapping)", open=False):
gr.Markdown("Pre-inpainting sends face to inpainting before swapping")
post_inpainting = face_inpainting_ui(
id_prefix=f"{id_prefix}_face{unit_num}_postinpainting",
)
gradio_components: List[gr.components.Component] = (
[
+2 -1
View File
@@ -5,7 +5,6 @@ import cv2
import numpy as np
from math import isqrt, ceil
import torch
from ifnude import detect
from modules import processing
import base64
from collections import Counter
@@ -31,6 +30,8 @@ def check_against_nsfw(img: PILImage) -> bool:
if NSFW_SCORE_THRESHOLD >= 1:
return False
from ifnude import detect
shapes: List[bool] = []
chunks: List[Dict[str, Union[int, float]]] = detect(img)
+9 -3
View File
@@ -72,10 +72,16 @@ def get_current_swap_model() -> str:
models = get_swap_models()
model = models[0] if len(models) else None
logger.info("Try to use model : %s", model)
if not os.path.isfile(model): # type: ignore
logger.error("The model %s cannot be found or loaded", model)
try:
if not model or not os.path.isfile(model): # type: ignore
logger.error("The model %s cannot be found or loaded", model)
raise FileNotFoundError(
"No faceswap model found. Please add it to the faceswaplab directory. Ensure the model is in the proper directory (<sdwebui>/models/faceswaplab/inswapper_128.onnx)"
)
except:
raise FileNotFoundError(
"No faceswap model found. Please add it to the faceswaplab directory."
"No faceswap model found. Please add it to the faceswaplab directory. Ensure the model is in the proper directory (<sdwebui>/models/faceswaplab/inswapper_128.onnx)"
)
assert model is not None
return model
+7
View File
@@ -3,8 +3,15 @@ from numpy import uint8
from insightface.app.common import Face as IFace
from PIL import Image
import numpy as np
from enum import Enum
PILImage = Image.Image
CV2ImgU8 = np.ndarray[int, np.dtype[uint8]]
Face = IFace
BoxCoords = Tuple[int, int, int, int]
class Gender(Enum):
AUTO = -1
FEMALE = 0
MALE = 1