From 4fa8d033355b95730de61aa313f0825223660b1b Mon Sep 17 00:00:00 2001 From: Henry Ruhs Date: Fri, 16 Jun 2023 23:17:41 +0200 Subject: [PATCH 1/7] Remove everything source face related from enhancer (#510) * Remove everything source face related from enhancer * Disable upscale for enhancer to double fps --- roop/processors/frame/face_enhancer.py | 33 ++++++++------------------ roop/processors/frame/face_swapper.py | 4 +--- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/roop/processors/frame/face_enhancer.py b/roop/processors/frame/face_enhancer.py index 586e569..e79b654 100644 --- a/roop/processors/frame/face_enhancer.py +++ b/roop/processors/frame/face_enhancer.py @@ -6,7 +6,7 @@ import gfpgan import roop.globals import roop.processors.frame.core from roop.core import update_status -from roop.face_analyser import get_one_face, get_many_faces +from roop.face_analyser import get_one_face from roop.utilities import conditional_download, resolve_relative_path, is_image, is_video FACE_ENHANCER = None @@ -35,53 +35,40 @@ def get_face_enhancer() -> None: if FACE_ENHANCER is None: model_path = resolve_relative_path('../models/GFPGANv1.3.pth') # todo: set models path https://github.com/TencentARC/GFPGAN/issues/399 - FACE_ENHANCER = gfpgan.GFPGANer( - model_path=model_path, - channel_multiplier=2 - ) + FACE_ENHANCER = gfpgan.GFPGANer(model_path=model_path, upscale=1) return FACE_ENHANCER -def enhance_face(source_face: Any, target_face: Any, temp_frame: Any) -> Any: - THREAD_SEMAPHORE.acquire() - if target_face: +def enhance_face(temp_frame: Any) -> Any: + with THREAD_SEMAPHORE: _, _, temp_frame = get_face_enhancer().enhance( temp_frame, paste_back=True ) - THREAD_SEMAPHORE.release() return temp_frame def process_frame(source_face: Any, temp_frame: Any) -> Any: - if roop.globals.many_faces: - many_faces = get_many_faces(temp_frame) - if many_faces: - for target_face in many_faces: - temp_frame = enhance_face(source_face, target_face, temp_frame) - else: - target_face = get_one_face(temp_frame) - if target_face: - temp_frame = enhance_face(source_face, target_face, temp_frame) + target_face = get_one_face(temp_frame) + if target_face: + temp_frame = enhance_face(temp_frame) return temp_frame def process_frames(source_path: str, temp_frame_paths: List[str], progress=None) -> None: - source_face = get_one_face(cv2.imread(source_path)) for temp_frame_path in temp_frame_paths: temp_frame = cv2.imread(temp_frame_path) - result = process_frame(source_face, temp_frame) + result = process_frame(None, temp_frame) cv2.imwrite(temp_frame_path, result) if progress: progress.update(1) def process_image(source_path: str, target_path: str, output_path: str) -> None: - source_face = get_one_face(cv2.imread(source_path)) target_frame = cv2.imread(target_path) - result = process_frame(source_face, target_frame) + result = process_frame(None, target_frame) cv2.imwrite(output_path, result) def process_video(source_path: str, temp_frame_paths: List[str]) -> None: - roop.processors.frame.core.process_video(source_path, temp_frame_paths, process_frames) + roop.processors.frame.core.process_video(None, temp_frame_paths, process_frames) diff --git a/roop/processors/frame/face_swapper.py b/roop/processors/frame/face_swapper.py index 291e054..86229ff 100644 --- a/roop/processors/frame/face_swapper.py +++ b/roop/processors/frame/face_swapper.py @@ -44,9 +44,7 @@ def get_face_swapper() -> None: def swap_face(source_face: Any, target_face: Any, temp_frame: Any) -> Any: - if target_face: - return get_face_swapper().get(temp_frame, target_face, source_face, paste_back=True) - return temp_frame + return get_face_swapper().get(temp_frame, target_face, source_face, paste_back=True) def process_frame(source_face: Any, temp_frame: Any) -> Any: From b7762123fe9b7193636539b3bb2e57f596b1a4bb Mon Sep 17 00:00:00 2001 From: henryruhs Date: Fri, 16 Jun 2023 23:45:32 +0200 Subject: [PATCH 2/7] Using futures for multi threading --- roop/processors/frame/core.py | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/roop/processors/frame/core.py b/roop/processors/frame/core.py index 9581253..e9f6912 100644 --- a/roop/processors/frame/core.py +++ b/roop/processors/frame/core.py @@ -1,6 +1,6 @@ import sys import importlib -import threading +from concurrent.futures import ThreadPoolExecutor from typing import Any, List from tqdm import tqdm @@ -38,24 +38,13 @@ def get_frame_processors_modules(frame_processors): def multi_process_frame(source_path: str, temp_frame_paths: List[str], process_frames, progress) -> None: - threads = [] - frames_per_thread = len(temp_frame_paths) // roop.globals.execution_threads - remaining_frames = len(temp_frame_paths) % roop.globals.execution_threads - start_index = 0 - # create threads by frames - for _ in range(roop.globals.execution_threads): - end_index = start_index + frames_per_thread - if remaining_frames > 0: - end_index += 1 - remaining_frames -= 1 - thread_paths = temp_frame_paths[start_index:end_index] - thread = threading.Thread(target=process_frames, args=(source_path, thread_paths, progress)) - threads.append(thread) - thread.start() - start_index = end_index - # join threads - for thread in threads: - thread.join() + with ThreadPoolExecutor(max_workers=roop.globals.execution_threads) as executor: + futures = [] + for path in temp_frame_paths: + future = executor.submit(process_frames, source_path, [path], progress) + futures.append(future) + for future in futures: + future.result() def process_video(source_path: str, frame_paths: list[str], process_frames: Any) -> None: From 8c1994f5d1e1ad8c97d1ccd174f6c7e2e82e8bed Mon Sep 17 00:00:00 2001 From: Henry Ruhs Date: Sun, 18 Jun 2023 09:26:10 +0200 Subject: [PATCH 3/7] Introduce predicter (#530) --- roop/core.py | 7 +++---- roop/predicter.py | 24 ++++++++++++++++++++++++ roop/ui.py | 3 +++ 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 roop/predicter.py diff --git a/roop/core.py b/roop/core.py index aa73cb3..c8e9927 100755 --- a/roop/core.py +++ b/roop/core.py @@ -16,10 +16,10 @@ import argparse import torch import onnxruntime import tensorflow -from opennsfw2 import predict_video_frames, predict_image import roop.globals import roop.ui as ui +from roop.predicter import predict_image, predict_video from roop.processors.frame.core import get_frame_processors_modules from roop.utilities import has_image_extension, is_image, is_video, detect_fps, create_video, extract_frames, get_temp_frame_paths, restore_audio, create_temp, move_temp, clean_temp, normalize_output_path @@ -164,7 +164,7 @@ def start() -> None: return # process image to image if has_image_extension(roop.globals.target_path): - if predict_image(roop.globals.target_path) > 0.85: + if predict_image(roop.globals.target_path): destroy() # todo: this needs a temp path for images to work with multiple frame processors for frame_processor in get_frame_processors_modules(roop.globals.frame_processors): @@ -177,8 +177,7 @@ def start() -> None: update_status('Processing to image failed!') return # process image to videos - seconds, probabilities = predict_video_frames(video_path=roop.globals.target_path, frame_interval=100) - if any(probability > 0.85 for probability in probabilities): + if predict_video(roop.globals.target_path): destroy() update_status('Creating temp resources...') create_temp(roop.globals.target_path) diff --git a/roop/predicter.py b/roop/predicter.py new file mode 100644 index 0000000..0411ce3 --- /dev/null +++ b/roop/predicter.py @@ -0,0 +1,24 @@ +import numpy +import opennsfw2 +from PIL import Image +from opennsfw2 import predict_video_frames + +MAX_PROBABILITY = 0.85 + + +def predict_frame(target_frame: Image) -> bool: + image = Image.fromarray(target_frame) + image = opennsfw2.preprocess_image(image, opennsfw2.Preprocessing.YAHOO) + model = opennsfw2.make_open_nsfw_model() + views = numpy.expand_dims(image, axis=0) + _, probability = model.predict(views)[0] + return probability > MAX_PROBABILITY + + +def predict_image(target_path: str) -> bool: + return predict_image(target_path) > MAX_PROBABILITY + + +def predict_video(target_path: str) -> bool: + _, probabilities = predict_video_frames(video_path=target_path, frame_interval=100) + return any(probability > MAX_PROBABILITY for probability in probabilities) diff --git a/roop/ui.py b/roop/ui.py index 95133d1..134fb4a 100644 --- a/roop/ui.py +++ b/roop/ui.py @@ -8,6 +8,7 @@ from PIL import Image, ImageOps import roop.globals from roop.face_analyser import get_one_face from roop.capturer import get_video_frame, get_video_frame_total +from roop.predicter import predict_frame from roop.processors.frame.core import get_frame_processors_modules from roop.utilities import is_image, is_video, resolve_relative_path @@ -200,6 +201,8 @@ def init_preview() -> None: def update_preview(frame_number: int = 0) -> None: if roop.globals.source_path and roop.globals.target_path: temp_frame = get_video_frame(roop.globals.target_path, frame_number) + if predict_frame(temp_frame): + quit() for frame_processor in get_frame_processors_modules(roop.globals.frame_processors): temp_frame = frame_processor.process_frame( get_one_face(cv2.imread(roop.globals.source_path)), From e38c6245d3db763e5eb2ff55342cb8c47fd83f86 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Sun, 18 Jun 2023 20:27:28 +0200 Subject: [PATCH 4/7] Hotfix predicter --- roop/predicter.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/roop/predicter.py b/roop/predicter.py index 0411ce3..ea9836b 100644 --- a/roop/predicter.py +++ b/roop/predicter.py @@ -1,7 +1,6 @@ import numpy import opennsfw2 from PIL import Image -from opennsfw2 import predict_video_frames MAX_PROBABILITY = 0.85 @@ -16,9 +15,9 @@ def predict_frame(target_frame: Image) -> bool: def predict_image(target_path: str) -> bool: - return predict_image(target_path) > MAX_PROBABILITY + return opennsfw2.predict_image(target_path) > MAX_PROBABILITY def predict_video(target_path: str) -> bool: - _, probabilities = predict_video_frames(video_path=target_path, frame_interval=100) + _, probabilities = opennsfw2.predict_video_frames(video_path=target_path, frame_interval=100) return any(probability > MAX_PROBABILITY for probability in probabilities) From 35f8e46b0ebe572091eb9b7b6e5ba303389cfef3 Mon Sep 17 00:00:00 2001 From: Pavel Dubrovsky Date: Sun, 18 Jun 2023 22:29:12 +0400 Subject: [PATCH 5/7] Fix square brackets in the target path (#532) * fixes the problem with square brackets in the target file path * fixes the problem with square brackets in the target file path * Ok, here is the fix without regexps * unused import * fix for ci * glob.escape fits here --- roop/utilities.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roop/utilities.py b/roop/utilities.py index f97e175..15effdc 100644 --- a/roop/utilities.py +++ b/roop/utilities.py @@ -62,7 +62,7 @@ def restore_audio(target_path: str, output_path: str) -> None: def get_temp_frame_paths(target_path: str) -> List[str]: temp_directory_path = get_temp_directory_path(target_path) - return glob.glob(os.path.join(temp_directory_path, '*.png')) + return glob.glob((os.path.join(glob.escape(temp_directory_path), '*.png'))) def get_temp_directory_path(target_path: str) -> str: From b5d3b058e2482821cbe875fcd136e0ddb7cfbac6 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Sun, 18 Jun 2023 21:55:53 +0200 Subject: [PATCH 6/7] Make multiple processors work with images --- roop/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roop/core.py b/roop/core.py index c8e9927..97b5514 100755 --- a/roop/core.py +++ b/roop/core.py @@ -166,10 +166,10 @@ def start() -> None: if has_image_extension(roop.globals.target_path): if predict_image(roop.globals.target_path): destroy() - # todo: this needs a temp path for images to work with multiple frame processors + shutil.copy2(roop.globals.target_path, roop.globals.output_path) for frame_processor in get_frame_processors_modules(roop.globals.frame_processors): update_status('Progressing...', frame_processor.NAME) - frame_processor.process_image(roop.globals.source_path, roop.globals.target_path, roop.globals.output_path) + frame_processor.process_image(roop.globals.source_path, roop.globals.output_path, roop.globals.output_path) release_resources() if is_image(roop.globals.target_path): update_status('Processing to image succeed!') From 395133e744d59729c89972ffea4c61150e3f194b Mon Sep 17 00:00:00 2001 From: henryruhs Date: Mon, 19 Jun 2023 10:30:03 +0200 Subject: [PATCH 7/7] Fix output normalize for deprecated args --- roop/core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/roop/core.py b/roop/core.py index 97b5514..e47bfa4 100755 --- a/roop/core.py +++ b/roop/core.py @@ -74,6 +74,7 @@ def parse_args() -> None: if args.source_path_deprecated: print('\033[33mArgument -f and --face are deprecated. Use -s and --source instead.\033[0m') roop.globals.source_path = args.source_path_deprecated + roop.globals.output_path = normalize_output_path(args.source_path_deprecated, roop.globals.target_path, args.output_path) if args.cpu_cores_deprecated: print('\033[33mArgument --cpu-cores is deprecated. Use --execution-threads instead.\033[0m') roop.globals.execution_threads = args.cpu_cores_deprecated