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:
parent
08aba2cdb6
commit
2c7187a3af
@ -2,7 +2,7 @@
|
||||
|
||||
<img src="example/ReActor_logo_red.png" alt="logo" width="180px"/>
|
||||
|
||||
<hr>
|
||||
<hr>
|
||||
[](https://github.com/Gourieff/sd-webui-reactor/commits/main)
|
||||

|
||||
[](https://github.com/Gourieff/sd-webui-reactor/issues?cacheSeconds=0)
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
<img src="example/ReActor_logo_red.png" alt="logo" width="180px"/>
|
||||
|
||||
<hr>
|
||||
<hr>
|
||||
[](https://github.com/Gourieff/sd-webui-reactor/commits/main)
|
||||

|
||||
[](https://github.com/Gourieff/sd-webui-reactor/issues?cacheSeconds=0)
|
||||
|
||||
@ -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...')
|
||||
|
||||
@ -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
55
scripts/helpers.py
Normal 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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user