Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 42d1c75b68 | |||
| bba4845dbf | |||
| c94d2aab4d | |||
| 0d0242e0ac | |||
| bf8ef5e9ec | |||
| 806086b533 | |||
| 38f46d3f01 | |||
| 9977168136 | |||
| 2e718ee4ae | |||
| d0c56ae6ef | |||
| c4badb7894 | |||
| 54adcc0fc6 |
@@ -1,3 +1,13 @@
|
||||
# 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
|
||||
|
||||
@@ -32,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.
|
||||
|
||||
@@ -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.
+9
-4
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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,5 +1,4 @@
|
||||
cython
|
||||
dill
|
||||
ifnude
|
||||
insightface==0.7.3
|
||||
onnx>=1.14.0
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
protobuf>=3.20.2
|
||||
cython
|
||||
dill
|
||||
ifnude
|
||||
insightface==0.7.3
|
||||
onnx>=1.14.0
|
||||
|
||||
+20
-15
@@ -25,21 +25,26 @@ def check_configuration() -> None:
|
||||
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)
|
||||
|
||||
@@ -111,9 +111,6 @@ class FaceSwapScript(scripts.Script):
|
||||
# If the order is modified, the before_process should be changed accordingly.
|
||||
|
||||
components = components + post_processing
|
||||
# Ask sd to not store in ui-config.json
|
||||
for component in components:
|
||||
setattr(component, "do_not_save_to_config", True)
|
||||
|
||||
return components
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ REFERENCE_PATH = os.path.join(
|
||||
)
|
||||
|
||||
# Defining the version flag for the application
|
||||
VERSION_FLAG: str = "v1.2.3"
|
||||
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,
|
||||
)
|
||||
|
||||
@@ -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 = {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]:
|
||||
@@ -66,9 +66,10 @@ def postprocessing_ui() -> List[gr.components.Component]:
|
||||
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",
|
||||
@@ -76,52 +77,8 @@ 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",
|
||||
)
|
||||
components = [
|
||||
face_restorer_name,
|
||||
face_restorer_visibility,
|
||||
@@ -130,13 +87,7 @@ 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:
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -80,7 +80,7 @@ def faceswap_unit_advanced_options(
|
||||
elem_id=f"{id_prefix}_face{unit_num}_erosion_factor",
|
||||
)
|
||||
|
||||
return [
|
||||
components = [
|
||||
face_restorer_name,
|
||||
face_restorer_visibility,
|
||||
codeformer_weight,
|
||||
@@ -91,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"
|
||||
@@ -244,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] = (
|
||||
[
|
||||
@@ -281,10 +286,6 @@ Otherwise, read the [doc](https://glucauze.github.io/sd-webui-faceswaplab/doc/)
|
||||
+ post_inpainting
|
||||
)
|
||||
|
||||
# Ask sd to not store in ui-config.json
|
||||
for component in gradio_components:
|
||||
setattr(component, "do_not_save_to_config", True)
|
||||
|
||||
# If changed, you need to change FaceSwapUnitSettings accordingly
|
||||
# ORDER of parameters is IMPORTANT. It should match the result of FaceSwapUnitSettings
|
||||
return gradio_components
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user