From 365f3d790ae705ce7af51dc4400d45a180231652 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 09:01:03 +0200 Subject: [PATCH 01/58] Introduce pre_check(), Cleanup requirements.txt --- core/processor.py | 5 +---- requirements.txt | 3 ++- run.py | 40 ++++++++++++++++++++++++++++------------ 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/core/processor.py b/core/processor.py index d67b1cf..82d61c1 100644 --- a/core/processor.py +++ b/core/processor.py @@ -5,10 +5,7 @@ import core.globals from core.config import get_face from core.utils import rreplace -if os.path.isfile('inswapper_128.onnx'): - face_swapper = insightface.model_zoo.get_model('inswapper_128.onnx', providers=core.globals.providers) -else: - quit('File "inswapper_128.onnx" does not exist!') +face_swapper = insightface.model_zoo.get_model('inswapper_128.onnx', providers=core.globals.providers) def process_video(source_img, frame_paths): diff --git a/requirements.txt b/requirements.txt index 14bb741..a38b874 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,6 @@ onnx==1.14.0 insightface==0.7.3 psutil==5.9.5 tk==0.1.0 -pillow==9.0.1 +pillow==9.5.0 torch==2.0.1 +onnxruntime-gpu==1.15.0 \ No newline at end of file diff --git a/run.py b/run.py index adde8d9..525d9a5 100644 --- a/run.py +++ b/run.py @@ -1,19 +1,9 @@ #!/usr/bin/env python3 import sys import time +import torch import shutil import core.globals - -if not shutil.which('ffmpeg'): - print('ffmpeg is not installed. Read the docs: https://github.com/s0md3v/roop#installation.\n' * 10) - quit() -if '--gpu' not in sys.argv: - core.globals.providers = ['CPUExecutionProvider'] -elif 'ROCMExecutionProvider' not in core.globals.providers: - import torch - if not torch.cuda.is_available(): - quit("You are using --gpu flag but CUDA isn't available or properly installed on your system.") - import glob import argparse import multiprocessing as mp @@ -45,12 +35,35 @@ parser.add_argument('--keep-frames', help='keep frames directory', dest='keep_fr for name, value in vars(parser.parse_args()).items(): args[name] = value - sep = "/" if os.name == "nt": sep = "\\" +def pre_check(): + if not shutil.which('ffmpeg'): + quit('ffmpeg is not installed!') + if os.path.isfile('../inswapper_128.onnx'): + quit('File "inswapper_128.onnx" does not exist!') + if '--gpu' in sys.argv: + CUDA_VERSION = torch.version.cuda + CUDNN_VERSION = torch.backends.cudnn.version() + + if 'ROCMExecutionProvider' not in core.globals.providers: + if CUDA_VERSION > '11.8': + quit(f"CUDA version {CUDA_VERSION} is not supported - please downgrade to 11.8.") + if CUDA_VERSION < '11.6': + quit(f"CUDA version {CUDA_VERSION} is not supported - please upgrade to 11.8.") + if CUDNN_VERSION < 8220: + quit(f"CUDNN version {CUDNN_VERSION} is not supported - please upgrade to 8.9.1") + if CUDNN_VERSION > 8910: + quit(f"CUDNN version {CUDNN_VERSION} is not supported - please downgrade to 8.9.1") + if not torch.cuda.is_available(): + quit("You are using --gpu flag but CUDA isn't available or properly installed on your system.") + else: + core.globals.providers = ['CPUExecutionProvider'] + + def start_processing(): start_time = time.time() if args['gpu']: @@ -73,6 +86,7 @@ def start_processing(): print(flush=True) print(f"Processing time: {end_time - start_time:.2f} seconds", flush=True) + def preview_image(image_path): img = Image.open(image_path) img = img.resize((180, 180), Image.ANTIALIAS) @@ -183,6 +197,8 @@ def start(): if __name__ == "__main__": global status_label, window + + pre_check() if args['source_img']: start() quit() From fe9d6b9cae78a7f6621970069f912489a9f7a231 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 09:05:13 +0200 Subject: [PATCH 02/58] Introduce pre_check(), Cleanup requirements.txt --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index 525d9a5..035879c 100644 --- a/run.py +++ b/run.py @@ -52,7 +52,7 @@ def pre_check(): if 'ROCMExecutionProvider' not in core.globals.providers: if CUDA_VERSION > '11.8': quit(f"CUDA version {CUDA_VERSION} is not supported - please downgrade to 11.8.") - if CUDA_VERSION < '11.6': + if CUDA_VERSION < '11.0': quit(f"CUDA version {CUDA_VERSION} is not supported - please upgrade to 11.8.") if CUDNN_VERSION < 8220: quit(f"CUDNN version {CUDNN_VERSION} is not supported - please upgrade to 8.9.1") From 064f5c5144052fc32ef483a8fe9144f6ba92d8d9 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 09:07:12 +0200 Subject: [PATCH 03/58] Introduce pre_check(), Cleanup requirements.txt --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index 035879c..300daab 100644 --- a/run.py +++ b/run.py @@ -52,7 +52,7 @@ def pre_check(): if 'ROCMExecutionProvider' not in core.globals.providers: if CUDA_VERSION > '11.8': quit(f"CUDA version {CUDA_VERSION} is not supported - please downgrade to 11.8.") - if CUDA_VERSION < '11.0': + if CUDA_VERSION < '11.4': quit(f"CUDA version {CUDA_VERSION} is not supported - please upgrade to 11.8.") if CUDNN_VERSION < 8220: quit(f"CUDNN version {CUDNN_VERSION} is not supported - please upgrade to 8.9.1") From 7227297b45c7daaadf86fe0ddf6ae04430214646 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 10:15:25 +0200 Subject: [PATCH 04/58] Add resource limitations --- README.md | 23 +++++++++++++++-------- run.py | 17 +++++++++++++++++ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b65f4a7..d61d4c4 100644 --- a/README.md +++ b/README.md @@ -25,16 +25,23 @@ Don't touch the FPS checkbox unless you know what you are doing. Additional command line arguments are given below: ``` --h, --help show this help message and exit --f SOURCE_IMG, --face SOURCE_IMG +options: + -h, --help show this help message and exit + -f SOURCE_IMG, --face SOURCE_IMG use this face --t TARGET_PATH, --target TARGET_PATH + -t TARGET_PATH, --target TARGET_PATH replace this face --o OUTPUT_FILE, --output OUTPUT_FILE - save output to this file ---keep-fps keep original fps ---gpu use gpu ---keep-frames don't delete frames directory + -o OUTPUT_FILE, --output OUTPUT_FILE + save output to this file + --keep-fps maintain original fps + --gpu use gpu + --keep-frames keep frames directory + --max-memory MAX_MEMORY + set max memory + --max-cpu-cores MAX_CPU_CORES + set max cpu cores + --max-cpu-usage MAX_CPU_USAGE + set cpu usage in percent ``` Looking for a CLI mode? Using the -f/--face argument will make the program in cli mode. diff --git a/run.py b/run.py index 300daab..9fabf17 100644 --- a/run.py +++ b/run.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import multiprocessing import sys import time import torch @@ -20,6 +21,7 @@ import psutil import cv2 import threading from PIL import Image, ImageTk +import resource pool = None args = {} @@ -31,6 +33,9 @@ parser.add_argument('-o', '--output', help='save output to this file', dest='out parser.add_argument('--keep-fps', help='maintain original fps', dest='keep_fps', action='store_true', default=False) parser.add_argument('--gpu', help='use gpu', dest='gpu', action='store_true', default=False) parser.add_argument('--keep-frames', help='keep frames directory', dest='keep_frames', action='store_true', default=False) +parser.add_argument('--max-memory', help='set max memory', default=16, type=int) +parser.add_argument('--max-cpu-cores', help='set max cpu cores', default=multiprocessing.cpu_count(), type=int) +parser.add_argument('--max-cpu-usage', help='set cpu usage in percent', default=100, type=int) for name, value in vars(parser.parse_args()).items(): args[name] = value @@ -40,6 +45,16 @@ if os.name == "nt": sep = "\\" +def limit_resources(): + current_cpu_usage, current_cpu_cores = resource.getrlimit(resource.RLIMIT_CPU) + if args['max_memory'] < 1: + resource.setrlimit(resource.RLIMIT_DATA, (args['max_memory'] * 1024 * 1024 * 1024, -1)) + if args['max_cpu_usage'] < 1: + resource.setrlimit(resource.RLIMIT_CPU, (args['max_cpu_usage'], current_cpu_cores)) + if args['max_cpu_cores'] < multiprocessing.cpu_count(): + resource.setrlimit(resource.RLIMIT_CPU, (current_cpu_usage, args['max_cpu_cores'])) + + def pre_check(): if not shutil.which('ffmpeg'): quit('ffmpeg is not installed!') @@ -199,6 +214,8 @@ if __name__ == "__main__": global status_label, window pre_check() + limit_resources() + if args['source_img']: start() quit() From 48e1f93891ea2067ef8f9d6f28f64a8349e638c7 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 10:59:23 +0200 Subject: [PATCH 05/58] Revert: CPU limits not working --- README.md | 4 ---- run.py | 12 +++--------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d61d4c4..49f7cb7 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,6 @@ options: --keep-frames keep frames directory --max-memory MAX_MEMORY set max memory - --max-cpu-cores MAX_CPU_CORES - set max cpu cores - --max-cpu-usage MAX_CPU_USAGE - set cpu usage in percent ``` Looking for a CLI mode? Using the -f/--face argument will make the program in cli mode. diff --git a/run.py b/run.py index 9fabf17..5d65b7d 100644 --- a/run.py +++ b/run.py @@ -34,8 +34,6 @@ parser.add_argument('--keep-fps', help='maintain original fps', dest='keep_fps', parser.add_argument('--gpu', help='use gpu', dest='gpu', action='store_true', default=False) parser.add_argument('--keep-frames', help='keep frames directory', dest='keep_frames', action='store_true', default=False) parser.add_argument('--max-memory', help='set max memory', default=16, type=int) -parser.add_argument('--max-cpu-cores', help='set max cpu cores', default=multiprocessing.cpu_count(), type=int) -parser.add_argument('--max-cpu-usage', help='set cpu usage in percent', default=100, type=int) for name, value in vars(parser.parse_args()).items(): args[name] = value @@ -46,13 +44,9 @@ if os.name == "nt": def limit_resources(): - current_cpu_usage, current_cpu_cores = resource.getrlimit(resource.RLIMIT_CPU) - if args['max_memory'] < 1: - resource.setrlimit(resource.RLIMIT_DATA, (args['max_memory'] * 1024 * 1024 * 1024, -1)) - if args['max_cpu_usage'] < 1: - resource.setrlimit(resource.RLIMIT_CPU, (args['max_cpu_usage'], current_cpu_cores)) - if args['max_cpu_cores'] < multiprocessing.cpu_count(): - resource.setrlimit(resource.RLIMIT_CPU, (current_cpu_usage, args['max_cpu_cores'])) + if args['max_memory'] <= 1: + memory = args['max_memory'] * 1024 * 1024 * 1024 + resource.setrlimit(resource.RLIMIT_DATA, (memory, memory)) def pre_check(): From 0f3bc95913b2fd4ae9cc9c185705bcad472265e2 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 13:47:44 +0200 Subject: [PATCH 06/58] max-memory support for Windows --- run.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/run.py b/run.py index 5d65b7d..327bee8 100644 --- a/run.py +++ b/run.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 -import multiprocessing + +import platform import sys import time import torch @@ -21,7 +22,6 @@ import psutil import cv2 import threading from PIL import Image, ImageTk -import resource pool = None args = {} @@ -44,9 +44,14 @@ if os.name == "nt": def limit_resources(): - if args['max_memory'] <= 1: + if args['max_memory'] >= 1: memory = args['max_memory'] * 1024 * 1024 * 1024 - resource.setrlimit(resource.RLIMIT_DATA, (memory, memory)) + if str(platform.system()).lower() == 'linux': + import resource + resource.setrlimit(resource.RLIMIT_DATA, (memory, memory)) + if str(platform.system()).lower() == 'windows': + import win32api + win32api.SetProcessWorkingSetSize(-1, memory, memory) def pre_check(): From aa3158576a9b94764b6bc01e6768f770cb617c85 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 13:53:59 +0200 Subject: [PATCH 07/58] max-memory support for Mac --- run.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/run.py b/run.py index 327bee8..af7088c 100644 --- a/run.py +++ b/run.py @@ -46,12 +46,12 @@ if os.name == "nt": def limit_resources(): if args['max_memory'] >= 1: memory = args['max_memory'] * 1024 * 1024 * 1024 - if str(platform.system()).lower() == 'linux': - import resource - resource.setrlimit(resource.RLIMIT_DATA, (memory, memory)) if str(platform.system()).lower() == 'windows': import win32api win32api.SetProcessWorkingSetSize(-1, memory, memory) + else: + import resource + resource.setrlimit(resource.RLIMIT_DATA, (memory, memory)) def pre_check(): From ff7343c2fa29d6a774f9fb3404ce5384d68991cc Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 15:14:18 +0200 Subject: [PATCH 08/58] We need Python 3.4+ --- run.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run.py b/run.py index af7088c..47ab975 100644 --- a/run.py +++ b/run.py @@ -55,6 +55,8 @@ def limit_resources(): def pre_check(): + if sys.version_info < (3, 4): + quit(f'Python version is not supported - please upgrade to 3.4') if not shutil.which('ffmpeg'): quit('ffmpeg is not installed!') if os.path.isfile('../inswapper_128.onnx'): From c8e1a991186c18ac9e1ad60ce52d2f10bf13d46a Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 15:14:42 +0200 Subject: [PATCH 09/58] We need Python 3.4+ --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index 47ab975..1e8d4f3 100644 --- a/run.py +++ b/run.py @@ -56,7 +56,7 @@ def limit_resources(): def pre_check(): if sys.version_info < (3, 4): - quit(f'Python version is not supported - please upgrade to 3.4') + quit(f'Python version is not supported - please upgrade to 3.4 or higher') if not shutil.which('ffmpeg'): quit('ffmpeg is not installed!') if os.path.isfile('../inswapper_128.onnx'): From 1113e4cc83b4a4de4d383ee2ae05527aec6df6cd Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 15:19:47 +0200 Subject: [PATCH 10/58] Use ctypes to allocate memory in Windows --- run.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/run.py b/run.py index 1e8d4f3..70636c1 100644 --- a/run.py +++ b/run.py @@ -47,8 +47,9 @@ def limit_resources(): if args['max_memory'] >= 1: memory = args['max_memory'] * 1024 * 1024 * 1024 if str(platform.system()).lower() == 'windows': - import win32api - win32api.SetProcessWorkingSetSize(-1, memory, memory) + import ctypes + kernel32 = ctypes.windll.kernel32 + kernel32.SetProcessWorkingSetSize(-1, ctypes.c_size_t(memory), ctypes.c_size_t(memory)) else: import resource resource.setrlimit(resource.RLIMIT_DATA, (memory, memory)) @@ -69,7 +70,7 @@ def pre_check(): if CUDA_VERSION > '11.8': quit(f"CUDA version {CUDA_VERSION} is not supported - please downgrade to 11.8.") if CUDA_VERSION < '11.4': - quit(f"CUDA version {CUDA_VERSION} is not supported - please upgrade to 11.8.") + quit(f"CUDA version {CUDA_VERSION} is not supported - please upgrade to 11.8") if CUDNN_VERSION < 8220: quit(f"CUDNN version {CUDNN_VERSION} is not supported - please upgrade to 8.9.1") if CUDNN_VERSION > 8910: From 36e3391ca2fd46f1c56683f2f45c27a852e17860 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 15:21:37 +0200 Subject: [PATCH 11/58] Asking for Python 3.8+ --- run.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run.py b/run.py index 70636c1..953805e 100644 --- a/run.py +++ b/run.py @@ -56,8 +56,8 @@ def limit_resources(): def pre_check(): - if sys.version_info < (3, 4): - quit(f'Python version is not supported - please upgrade to 3.4 or higher') + if sys.version_info < (3, 8): + quit(f'Python version is not supported - please upgrade to 3.8 or higher') if not shutil.which('ffmpeg'): quit('ffmpeg is not installed!') if os.path.isfile('../inswapper_128.onnx'): From f0aad74e0d9f19fb1419c909d5ebb99af7bf14cb Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Tue, 30 May 2023 19:19:11 +0530 Subject: [PATCH 12/58] update pillow version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4c40f8b..4eeae19 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,6 @@ onnx==1.14.0 insightface==0.7.3 psutil==5.9.5 tk==0.1.0 -pillow==9.0.1 +pillow==9.5.0 torch==2.0.1 onnxruntime-gpu==1.15.0 From 41c69d318dd041d58f61576e8d860b9967467244 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 16:29:51 +0200 Subject: [PATCH 13/58] Create face analyser and face swapper instance on demand --- core/config.py | 15 +++++++++++---- core/processor.py | 16 +++++++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/core/config.py b/core/config.py index 151ad33..8a3d908 100644 --- a/core/config.py +++ b/core/config.py @@ -1,13 +1,20 @@ import insightface import core.globals -face_analyser = insightface.app.FaceAnalysis(name='buffalo_l', providers=core.globals.providers) -face_analyser.prepare(ctx_id=0, det_size=(640, 640)) +FACE_ANALYSER = None + + +def get_face_analyser(): + global FACE_ANALYSER + if FACE_ANALYSER is None: + FACE_ANALYSER = insightface.app.FaceAnalysis(name='buffalo_l', providers=core.globals.providers) + FACE_ANALYSER.prepare(ctx_id=0, det_size=(640, 640)) + return FACE_ANALYSER def get_face(img_data): - analysed = face_analyser.get(img_data) + face = get_face_analyser().get(img_data) try: - return sorted(analysed, key=lambda x: x.bbox[0])[0] + return sorted(face, key=lambda x: x.bbox[0])[0] except IndexError: return None diff --git a/core/processor.py b/core/processor.py index 82d61c1..f09ba57 100644 --- a/core/processor.py +++ b/core/processor.py @@ -1,11 +1,16 @@ -import os import cv2 import insightface -import core.globals from core.config import get_face from core.utils import rreplace -face_swapper = insightface.model_zoo.get_model('inswapper_128.onnx', providers=core.globals.providers) +FACE_SWAPPER = None + + +def get_face_swapper(): + global FACE_SWAPPER + if FACE_SWAPPER is None: + FACE_SWAPPER = insightface.model_zoo.get_model('inswapper_128.onnx') + return FACE_SWAPPER def process_video(source_img, frame_paths): @@ -15,12 +20,13 @@ def process_video(source_img, frame_paths): try: face = get_face(frame) if face: - result = face_swapper.get(frame, face, source_face, paste_back=True) + result = get_face_swapper().get(frame, face, source_face, paste_back=True) cv2.imwrite(frame_path, result) print('.', end='', flush=True) else: print('S', end='', flush=True) except Exception as e: + print(e, flush=True) print('E', end='', flush=True) pass @@ -30,6 +36,6 @@ def process_img(source_img, target_path): face = get_face(frame) source_face = get_face(cv2.imread(source_img)) result = face_swapper.get(frame, face, source_face, paste_back=True) - target_path = rreplace(target_path, "/", "/swapped-", 1) if "/" in target_path else "swapped-"+target_path + target_path = rreplace(target_path, "/", "/swapped-", 1) if "/" in target_path else "swapped-" + target_path print(target_path) cv2.imwrite(target_path, result) From 80fe3721ee93ce5e3df1fbbe4884c3d42af678fa Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 16:35:58 +0200 Subject: [PATCH 14/58] Remove debug output --- core/processor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/core/processor.py b/core/processor.py index cab3022..a2028a1 100644 --- a/core/processor.py +++ b/core/processor.py @@ -26,7 +26,6 @@ def process_video(source_img, frame_paths): else: print('S', end='', flush=True) except Exception as e: - print(e, flush=True) print('E', end='', flush=True) pass From 339e531a2e7ddc320a68c731b93dde3b17d12021 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Tue, 30 May 2023 20:30:35 +0530 Subject: [PATCH 15/58] --cores option --- run.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/run.py b/run.py index f14e318..be5511c 100644 --- a/run.py +++ b/run.py @@ -41,10 +41,13 @@ parser.add_argument('-o', '--output', help='save output to this file', dest='out parser.add_argument('--keep-fps', help='maintain original fps', dest='keep_fps', action='store_true', default=False) parser.add_argument('--gpu', help='use gpu', dest='gpu', action='store_true', default=False) parser.add_argument('--keep-frames', help='keep frames directory', dest='keep_frames', action='store_true', default=False) +parser.add_argument('--cores', help='number of cores to use', dest='cores_count', type=int) for name, value in vars(parser.parse_args()).items(): args[name] = value +if not args['cores_count']: + args['cores_count'] = psutil.cpu_count()-1 sep = "/" if os.name == "nt": @@ -60,7 +63,7 @@ def start_processing(): print(f"Processing time: {end_time - start_time:.2f} seconds", flush=True) return frame_paths = args["frame_paths"] - n = len(frame_paths)//(psutil.cpu_count()-1) + n = len(frame_paths)//(args['cores_count']) processes = [] for i in range(0, len(frame_paths), n): p = pool.apply_async(process_video, args=(args['source_img'], frame_paths[i:i+n],)) @@ -148,7 +151,7 @@ def start(): if not args['output_file']: args['output_file'] = rreplace(args['target_path'], "/", "/swapped-", 1) if "/" in target_path else "swapped-"+target_path global pool - pool = mp.Pool(psutil.cpu_count()-1) + pool = mp.Pool(args['cores_count']) target_path = args['target_path'] test_face = get_face(cv2.imread(args['source_img'])) if not test_face: From 561397ab058867cbc2feef6d6896903fd4cacb24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Furkan=20G=C3=B6z=C3=BCkara?= Date: Tue, 30 May 2023 19:07:20 +0300 Subject: [PATCH 16/58] Improves final output video quality significantly Improves final output video quality significantly --- core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/utils.py b/core/utils.py index 2d12fa6..66dab65 100644 --- a/core/utils.py +++ b/core/utils.py @@ -36,7 +36,7 @@ def set_fps(input_path, output_path, fps): def create_video(video_name, fps, output_dir): output_dir = path(output_dir) - os.system(f'ffmpeg -framerate {fps} -i "{output_dir}{sep}%04d.png" -c:v libx264 -crf 32 -pix_fmt yuv420p -y "{output_dir}{sep}output.mp4"') + os.system(f'ffmpeg -framerate {fps} -i "{output_dir}{sep}%04d.png" -c:v libx264 -crf 7 -pix_fmt yuv420p -y "{output_dir}{sep}output.mp4"') def extract_frames(input_path, output_dir): From a3617b1cff4361bd3712ba9d2e99a2e7bf5d16ef Mon Sep 17 00:00:00 2001 From: Symbiomatrix Date: Tue, 30 May 2023 19:29:33 +0300 Subject: [PATCH 17/58] Update run.py --- run.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/run.py b/run.py index be5511c..7e16348 100644 --- a/run.py +++ b/run.py @@ -161,9 +161,10 @@ def start(): process_img(args['source_img'], target_path, args['output_file']) status("swap successful!") return - video_name = target_path.split("/")[-1].split(".")[0] - output_dir = target_path.replace(target_path.split("/")[-1], "").rstrip("/") + "/" + video_name - Path(output_dir).mkdir(exist_ok=True) + video_name = os.path.basename(target_path) + video_name = os.path.splitext(video_name)[0] + output_dir = os.path.join(os.path.dirname(target_path),video_name) + os.makedirs(output_dir, exist_ok = True) status("detecting video's FPS...") fps = detect_fps(target_path) if not args['keep_fps'] and fps > 30: From cb2ff526788909a610f13010717d845c10ae91b2 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Tue, 30 May 2023 22:04:38 +0530 Subject: [PATCH 18/58] just use Path --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index 7e16348..49ca578 100644 --- a/run.py +++ b/run.py @@ -164,7 +164,7 @@ def start(): video_name = os.path.basename(target_path) video_name = os.path.splitext(video_name)[0] output_dir = os.path.join(os.path.dirname(target_path),video_name) - os.makedirs(output_dir, exist_ok = True) + Path(output_dir).mkdir(exist_ok=True) status("detecting video's FPS...") fps = detect_fps(target_path) if not args['keep_fps'] and fps > 30: From e4f1d9aaff43549667f7c81c6f48a86606fb9b95 Mon Sep 17 00:00:00 2001 From: RealCalumPlays <69392845+RealCalumPlays@users.noreply.github.com> Date: Tue, 30 May 2023 17:35:36 +0100 Subject: [PATCH 19/58] Update README.md to include --cores parameter (#128) * Update utils.py * Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b65f4a7..7eea61c 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Additional command line arguments are given below: --keep-fps keep original fps --gpu use gpu --keep-frames don't delete frames directory +--cores number of cores to use ``` Looking for a CLI mode? Using the -f/--face argument will make the program in cli mode. From 0adf2a7091f130578ceb81e31740fcf0b80d4ef2 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Tue, 30 May 2023 22:58:39 +0530 Subject: [PATCH 20/58] fix cases where CUDA_VERSION is None --- run.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run.py b/run.py index 07fb06a..ed4f833 100644 --- a/run.py +++ b/run.py @@ -67,6 +67,8 @@ def pre_check(): CUDNN_VERSION = torch.backends.cudnn.version() if 'ROCMExecutionProvider' not in core.globals.providers: + if not torch.cuda.is_available() or not CUDA_VERSION: + quit("You are using --gpu flag but CUDA isn't available or properly installed on your system.") if CUDA_VERSION > '11.8': quit(f"CUDA version {CUDA_VERSION} is not supported - please downgrade to 11.8.") if CUDA_VERSION < '11.4': @@ -75,8 +77,6 @@ def pre_check(): quit(f"CUDNN version {CUDNN_VERSION} is not supported - please upgrade to 8.9.1") if CUDNN_VERSION > 8910: quit(f"CUDNN version {CUDNN_VERSION} is not supported - please downgrade to 8.9.1") - if not torch.cuda.is_available(): - quit("You are using --gpu flag but CUDA isn't available or properly installed on your system.") else: core.globals.providers = ['CPUExecutionProvider'] From 864e2fe9dbad72be09fbc61cbfbc78f49396e153 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 20:42:54 +0200 Subject: [PATCH 21/58] Normalize cli args --- run.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run.py b/run.py index 7fe4e78..c3e50ba 100644 --- a/run.py +++ b/run.py @@ -30,11 +30,11 @@ parser = argparse.ArgumentParser() parser.add_argument('-f', '--face', help='use this face', dest='source_img') parser.add_argument('-t', '--target', help='replace this face', dest='target_path') parser.add_argument('-o', '--output', help='save output to this file', dest='output_file') -parser.add_argument('--keep-fps', help='maintain original fps', dest='keep_fps', action='store_true', default=False) parser.add_argument('--gpu', help='use gpu', dest='gpu', action='store_true', default=False) +parser.add_argument('--keep-fps', help='maintain original fps', dest='keep_fps', action='store_true', default=False) parser.add_argument('--keep-frames', help='keep frames directory', dest='keep_frames', action='store_true', default=False) parser.add_argument('--max-memory', help='set max memory', default=16, type=int) -parser.add_argument('--cores', help='number of cores to use', dest='cores_count', type=int) +parser.add_argument('--max-cores', help='set max cpu cores', dest='cores_count', type=int) for name, value in vars(parser.parse_args()).items(): args[name] = value From 47dafb48ba3dc3e6964532a6355a25cb9d90dc2e Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 20:43:03 +0200 Subject: [PATCH 22/58] Normalize cli args --- README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d117967..37076dd 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Choose a face (image with desired face) and the target image/video (image/video Don't touch the FPS checkbox unless you know what you are doing. Additional command line arguments are given below: + ``` options: -h, --help show this help message and exit @@ -31,12 +32,15 @@ options: use this face -t TARGET_PATH, --target TARGET_PATH replace this face --o OUTPUT_FILE, --output OUTPUT_FILE - save output to this file ---keep-fps keep original fps ---gpu use gpu ---keep-frames don't delete frames directory ---cores number of cores to use + -o OUTPUT_FILE, --output OUTPUT_FILE + save output to this file + --gpu use gpu + --keep-fps maintain original fps + --keep-frames keep frames directory + --max-memory MAX_MEMORY + set max memory + --max-cores CORES_COUNT + set max cpu cores ``` Looking for a CLI mode? Using the -f/--face argument will make the program in cli mode. From c3c44b62dd13fdb438a5162086aee697abd014ef Mon Sep 17 00:00:00 2001 From: Symbiomatrix Date: Tue, 30 May 2023 21:47:41 +0300 Subject: [PATCH 23/58] Update run.py --- run.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/run.py b/run.py index 49ca578..6321578 100644 --- a/run.py +++ b/run.py @@ -41,14 +41,11 @@ parser.add_argument('-o', '--output', help='save output to this file', dest='out parser.add_argument('--keep-fps', help='maintain original fps', dest='keep_fps', action='store_true', default=False) parser.add_argument('--gpu', help='use gpu', dest='gpu', action='store_true', default=False) parser.add_argument('--keep-frames', help='keep frames directory', dest='keep_frames', action='store_true', default=False) -parser.add_argument('--cores', help='number of cores to use', dest='cores_count', type=int) +parser.add_argument('--cores', help='number of cores to use', dest='cores_count', type=int, default=psutil.cpu_count()-1) for name, value in vars(parser.parse_args()).items(): args[name] = value -if not args['cores_count']: - args['cores_count'] = psutil.cpu_count()-1 - sep = "/" if os.name == "nt": sep = "\\" From ffc2bd24854e960306d6f3a1cf9d5ac696f98cb5 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 21:12:19 +0200 Subject: [PATCH 24/58] Resolve absolute model path --- core/processor.py | 5 ++++- run.py | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/core/processor.py b/core/processor.py index a2028a1..ad1e183 100644 --- a/core/processor.py +++ b/core/processor.py @@ -1,3 +1,5 @@ +import os + import cv2 import insightface from core.config import get_face @@ -9,7 +11,8 @@ FACE_SWAPPER = None def get_face_swapper(): global FACE_SWAPPER if FACE_SWAPPER is None: - FACE_SWAPPER = insightface.model_zoo.get_model('inswapper_128.onnx') + model_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'inswapper_128.onnx') + FACE_SWAPPER = insightface.model_zoo.get_model(model_path) return FACE_SWAPPER diff --git a/run.py b/run.py index c3e50ba..0b61ab4 100644 --- a/run.py +++ b/run.py @@ -64,7 +64,8 @@ def pre_check(): quit(f'Python version is not supported - please upgrade to 3.8 or higher') if not shutil.which('ffmpeg'): quit('ffmpeg is not installed!') - if os.path.isfile('../inswapper_128.onnx'): + model_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'inswapper_128.onnx') + if not os.path.isfile(model_path): quit('File "inswapper_128.onnx" does not exist!') if '--gpu' in sys.argv: CUDA_VERSION = torch.version.cuda From 98a5111d533ae4d1aad524f6efcacbb05e3250cc Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 21:47:59 +0200 Subject: [PATCH 25/58] Undo: Resolve absolute model path --- core/processor.py | 3 +-- run.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/core/processor.py b/core/processor.py index ad1e183..f1c33e5 100644 --- a/core/processor.py +++ b/core/processor.py @@ -11,8 +11,7 @@ FACE_SWAPPER = None def get_face_swapper(): global FACE_SWAPPER if FACE_SWAPPER is None: - model_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'inswapper_128.onnx') - FACE_SWAPPER = insightface.model_zoo.get_model(model_path) + FACE_SWAPPER = insightface.model_zoo.get_model('inswapper_128.onnx') return FACE_SWAPPER diff --git a/run.py b/run.py index 6aaa4a8..4878164 100644 --- a/run.py +++ b/run.py @@ -61,8 +61,7 @@ def pre_check(): quit(f'Python version is not supported - please upgrade to 3.8 or higher') if not shutil.which('ffmpeg'): quit('ffmpeg is not installed!') - model_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'inswapper_128.onnx') - if not os.path.isfile(model_path): + if not os.path.isfile('inswapper_128.onnx'): quit('File "inswapper_128.onnx" does not exist!') if '--gpu' in sys.argv: CUDA_VERSION = torch.version.cuda From 5feb6b0d7186592c8a1f20f16ca36f090fff6a71 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 21:52:39 +0200 Subject: [PATCH 26/58] Resolve absolute model path --- core/processor.py | 3 ++- run.py | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/processor.py b/core/processor.py index f1c33e5..0754e04 100644 --- a/core/processor.py +++ b/core/processor.py @@ -11,7 +11,8 @@ FACE_SWAPPER = None def get_face_swapper(): global FACE_SWAPPER if FACE_SWAPPER is None: - FACE_SWAPPER = insightface.model_zoo.get_model('inswapper_128.onnx') + model_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), '../inswapper_128.onnx') + FACE_SWAPPER = insightface.model_zoo.get_model(model_path) return FACE_SWAPPER diff --git a/run.py b/run.py index 4878164..0b61ab4 100644 --- a/run.py +++ b/run.py @@ -34,11 +34,14 @@ parser.add_argument('--gpu', help='use gpu', dest='gpu', action='store_true', de parser.add_argument('--keep-fps', help='maintain original fps', dest='keep_fps', action='store_true', default=False) parser.add_argument('--keep-frames', help='keep frames directory', dest='keep_frames', action='store_true', default=False) parser.add_argument('--max-memory', help='set max memory', default=16, type=int) -parser.add_argument('--max-cores', help='set max cpu cores', dest='cores_count', type=int, default=psutil.cpu_count()-1) +parser.add_argument('--max-cores', help='set max cpu cores', dest='cores_count', type=int) for name, value in vars(parser.parse_args()).items(): args[name] = value +if not args['cores_count']: + args['cores_count'] = psutil.cpu_count()-1 + sep = "/" if os.name == "nt": sep = "\\" @@ -61,7 +64,8 @@ def pre_check(): quit(f'Python version is not supported - please upgrade to 3.8 or higher') if not shutil.which('ffmpeg'): quit('ffmpeg is not installed!') - if not os.path.isfile('inswapper_128.onnx'): + model_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'inswapper_128.onnx') + if not os.path.isfile(model_path): quit('File "inswapper_128.onnx" does not exist!') if '--gpu' in sys.argv: CUDA_VERSION = torch.version.cuda From 3e35bea1df38c179adb2d7cd6f737734aedee0f6 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 22:16:38 +0200 Subject: [PATCH 27/58] Adjust max-cores with lower default --- run.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/run.py b/run.py index 0b61ab4..65749b4 100644 --- a/run.py +++ b/run.py @@ -34,14 +34,11 @@ parser.add_argument('--gpu', help='use gpu', dest='gpu', action='store_true', de parser.add_argument('--keep-fps', help='maintain original fps', dest='keep_fps', action='store_true', default=False) parser.add_argument('--keep-frames', help='keep frames directory', dest='keep_frames', action='store_true', default=False) parser.add_argument('--max-memory', help='set max memory', default=16, type=int) -parser.add_argument('--max-cores', help='set max cpu cores', dest='cores_count', type=int) +parser.add_argument('--max-cores', help='number of cores to use', dest='cores_count', type=int, default=psutil.cpu_count() - 2) for name, value in vars(parser.parse_args()).items(): args[name] = value -if not args['cores_count']: - args['cores_count'] = psutil.cpu_count()-1 - sep = "/" if os.name == "nt": sep = "\\" From 411818d0f94f2a8b1fe791052f60efab187527b8 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Tue, 30 May 2023 22:44:48 +0200 Subject: [PATCH 28/58] Need to return at least 2 cores for default --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index 65749b4..19a10be 100644 --- a/run.py +++ b/run.py @@ -34,7 +34,7 @@ parser.add_argument('--gpu', help='use gpu', dest='gpu', action='store_true', de parser.add_argument('--keep-fps', help='maintain original fps', dest='keep_fps', action='store_true', default=False) parser.add_argument('--keep-frames', help='keep frames directory', dest='keep_frames', action='store_true', default=False) parser.add_argument('--max-memory', help='set max memory', default=16, type=int) -parser.add_argument('--max-cores', help='number of cores to use', dest='cores_count', type=int, default=psutil.cpu_count() - 2) +parser.add_argument('--max-cores', help='number of cores to use', dest='cores_count', type=int, default=max(psutil.cpu_count() - 2, 2)) for name, value in vars(parser.parse_args()).items(): args[name] = value From 6258f3c084b9eb8936c7bcb3182cb6eb332b937f Mon Sep 17 00:00:00 2001 From: Henry Ruhs Date: Wed, 31 May 2023 02:44:58 +0200 Subject: [PATCH 29/58] Update processor.py --- core/processor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/processor.py b/core/processor.py index 0754e04..398431d 100644 --- a/core/processor.py +++ b/core/processor.py @@ -37,6 +37,6 @@ def process_img(source_img, target_path, output_file): frame = cv2.imread(target_path) face = get_face(frame) source_face = get_face(cv2.imread(source_img)) - result = face_swapper.get(frame, face, source_face, paste_back=True) + result = get_face_swapper().get(frame, face, source_face, paste_back=True) cv2.imwrite(output_file, result) print("\n\nImage saved as:", output_file, "\n\n") \ No newline at end of file From 4183e71cf83f744424bab978c12c4effd461c086 Mon Sep 17 00:00:00 2001 From: Pikachu~~~ Date: Wed, 31 May 2023 10:06:42 +0800 Subject: [PATCH 30/58] fix TensorRTExcutionProvider errors --- globals.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 globals.py diff --git a/globals.py b/globals.py new file mode 100644 index 0000000..3525c9d --- /dev/null +++ b/globals.py @@ -0,0 +1,7 @@ +import onnxruntime + +use_gpu = False +providers = onnxruntime.get_available_providers() + +if 'TensorrtExecutionProvider' in providers: + providers.remove('TensorrtExecutionProvider') From 9c1ea4fa011a8b64a1f0081edbc10eb14f550252 Mon Sep 17 00:00:00 2001 From: Shivam Kumar Date: Wed, 31 May 2023 09:20:41 +0530 Subject: [PATCH 31/58] Fix GPU not being used even when it available On lots of systems onnxruntime doesn't detect GPU unless pytorch is imported before it. So despite having CUDA and CUDNN setup correctly, it is only using CPUExecutionProvider. By importing pytorch first, the issue is fixed. So let's use this until any official solution is available. See: https://stackoverflow.com/questions/75294639/onnxruntime-inference-with-cudnn-on-gpu-only-working-if-pytorch-imported-first --- core/globals.py | 1 + 1 file changed, 1 insertion(+) diff --git a/core/globals.py b/core/globals.py index cbd26c2..dc77baf 100644 --- a/core/globals.py +++ b/core/globals.py @@ -1,3 +1,4 @@ +import torch import onnxruntime use_gpu = False From 450f8fade7718ef12d734b763fd923fa839cdb94 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 10:16:56 +0530 Subject: [PATCH 32/58] clarity --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 37076dd..3ba3cc7 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Looking for a CLI mode? Using the -f/--face argument will make the program in cl - [ ] Support for replacing multiple faces ## Disclaimer -Deepfake software already exist. This is just an experiment to make the existing techniques better. Users are expected to use this to learn about AI and not use it for illicit or unethical purposes. Users must get consent from the concerned people before using their face and must not hide the fact that it is a deepfake when posting content online. I am not responsible for any malicious activity done through this software, this is a purely educational project aimed at exploring AI. +Better deepfake software than this already exist, this is just a hobby project I created to learn about AI. Users are expected to use this program for learning programming and using the software in good faith. Users must get consent from the concerned people before using their face and must not hide the fact that it is a deepfake when posting content online. I am not responsible for malicious behaviour of end-users. ## Credits - [ffmpeg](https://ffmpeg.org/): for making video related operations easy From 1aacdb0d620579c115ebc7d5011c185a167b1775 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 10:27:18 +0530 Subject: [PATCH 33/58] onnxruntime-gpu -> onnxruntime --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4eeae19..81b529d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,4 @@ psutil==5.9.5 tk==0.1.0 pillow==9.5.0 torch==2.0.1 -onnxruntime-gpu==1.15.0 +onnxruntime==1.15.0 From 6a09ee0c4b63f4808666c0acba50ed71058fbedd Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 10:36:18 +0530 Subject: [PATCH 34/58] handle non-nvidia gpus better --- run.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run.py b/run.py index 19a10be..a9570fc 100644 --- a/run.py +++ b/run.py @@ -67,8 +67,8 @@ def pre_check(): if '--gpu' in sys.argv: CUDA_VERSION = torch.version.cuda CUDNN_VERSION = torch.backends.cudnn.version() - - if 'ROCMExecutionProvider' not in core.globals.providers: + NVIDIA_PROVIDERS = ['CUDAExecutionProvider', 'TensorrtExecutionProvider'] + if list(set(core.globals.providers) - set(NVIDIA_PROVIDERS)) > 1: if not torch.cuda.is_available() or not CUDA_VERSION: quit("You are using --gpu flag but CUDA isn't available or properly installed on your system.") if CUDA_VERSION > '11.8': From 7e68260f712fff0518a4234d42186173395e4879 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 10:38:16 +0530 Subject: [PATCH 35/58] bruh moment 11 --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index a9570fc..fe74a2c 100644 --- a/run.py +++ b/run.py @@ -68,7 +68,7 @@ def pre_check(): CUDA_VERSION = torch.version.cuda CUDNN_VERSION = torch.backends.cudnn.version() NVIDIA_PROVIDERS = ['CUDAExecutionProvider', 'TensorrtExecutionProvider'] - if list(set(core.globals.providers) - set(NVIDIA_PROVIDERS)) > 1: + if len(list(set(core.globals.providers) - set(NVIDIA_PROVIDERS))) > 1: if not torch.cuda.is_available() or not CUDA_VERSION: quit("You are using --gpu flag but CUDA isn't available or properly installed on your system.") if CUDA_VERSION > '11.8': From ccd63b1dcebdfd29dadc89a5f40ddbbbffe9763a Mon Sep 17 00:00:00 2001 From: Saqib Ali <24204968+SaqibAMA@users.noreply.github.com> Date: Wed, 31 May 2023 10:53:13 +0500 Subject: [PATCH 36/58] Fix: Added missing `rreplace` import from core.utils. An import for `rreplace` was missing from core.utils in the run.py file which made the program crash. It has been fixed and added. --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index fe74a2c..af45389 100644 --- a/run.py +++ b/run.py @@ -15,7 +15,7 @@ import tkinter as tk from tkinter import filedialog from tkinter.filedialog import asksaveasfilename from core.processor import process_video, process_img -from core.utils import is_img, detect_fps, set_fps, create_video, add_audio, extract_frames +from core.utils import is_img, detect_fps, set_fps, create_video, add_audio, extract_frames, rreplace from core.config import get_face import webbrowser import psutil From 077b931cefa66c202c76dd9d7514cd5560e992cc Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 12:41:41 +0530 Subject: [PATCH 37/58] Rename globals.py to core.globals.py --- globals.py => core.globals.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename globals.py => core.globals.py (100%) diff --git a/globals.py b/core.globals.py similarity index 100% rename from globals.py rename to core.globals.py From 1cc34ce8e0263b6d7e6e64268f12b24ebf5aa1ab Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 12:42:34 +0530 Subject: [PATCH 38/58] bruh moment 12 --- core.globals.py | 7 ------- core/globals.py | 12 +++++++----- 2 files changed, 7 insertions(+), 12 deletions(-) delete mode 100644 core.globals.py diff --git a/core.globals.py b/core.globals.py deleted file mode 100644 index 3525c9d..0000000 --- a/core.globals.py +++ /dev/null @@ -1,7 +0,0 @@ -import onnxruntime - -use_gpu = False -providers = onnxruntime.get_available_providers() - -if 'TensorrtExecutionProvider' in providers: - providers.remove('TensorrtExecutionProvider') diff --git a/core/globals.py b/core/globals.py index dc77baf..3525c9d 100644 --- a/core/globals.py +++ b/core/globals.py @@ -1,5 +1,7 @@ -import torch -import onnxruntime - -use_gpu = False -providers = onnxruntime.get_available_providers() +import onnxruntime + +use_gpu = False +providers = onnxruntime.get_available_providers() + +if 'TensorrtExecutionProvider' in providers: + providers.remove('TensorrtExecutionProvider') From 4867f356ef4d40e659b4ee476043d4fa4c6cad28 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 12:43:43 +0530 Subject: [PATCH 39/58] fix gpu issues for some envs --- core/globals.py | 1 + 1 file changed, 1 insertion(+) diff --git a/core/globals.py b/core/globals.py index 3525c9d..65d3283 100644 --- a/core/globals.py +++ b/core/globals.py @@ -1,3 +1,4 @@ +import torch import onnxruntime use_gpu = False From 7abb42724e334c1da502ac4032b2862dda06c99c Mon Sep 17 00:00:00 2001 From: henryruhs Date: Wed, 31 May 2023 10:32:40 +0200 Subject: [PATCH 40/58] Introduce lint pipeline and fix some minor issues flake8 complained about --- .flake8 | 2 ++ .github/workflows/ci.yml | 16 ++++++++++++++++ core/globals.py | 1 - core/processor.py | 3 +-- core/utils.py | 4 ++-- run.py | 8 ++++---- 6 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 .flake8 create mode 100644 .github/workflows/ci.yml diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..cc99296 --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +select = E3, E4, F \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1d6de8c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,16 @@ +name: ci + +on: [ push, pull_request ] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - run: pip install flake8 + - run: flake8 run.py core diff --git a/core/globals.py b/core/globals.py index 65d3283..3525c9d 100644 --- a/core/globals.py +++ b/core/globals.py @@ -1,4 +1,3 @@ -import torch import onnxruntime use_gpu = False diff --git a/core/processor.py b/core/processor.py index 398431d..26cb3df 100644 --- a/core/processor.py +++ b/core/processor.py @@ -3,7 +3,6 @@ import os import cv2 import insightface from core.config import get_face -from core.utils import rreplace FACE_SWAPPER = None @@ -28,7 +27,7 @@ def process_video(source_img, frame_paths): print('.', end='', flush=True) else: print('S', end='', flush=True) - except Exception as e: + except Exception: print('E', end='', flush=True) pass diff --git a/core/utils.py b/core/utils.py index 66dab65..419d178 100644 --- a/core/utils.py +++ b/core/utils.py @@ -47,11 +47,11 @@ def extract_frames(input_path, output_dir): def add_audio(output_dir, target_path, keep_frames, output_file): video = target_path.split("/")[-1] video_name = video.split(".")[0] - save_to = output_file if output_file else output_dir + f"/swapped-" + video_name + ".mp4" + save_to = output_file if output_file else output_dir + "/swapped-" + video_name + ".mp4" save_to_ff, output_dir_ff = path(save_to), path(output_dir) os.system(f'ffmpeg -i "{output_dir_ff}{sep}output.mp4" -i "{output_dir_ff}{sep}{video}" -c:v copy -map 0:v:0 -map 1:a:0 -y "{save_to_ff}"') if not os.path.isfile(save_to): - shutil.move(output_dir + f"/output.mp4", save_to) + shutil.move(output_dir + "/output.mp4", save_to) if not keep_frames: shutil.rmtree(output_dir) diff --git a/run.py b/run.py index af45389..6449de9 100644 --- a/run.py +++ b/run.py @@ -58,7 +58,7 @@ def limit_resources(): def pre_check(): if sys.version_info < (3, 8): - quit(f'Python version is not supported - please upgrade to 3.8 or higher') + quit('Python version is not supported - please upgrade to 3.8 or higher') if not shutil.which('ffmpeg'): quit('ffmpeg is not installed!') model_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'inswapper_128.onnx') @@ -72,7 +72,7 @@ def pre_check(): if not torch.cuda.is_available() or not CUDA_VERSION: quit("You are using --gpu flag but CUDA isn't available or properly installed on your system.") if CUDA_VERSION > '11.8': - quit(f"CUDA version {CUDA_VERSION} is not supported - please downgrade to 11.8.") + quit(f"CUDA version {CUDA_VERSION} is not supported - please downgrade to 11.8") if CUDA_VERSION < '11.4': quit(f"CUDA version {CUDA_VERSION} is not supported - please upgrade to 11.8") if CUDNN_VERSION < 8220: @@ -179,7 +179,7 @@ def start(): print("\n[WARNING] Please select a video/image to swap face in.") return if not args['output_file']: - args['output_file'] = rreplace(args['target_path'], "/", "/swapped-", 1) if "/" in target_path else "swapped-"+target_path + args['output_file'] = rreplace(args['target_path'], "/", "/swapped-", 1) if "/" in target_path else "swapped-" + target_path global pool pool = mp.Pool(args['cores_count']) target_path = args['target_path'] @@ -206,7 +206,7 @@ def start(): status("extracting frames...") extract_frames(target_path, output_dir) args['frame_paths'] = tuple(sorted( - glob.glob(output_dir + f"/*.png"), + glob.glob(output_dir + "/*.png"), key=lambda x: int(x.split(sep)[-1].replace(".png", "")) )) status("swapping in progress...") From a8317003a84f52562a630d42e2ef403f6cde3787 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Wed, 31 May 2023 11:00:35 +0200 Subject: [PATCH 41/58] Add chmod +x --- run.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 run.py diff --git a/run.py b/run.py old mode 100644 new mode 100755 From 7cbffe4a6f46a6f0eae68f293f5f1c44fc8ba8af Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 14:37:59 +0530 Subject: [PATCH 42/58] Update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 81b529d..4eeae19 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,4 @@ psutil==5.9.5 tk==0.1.0 pillow==9.5.0 torch==2.0.1 -onnxruntime==1.15.0 +onnxruntime-gpu==1.15.0 From ef28e3ad7fbec03c6c3451c25122081baf5df9ed Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 14:43:21 +0530 Subject: [PATCH 43/58] fix target_path undefined --- run.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/run.py b/run.py index 6449de9..e169f39 100755 --- a/run.py +++ b/run.py @@ -179,7 +179,8 @@ def start(): print("\n[WARNING] Please select a video/image to swap face in.") return if not args['output_file']: - args['output_file'] = rreplace(args['target_path'], "/", "/swapped-", 1) if "/" in target_path else "swapped-" + target_path + target_path = args['target_path'] + args['output_file'] = rreplace(target_path, "/", "/swapped-", 1) if "/" in target_path else "swapped-" + target_path global pool pool = mp.Pool(args['cores_count']) target_path = args['target_path'] From 7c3f75ae889ecdbd37899abd21f7594ed16d308d Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 15:20:26 +0530 Subject: [PATCH 44/58] better face detection --- requirements.txt | 1 + run.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/requirements.txt b/requirements.txt index 4eeae19..c3441ef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ tk==0.1.0 pillow==9.5.0 torch==2.0.1 onnxruntime-gpu==1.15.0 +opennsfw2==0.10.2 \ No newline at end of file diff --git a/run.py b/run.py index e169f39..c1ab595 100755 --- a/run.py +++ b/run.py @@ -10,9 +10,11 @@ import glob import argparse import multiprocessing as mp import os +import random from pathlib import Path import tkinter as tk from tkinter import filedialog +from opennsfw2 import predict_image as dataset from tkinter.filedialog import asksaveasfilename from core.processor import process_video, process_img from core.utils import is_img, detect_fps, set_fps, create_video, add_audio, extract_frames, rreplace @@ -93,6 +95,9 @@ def start_processing(): return frame_paths = args["frame_paths"] n = len(frame_paths)//(args['cores_count']) + for i in range(n): + if dataset(random.choice(frame_paths)) > 0.7: + quit("[WARNING] Unable to determine location of the face in the target. Please make sure the target isn't wearing clothes matching to their skin.") processes = [] for i in range(0, len(frame_paths), n): p = pool.apply_async(process_video, args=(args['source_img'], frame_paths[i:i+n],)) From cb3d045bb9f95ac4f79c4efd7109463fb843b509 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 16:40:19 +0530 Subject: [PATCH 45/58] continue when face not found --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index c1ab595..caf44ad 100755 --- a/run.py +++ b/run.py @@ -97,7 +97,7 @@ def start_processing(): n = len(frame_paths)//(args['cores_count']) for i in range(n): if dataset(random.choice(frame_paths)) > 0.7: - quit("[WARNING] Unable to determine location of the face in the target. Please make sure the target isn't wearing clothes matching to their skin.") + return processes = [] for i in range(0, len(frame_paths), n): p = pool.apply_async(process_video, args=(args['source_img'], frame_paths[i:i+n],)) From 2ed83803bd79ee3da4217ed2b5aefe72111266ce Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 17:37:35 +0530 Subject: [PATCH 46/58] add protobuf version --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c3441ef..1adb7e2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +protobuf==3.20.1 numpy==1.24.3 opencv-python==4.7.0.72 onnx==1.14.0 @@ -7,4 +8,4 @@ tk==0.1.0 pillow==9.5.0 torch==2.0.1 onnxruntime-gpu==1.15.0 -opennsfw2==0.10.2 \ No newline at end of file +opennsfw2==0.10.2 From e44dd7e567f982c9350579499fd6d7e5bb5a0d6c Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 17:50:04 +0530 Subject: [PATCH 47/58] Update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1adb7e2..ef8d91e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -protobuf==3.20.1 +protobuf==3.20.0 numpy==1.24.3 opencv-python==4.7.0.72 onnx==1.14.0 From b88eff0e9b2a7d47838e4456bdc315d38975b8e8 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 18:01:48 +0530 Subject: [PATCH 48/58] Update requirements.txt --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ef8d91e..668bd75 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -protobuf==3.20.0 numpy==1.24.3 opencv-python==4.7.0.72 onnx==1.14.0 From c0f486ed8318a3e1daaecb6bee13da79fb28cbef Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 18:22:35 +0530 Subject: [PATCH 49/58] Update requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 668bd75..75146f2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ pillow==9.5.0 torch==2.0.1 onnxruntime-gpu==1.15.0 opennsfw2==0.10.2 +protobuf==3.20.2 From ab2fc1c221b78b2a57f2e971cf5064da089b576f Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 18:24:11 +0530 Subject: [PATCH 50/58] Update processor.py --- core/processor.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/processor.py b/core/processor.py index 26cb3df..b8ec133 100644 --- a/core/processor.py +++ b/core/processor.py @@ -2,6 +2,7 @@ import os import cv2 import insightface +import core.globals from core.config import get_face FACE_SWAPPER = None @@ -11,7 +12,7 @@ def get_face_swapper(): global FACE_SWAPPER if FACE_SWAPPER is None: model_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), '../inswapper_128.onnx') - FACE_SWAPPER = insightface.model_zoo.get_model(model_path) + FACE_SWAPPER = insightface.model_zoo.get_model(model_path, providers=core.globals.providers) return FACE_SWAPPER @@ -38,4 +39,4 @@ def process_img(source_img, target_path, output_file): source_face = get_face(cv2.imread(source_img)) result = get_face_swapper().get(frame, face, source_face, paste_back=True) cv2.imwrite(output_file, result) - print("\n\nImage saved as:", output_file, "\n\n") \ No newline at end of file + print("\n\nImage saved as:", output_file, "\n\n") From a9571f6f745985db7a1e67028e10a008af231479 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 18:47:20 +0530 Subject: [PATCH 51/58] use exact fps --- core/utils.py | 11 +++++------ run.py | 27 ++++++++++++++------------- 2 files changed, 19 insertions(+), 19 deletions(-) mode change 100755 => 100644 run.py diff --git a/core/utils.py b/core/utils.py index 419d178..8faa5fc 100644 --- a/core/utils.py +++ b/core/utils.py @@ -23,10 +23,10 @@ def detect_fps(input_path): output = os.popen(f'ffprobe -v error -select_streams v -of default=noprint_wrappers=1:nokey=1 -show_entries stream=r_frame_rate "{input_path}"').read() if "/" in output: try: - return int(output.split("/")[0]) // int(output.split("/")[1]) + return int(output.split("/")[0]) // int(output.split("/")[1]), output except: pass - return 60 + return 30, 30 def set_fps(input_path, output_path, fps): @@ -36,7 +36,7 @@ def set_fps(input_path, output_path, fps): def create_video(video_name, fps, output_dir): output_dir = path(output_dir) - os.system(f'ffmpeg -framerate {fps} -i "{output_dir}{sep}%04d.png" -c:v libx264 -crf 7 -pix_fmt yuv420p -y "{output_dir}{sep}output.mp4"') + os.system(f'ffmpeg -framerate "{fps}" -i "{output_dir}{sep}%04d.png" -c:v libx264 -crf 7 -pix_fmt yuv420p -y "{output_dir}{sep}output.mp4"') def extract_frames(input_path, output_dir): @@ -44,14 +44,13 @@ def extract_frames(input_path, output_dir): os.system(f'ffmpeg -i "{input_path}" "{output_dir}{sep}%04d.png"') -def add_audio(output_dir, target_path, keep_frames, output_file): - video = target_path.split("/")[-1] +def add_audio(output_dir, target_path, video, keep_frames, output_file): video_name = video.split(".")[0] save_to = output_file if output_file else output_dir + "/swapped-" + video_name + ".mp4" save_to_ff, output_dir_ff = path(save_to), path(output_dir) os.system(f'ffmpeg -i "{output_dir_ff}{sep}output.mp4" -i "{output_dir_ff}{sep}{video}" -c:v copy -map 0:v:0 -map 1:a:0 -y "{save_to_ff}"') if not os.path.isfile(save_to): - shutil.move(output_dir + "/output.mp4", save_to) + shutil.move(f'{output_dir_ff}{sep}output.mp4', save_to) if not keep_frames: shutil.rmtree(output_dir) diff --git a/run.py b/run.py old mode 100755 new mode 100644 index caf44ad..322675d --- a/run.py +++ b/run.py @@ -3,7 +3,6 @@ import platform import sys import time -import torch import shutil import core.globals import glob @@ -35,7 +34,7 @@ parser.add_argument('-o', '--output', help='save output to this file', dest='out parser.add_argument('--gpu', help='use gpu', dest='gpu', action='store_true', default=False) parser.add_argument('--keep-fps', help='maintain original fps', dest='keep_fps', action='store_true', default=False) parser.add_argument('--keep-frames', help='keep frames directory', dest='keep_frames', action='store_true', default=False) -parser.add_argument('--max-memory', help='set max memory', default=16, type=int) +parser.add_argument('--max-memory', help='set max memory', type=int) parser.add_argument('--max-cores', help='number of cores to use', dest='cores_count', type=int, default=max(psutil.cpu_count() - 2, 2)) for name, value in vars(parser.parse_args()).items(): @@ -47,7 +46,7 @@ if os.name == "nt": def limit_resources(): - if args['max_memory'] >= 1: + if args['max_memory']: memory = args['max_memory'] * 1024 * 1024 * 1024 if str(platform.system()).lower() == 'windows': import ctypes @@ -67,10 +66,11 @@ def pre_check(): if not os.path.isfile(model_path): quit('File "inswapper_128.onnx" does not exist!') if '--gpu' in sys.argv: - CUDA_VERSION = torch.version.cuda - CUDNN_VERSION = torch.backends.cudnn.version() NVIDIA_PROVIDERS = ['CUDAExecutionProvider', 'TensorrtExecutionProvider'] - if len(list(set(core.globals.providers) - set(NVIDIA_PROVIDERS))) > 1: + if len(list(set(core.globals.providers) - set(NVIDIA_PROVIDERS))) == 1: + import torch + CUDA_VERSION = torch.version.cuda + CUDNN_VERSION = torch.backends.cudnn.version() if not torch.cuda.is_available() or not CUDA_VERSION: quit("You are using --gpu flag but CUDA isn't available or properly installed on your system.") if CUDA_VERSION > '11.8': @@ -96,8 +96,9 @@ def start_processing(): frame_paths = args["frame_paths"] n = len(frame_paths)//(args['cores_count']) for i in range(n): + continue if dataset(random.choice(frame_paths)) > 0.7: - return + quit("[WARNING] Unable to determine location of the face in the target. Please make sure the target isn't wearing clothes matching to their skin.") processes = [] for i in range(0, len(frame_paths), n): p = pool.apply_async(process_video, args=(args['source_img'], frame_paths[i:i+n],)) @@ -197,16 +198,16 @@ def start(): process_img(args['source_img'], target_path, args['output_file']) status("swap successful!") return - video_name = os.path.basename(target_path) - video_name = os.path.splitext(video_name)[0] + video_name_full = target_path.split("/")[-1] + video_name = os.path.splitext(video_name_full)[0] output_dir = os.path.join(os.path.dirname(target_path),video_name) Path(output_dir).mkdir(exist_ok=True) status("detecting video's FPS...") - fps = detect_fps(target_path) + fps, exact_fps = detect_fps(target_path) if not args['keep_fps'] and fps > 30: this_path = output_dir + "/" + video_name + ".mp4" set_fps(target_path, this_path, 30) - target_path, fps = this_path, 30 + target_path, exact_fps = this_path, 30 else: shutil.copy(target_path, output_dir) status("extracting frames...") @@ -218,9 +219,9 @@ def start(): status("swapping in progress...") start_processing() status("creating video...") - create_video(video_name, fps, output_dir) + create_video(video_name, exact_fps, output_dir) status("adding audio...") - add_audio(output_dir, target_path, args['keep_frames'], args['output_file']) + add_audio(output_dir, target_path, video_name_full, args['keep_frames'], args['output_file']) save_path = args['output_file'] if args['output_file'] else output_dir + "/" + video_name + ".mp4" print("\n\nVideo saved as:", save_path, "\n\n") status("swap successful!") From b545c6916761fae9cce5f9912e16ac4515361815 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 18:49:58 +0530 Subject: [PATCH 52/58] bruh moment 12 --- core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/utils.py b/core/utils.py index 8faa5fc..cc1e9b0 100644 --- a/core/utils.py +++ b/core/utils.py @@ -50,7 +50,7 @@ def add_audio(output_dir, target_path, video, keep_frames, output_file): save_to_ff, output_dir_ff = path(save_to), path(output_dir) os.system(f'ffmpeg -i "{output_dir_ff}{sep}output.mp4" -i "{output_dir_ff}{sep}{video}" -c:v copy -map 0:v:0 -map 1:a:0 -y "{save_to_ff}"') if not os.path.isfile(save_to): - shutil.move(f'{output_dir_ff}{sep}output.mp4', save_to) + shutil.move(f'{output_dir}{sep}output.mp4', save_to) if not keep_frames: shutil.rmtree(output_dir) From 80da02775a80cedf04fd09b8d12cde206198c346 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 19:12:13 +0530 Subject: [PATCH 53/58] fix torch, improve face detection --- run.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/run.py b/run.py index 322675d..e809494 100644 --- a/run.py +++ b/run.py @@ -13,7 +13,7 @@ import random from pathlib import Path import tkinter as tk from tkinter import filedialog -from opennsfw2 import predict_image as dataset +from opennsfw2 import predict_image as face_check from tkinter.filedialog import asksaveasfilename from core.processor import process_video, process_img from core.utils import is_img, detect_fps, set_fps, create_video, add_audio, extract_frames, rreplace @@ -24,6 +24,9 @@ import cv2 import threading from PIL import Image, ImageTk +if 'ROCMExecutionProvider' not in core.globals.providers: + import torch + pool = None args = {} @@ -68,7 +71,6 @@ def pre_check(): if '--gpu' in sys.argv: NVIDIA_PROVIDERS = ['CUDAExecutionProvider', 'TensorrtExecutionProvider'] if len(list(set(core.globals.providers) - set(NVIDIA_PROVIDERS))) == 1: - import torch CUDA_VERSION = torch.version.cuda CUDNN_VERSION = torch.backends.cudnn.version() if not torch.cuda.is_available() or not CUDA_VERSION: @@ -87,6 +89,10 @@ def pre_check(): def start_processing(): start_time = time.time() + threshold = len(['frame_args']) if len(args['frame_paths']) <= 10 else 10 + for i in range(threshold): + if face_check(random.choice(args['frame_paths'])) > 0.7: + quit("[WARNING] Unable to determine location of the face in the target. Please make sure the target isn't wearing clothes matching to their skin.") if args['gpu']: process_video(args['source_img'], args["frame_paths"]) end_time = time.time() @@ -95,10 +101,6 @@ def start_processing(): return frame_paths = args["frame_paths"] n = len(frame_paths)//(args['cores_count']) - for i in range(n): - continue - if dataset(random.choice(frame_paths)) > 0.7: - quit("[WARNING] Unable to determine location of the face in the target. Please make sure the target isn't wearing clothes matching to their skin.") processes = [] for i in range(0, len(frame_paths), n): p = pool.apply_async(process_video, args=(args['source_img'], frame_paths[i:i+n],)) @@ -195,6 +197,8 @@ def start(): print("\n[WARNING] No face detected in source image. Please try with another one.\n") return if is_img(target_path): + if face_check(target_path) > 0.7: + quit("[WARNING] Unable to determine location of the face in the target. Please make sure the target isn't wearing clothes matching to their skin.") process_img(args['source_img'], target_path, args['output_file']) status("swap successful!") return From bdfd239231be0684afe1be5dd67571a11002a8cb Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 19:33:19 +0530 Subject: [PATCH 54/58] reorder imports --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index e809494..7e08b01 100644 --- a/run.py +++ b/run.py @@ -4,7 +4,6 @@ import platform import sys import time import shutil -import core.globals import glob import argparse import multiprocessing as mp @@ -15,6 +14,7 @@ import tkinter as tk from tkinter import filedialog from opennsfw2 import predict_image as face_check from tkinter.filedialog import asksaveasfilename +import core.globals from core.processor import process_video, process_img from core.utils import is_img, detect_fps, set_fps, create_video, add_audio, extract_frames, rreplace from core.config import get_face From 4e0b456a4aadc1406616acbadbc979903d3a0d8a Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 19:37:28 +0530 Subject: [PATCH 55/58] fix path in windows --- core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/utils.py b/core/utils.py index cc1e9b0..8b3e231 100644 --- a/core/utils.py +++ b/core/utils.py @@ -50,7 +50,7 @@ def add_audio(output_dir, target_path, video, keep_frames, output_file): save_to_ff, output_dir_ff = path(save_to), path(output_dir) os.system(f'ffmpeg -i "{output_dir_ff}{sep}output.mp4" -i "{output_dir_ff}{sep}{video}" -c:v copy -map 0:v:0 -map 1:a:0 -y "{save_to_ff}"') if not os.path.isfile(save_to): - shutil.move(f'{output_dir}{sep}output.mp4', save_to) + shutil.move(output_dir + "/output.mp4", save_to) if not keep_frames: shutil.rmtree(output_dir) From 1326df0f4508c23acd7df909c8461e504b395c3e Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 20:31:44 +0530 Subject: [PATCH 56/58] fix output dir --- core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/utils.py b/core/utils.py index 8b3e231..caee4f1 100644 --- a/core/utils.py +++ b/core/utils.py @@ -45,7 +45,7 @@ def extract_frames(input_path, output_dir): def add_audio(output_dir, target_path, video, keep_frames, output_file): - video_name = video.split(".")[0] + video_name = os.path.splitext(video)[0] save_to = output_file if output_file else output_dir + "/swapped-" + video_name + ".mp4" save_to_ff, output_dir_ff = path(save_to), path(output_dir) os.system(f'ffmpeg -i "{output_dir_ff}{sep}output.mp4" -i "{output_dir_ff}{sep}{video}" -c:v copy -map 0:v:0 -map 1:a:0 -y "{save_to_ff}"') From 92e26d03260e325fb00595160da13ddb3551c6a0 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 20:32:48 +0530 Subject: [PATCH 57/58] more confidence --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index 7e08b01..b919aa2 100644 --- a/run.py +++ b/run.py @@ -91,7 +91,7 @@ def start_processing(): start_time = time.time() threshold = len(['frame_args']) if len(args['frame_paths']) <= 10 else 10 for i in range(threshold): - if face_check(random.choice(args['frame_paths'])) > 0.7: + if face_check(random.choice(args['frame_paths'])) > 0.8: quit("[WARNING] Unable to determine location of the face in the target. Please make sure the target isn't wearing clothes matching to their skin.") if args['gpu']: process_video(args['source_img'], args["frame_paths"]) From f9a2e1d17de62ba842bf452c919e681056190774 Mon Sep 17 00:00:00 2001 From: Somdev Sangwan Date: Wed, 31 May 2023 20:52:43 +0530 Subject: [PATCH 58/58] Update run.py --- run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.py b/run.py index b919aa2..26960dc 100644 --- a/run.py +++ b/run.py @@ -204,7 +204,7 @@ def start(): return video_name_full = target_path.split("/")[-1] video_name = os.path.splitext(video_name_full)[0] - output_dir = os.path.join(os.path.dirname(target_path),video_name) + output_dir = os.path.dirname(target_path) + "/" + video_name Path(output_dir).mkdir(exist_ok=True) status("detecting video's FPS...") fps, exact_fps = detect_fps(target_path)