UPDATE: Gender Detection; FIX: install cond ">="

+ VersionUP (beta)
This commit is contained in:
Gourieff 2023-08-11 12:43:18 +07:00
parent b0307f6428
commit eb6d361ab5
7 changed files with 121 additions and 27 deletions

View File

@ -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>

View File

@ -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

View File

@ -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')

View File

@ -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

View File

@ -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)

View File

@ -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}.")

View File

@ -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