wip, add nsfw option due to perf, still some mypy warnings
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from scripts.configure import check_configuration
|
||||
from scripts.faceswaplab_utils.sd_utils import get_sd_option
|
||||
|
||||
check_configuration()
|
||||
|
||||
@@ -76,7 +77,7 @@ class FaceSwapScript(scripts.Script):
|
||||
|
||||
@property
|
||||
def units_count(self) -> int:
|
||||
return opts.data.get("faceswaplab_units_count", 3)
|
||||
return get_sd_option("faceswaplab_units_count", 3)
|
||||
|
||||
@property
|
||||
def enabled(self) -> bool:
|
||||
@@ -85,7 +86,7 @@ class FaceSwapScript(scripts.Script):
|
||||
|
||||
@property
|
||||
def keep_original_images(self) -> bool:
|
||||
return opts.data.get("faceswaplab_keep_original", False)
|
||||
return get_sd_option("faceswaplab_keep_original", False)
|
||||
|
||||
@property
|
||||
def swap_in_generated_units(self) -> List[FaceSwapUnitSettings]:
|
||||
|
||||
@@ -18,7 +18,7 @@ from scripts.faceswaplab_postprocessing.postprocessing_options import (
|
||||
PostProcessingOptions,
|
||||
)
|
||||
from client_api import api_utils
|
||||
from scripts.faceswaplab_utils.face_checkpoints_utils import (
|
||||
from scripts.faceswaplab_swapping.face_checkpoints import (
|
||||
build_face_checkpoint_and_save,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import os
|
||||
from modules import scripts
|
||||
from modules.shared import opts
|
||||
|
||||
# Defining the absolute path for the 'faceswaplab' directory inside 'models' directory
|
||||
MODELS_DIR = os.path.abspath(os.path.join("models", "faceswaplab"))
|
||||
@@ -21,7 +20,5 @@ VERSION_FLAG: str = "v1.2.2"
|
||||
# Defining the path for 'sd-webui-faceswaplab' inside the 'extensions' directory
|
||||
EXTENSION_PATH = os.path.join("extensions", "sd-webui-faceswaplab")
|
||||
|
||||
# Defining the NSFW score threshold. Any image part with a score above this value will be treated as NSFW (Not Safe For Work)
|
||||
NSFW_SCORE_THRESHOLD: float = opts.data.get("faceswaplab_nsfw_threshold", 0.7) # type: ignore
|
||||
# Defining the expected SHA1 hash value for 'INSWAPPER'
|
||||
EXPECTED_INSWAPPER_SHA1 = "17a64851eaefd55ea597ee41e5c18409754244c5"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
import gradio as gr
|
||||
from client_api import api_utils
|
||||
|
||||
@@ -15,10 +15,10 @@ class InpaintingOptions:
|
||||
|
||||
@staticmethod
|
||||
def from_gradio(components: List[gr.components.Component]) -> "InpaintingOptions":
|
||||
return InpaintingOptions(*components)
|
||||
return InpaintingOptions(*components) # type: ignore
|
||||
|
||||
@staticmethod
|
||||
def from_api_dto(dto: api_utils.InpaintingOptions) -> "InpaintingOptions":
|
||||
def from_api_dto(dto: Optional[api_utils.InpaintingOptions]) -> "InpaintingOptions":
|
||||
"""
|
||||
Converts a InpaintingOptions object from an API DTO (Data Transfer Object).
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from typing import Optional
|
||||
from modules.face_restoration import FaceRestoration
|
||||
from modules.upscaler import UpscalerData
|
||||
from dataclasses import dataclass
|
||||
@@ -27,17 +28,17 @@ class PostProcessingOptions:
|
||||
inpainting_when: InpaintingWhen = InpaintingWhen.BEFORE_UPSCALING
|
||||
|
||||
# (Don't use optional for this or gradio parsing will fail) :
|
||||
inpainting_options: InpaintingOptions = None
|
||||
inpainting_options: InpaintingOptions = None # type: ignore
|
||||
|
||||
@property
|
||||
def upscaler(self) -> UpscalerData:
|
||||
def upscaler(self) -> Optional[UpscalerData]:
|
||||
for upscaler in shared.sd_upscalers:
|
||||
if upscaler.name == self.upscaler_name:
|
||||
return upscaler
|
||||
return None
|
||||
|
||||
@property
|
||||
def face_restorer(self) -> FaceRestoration:
|
||||
def face_restorer(self) -> Optional[FaceRestoration]:
|
||||
for face_restorer in shared.face_restorers:
|
||||
if face_restorer.name() == self.face_restorer_name:
|
||||
return face_restorer
|
||||
|
||||
@@ -17,7 +17,7 @@ def upscale_img(image: PILImage, pp_options: PostProcessingOptions) -> PILImage:
|
||||
pp_options.scale,
|
||||
)
|
||||
result_image = pp_options.upscaler.scaler.upscale(
|
||||
image, pp_options.scale, pp_options.upscaler.data_path
|
||||
image, pp_options.scale, pp_options.upscaler.data_path # type: ignore
|
||||
)
|
||||
|
||||
# FIXME : Could be better (managing images whose dimensions are not multiples of 16)
|
||||
|
||||
@@ -46,6 +46,16 @@ def on_ui_settings() -> None:
|
||||
section=section,
|
||||
),
|
||||
)
|
||||
shared.opts.add_option(
|
||||
"faceswaplab_nsfw_threshold",
|
||||
shared.OptionInfo(
|
||||
0.7,
|
||||
"NSFW score threshold. Any image part with a score above this value will be treated as NSFW (use extension responsibly !)",
|
||||
gr.Slider,
|
||||
{"minimum": 0, "maximum": 1, "step": 0.01},
|
||||
section=section,
|
||||
),
|
||||
)
|
||||
|
||||
shared.opts.add_option(
|
||||
"faceswaplab_det_size",
|
||||
|
||||
+1
-2
@@ -63,7 +63,7 @@ def build_face_checkpoint_and_save(
|
||||
scripts.basedir(), "extensions", "sd-webui-faceswaplab", "references"
|
||||
)
|
||||
|
||||
reference_preview_img: PILImage = None
|
||||
reference_preview_img: PILImage
|
||||
if blended_face:
|
||||
if blended_face["gender"] == 0:
|
||||
reference_preview_img = Image.open(
|
||||
@@ -86,7 +86,6 @@ def build_face_checkpoint_and_save(
|
||||
)
|
||||
else:
|
||||
result = swapper.swap_face(
|
||||
reference_face=blended_face,
|
||||
target_faces=[target_face],
|
||||
source_face=blended_face,
|
||||
target_img=reference_preview_img,
|
||||
@@ -83,7 +83,7 @@ def generate_face_mask(face_image: np.ndarray, device: torch.device) -> np.ndarr
|
||||
convert_bgr_to_rgb=True,
|
||||
use_float32=True,
|
||||
)
|
||||
normalize(face_input, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5), inplace=True)
|
||||
normalize(face_input, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5), inplace=True) # type: ignore
|
||||
assert isinstance(face_input, torch.Tensor)
|
||||
face_input = torch.unsqueeze(face_input, 0).to(device)
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ from scripts.faceswaplab_utils.imgutils import (
|
||||
)
|
||||
from scripts.faceswaplab_utils.faceswaplab_logging import logger, save_img_debug
|
||||
from scripts import faceswaplab_globals
|
||||
from modules.shared import opts
|
||||
from functools import lru_cache
|
||||
from scripts.faceswaplab_ui.faceswaplab_unit_settings import FaceSwapUnitSettings
|
||||
from scripts.faceswaplab_postprocessing.postprocessing import enhance_image
|
||||
@@ -38,12 +37,13 @@ from scripts.faceswaplab_utils.typing import CV2ImgU8, PILImage, Face
|
||||
from scripts.faceswaplab_inpainting.i2i_pp import img2img_diffusion
|
||||
from modules import shared
|
||||
import onnxruntime
|
||||
from scripts.faceswaplab_utils.sd_utils import get_sd_option
|
||||
|
||||
|
||||
def use_gpu() -> bool:
|
||||
return (
|
||||
getattr(shared.cmd_opts, "faceswaplab_gpu", False)
|
||||
or opts.data.get("faceswaplab_use_gpu", False)
|
||||
or get_sd_option("faceswaplab_use_gpu", False)
|
||||
) and sys.platform != "darwin"
|
||||
|
||||
|
||||
@@ -166,6 +166,7 @@ def batch_process(
|
||||
if src_images is not None and len(units) > 0:
|
||||
result_images = []
|
||||
for src_image in src_images:
|
||||
path: str = ""
|
||||
if isinstance(src_image, str):
|
||||
if save_path:
|
||||
path = os.path.join(
|
||||
@@ -182,7 +183,7 @@ def batch_process(
|
||||
swapped_images = process_images_units(
|
||||
get_current_swap_model(), images=[(src_image, None)], units=units
|
||||
)
|
||||
if len(swapped_images) > 0:
|
||||
if swapped_images and len(swapped_images) > 0:
|
||||
current_images += [img for img, _ in swapped_images]
|
||||
|
||||
logger.info("%s images generated", len(current_images))
|
||||
@@ -209,7 +210,7 @@ def extract_faces(
|
||||
images: List[PILImage],
|
||||
extract_path: Optional[str],
|
||||
postprocess_options: PostProcessingOptions,
|
||||
) -> Optional[List[str]]:
|
||||
) -> Optional[List[PILImage]]:
|
||||
"""
|
||||
Extracts faces from a list of image files.
|
||||
|
||||
@@ -232,14 +233,14 @@ def extract_faces(
|
||||
os.makedirs(extract_path, exist_ok=True)
|
||||
|
||||
if images:
|
||||
result_images = []
|
||||
result_images: list[PILImage] = []
|
||||
for img in images:
|
||||
faces = get_faces(pil_to_cv2(img))
|
||||
|
||||
if faces:
|
||||
face_images = []
|
||||
for face in faces:
|
||||
bbox = face.bbox.astype(int)
|
||||
bbox = face.bbox.astype(int) # type: ignore
|
||||
x_min, y_min, x_max, y_max = bbox
|
||||
face_image = img.crop((x_min, y_min, x_max, y_max))
|
||||
|
||||
@@ -370,7 +371,7 @@ def getFaceSwapModel(model_path: str) -> upscaled_inswapper.UpscaledINSwapper:
|
||||
with tqdm(total=1, desc="Loading swap model", unit="model") as pbar:
|
||||
with capture_stdout() as captured:
|
||||
model = upscaled_inswapper.UpscaledINSwapper(
|
||||
insightface.model_zoo.get_model(model_path, providers=providers)
|
||||
insightface.model_zoo.get_model(model_path, providers=providers) # type: ignore
|
||||
)
|
||||
pbar.update(1)
|
||||
logger.info("%s", pformat(captured.getvalue()))
|
||||
@@ -402,11 +403,11 @@ def get_faces(
|
||||
"""
|
||||
|
||||
if det_thresh is None:
|
||||
det_thresh = opts.data.get("faceswaplab_detection_threshold", 0.5)
|
||||
det_thresh = get_sd_option("faceswaplab_detection_threshold", 0.5)
|
||||
|
||||
auto_det_size = opts.data.get("faceswaplab_auto_det_size", True)
|
||||
auto_det_size = get_sd_option("faceswaplab_auto_det_size", True)
|
||||
if not auto_det_size:
|
||||
x = opts.data.get("faceswaplab_det_size", 640)
|
||||
x = get_sd_option("faceswaplab_det_size", 640)
|
||||
det_size = (x, x)
|
||||
|
||||
face_analyser = getAnalysisModel(det_size, det_thresh)
|
||||
@@ -433,7 +434,7 @@ def get_faces(
|
||||
|
||||
try:
|
||||
# Sort the detected faces based on their x-coordinate of the bounding box
|
||||
return sorted(faces, key=lambda x: x.bbox[0])
|
||||
return sorted(faces, key=lambda x: x.bbox[0]) # type: ignore
|
||||
except Exception as e:
|
||||
logger.error("Failed to get faces %s", e)
|
||||
traceback.print_exc()
|
||||
@@ -470,7 +471,7 @@ def filter_faces(
|
||||
filtered_faces = sorted(
|
||||
all_faces,
|
||||
reverse=True,
|
||||
key=lambda x: (x.bbox[2] - x.bbox[0]) * (x.bbox[3] - x.bbox[1]),
|
||||
key=lambda x: (x.bbox[2] - x.bbox[0]) * (x.bbox[3] - x.bbox[1]), # type: ignore
|
||||
)
|
||||
|
||||
if filtering_options.source_gender is not None:
|
||||
@@ -566,7 +567,7 @@ def blend_faces(faces: List[Face]) -> Optional[Face]:
|
||||
ValueError: If the embeddings have different shapes.
|
||||
|
||||
"""
|
||||
embeddings = [face.embedding for face in faces]
|
||||
embeddings: list[Any] = [face.embedding for face in faces]
|
||||
|
||||
if len(embeddings) > 0:
|
||||
embedding_shape = embeddings[0].shape
|
||||
@@ -592,7 +593,6 @@ def blend_faces(faces: List[Face]) -> Optional[Face]:
|
||||
|
||||
|
||||
def swap_face(
|
||||
reference_face: CV2ImgU8,
|
||||
source_face: Face,
|
||||
target_img: PILImage,
|
||||
target_faces: List[Face],
|
||||
@@ -604,7 +604,6 @@ def swap_face(
|
||||
Swaps faces in the target image with the source face.
|
||||
|
||||
Args:
|
||||
reference_face (CV2ImgU8): The reference face used for similarity comparison.
|
||||
source_face (CV2ImgU8): The source face to be swapped.
|
||||
target_img (PILImage): The target image to swap faces in.
|
||||
model (str): Path to the face swap model.
|
||||
@@ -614,7 +613,9 @@ def swap_face(
|
||||
|
||||
"""
|
||||
return_result = ImageResult(target_img, {}, {})
|
||||
target_img_cv2: CV2ImgU8 = cv2.cvtColor(np.array(target_img), cv2.COLOR_RGB2BGR)
|
||||
target_img_cv2: CV2ImgU8 = cv2.cvtColor(
|
||||
np.array(target_img), cv2.COLOR_RGB2BGR
|
||||
).astype("uint8")
|
||||
try:
|
||||
gender = source_face["gender"]
|
||||
logger.info("Source Gender %s", gender)
|
||||
@@ -732,7 +733,6 @@ def process_image_unit(
|
||||
|
||||
save_img_debug(image, "Before swap")
|
||||
result: ImageResult = swap_face(
|
||||
reference_face=reference_face,
|
||||
source_face=src_face,
|
||||
target_img=current_image,
|
||||
target_faces=target_faces,
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
from dataclasses import *
|
||||
from typing import Optional
|
||||
from client_api import api_utils
|
||||
|
||||
|
||||
@dataclass
|
||||
class InswappperOptions:
|
||||
face_restorer_name: str = None
|
||||
face_restorer_name: Optional[str] = None
|
||||
restorer_visibility: float = 1
|
||||
codeformer_weight: float = 1
|
||||
upscaler_name: str = None
|
||||
upscaler_name: Optional[str] = None
|
||||
improved_mask: bool = False
|
||||
color_corrections: bool = False
|
||||
sharpen: bool = False
|
||||
erosion_factor: float = 1.0
|
||||
|
||||
@staticmethod
|
||||
def from_api_dto(dto: api_utils.InswappperOptions) -> "InswappperOptions":
|
||||
def from_api_dto(dto: Optional[api_utils.InswappperOptions]) -> "InswappperOptions":
|
||||
"""
|
||||
Converts a InpaintingOptions object from an API DTO (Data Transfer Object).
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
from typing import Any, Tuple, Union
|
||||
from typing import Any, Optional, Tuple, Union
|
||||
import cv2
|
||||
import numpy as np
|
||||
from insightface.model_zoo.inswapper import INSwapper
|
||||
from insightface.utils import face_align
|
||||
from modules import processing, shared
|
||||
from modules.shared import opts
|
||||
from modules.upscaler import UpscalerData
|
||||
|
||||
from scripts.faceswaplab_postprocessing import upscaling
|
||||
@@ -14,13 +13,14 @@ from scripts.faceswaplab_postprocessing.postprocessing_options import (
|
||||
from scripts.faceswaplab_swapping.facemask import generate_face_mask
|
||||
from scripts.faceswaplab_swapping.upcaled_inswapper_options import InswappperOptions
|
||||
from scripts.faceswaplab_utils.imgutils import cv2_to_pil, pil_to_cv2
|
||||
from scripts.faceswaplab_utils.sd_utils import get_sd_option
|
||||
from scripts.faceswaplab_utils.typing import CV2ImgU8, Face
|
||||
from scripts.faceswaplab_utils.faceswaplab_logging import logger
|
||||
|
||||
|
||||
def get_upscaler() -> UpscalerData:
|
||||
def get_upscaler() -> Optional[UpscalerData]:
|
||||
for upscaler in shared.sd_upscalers:
|
||||
if upscaler.name == opts.data.get(
|
||||
if upscaler.name == get_sd_option(
|
||||
"faceswaplab_upscaled_swapper_upscaler", "LDSR"
|
||||
):
|
||||
return upscaler
|
||||
@@ -130,8 +130,14 @@ class UpscaledINSwapper(INSwapper):
|
||||
self.__dict__.update(inswapper.__dict__)
|
||||
|
||||
def upscale_and_restore(
|
||||
self, img: CV2ImgU8, k: int = 2, inswapper_options: InswappperOptions = None
|
||||
self,
|
||||
img: CV2ImgU8,
|
||||
k: int = 2,
|
||||
inswapper_options: Optional[InswappperOptions] = None,
|
||||
) -> CV2ImgU8:
|
||||
if inswapper_options is None:
|
||||
return img
|
||||
|
||||
pil_img = cv2_to_pil(img)
|
||||
pp_options = PostProcessingOptions(
|
||||
upscaler_name=inswapper_options.upscaler_name,
|
||||
@@ -156,7 +162,7 @@ class UpscaledINSwapper(INSwapper):
|
||||
target_face: Face,
|
||||
source_face: Face,
|
||||
paste_back: bool = True,
|
||||
options: InswappperOptions = None,
|
||||
options: Optional[InswappperOptions] = None,
|
||||
) -> Union[CV2ImgU8, Tuple[CV2ImgU8, Any]]:
|
||||
aimg, M = face_align.norm_crop2(img, target_face.kps, self.input_size[0])
|
||||
blob = cv2.dnn.blobFromImage(
|
||||
@@ -166,9 +172,10 @@ class UpscaledINSwapper(INSwapper):
|
||||
(self.input_mean, self.input_mean, self.input_mean),
|
||||
swapRB=True,
|
||||
)
|
||||
latent = source_face.normed_embedding.reshape((1, -1))
|
||||
latent = source_face.normed_embedding.reshape((1, -1)) # type: ignore
|
||||
latent = np.dot(latent, self.emap)
|
||||
latent /= np.linalg.norm(latent)
|
||||
assert self.session is not None
|
||||
pred = self.session.run(
|
||||
self.output_names, {self.input_names[0]: blob, self.input_names[1]: latent}
|
||||
)[0]
|
||||
@@ -274,7 +281,7 @@ class UpscaledINSwapper(INSwapper):
|
||||
mask_h = np.max(mask_h_inds) - np.min(mask_h_inds)
|
||||
mask_w = np.max(mask_w_inds) - np.min(mask_w_inds)
|
||||
mask_size = int(np.sqrt(mask_h * mask_w))
|
||||
erosion_factor = options.erosion_factor
|
||||
erosion_factor = options.erosion_factor if options else 1
|
||||
|
||||
k = max(int(mask_size // 10 * erosion_factor), int(10 * erosion_factor))
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from typing import List
|
||||
import gradio as gr
|
||||
from modules.shared import opts
|
||||
from modules import sd_models, sd_samplers
|
||||
from scripts.faceswaplab_utils.sd_utils import get_sd_option
|
||||
|
||||
|
||||
def face_inpainting_ui(
|
||||
@@ -19,14 +19,14 @@ def face_inpainting_ui(
|
||||
)
|
||||
|
||||
inpainting_denoising_prompt = gr.Textbox(
|
||||
opts.data.get(
|
||||
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(
|
||||
opts.data.get(
|
||||
get_sd_option(
|
||||
"faceswaplab_pp_default_inpainting_negative_prompt", "blurry"
|
||||
),
|
||||
elem_id=f"{id_prefix}_pp_inpainting_denoising_neg_prompt",
|
||||
|
||||
@@ -2,8 +2,8 @@ from typing import List
|
||||
import gradio as gr
|
||||
import modules
|
||||
from modules import shared, sd_models
|
||||
from modules.shared import opts
|
||||
from scripts.faceswaplab_postprocessing.postprocessing_options import InpaintingWhen
|
||||
from scripts.faceswaplab_utils.sd_utils import get_sd_option
|
||||
|
||||
|
||||
def postprocessing_ui() -> List[gr.components.Component]:
|
||||
@@ -15,7 +15,7 @@ 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: opts.data.get(
|
||||
value=lambda: get_sd_option(
|
||||
"faceswaplab_pp_default_face_restorer",
|
||||
shared.face_restorers[0].name(),
|
||||
),
|
||||
@@ -26,7 +26,7 @@ def postprocessing_ui() -> List[gr.components.Component]:
|
||||
face_restorer_visibility = gr.Slider(
|
||||
0,
|
||||
1,
|
||||
value=lambda: opts.data.get(
|
||||
value=lambda: get_sd_option(
|
||||
"faceswaplab_pp_default_face_restorer_visibility", 1
|
||||
),
|
||||
step=0.001,
|
||||
@@ -36,7 +36,7 @@ def postprocessing_ui() -> List[gr.components.Component]:
|
||||
codeformer_weight = gr.Slider(
|
||||
0,
|
||||
1,
|
||||
value=lambda: opts.data.get(
|
||||
value=lambda: get_sd_option(
|
||||
"faceswaplab_pp_default_face_restorer_weight", 1
|
||||
),
|
||||
step=0.001,
|
||||
@@ -45,7 +45,7 @@ def postprocessing_ui() -> List[gr.components.Component]:
|
||||
)
|
||||
upscaler_name = gr.Dropdown(
|
||||
choices=[upscaler.name for upscaler in shared.sd_upscalers],
|
||||
value=lambda: opts.data.get("faceswaplab_pp_default_upscaler", "None"),
|
||||
value=lambda: get_sd_option("faceswaplab_pp_default_upscaler", "None"),
|
||||
label="Upscaler",
|
||||
elem_id="faceswaplab_pp_upscaler",
|
||||
)
|
||||
@@ -60,7 +60,7 @@ def postprocessing_ui() -> List[gr.components.Component]:
|
||||
upscaler_visibility = gr.Slider(
|
||||
0,
|
||||
1,
|
||||
value=lambda: opts.data.get(
|
||||
value=lambda: get_sd_option(
|
||||
"faceswaplab_pp_default_upscaler_visibility", 1
|
||||
),
|
||||
step=0.1,
|
||||
@@ -87,21 +87,21 @@ def postprocessing_ui() -> List[gr.components.Component]:
|
||||
)
|
||||
|
||||
inpainting_denoising_prompt = gr.Textbox(
|
||||
opts.data.get(
|
||||
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(
|
||||
opts.data.get(
|
||||
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]
|
||||
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]],
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import traceback
|
||||
from pprint import pformat
|
||||
from typing import *
|
||||
from scripts.faceswaplab_swapping import face_checkpoints
|
||||
from scripts.faceswaplab_utils.sd_utils import get_sd_option
|
||||
from scripts.faceswaplab_utils.typing import *
|
||||
import gradio as gr
|
||||
import onnx
|
||||
import pandas as pd
|
||||
from modules.shared import opts
|
||||
from PIL import Image
|
||||
|
||||
import scripts.faceswaplab_swapping.swapper as swapper
|
||||
@@ -15,7 +16,7 @@ from scripts.faceswaplab_postprocessing.postprocessing_options import (
|
||||
from scripts.faceswaplab_ui.faceswaplab_postprocessing_ui import postprocessing_ui
|
||||
from scripts.faceswaplab_ui.faceswaplab_unit_settings import FaceSwapUnitSettings
|
||||
from scripts.faceswaplab_ui.faceswaplab_unit_ui import faceswap_unit_ui
|
||||
from scripts.faceswaplab_utils import face_checkpoints_utils, imgutils
|
||||
from scripts.faceswaplab_utils import imgutils
|
||||
from scripts.faceswaplab_utils.faceswaplab_logging import logger
|
||||
from scripts.faceswaplab_utils.models_utils import get_swap_models
|
||||
from scripts.faceswaplab_utils.ui_utils import dataclasses_from_flat_list
|
||||
@@ -74,7 +75,7 @@ def extract_faces(
|
||||
[PostProcessingOptions], components
|
||||
).pop()
|
||||
images = [
|
||||
Image.open(file.name) for file in files
|
||||
Image.open(file.name) for file in files # type: ignore
|
||||
] # potentially greedy but Image.open is supposed to be lazy
|
||||
result_images = swapper.extract_faces(
|
||||
images, extract_path=extract_path, postprocess_options=postprocess_options
|
||||
@@ -136,7 +137,7 @@ def analyse_faces(image: PILImage, det_threshold: float = 0.5) -> Optional[str]:
|
||||
|
||||
|
||||
def build_face_checkpoint_and_save(
|
||||
batch_files: gr.File, name: str, overwrite: bool
|
||||
batch_files: List[gr.File], name: str, overwrite: bool
|
||||
) -> PILImage:
|
||||
"""
|
||||
Builds a face checkpoint using the provided image files, performs face swapping,
|
||||
@@ -154,16 +155,16 @@ def build_face_checkpoint_and_save(
|
||||
try:
|
||||
if not batch_files:
|
||||
logger.error("No face found")
|
||||
return None
|
||||
images = [Image.open(file.name) for file in batch_files]
|
||||
preview_image = face_checkpoints_utils.build_face_checkpoint_and_save(
|
||||
return None # type: ignore (Optional not really supported by old gradio)
|
||||
images = [Image.open(file.name) for file in batch_files] # type: ignore
|
||||
preview_image = face_checkpoints.build_face_checkpoint_and_save(
|
||||
images, name, overwrite=overwrite
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Failed to build checkpoint %s", e)
|
||||
|
||||
traceback.print_exc()
|
||||
return None
|
||||
return None # type: ignore
|
||||
return preview_image
|
||||
|
||||
|
||||
@@ -197,7 +198,7 @@ def explore_onnx_faceswap_model(model_path: str) -> pd.DataFrame:
|
||||
logger.error("Failed to explore model %s", e)
|
||||
|
||||
traceback.print_exc()
|
||||
return None
|
||||
return None # type: ignore
|
||||
return df
|
||||
|
||||
|
||||
@@ -205,7 +206,7 @@ def batch_process(
|
||||
files: List[gr.File], save_path: str, *components: Tuple[Any, ...]
|
||||
) -> List[PILImage]:
|
||||
try:
|
||||
units_count = opts.data.get("faceswaplab_units_count", 3)
|
||||
units_count = get_sd_option("faceswaplab_units_count", 3)
|
||||
|
||||
classes: List[Any] = dataclasses_from_flat_list(
|
||||
[FaceSwapUnitSettings] * units_count + [PostProcessingOptions],
|
||||
@@ -216,13 +217,16 @@ def batch_process(
|
||||
]
|
||||
postprocess_options = classes[-1]
|
||||
|
||||
images_paths = [file.name for file in files]
|
||||
images_paths = [file.name for file in files] # type: ignore
|
||||
|
||||
return swapper.batch_process(
|
||||
images_paths,
|
||||
save_path=save_path,
|
||||
units=units,
|
||||
postprocess_options=postprocess_options,
|
||||
return (
|
||||
swapper.batch_process(
|
||||
images_paths,
|
||||
save_path=save_path,
|
||||
units=units,
|
||||
postprocess_options=postprocess_options,
|
||||
)
|
||||
or []
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Batch Process error : %s", e)
|
||||
@@ -304,7 +308,7 @@ def tools_ui() -> None:
|
||||
label="Extracted faces",
|
||||
show_label=False,
|
||||
elem_id="faceswaplab_extract_results",
|
||||
).style(columns=[2], rows=[2])
|
||||
)
|
||||
extract_save_path = gr.Textbox(
|
||||
label="Destination Directory",
|
||||
value="",
|
||||
@@ -360,7 +364,7 @@ def tools_ui() -> None:
|
||||
label="Batch result",
|
||||
show_label=False,
|
||||
elem_id="faceswaplab_batch_results",
|
||||
).style(columns=[2], rows=[2])
|
||||
)
|
||||
batch_save_path = gr.Textbox(
|
||||
label="Destination Directory",
|
||||
value="outputs/faceswap/",
|
||||
@@ -370,7 +374,7 @@ def tools_ui() -> None:
|
||||
"Process & Save", elem_id="faceswaplab_extract_btn"
|
||||
)
|
||||
unit_components = []
|
||||
for i in range(1, opts.data.get("faceswaplab_units_count", 3) + 1):
|
||||
for i in range(1, get_sd_option("faceswaplab_units_count", 3) + 1):
|
||||
unit_components += faceswap_unit_ui(False, i, id_prefix="faceswaplab_tab")
|
||||
|
||||
upscale_options = postprocessing_ui()
|
||||
|
||||
@@ -9,7 +9,7 @@ from PIL import Image
|
||||
from scripts.faceswaplab_swapping.upcaled_inswapper_options import InswappperOptions
|
||||
from scripts.faceswaplab_utils.imgutils import pil_to_cv2
|
||||
from scripts.faceswaplab_utils.faceswaplab_logging import logger
|
||||
from scripts.faceswaplab_utils import face_checkpoints_utils
|
||||
from scripts.faceswaplab_swapping import face_checkpoints
|
||||
from scripts.faceswaplab_inpainting.faceswaplab_inpainting import InpaintingOptions
|
||||
from client_api import api_utils
|
||||
|
||||
@@ -124,7 +124,7 @@ class FaceSwapUnitSettings:
|
||||
if self.source_face and self.source_face != "None":
|
||||
try:
|
||||
logger.info(f"loading face {self.source_face}")
|
||||
face = face_checkpoints_utils.load_face(self.source_face)
|
||||
face = face_checkpoints.load_face(self.source_face)
|
||||
self._reference_face = face
|
||||
except Exception as e:
|
||||
logger.error("Failed to load checkpoint : %s", e)
|
||||
@@ -169,7 +169,7 @@ class FaceSwapUnitSettings:
|
||||
if isinstance(file, Image.Image):
|
||||
img = file
|
||||
else:
|
||||
img = Image.open(file.name)
|
||||
img = Image.open(file.name) # type: ignore
|
||||
|
||||
face = swapper.get_or_default(
|
||||
swapper.get_faces(pil_to_cv2(img)), 0, None
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from typing import List
|
||||
from scripts.faceswaplab_ui.faceswaplab_inpainting_ui import face_inpainting_ui
|
||||
from scripts.faceswaplab_utils.face_checkpoints_utils import get_face_checkpoints
|
||||
from scripts.faceswaplab_swapping.face_checkpoints import get_face_checkpoints
|
||||
import gradio as gr
|
||||
from modules.shared import opts
|
||||
from modules import shared
|
||||
from scripts.faceswaplab_utils.sd_utils import get_sd_option
|
||||
|
||||
|
||||
def faceswap_unit_advanced_options(
|
||||
@@ -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: opts.data.get(
|
||||
value=lambda: 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: opts.data.get(
|
||||
value=lambda: 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: opts.data.get(
|
||||
value=lambda: get_sd_option(
|
||||
"faceswaplab_default_upscaled_swapper_face_restorer_weight", 1.0
|
||||
),
|
||||
step=0.001,
|
||||
@@ -48,7 +48,7 @@ def faceswap_unit_advanced_options(
|
||||
)
|
||||
upscaler_name = gr.Dropdown(
|
||||
choices=[upscaler.name for upscaler in shared.sd_upscalers],
|
||||
value=lambda: opts.data.get(
|
||||
value=lambda: get_sd_option(
|
||||
"faceswaplab_default_upscaled_swapper_upscaler", ""
|
||||
),
|
||||
label="Upscaler",
|
||||
@@ -56,7 +56,7 @@ def faceswap_unit_advanced_options(
|
||||
)
|
||||
|
||||
improved_mask = gr.Checkbox(
|
||||
lambda: opts.data.get(
|
||||
lambda: get_sd_option(
|
||||
"faceswaplab_default_upscaled_swapper_improved_mask", False
|
||||
),
|
||||
interactive=True,
|
||||
@@ -64,7 +64,7 @@ def faceswap_unit_advanced_options(
|
||||
elem_id=f"{id_prefix}_face{unit_num}_improved_mask",
|
||||
)
|
||||
color_corrections = gr.Checkbox(
|
||||
lambda: opts.data.get(
|
||||
lambda: get_sd_option(
|
||||
"faceswaplab_default_upscaled_swapper_fixcolor", False
|
||||
),
|
||||
interactive=True,
|
||||
@@ -72,7 +72,7 @@ def faceswap_unit_advanced_options(
|
||||
elem_id=f"{id_prefix}_face{unit_num}_color_corrections",
|
||||
)
|
||||
sharpen_face = gr.Checkbox(
|
||||
lambda: opts.data.get(
|
||||
lambda: get_sd_option(
|
||||
"faceswaplab_default_upscaled_swapper_sharpen", False
|
||||
),
|
||||
interactive=True,
|
||||
@@ -82,7 +82,7 @@ def faceswap_unit_advanced_options(
|
||||
erosion_factor = gr.Slider(
|
||||
0.0,
|
||||
10.0,
|
||||
lambda: opts.data.get("faceswaplab_default_upscaled_swapper_erosion", 1.0),
|
||||
lambda: 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",
|
||||
|
||||
@@ -6,10 +6,10 @@ import numpy as np
|
||||
from math import isqrt, ceil
|
||||
import torch
|
||||
from ifnude import detect
|
||||
from scripts.faceswaplab_globals import NSFW_SCORE_THRESHOLD
|
||||
from modules import processing
|
||||
import base64
|
||||
from collections import Counter
|
||||
from scripts.faceswaplab_utils.sd_utils import get_sd_option
|
||||
from scripts.faceswaplab_utils.typing import BoxCoords, CV2ImgU8, PILImage
|
||||
from scripts.faceswaplab_utils.faceswaplab_logging import logger
|
||||
|
||||
@@ -25,6 +25,12 @@ def check_against_nsfw(img: PILImage) -> bool:
|
||||
bool: True if any part of the image is considered NSFW, False otherwise.
|
||||
"""
|
||||
|
||||
NSFW_SCORE_THRESHOLD = get_sd_option("faceswaplab_nsfw_threshold", 0.7)
|
||||
|
||||
# For testing purpose :
|
||||
if NSFW_SCORE_THRESHOLD >= 1:
|
||||
return False
|
||||
|
||||
shapes: List[bool] = []
|
||||
chunks: List[Dict[str, Union[int, float]]] = detect(img)
|
||||
|
||||
|
||||
@@ -77,4 +77,5 @@ def get_current_swap_model() -> str:
|
||||
raise FileNotFoundError(
|
||||
"No faceswap model found. Please add it to the faceswaplab directory."
|
||||
)
|
||||
assert model is not None
|
||||
return model
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
from typing import Any
|
||||
from modules.shared import opts
|
||||
|
||||
|
||||
def get_sd_option(name: str, default: Any) -> Any:
|
||||
assert opts.data is not None
|
||||
return opts.data.get(name, default)
|
||||
Reference in New Issue
Block a user