Compare commits

...

25 Commits
v0.7.0 ... main

Author SHA1 Message Date
Евгений Гурьев | Eugene Gourieff | 古仁
2c6a6e6352 VersionUP
0.7.1 Beta2
2024-10-08 03:40:22 +07:00
Евгений Гурьев | Eugene Gourieff | 古仁
c7b8556856 FIX.1: onnx, onnxruntime-gpu stable versions
Issues: #483 #486 #502 #536 #538 #539
2024-10-08 03:39:49 +07:00
Евгений Гурьев | Eugene Gourieff | 古仁
0458e56cb9 UPDATE: What's new 2024-09-23 15:05:45 +07:00
Евгений Гурьев | Eugene Gourieff | 古仁
17f031356a FIX: Shape check False by default 2024-09-23 14:57:17 +07:00
Евгений Гурьев | Eugene Gourieff | 古仁
58ddc725db VersionUP
0.7.1 Beta1 - Alpha passed
2024-09-23 14:41:14 +07:00
Евгений Гурьев | Eugene Gourieff | 古仁
d74478114f FIX: async fn, fn name 2024-09-23 14:34:19 +07:00
Евгений Гурьев | Eugene Gourieff | 古仁
f680b43100
Merge pull request #438 from KY00KIM/main
UPDATE: Add api-endpoint for building face model
2024-09-15 17:45:30 +07:00
Евгений Гурьев | Eugene Gourieff | 古仁
7298d8650d
Merge pull request #452 from ryanwalder/main
UPDATE: Sort models list alphabetically
2024-09-15 17:44:29 +07:00
Евгений Гурьев | Eugene Gourieff | 古仁
1242914609
Merge pull request #527 from zappityzap/pr-face-index-spaces
UPDATE: Allow using spaces in face index lists
2024-09-15 17:43:59 +07:00
zappityzap
da963b8796 allow using spaces in face index lists 2024-09-14 15:29:05 -07:00
Евгений Гурьев | Eugene Gourieff | 古仁
4493fd7133 FIX: Gradio4 "update" deprecation
Issues: #507 #496 #491
2024-08-19 15:06:39 +07:00
Art Gourieff
613b7d74ea VersionUP
0.7.1 Alpha1
2024-06-26 21:07:09 +07:00
Art Gourieff
1ee4d0e949 Merge branch 'main' into evolve 2024-06-26 21:03:16 +07:00
Art Gourieff
9b0cc02791 Merge branch 'equalize' into evolve 2024-06-26 20:49:55 +07:00
Ryan Walder
ad51f737d1 Sort models list alphabetically 2024-05-16 18:45:24 +01:00
KYOOKIM
d2f6b7d29d Addbuild facemodel api 2024-04-28 08:15:44 +09:00
Art Gourieff
f57c2acc55 Merge branch 'main' into equalize 2024-04-19 11:34:16 +07:00
Eugene Gourieff
be31df8040
Merge pull request #404 from light-and-ray/save_extra_images
UPDATE: Save all images in extras tab
2024-04-07 01:29:51 +07:00
Eugene Gourieff
2b945ae0b2
Merge pull request #403 from light-and-ray/main
UPDATE: Separate single and multiple sources with tabs
2024-04-07 01:28:36 +07:00
Art Gourieff
7633e58182 UPDATE: Old SD.WebUI < 1.7.0 support 2024-04-07 01:25:13 +07:00
Art Gourieff
97598387b1 UPDATE: async api try-1, XYZ init 2024-04-07 01:21:40 +07:00
Art Gourieff
1b706db767 FIX: Insightface default_providers patch 2024-04-07 01:17:13 +07:00
Art Gourieff
8651bc2639 FIX: Typo 2024-04-07 01:16:00 +07:00
Andray
b7b094ba78 save all images in extras tab 2024-03-21 13:28:01 +04:00
Andray
bb3e97c74c separate single and multiple sources with tabs 2024-03-21 12:48:48 +04:00
14 changed files with 260 additions and 115 deletions

16
API.md
View File

@ -83,3 +83,19 @@ A list of available models can be seen by GET:
* http://127.0.0.1:7860/reactor/models
* http://127.0.0.1:7860/reactor/upscalers
* http://127.0.0.1:7860/reactor/facemodels
### FaceModel Buid API
Send POST to http://127.0.0.1:7860/reactor/facemodels with body:
```
{
"source_images": ["data:image/png;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAABQAAD/7g...","data:image/png;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAABQAAD/7g...","data:image/png;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAABQAAD/7g..."],
"name": "my_super_model",
"compute_method": 0
}
```
where:<br>
"source_images" is a list of base64 encoded images,<br>
"compute_method" is: 0 - Mean, 1- Median, 2 - Mode

View File

@ -2,7 +2,7 @@
<img src="https://github.com/Gourieff/Assets/raw/main/sd-webui-reactor/ReActor_logo_NEW_EN.png?raw=true" alt="logo" width="180px"/>
![Version](https://img.shields.io/badge/version-0.7.0-lightgreen?style=for-the-badge&labelColor=darkgreen)
![Version](https://img.shields.io/badge/version-0.7.1_beta2-green?style=for-the-badge&labelColor=darkgreen)
<a href="https://boosty.to/artgourieff" target="_blank">
<img src="https://lovemet.ru/www/boosty.jpg" width="108" alt="Support Me on Boosty"/>
@ -40,8 +40,15 @@
## What's new in the latest updates
### 0.7.1 <sub><sup>BETA1
- Allow spaces for face indexes (e.g.: 0, 1, 2)
- Sorting of face models list alphabetically
- [FaceModels Build API](./API.md#facemodel-build-api)
- Fixes and improvements
<details>
<summary><a>Click to expand</a></summary>
<summary><a>Click to expand more</a></summary>
### 0.7.0 <sub><sup>BETA2

View File

@ -2,7 +2,7 @@
<img src="https://github.com/Gourieff/Assets/raw/main/sd-webui-reactor/ReActor_logo_NEW_RU.png?raw=true" alt="logo" width="180px"/>
![Version](https://img.shields.io/badge/версия-0.7.0-lightgreen?style=for-the-badge&labelColor=darkgreen)
![Version](https://img.shields.io/badge/версия-0.7.1_beta2-green?style=for-the-badge&labelColor=darkgreen)
<a href="https://boosty.to/artgourieff" target="_blank">
<img src="https://lovemet.ru/www/boosty.jpg" width="108" alt="Поддержать проект на Boosty"/>
@ -39,8 +39,15 @@
## Что нового в последних обновлениях
### 0.7.1 <sub><sup>BETA1
- Использование пробелов в индексах лиц (пример: 0, 1, 2)
- Список моделей лиц теперь отсортирован по алфавиту
- [API для создания моделей лиц](./API.md#facemodel-build-api)
- Правки и улучшения
<details>
<summary><a>Нажмите, чтобы посмотреть</a></summary>
<summary><a>Нажмите, чтобы посмотреть больше</a></summary>
### 0.7.0 <sub><sup>BETA2

View File

@ -21,20 +21,6 @@ req_file = os.path.join(BASE_PATH, "requirements.txt")
models_dir = os.path.join(models_path, "insightface")
# DEPRECATED:
# models_dir_old = os.path.join(models_path, "roop")
# if os.path.exists(models_dir_old):
# if not os.listdir(models_dir_old) and (not os.listdir(models_dir) or not os.path.exists(models_dir)):
# os.rename(models_dir_old, models_dir)
# else:
# import shutil
# for file in os.listdir(models_dir_old):
# shutil.move(os.path.join(models_dir_old, file), os.path.join(models_dir, file))
# try:
# os.rmdir(models_dir_old)
# except Exception as e:
# print(f"OSError: {e}")
model_url = "https://huggingface.co/datasets/Gourieff/ReActor/resolve/main/models/inswapper_128.onnx"
model_name = os.path.basename(model_url)
model_path = os.path.join(models_dir, model_name)
@ -117,12 +103,17 @@ with open(req_file) as file:
last_device = "CPU"
with open(os.path.join(BASE_PATH, "last_device.txt"), "w") as txt:
txt.write(last_device)
if cuda_version is not None and float(cuda_version)>=12: # CU12
if not is_installed(ort,"1.17.1",False):
if cuda_version is not None:
if float(cuda_version)>=12: # CU12.x
extra_index_url = "https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/"
else: # CU11.8
extra_index_url = "https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-11/pypi/simple"
if not is_installed(ort,"1.17.1",True):
install_count += 1
ort = "onnxruntime-gpu==1.17.1"
pip_uninstall("onnxruntime", "onnxruntime-gpu")
pip_install(ort,"--extra-index-url","https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/")
elif not is_installed(ort,"1.16.1",False):
pip_install(ort,"--extra-index-url",extra_index_url)
elif not is_installed(ort,"1.18.1",False):
install_count += 1
pip_install(ort, "-U")
except Exception as e:

View File

@ -11,9 +11,14 @@ from modules import shared
# SAVE_ORIGINAL: bool = False
def update_fm_list(selected: str):
return gr.Dropdown.update(
value=selected, choices=get_model_names(get_facemodels)
)
try: # GR3.x
return gr.Dropdown.update(
value=selected, choices=get_model_names(get_facemodels)
)
except: # GR4.x
return gr.Dropdown(
value=selected, choices=get_model_names(get_facemodels)
)
# TAB MAIN
def show(is_img2img: bool, show_br: bool = True, **msgs):
@ -24,29 +29,56 @@ def show(is_img2img: bool, show_br: bool = True, **msgs):
if evt.index == 2:
# if SAVE_ORIGINAL != selected:
# SAVE_ORIGINAL = selected
return {
control_col_1: gr.Column.update(visible=False),
control_col_2: gr.Column.update(visible=False),
control_col_3: gr.Column.update(visible=True),
# save_original: gr.Checkbox.update(value=False,visible=False),
imgs_hash_clear: gr.Button.update(visible=True)
}
try: # GR3.x
return {
control_col_1: gr.Column.update(visible=False),
control_col_2: gr.Column.update(visible=False),
control_col_3: gr.Column.update(visible=True),
# save_original: gr.Checkbox.update(value=False,visible=False),
imgs_hash_clear: gr.Button.update(visible=True)
}
except: # GR4.x
return {
control_col_1: gr.Column(visible=False),
control_col_2: gr.Column(visible=False),
control_col_3: gr.Column(visible=True),
# save_original: gr.Checkbox.update(value=False,visible=False),
imgs_hash_clear: gr.Button(visible=True)
}
if evt.index == 0:
return {
control_col_1: gr.Column.update(visible=True),
control_col_2: gr.Column.update(visible=False),
control_col_3: gr.Column.update(visible=False),
# save_original: gr.Checkbox.update(value=SAVE_ORIGINAL,visible=show_br),
imgs_hash_clear: gr.Button.update(visible=False)
}
try: # GR3.x
return {
control_col_1: gr.Column.update(visible=True),
control_col_2: gr.Column.update(visible=False),
control_col_3: gr.Column.update(visible=False),
# save_original: gr.Checkbox.update(value=SAVE_ORIGINAL,visible=show_br),
imgs_hash_clear: gr.Button.update(visible=False)
}
except: # GR4.x
return {
control_col_1: gr.Column(visible=True),
control_col_2: gr.Column(visible=False),
control_col_3: gr.Column(visible=False),
# save_original: gr.Checkbox.update(value=SAVE_ORIGINAL,visible=show_br),
imgs_hash_clear: gr.Button(visible=False)
}
if evt.index == 1:
return {
control_col_1: gr.Column.update(visible=False),
control_col_2: gr.Column.update(visible=True),
control_col_3: gr.Column.update(visible=False),
# save_original: gr.Checkbox.update(value=SAVE_ORIGINAL,visible=show_br),
imgs_hash_clear: gr.Button.update(visible=False)
}
try: # GR3.x
return {
control_col_1: gr.Column.update(visible=False),
control_col_2: gr.Column.update(visible=True),
control_col_3: gr.Column.update(visible=False),
# save_original: gr.Checkbox.update(value=SAVE_ORIGINAL,visible=show_br),
imgs_hash_clear: gr.Button.update(visible=False)
}
except: # GR4.x
return {
control_col_1: gr.Column(visible=False),
control_col_2: gr.Column(visible=True),
control_col_3: gr.Column(visible=False),
# save_original: gr.Checkbox.update(value=SAVE_ORIGINAL,visible=show_br),
imgs_hash_clear: gr.Button(visible=False)
}
progressbar_area = gr.Markdown("")
with gr.Tab("Main"):
@ -85,16 +117,21 @@ def show(is_img2img: bool, show_br: bool = True, **msgs):
imgs_hash_clear.click(clear_faces_list,None,[progressbar_area])
gr.Markdown("<br>", visible=show_br)
with gr.Column(visible=True) as control_col_1:
gr.Markdown("<center>🔽🔽🔽 Single Image has priority when both Areas in use 🔽🔽🔽</center>")
with gr.Row():
img = gr.Image(
type="pil",
label="Single Source Image",
)
imgs = gr.Files(
label=f"Multiple Source Images{msgs['extra_multiple_source']}",
file_types=["image"],
)
selected_tab = gr.Textbox('tab_single', visible=False)
with gr.Tabs() as tab_single:
with gr.Tab('Single'):
img = gr.Image(
type="pil",
label="Single Source Image",
)
with gr.Tab('Multiple') as tab_multiple:
imgs = gr.Files(
label=f"Multiple Source Images{msgs['extra_multiple_source']}",
file_types=["image"],
)
tab_single.select(fn=lambda: 'tab_single', inputs=[], outputs=[selected_tab])
tab_multiple.select(fn=lambda: 'tab_multiple', inputs=[], outputs=[selected_tab])
with gr.Column(visible=False) as control_col_3:
gr.Markdown("<span style='display:block;text-align:right;padding-right:3px;margin: -15px 0;font-size:1.1em'><sup>Clear Hash if you see the previous face was swapped instead of the new one</sup></span>")
with gr.Row():
@ -189,4 +226,4 @@ def show(is_img2img: bool, show_br: bool = True, **msgs):
# select_source.select(on_select_source,[save_original],[control_col_1,control_col_2,control_col_3,save_original,imgs_hash_clear],show_progress=False)
select_source.select(on_select_source,None,[control_col_1,control_col_2,control_col_3,imgs_hash_clear],show_progress=False)
return img, imgs, select_source, face_model, source_folder, save_original, mask_face, source_faces_index, gender_source, faces_index, gender_target, face_restorer_name, face_restorer_visibility, codeformer_weight, swap_in_source, swap_in_generated, random_image
return img, imgs, selected_tab, select_source, face_model, source_folder, save_original, mask_face, source_faces_index, gender_source, faces_index, gender_target, face_restorer_name, face_restorer_visibility, codeformer_weight, swap_in_source, swap_in_generated, random_image

View File

@ -39,7 +39,7 @@ def show():
value="Mean",
label="Compute Method",
type="index",
info="Mean (recommended) - Average value (best result 👍); Median* - Mid-point value (may be funny 😅); Mode - Most common value (may be scary 😨); *Mean and Median will be simillar if you load two images"
info="Mean (recommended) - Average value (best result 👍); Median* - Mid-point value (may be funny 😅); Mode - Most common value (may be scary 😨); *Mean and Median will be similar if you load two images"
)
shape_check = gr.Checkbox(
False,

View File

@ -1,4 +1,4 @@
albumentations==1.4.3
insightface==0.7.3
onnx>=1.14.0
onnx==1.16.1
opencv-python>=4.7.0.72

View File

@ -2,7 +2,7 @@ import os.path as osp
import glob
import logging
import insightface
from insightface.model_zoo.model_zoo import ModelRouter, PickableInferenceSession
from insightface.model_zoo.model_zoo import ModelRouter, PickableInferenceSession, get_default_providers
from insightface.model_zoo.retinaface import RetinaFace
from insightface.model_zoo.landmark import Landmark
from insightface.model_zoo.attribute import Attribute
@ -97,15 +97,20 @@ def patched_inswapper_init(self, model_file=None, session=None):
self.input_size = tuple(input_shape[2:4][::-1])
def patch_insightface(get_model, faceanalysis_init, faceanalysis_prepare, inswapper_init):
def patched_get_default_providers():
return ['TensorrtExecutionProvider', 'CUDAExecutionProvider', 'CPUExecutionProvider']
def patch_insightface(get_default_providers, get_model, faceanalysis_init, faceanalysis_prepare, inswapper_init):
insightface.model_zoo.model_zoo.get_default_providers = get_default_providers
insightface.model_zoo.model_zoo.ModelRouter.get_model = get_model
insightface.app.FaceAnalysis.__init__ = faceanalysis_init
insightface.app.FaceAnalysis.prepare = faceanalysis_prepare
insightface.model_zoo.inswapper.INSwapper.__init__ = inswapper_init
original_functions = [ModelRouter.get_model, FaceAnalysis.__init__, FaceAnalysis.prepare, INSwapper.__init__]
patched_functions = [patched_get_model, patched_faceanalysis_init, patched_faceanalysis_prepare, patched_inswapper_init]
original_functions = [patched_get_default_providers, ModelRouter.get_model, FaceAnalysis.__init__, FaceAnalysis.prepare, INSwapper.__init__]
patched_functions = [patched_get_default_providers, patched_get_model, patched_faceanalysis_init, patched_faceanalysis_prepare, patched_inswapper_init]
def apply_logging_patch(console_logging_level):

View File

@ -1,7 +1,7 @@
'''
Thanks SpenserCai for the original version of the roop api script
-----------------------------------
--- ReActor External API v1.0.7 ---
--- ReActor External API v1.0.8a ---
-----------------------------------
'''
import os, glob
@ -13,6 +13,11 @@ from fastapi import FastAPI, Body
# import base64
# import numpy as np
# import cv2
import asyncio
from concurrent.futures import ThreadPoolExecutor
# from concurrent.futures.process import ProcessPoolExecutor
# from contextlib import asynccontextmanager
# import multiprocessing
# from modules.api.models import *
from modules import scripts, shared
@ -20,18 +25,32 @@ from modules.api import api
import gradio as gr
from scripts.reactor_swapper import EnhancementOptions, swap_face, DetectionOptions
from scripts.reactor_swapper import EnhancementOptions, blend_faces, swap_face, DetectionOptions
from scripts.reactor_logger import logger
from scripts.reactor_helpers import get_facemodels
# XYZ init:
from scripts.reactor_xyz import run
try:
import modules.script_callbacks as script_callbacks
script_callbacks.on_before_ui(run)
# script_callbacks.on_app_started(reactor_api)
except:
pass
# @asynccontextmanager
# async def lifespan(app: FastAPI):
# app.state.executor = ProcessPoolExecutor(max_workers=4)
# yield
# app.state.executor.shutdown()
# app = FastAPI(lifespan=lifespan)
# def run_app(a: FastAPI):
# global app
# a = app
# return a
# _executor_tp = ThreadPoolExecutor(max_workers=8)
# def entry_point():
# _executor_pp = ProcessPoolExecutor(max_workers=8)
# pool = multiprocessing.Pool(4)
async def run_event(app, fn, *args):
loop = asyncio.get_event_loop()
return await loop.run_in_executor(app.state.executor, fn, *args)
def default_file_path():
@ -82,6 +101,7 @@ def get_full_model(model_name):
# raise HTTPException(status_code=500, detail="Invalid encoded image") from e
def reactor_api(_: gr.Blocks, app: FastAPI):
app.state.executor = ThreadPoolExecutor(max_workers=8)
@app.post("/reactor/image")
async def reactor_image(
source_image: str = Body("",title="Source Face Image"),
@ -131,22 +151,26 @@ def reactor_api(_: gr.Blocks, app: FastAPI):
use_model = get_full_model(model)
if use_model is None:
Exception("Model not found")
result = swap_face(s_image, t_image, use_model, sf_index, f_index, up_options, gender_s, gender_t, True, True, device, mask_face, select_source, face_model, source_folder, None, random_image,det_options)
result_img = result[0]
args = [s_image, t_image, use_model, sf_index, f_index, up_options, gender_s, gender_t, True, True, device, mask_face, select_source, face_model, source_folder, None, random_image,det_options]
# result,_,_ = pool.map(swap_face, *args)
result,_,_ = await run_event(app,swap_face,*args)
# result,_,_ = swap_face(s_image, t_image, use_model, sf_index, f_index, up_options, gender_s, gender_t, True, True, device, mask_face, select_source, face_model, source_folder, None, random_image,det_options)
if alpha is not None:
result_img = result_img.convert("RGBA")
result_img.putalpha(alpha)
result = result.convert("RGBA")
result.putalpha(alpha)
if save_to_file == 1:
if result_file_path == "":
result_file_path = default_file_path()
try:
result_img.save(result_file_path, format='PNG')
file_format = os.path.split(result_file_path)[1].split(".")[1]
result.save(result_file_path, format=file_format)
logger.status("Result has been saved to: %s", result_file_path)
except Exception as e:
logger.error("Error while saving result: %s",e)
return {"image": api.encode_pil_to_base64(result_img)}
return {"image": api.encode_pil_to_base64(result)}
@app.get("/reactor/models")
async def reactor_models():
@ -163,9 +187,18 @@ def reactor_api(_: gr.Blocks, app: FastAPI):
facemodels = [os.path.split(model)[1].split(".")[0] for model in get_facemodels()]
return {"facemodels": facemodels}
@app.post("/reactor/facemodels")
async def reactor_facemodels_build(
source_images: list[str] = Body([""],title="Source Face Image List"),
name: str = Body("",title="Face Model Name"),
compute_method: int = Body(0,title="Compute Method (Mean, Median, Mode)"),
):
images = [api.decode_base64_to_image(img) for img in source_images]
blend_faces(images, name, compute_method, False, is_api=True)
return {"facemodels": [os.path.split(model)[1].split(".")[0] for model in get_facemodels()]}
try:
import modules.script_callbacks as script_callbacks
script_callbacks.on_app_started(reactor_api)
except:
pass

View File

@ -6,7 +6,7 @@ from typing import List
import modules.scripts as scripts
from modules.upscaler import Upscaler, UpscalerData
from modules import scripts, shared, images, scripts_postprocessing, ui_components
from modules import scripts, shared, images, scripts_postprocessing
from modules.processing import (
Processed,
StableDiffusionProcessing,
@ -39,6 +39,20 @@ from scripts.reactor_helpers import (
)
from scripts.reactor_globals import SWAPPER_MODELS_PATH #, DEVICE, DEVICE_LIST
def IA_cap(cond: bool, label: str=""):
return None
try:
from modules.ui_components import InputAccordion
NO_IA = False
except:
NO_IA = True
InputAccordion = IA_cap
def check_old_webui():
return NO_IA
class FaceSwapScript(scripts.Script):
def title(self):
@ -48,19 +62,12 @@ class FaceSwapScript(scripts.Script):
return scripts.AlwaysVisible
def ui(self, is_img2img):
with ui_components.InputAccordion(False, label=f"{app_title}") as enable:
# with gr.Accordion(f"{app_title}", open=False):
with (
gr.Accordion(f"{app_title}", open=False) if check_old_webui() else InputAccordion(False, label=f"{app_title}") as enable
):
# def on_files_upload_uncheck_so(selected: bool):
# global SAVE_ORIGINAL
# SAVE_ORIGINAL = selected
# return gr.Checkbox.update(value=False,visible=False)
# def on_files_clear():
# clear_faces_list()
# return gr.Checkbox.update(value=SAVE_ORIGINAL,visible=True)
# SD.Next fix
if get_SDNEXT():
# SD.Next or A1111 1.52:
if get_SDNEXT() or check_old_webui():
enable = gr.Checkbox(False, label="Enable")
# enable = gr.Checkbox(False, label="Enable", info=f"The Fast and Simple FaceSwap Extension - {version_flag}")
@ -70,7 +77,7 @@ class FaceSwapScript(scripts.Script):
msgs: dict = {
"extra_multiple_source": "",
}
img, imgs, select_source, face_model, source_folder, save_original, mask_face, source_faces_index, gender_source, faces_index, gender_target, face_restorer_name, face_restorer_visibility, codeformer_weight, swap_in_source, swap_in_generated, random_image = ui_main.show(is_img2img=is_img2img, **msgs)
img, imgs, selected_tab, select_source, face_model, source_folder, save_original, mask_face, source_faces_index, gender_source, faces_index, gender_target, face_restorer_name, face_restorer_visibility, codeformer_weight, swap_in_source, swap_in_generated, random_image = ui_main.show(is_img2img=is_img2img, **msgs)
# TAB DETECTION
det_thresh, det_maxnum = ui_detection.show()
@ -116,7 +123,8 @@ class FaceSwapScript(scripts.Script):
random_image,
upscale_force,
det_thresh,
det_maxnum
det_maxnum,
selected_tab,
]
@ -186,7 +194,8 @@ class FaceSwapScript(scripts.Script):
random_image,
upscale_force,
det_thresh,
det_maxnum
det_maxnum,
selected_tab,
):
self.enable = enable
if self.enable:
@ -198,7 +207,10 @@ class FaceSwapScript(scripts.Script):
return
global SWAPPER_MODELS_PATH
self.source = img
if selected_tab == "tab_single":
self.source = img
else:
self.source = None
self.face_restorer_name = face_restorer_name
self.upscaler_scale = upscaler_scale
self.upscaler_visibility = upscaler_visibility
@ -220,7 +232,10 @@ class FaceSwapScript(scripts.Script):
self.select_source = select_source
self.face_model = face_model
self.source_folder = source_folder
self.source_imgs = imgs
if selected_tab == "tab_single":
self.source_imgs = None
else:
self.source_imgs = imgs
self.random_image = random_image
self.upscale_force = upscale_force
self.det_thresh=det_thresh
@ -230,10 +245,10 @@ class FaceSwapScript(scripts.Script):
if self.gender_target is None or self.gender_target == "No":
self.gender_target = 0
self.source_faces_index = [
int(x) for x in source_faces_index.strip(",").split(",") if x.isnumeric()
int(x) for x in source_faces_index.strip().replace(" ", "").strip(",").split(",") if x.isnumeric()
]
self.faces_index = [
int(x) for x in faces_index.strip(",").split(",") if x.isnumeric()
int(x) for x in faces_index.strip().replace(" ", "").strip(",").split(",") if x.isnumeric()
]
if len(self.source_faces_index) == 0:
self.source_faces_index = [0]
@ -488,11 +503,14 @@ class FaceSwapScriptExtras(scripts_postprocessing.ScriptPostprocessing):
order = 20000
def ui(self):
with ui_components.InputAccordion(False, label=f"{app_title}") as enable:
with (
gr.Accordion(f"{app_title}", open=False) if check_old_webui() else InputAccordion(False, label=f"{app_title}") as enable
):
# with ui_components.InputAccordion(False, label=f"{app_title}") as enable:
# with gr.Accordion(f"{app_title}", open=False):
# SD.Next fix
if get_SDNEXT():
# SD.Next or A1111 1.52:
if get_SDNEXT() or check_old_webui():
enable = gr.Checkbox(False, label="Enable")
# enable = gr.Checkbox(False, label="Enable", info=f"The Fast and Simple FaceSwap Extension - {version_flag}")
@ -500,9 +518,9 @@ class FaceSwapScriptExtras(scripts_postprocessing.ScriptPostprocessing):
# TAB MAIN
msgs: dict = {
"extra_multiple_source": " | Сomparison grid as a result",
"extra_multiple_source": "",
}
img, imgs, select_source, face_model, source_folder, save_original, mask_face, source_faces_index, gender_source, faces_index, gender_target, face_restorer_name, face_restorer_visibility, codeformer_weight, swap_in_source, swap_in_generated, random_image = ui_main.show(is_img2img=False, show_br=False, **msgs)
img, imgs, selected_tab, select_source, face_model, source_folder, save_original, mask_face, source_faces_index, gender_source, faces_index, gender_target, face_restorer_name, face_restorer_visibility, codeformer_weight, swap_in_source, swap_in_generated, random_image = ui_main.show(is_img2img=False, show_br=False, **msgs)
# TAB DETECTION
det_thresh, det_maxnum = ui_detection.show()
@ -544,6 +562,7 @@ class FaceSwapScriptExtras(scripts_postprocessing.ScriptPostprocessing):
'upscale_force': upscale_force,
'det_thresh': det_thresh,
'det_maxnum': det_maxnum,
'selected_tab': selected_tab,
}
return args
@ -588,7 +607,10 @@ class FaceSwapScriptExtras(scripts_postprocessing.ScriptPostprocessing):
return
global SWAPPER_MODELS_PATH
self.source = args['img']
if args['selected_tab'] == "tab_single":
self.source = args['img']
else:
self.source = None
self.face_restorer_name = args['face_restorer_name']
self.upscaler_scale = args['upscaler_scale']
self.upscaler_visibility = args['upscaler_visibility']
@ -605,7 +627,10 @@ class FaceSwapScriptExtras(scripts_postprocessing.ScriptPostprocessing):
self.select_source = args['select_source']
self.face_model = args['face_model']
self.source_folder = args['source_folder']
self.source_imgs = args['imgs']
if args['selected_tab'] == "tab_single":
self.source_imgs = None
else:
self.source_imgs = args['imgs']
self.random_image = args['random_image']
self.upscale_force = args['upscale_force']
self.det_thresh = args['det_thresh']
@ -684,9 +709,13 @@ class FaceSwapScriptExtras(scripts_postprocessing.ScriptPostprocessing):
if len(result) > 0 and swapped > 0:
image = result[0]
if len(result) > 1:
grid = make_grid(result)
result.insert(0, grid)
image = grid
if hasattr(pp, 'extra_images'):
image = result[0]
pp.extra_images.extend(result[1:])
else:
grid = make_grid(result)
result.insert(0, grid)
image = grid
pp.info["ReActor"] = True
pp.image = image
logger.status("---Done!---")

View File

@ -203,9 +203,12 @@ def get_facemodels():
def get_model_names(get_models):
models = get_models()
names = ["None"]
names = []
for x in models:
names.append(os.path.basename(x))
# Sort ignoring case during sort but retain in output
names.sort(key=str.lower)
names.insert(0, "None")
return names
def get_images_from_folder(path: str):

View File

@ -661,13 +661,19 @@ def build_face_model(image: Image.Image, name: str, save_model: bool = True, det
logger.error(no_face_msg)
return no_face_msg
def blend_faces(images_list: List, name: str, compute_method: int = 0, shape_check: bool = False):
def blend_faces(images_list: List, name: str, compute_method: int = 0, shape_check: bool = False, is_api: bool = False):
faces = []
embeddings = []
images: List[Image.Image] = []
images, images_names = get_images_from_list(images_list)
if not is_api:
images, images_names = get_images_from_list(images_list)
else:
images = images_list
for i,image in enumerate(images):
logger.status(f"Building Face Model for {images_names[i]}...")
if not is_api:
logger.status(f"Building Face Model for {images_names[i]}...")
else:
logger.status(f"Building Face Model for Image {i+1}...")
face = build_face_model(image,str(i),save_model=False)
if isinstance(face, str):
# logger.error(f"No faces found in {images_names[i]}, skipping")
@ -676,7 +682,10 @@ def blend_faces(images_list: List, name: str, compute_method: int = 0, shape_che
if i == 0:
embedding_shape = face.embedding.shape
elif face.embedding.shape != embedding_shape:
logger.error(f"Embedding Shape Mismatch for {images_names[i]}, skipping")
if not is_api:
logger.error(f"Embedding Shape Mismatch for {images_names[i]}, skipping")
else:
logger.error(f"Embedding Shape Mismatch for Image {i+1}, skipping")
continue
faces.append(face)
embeddings.append(face.embedding)

View File

@ -1,5 +1,5 @@
app_title = "ReActor"
version_flag = "v0.7.0"
version_flag = "v0.7.1-b2"
from scripts.reactor_logger import logger, get_Run, set_Run
from scripts.reactor_globals import DEVICE

View File

@ -10,6 +10,7 @@ from scripts.reactor_helpers import (
get_facemodels
)
# xyz_grid = [x for x in scripts.scripts_data if x.script_class.__module__ == "xyz_grid.py"][0].module
def find_module(module_names):
@ -84,3 +85,10 @@ def run():
xyz_grid = find_module("xyz_grid.py, xy_grid.py")
if xyz_grid:
add_axis_options(xyz_grid)
# XYZ init:
try:
import modules.script_callbacks as script_callbacks
script_callbacks.on_before_ui(run)
except:
pass