UPDATE: Save Original; FIXES: different

"Save Original" is available now (discussion #73)

FIXES:
- model path issue #78
- api model path string

+VersionUP (beta3)
This commit is contained in:
Gourieff 2023-09-01 03:56:29 +07:00
parent 08aba2cdb6
commit 2c7187a3af
8 changed files with 136 additions and 13 deletions

View File

@ -2,7 +2,7 @@
<img src="example/ReActor_logo_red.png" alt="logo" width="180px"/>
![Version](https://img.shields.io/badge/version-0.4.1_beta2-green?style=for-the-badge&labelColor=darkgreen)<hr>
![Version](https://img.shields.io/badge/version-0.4.1_beta3-green?style=for-the-badge&labelColor=darkgreen)<hr>
[![Commit activity](https://img.shields.io/github/commit-activity/t/Gourieff/sd-webui-reactor/main?cacheSeconds=0)](https://github.com/Gourieff/sd-webui-reactor/commits/main)
![Last commit](https://img.shields.io/github/last-commit/Gourieff/sd-webui-reactor/main?cacheSeconds=0)
[![Opened issues](https://img.shields.io/github/issues/Gourieff/sd-webui-reactor?color=red)](https://github.com/Gourieff/sd-webui-reactor/issues?cacheSeconds=0)

View File

@ -2,7 +2,7 @@
<img src="example/ReActor_logo_red.png" alt="logo" width="180px"/>
![Version](https://img.shields.io/badge/версия-0.4.1_beta2-green?style=for-the-badge&labelColor=darkgreen)<hr>
![Version](https://img.shields.io/badge/версия-0.4.1_beta3-green?style=for-the-badge&labelColor=darkgreen)<hr>
[![Commit activity](https://img.shields.io/github/commit-activity/t/Gourieff/sd-webui-reactor/main?cacheSeconds=0)](https://github.com/Gourieff/sd-webui-reactor/commits/main)
![Last commit](https://img.shields.io/github/last-commit/Gourieff/sd-webui-reactor/main?cacheSeconds=0)
[![Opened issues](https://img.shields.io/github/issues/Gourieff/sd-webui-reactor?color=red)](https://github.com/Gourieff/sd-webui-reactor/issues?cacheSeconds=0)

View File

@ -8,7 +8,7 @@ time = datetime.now()
today = date.today()
current_date = today.strftime('%Y-%m-%d')
current_time = time.strftime('%H-%M-%S')
output_file = 'outputs/api/output_'+current_date+'_'+current_time+'.png' # Output file path
output = 'outputs/api/output_'+current_date+'_'+current_time # Output file path + name index
try:
im = Image.open(input_file)
except Exception as e:
@ -26,7 +26,7 @@ args=[
True, #1 Enable ReActor
'0', #2 Comma separated face number(s) from swap-source image
'0', #3 Comma separated face number(s) for target image (result)
'C:\stable-diffusion-webui\models/roop\inswapper_128.onnx', #4 model path
'C:\stable-diffusion-webui\models\insightface\inswapper_128.onnx', #4 model path
'CodeFormer', #4 Restore Face: None; CodeFormer; GFPGAN
1, #5 Restore visibility value
True, #7 Restore face -> Upscale
@ -38,6 +38,7 @@ args=[
1, #13 Console Log Level (0 - min, 1 - med or 2 - max)
0, #14 Gender Detection (Source) (0 - No, 1 - Female Only, 2 - Male Only)
0, #15 Gender Detection (Target) (0 - No, 1 - Female Only, 2 - Male Only)
False, #16 Save the original image(s) made before swapping
]
# The args for ReActor can be found by
@ -70,6 +71,7 @@ finally:
if result is not None:
r = result.json()
n = 0
for i in r['images']:
image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0])))
@ -81,11 +83,13 @@ if result is not None:
pnginfo = PngImagePlugin.PngInfo()
pnginfo.add_text("parameters", response2.json().get("info"))
output_file = output+'_'+str(n)+'_.png'
try:
image.save(output_file, pnginfo=pnginfo)
except Exception as e:
print(e)
finally:
print(f'{output_file} is saved\nAll is done!')
n += 1
else:
print('Something went wrong...')

View File

@ -2,20 +2,25 @@ import os, glob
import gradio as gr
from PIL import Image
from typing import List
import modules.scripts as scripts
from modules.upscaler import Upscaler, UpscalerData
from modules import scripts, shared, images, scripts_postprocessing
from modules.processing import (
Processed,
StableDiffusionProcessing,
StableDiffusionProcessingImg2Img,
)
from modules.face_restoration import FaceRestoration
from modules.paths_internal import models_path
from modules.images import save_image
from scripts.logger import logger
from scripts.swapper import UpscaleOptions, swap_face, check_process_halt, reset_messaged
from scripts.version import version_flag, app_title
from scripts.console_log_patch import apply_logging_patch
from scripts.helpers import make_grid
MODELS_PATH = None
@ -44,10 +49,11 @@ class FaceSwapScript(scripts.Script):
def ui(self, is_img2img):
with gr.Accordion(f"{app_title}", open=False):
with gr.Tab("Input"):
with gr.Tab("Main"):
with gr.Column():
img = gr.inputs.Image(type="pil")
enable = gr.Checkbox(False, label="Enable", info=f"The Fast and Simple FaceSwap Extension - {version_flag}")
save_original = gr.Checkbox(False, label="Save Original", info="Save the original image(s) made before swapping; If you use \"img2img\" - this option will affect with \"Swap in generated\" only")
gr.Markdown("<br>")
gr.Markdown("Source Image (above):")
with gr.Row():
@ -153,6 +159,7 @@ class FaceSwapScript(scripts.Script):
console_logging_level,
gender_source,
gender_target,
save_original,
]
@ -200,6 +207,7 @@ class FaceSwapScript(scripts.Script):
console_logging_level,
gender_source,
gender_target,
save_original,
):
self.enable = enable
if self.enable:
@ -221,6 +229,7 @@ class FaceSwapScript(scripts.Script):
self.console_logging_level = console_logging_level
self.gender_source = gender_source
self.gender_target = gender_target
self.save_original = save_original
if self.gender_source is None or self.gender_source == "No":
self.gender_source = 0
if self.gender_target is None or self.gender_target == "No":
@ -242,7 +251,8 @@ class FaceSwapScript(scripts.Script):
logger.info("Working: source face index %s, target face index %s", self.source_faces_index, self.faces_index)
for i in range(len(p.init_images)):
logger.info("Swap in %s", i)
if len(p.init_images) > 1:
logger.info("Swap in %s", i)
result = swap_face(
self.source,
p.init_images[i],
@ -261,12 +271,67 @@ class FaceSwapScript(scripts.Script):
else:
logger.error("Please provide a source face")
def postprocess_batch(self, p, *args, **kwargs):
def postprocess(self, p: StableDiffusionProcessing, processed: Processed, *args):
if self.enable:
reset_messaged()
if check_process_halt():
return
if self.save_original:
postprocess_run: bool = True
orig_images : List[Image.Image] = processed.images[processed.index_of_first_image:]
orig_infotexts : List[str] = processed.infotexts[processed.index_of_first_image:]
result_images: List = processed.images
if self.swap_in_generated:
logger.info("Working: source face index %s, target face index %s", self.source_faces_index, self.faces_index)
if self.source is not None:
for i,(img,info) in enumerate(zip(orig_images, orig_infotexts)):
if check_process_halt():
postprocess_run = False
break
if len(orig_images) > 1:
logger.info("Swap in %s", i)
result = swap_face(
self.source,
img,
source_faces_index=self.source_faces_index,
faces_index=self.faces_index,
model=self.model,
upscale_options=self.upscale_options,
gender_source=self.gender_source,
gender_target=self.gender_target,
)
if result is not None:
suffix = "-swapped"
result_images.append(result)
try:
save_image(result, p.outpath_samples, "", p.all_seeds[0], p.all_prompts[0], "png",info=info, p=p, suffix=suffix)
except:
logger.error("Cannot save a result image - please, check SD WebUI Settings (Saving and Paths)")
else:
logger.error("Cannot create a result image")
if shared.opts.return_grid and len(result_images) > 2 and postprocess_run:
grid = make_grid(result_images)
result_images.insert(0, grid)
try:
save_image(grid, p.outpath_grids, "grid", p.all_seeds[0], p.all_prompts[0], shared.opts.grid_format, info=info, short_filename=not shared.opts.grid_extended_filename, p=p, grid=True)
except:
logger.error("Cannot save a grid - please, check SD WebUI Settings (Saving and Paths)")
processed.images = result_images
def postprocess_batch(self, p, *args, **kwargs):
if self.enable and not self.save_original:
images = kwargs["images"]
def postprocess_image(self, p, script_pp: scripts.PostprocessImageArgs, *args):
if self.enable and self.swap_in_generated:
if self.enable and self.swap_in_generated and not self.save_original:
current_job_number = shared.state.job_no + 1
job_count = shared.state.job_count
@ -274,7 +339,7 @@ class FaceSwapScript(scripts.Script):
reset_messaged()
if check_process_halt():
return
if self.source is not None:
logger.info("Working: source face index %s, target face index %s", self.source_faces_index, self.faces_index)
image: Image.Image = script_pp.image

55
scripts/helpers.py Normal file
View File

@ -0,0 +1,55 @@
from collections import Counter
from PIL import Image
from math import isqrt, ceil
from typing import List
def make_grid(image_list: List):
"""
Creates a square image by combining multiple images in a grid pattern.
Args:
image_list (list): List of PIL Image objects to be combined.
Returns:
PIL Image object: The resulting square image.
None: If the image_list is empty or contains only one image.
"""
# Count the occurrences of each image size in the image_list
size_counter = Counter(image.size for image in image_list)
# Get the most common image size (size with the highest count)
common_size = size_counter.most_common(1)[0][0]
# Filter the image_list to include only images with the common size
image_list = [image for image in image_list if image.size == common_size]
# Get the dimensions (width and height) of the common size
size = common_size
# If there are more than one image in the image_list
if len(image_list) > 1:
num_images = len(image_list)
# Calculate the number of rows and columns for the grid
rows = isqrt(num_images)
cols = ceil(num_images / rows)
# Calculate the size of the square image
square_size = (cols * size[0], rows * size[1])
# Create a new RGB image with the square size
square_image = Image.new("RGB", square_size)
# Paste each image onto the square image at the appropriate position
for i, image in enumerate(image_list):
row = i // cols
col = i % cols
square_image.paste(image, (col * size[0], row * size[1]))
# Return the resulting square image
return square_image
# Return None if there are no images or only one image in the image_list
return None

View File

@ -39,7 +39,7 @@ def get_upscaler(name):
return None
def get_models():
models_path = os.path.join(scripts.basedir(), "models/roop/*")
models_path = os.path.join(scripts.basedir(), "models/insightface/*")
models = glob.glob(models_path)
models = [x for x in models if x.endswith(".onnx") or x.endswith(".pth")]
return models

View File

@ -257,8 +257,7 @@ def swap_face(
elif source_face is not None:
result = target_img
model_path = os.path.join(models_path, "insightface", model)
face_swapper = getFaceSwapModel(model_path)
face_swapper = getFaceSwapModel(model)
source_face_idx = 0

View File

@ -1,5 +1,5 @@
app_title = "ReActor"
version_flag = "v0.4.1-b2"
version_flag = "v0.4.1-b3"
from scripts.logger import logger, get_Run, set_Run