UPDATE: Gender Detection; FIX: install cond ">="
+ VersionUP (beta)
This commit is contained in:
parent
b0307f6428
commit
eb6d361ab5
@ -1,4 +1,4 @@
|
||||
# ReActor 0.3.0 for StableDiffusion
|
||||
# ReActor 0.3.1b for StableDiffusion
|
||||
### The Fast and Simple "[roop-based](https://github.com/s0md3v/sd-webui-roop)" FaceSwap Extension with a lot of improvements and without NSFW filter (uncensored, use it on your own [responsibility](#disclaimer))
|
||||
|
||||
> Ex "Roop-GE" (GE - Gourieff Edition, aka "NSFW-Roop"), the extension was renamed with the version 0.3.0<br>
|
||||
|
||||
@ -36,6 +36,8 @@ args=[
|
||||
False, #11 Swap in source image
|
||||
True, #12 Swap in generated image
|
||||
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)
|
||||
]
|
||||
|
||||
# The args for ReActor can be found by
|
||||
|
||||
17
install.py
17
install.py
@ -3,6 +3,7 @@ import os, sys
|
||||
import pkg_resources
|
||||
from tqdm import tqdm
|
||||
import urllib.request
|
||||
from packaging import version as pv
|
||||
|
||||
req_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "requirements.txt")
|
||||
|
||||
@ -16,20 +17,21 @@ def run_pip(*args):
|
||||
subprocess.run([sys.executable, "-m", "pip", "install", *args])
|
||||
|
||||
def is_installed (
|
||||
package: str, version: str | None = None
|
||||
package: str, version: str | None = None, strict: bool = True
|
||||
):
|
||||
has_package = None
|
||||
try:
|
||||
has_package = pkg_resources.get_distribution(package)
|
||||
if has_package is not None:
|
||||
installed_version = has_package.version
|
||||
if installed_version != version:
|
||||
if (installed_version != version and strict == True) or (pv.parse(installed_version) < pv.parse(version) and strict == False):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except:
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return False
|
||||
|
||||
def download(url, path):
|
||||
@ -44,16 +46,20 @@ if not os.path.exists(models_dir):
|
||||
if not os.path.exists(model_path):
|
||||
download(model_url, model_path)
|
||||
|
||||
print("Checking ReActor (ex Roop-GE) requirements...", end=' ')
|
||||
print("Checking ReActor requirements...", end=' ')
|
||||
with open(req_file) as file:
|
||||
install_count = 0
|
||||
strict = True
|
||||
for package in file:
|
||||
package_version = None
|
||||
try:
|
||||
package = package.strip()
|
||||
if "==" in package:
|
||||
package_version = package.split('==')[1]
|
||||
if not is_installed(package,package_version):
|
||||
elif ">=" in package:
|
||||
package_version = package.split('>=')[1]
|
||||
strict = False
|
||||
if not is_installed(package,package_version,strict):
|
||||
install_count += 1
|
||||
run_pip(package)
|
||||
except Exception as e:
|
||||
@ -61,6 +67,7 @@ with open(req_file) as file:
|
||||
print(f"\nERROR: Failed to install {package} - ReActor won't start")
|
||||
raise e
|
||||
if install_count > 0:
|
||||
print(f'install_count={install_count}')
|
||||
print(f'\n--- PLEASE, RESTART the Server! ---\n')
|
||||
else:
|
||||
print('Ok')
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
insightface==0.7.3
|
||||
onnx==1.14.0
|
||||
onnxruntime==1.15.0
|
||||
opencv-python==4.7.0.72
|
||||
opencv-python>=4.7.0.72
|
||||
|
||||
@ -42,21 +42,39 @@ class FaceSwapScript(scripts.Script):
|
||||
return scripts.AlwaysVisible
|
||||
|
||||
def ui(self, is_img2img):
|
||||
with gr.Accordion(f"{app_title} (ex Roop-GE)", open=False):
|
||||
with gr.Accordion(f"{app_title}", open=False):
|
||||
with gr.Column():
|
||||
img = gr.inputs.Image(type="pil")
|
||||
enable = gr.Checkbox(False, label="Enable", info=f"The Fast and Simple \"roop-based\" FaceSwap Extension - {version_flag}")
|
||||
gr.Markdown("---")
|
||||
gr.Markdown("Source Image (above):")
|
||||
with gr.Row():
|
||||
source_faces_index = gr.Textbox(
|
||||
value="0",
|
||||
placeholder="Which face(s) to use as source (comma separated)",
|
||||
label="Comma separated face number(s) from swap-source image (above); Example: 0,2,1",
|
||||
placeholder="Which face(s) to use as Source (comma separated)",
|
||||
label="Comma separated face number(s); Example: 0,2,1",
|
||||
)
|
||||
gender_source = gr.Radio(
|
||||
["No", "Female Only", "Male Only"],
|
||||
value="No",
|
||||
label="Gender Detection (Source)",
|
||||
type="index",
|
||||
)
|
||||
gr.Markdown("---")
|
||||
gr.Markdown("Target Image (result):")
|
||||
with gr.Row():
|
||||
faces_index = gr.Textbox(
|
||||
value="0",
|
||||
placeholder="Which face to swap (comma separated)",
|
||||
label="Comma separated face number(s) for target image (result); Example: 1,0,2",
|
||||
placeholder="Which face(s) to Swap into Target (comma separated)",
|
||||
label="Comma separated face number(s); Example: 1,0,2",
|
||||
)
|
||||
gender_target = gr.Radio(
|
||||
["No", "Female Only", "Male Only"],
|
||||
value="No",
|
||||
label="Gender Detection (Target)",
|
||||
type="index",
|
||||
)
|
||||
gr.Markdown("---")
|
||||
with gr.Row():
|
||||
face_restorer_name = gr.Radio(
|
||||
label="Restore Face",
|
||||
@ -81,7 +99,7 @@ class FaceSwapScript(scripts.Script):
|
||||
upscaler_visibility = gr.Slider(
|
||||
0, 1, 1, step=0.1, label="Upscaler Visibility (if scale = 1)"
|
||||
)
|
||||
|
||||
gr.Markdown("---")
|
||||
swap_in_source = gr.Checkbox(
|
||||
False,
|
||||
label="Swap in source image",
|
||||
@ -113,6 +131,7 @@ class FaceSwapScript(scripts.Script):
|
||||
label="Console Log Level",
|
||||
type="index",
|
||||
)
|
||||
gr.Markdown("---")
|
||||
|
||||
return [
|
||||
img,
|
||||
@ -128,7 +147,9 @@ class FaceSwapScript(scripts.Script):
|
||||
upscaler_visibility,
|
||||
swap_in_source,
|
||||
swap_in_generated,
|
||||
console_logging_level
|
||||
console_logging_level,
|
||||
gender_source,
|
||||
gender_target,
|
||||
]
|
||||
|
||||
|
||||
@ -174,6 +195,8 @@ class FaceSwapScript(scripts.Script):
|
||||
swap_in_source,
|
||||
swap_in_generated,
|
||||
console_logging_level,
|
||||
gender_source,
|
||||
gender_target,
|
||||
):
|
||||
global MODELS_PATH
|
||||
self.source = img
|
||||
@ -187,6 +210,8 @@ class FaceSwapScript(scripts.Script):
|
||||
self.swap_in_generated = swap_in_generated
|
||||
self.model = os.path.join(MODELS_PATH,model)
|
||||
self.console_logging_level = console_logging_level
|
||||
self.gender_source = gender_source
|
||||
self.gender_target = gender_target
|
||||
self.source_faces_index = [
|
||||
int(x) for x in source_faces_index.strip(",").split(",") if x.isnumeric()
|
||||
]
|
||||
@ -212,6 +237,8 @@ class FaceSwapScript(scripts.Script):
|
||||
faces_index=self.faces_index,
|
||||
model=self.model,
|
||||
upscale_options=self.upscale_options,
|
||||
gender_source=self.gender_source,
|
||||
gender_target=self.gender_target,
|
||||
)
|
||||
p.init_images[i] = result
|
||||
else:
|
||||
@ -233,6 +260,8 @@ class FaceSwapScript(scripts.Script):
|
||||
faces_index=self.faces_index,
|
||||
model=self.model,
|
||||
upscale_options=self.upscale_options,
|
||||
gender_source=self.gender_source,
|
||||
gender_target=self.gender_target,
|
||||
)
|
||||
try:
|
||||
pp = scripts_postprocessing.PostprocessedImage(result)
|
||||
|
||||
@ -60,7 +60,7 @@ def getAnalysisModel():
|
||||
global ANALYSIS_MODEL
|
||||
if ANALYSIS_MODEL is None:
|
||||
ANALYSIS_MODEL = insightface.app.FaceAnalysis(
|
||||
name="buffalo_l", providers=providers
|
||||
name="buffalo_l", providers=providers # note: allowed_modules=['detection', 'genderage']
|
||||
)
|
||||
return ANALYSIS_MODEL
|
||||
|
||||
@ -129,19 +129,57 @@ def upscale_image(image: Image, upscale_options: UpscaleOptions):
|
||||
return result_image
|
||||
|
||||
|
||||
def get_face_single(img_data: np.ndarray, face_index=0, det_size=(640, 640)):
|
||||
def get_face_gender(
|
||||
face,
|
||||
face_index,
|
||||
gender_condition,
|
||||
operated: str
|
||||
):
|
||||
gender = [
|
||||
x.sex
|
||||
for x in face
|
||||
]
|
||||
gender.reverse()
|
||||
face_gender = gender[face_index]
|
||||
logger.info("%s Face %s: Detected Gender -%s-", operated, face_index, face_gender)
|
||||
if (gender_condition == 1 and face_gender == "F") or (gender_condition == 2 and face_gender == "M"):
|
||||
logger.info("OK - Detected Gender matches Condition")
|
||||
try:
|
||||
return sorted(face, key=lambda x: x.bbox[0])[face_index], 0
|
||||
except IndexError:
|
||||
return None, 0
|
||||
else:
|
||||
logger.info("WRONG - Detected Gender doesn't match Condition")
|
||||
return sorted(face, key=lambda x: x.bbox[0])[face_index], 1
|
||||
|
||||
|
||||
def reget_face_single(img_data, det_size, face_index):
|
||||
det_size_half = (det_size[0] // 2, det_size[1] // 2)
|
||||
return get_face_single(img_data, face_index=face_index, det_size=det_size_half)
|
||||
|
||||
|
||||
def get_face_single(img_data: np.ndarray, face_index=0, det_size=(640, 640), gender_source=0, gender_target=0):
|
||||
face_analyser = copy.deepcopy(getAnalysisModel())
|
||||
face_analyser.prepare(ctx_id=0, det_size=det_size)
|
||||
face = face_analyser.get(img_data)
|
||||
|
||||
if gender_source != 0:
|
||||
if len(face) == 0 and det_size[0] > 320 and det_size[1] > 320:
|
||||
return reget_face_single(img_data, det_size, face_index)
|
||||
return get_face_gender(face,face_index,gender_source,"Source")
|
||||
|
||||
if gender_target != 0:
|
||||
if len(face) == 0 and det_size[0] > 320 and det_size[1] > 320:
|
||||
return reget_face_single(img_data, det_size, face_index)
|
||||
return get_face_gender(face,face_index,gender_target,"Target")
|
||||
|
||||
if len(face) == 0 and det_size[0] > 320 and det_size[1] > 320:
|
||||
det_size_half = (det_size[0] // 2, det_size[1] // 2)
|
||||
return get_face_single(img_data, face_index=face_index, det_size=det_size_half)
|
||||
return reget_face_single(img_data, det_size, face_index)
|
||||
|
||||
try:
|
||||
return sorted(face, key=lambda x: x.bbox[0])[face_index]
|
||||
return sorted(face, key=lambda x: x.bbox[0])[face_index], 0
|
||||
except IndexError:
|
||||
return None
|
||||
return None, 0
|
||||
|
||||
|
||||
def swap_face(
|
||||
@ -151,6 +189,8 @@ def swap_face(
|
||||
source_faces_index: List[int] = [0],
|
||||
faces_index: List[int] = [0],
|
||||
upscale_options: Union[UpscaleOptions, None] = None,
|
||||
gender_source: int = 0,
|
||||
gender_target: int = 0,
|
||||
):
|
||||
result_image = target_img
|
||||
if model is not None:
|
||||
@ -170,9 +210,11 @@ def swap_face(
|
||||
|
||||
source_img = cv2.cvtColor(np.array(source_img), cv2.COLOR_RGB2BGR)
|
||||
target_img = cv2.cvtColor(np.array(target_img), cv2.COLOR_RGB2BGR)
|
||||
source_face = get_face_single(source_img, face_index=source_faces_index[0])
|
||||
|
||||
source_face, wrong_gender = get_face_single(source_img, face_index=source_faces_index[0], gender_source=gender_source)
|
||||
|
||||
if len(source_faces_index) != 0 and len(source_faces_index) != 1 and len(source_faces_index) != len(faces_index):
|
||||
logger.info(f'Source Faces must have no entries (default=0), one entry, or same number of entries as target faces.')
|
||||
logger.info(f'Source Faces must have no entries (default=0), one entry, or same number of entries as target faces.')
|
||||
elif source_face is not None:
|
||||
result = target_img
|
||||
model_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), model)
|
||||
@ -182,15 +224,29 @@ def swap_face(
|
||||
|
||||
for face_num in faces_index:
|
||||
if len(source_faces_index) > 1 and source_face_idx > 0:
|
||||
source_face = get_face_single(source_img, face_index=source_faces_index[source_face_idx])
|
||||
source_face, wrong_gender = get_face_single(source_img, face_index=source_faces_index[source_face_idx], gender_source=gender_source)
|
||||
source_face_idx += 1
|
||||
|
||||
if source_face is not None:
|
||||
target_face = get_face_single(target_img, face_index=face_num)
|
||||
if target_face is not None:
|
||||
if source_face is not None and wrong_gender == 0:
|
||||
target_face, wrong_gender = get_face_single(target_img, face_index=face_num, gender_target=gender_target)
|
||||
if target_face is not None and wrong_gender == 0:
|
||||
result = face_swapper.get(result, target_face, source_face)
|
||||
elif wrong_gender == 1:
|
||||
wrong_gender = 0
|
||||
if source_face_idx == len(source_faces_index):
|
||||
result_image = Image.fromarray(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
|
||||
if upscale_options is not None:
|
||||
result_image = upscale_image(result_image, upscale_options)
|
||||
return result_image
|
||||
else:
|
||||
logger.info(f"No target face found for {face_num}")
|
||||
elif wrong_gender == 1:
|
||||
wrong_gender = 0
|
||||
if source_face_idx == len(source_faces_index):
|
||||
result_image = Image.fromarray(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
|
||||
if upscale_options is not None:
|
||||
result_image = upscale_image(result_image, upscale_options)
|
||||
return result_image
|
||||
else:
|
||||
logger.info(f"No source face found for face number {source_face_idx}.")
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
app_title = "ReActor"
|
||||
version_flag = "v0.3.0"
|
||||
version_flag = "v0.3.1b"
|
||||
|
||||
from scripts.logger import logger, get_Run, set_Run
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user