Compare commits
55 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b5f2bd0261 | ||
|
04954d7ee2 | ||
|
2f6e56d05f | ||
|
442c070229 | ||
|
e7edbecff4 | ||
|
8509160850 | ||
|
bf100f4974 | ||
|
a66dd5cde1 | ||
|
7d42dbc4bc | ||
|
5aa91e9157 | ||
|
91b7301f32 | ||
|
7c385cc4f4 | ||
|
3daf82b3f8 | ||
|
f48f0b742e | ||
|
509ff11995 | ||
|
c208ffa551 | ||
|
946e5f35ff | ||
|
6327c0b459 | ||
|
cec2c21401 | ||
|
f85ae76367 | ||
|
5d6ff54e9b | ||
|
4a8ddf7585 | ||
|
30d33f9f58 | ||
|
50283c88e0 | ||
|
421df6b159 | ||
|
4f5f79d32b | ||
|
54c5987ef0 | ||
|
23753b523e | ||
|
96a61397ef | ||
|
4e2be506ce | ||
|
c16049517d | ||
|
667c7da540 | ||
|
cfd29513b4 | ||
|
38fb60efca | ||
|
51664c6d71 | ||
|
f9a2e1d17d | ||
|
92e26d0326 | ||
|
1326df0f45 | ||
|
4e0b456a4a | ||
|
bdfd239231 | ||
|
80da02775a | ||
|
b545c69167 | ||
|
a9571f6f74 | ||
|
ab2fc1c221 | ||
|
c0f486ed83 | ||
|
b88eff0e9b | ||
|
e44dd7e567 | ||
|
2ed83803bd | ||
|
cb3d045bb9 | ||
|
7c3f75ae88 | ||
|
2c9631e156 | ||
|
ef28e3ad7f | ||
|
7cbffe4a6f | ||
|
a8317003a8 | ||
|
7abb42724e |
16
.github/workflows/ci.yml
vendored
Normal file
16
.github/workflows/ci.yml
vendored
Normal file
@ -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.9
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
- run: pip install flake8
|
||||||
|
- run: flake8 run.py core
|
15
README.md
15
README.md
@ -4,8 +4,14 @@ That's it, that's the software. You can watch some demos [here](https://drive.go
|
|||||||
|
|
||||||
![demo-gif](demo.gif)
|
![demo-gif](demo.gif)
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
Better deepfake software than this already exist, this is just a hobby project I created to learn about AI. 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.
|
||||||
|
|
||||||
|
To prevent misuse, it has a built-in check which prevents the program from working on inappropriate media.
|
||||||
|
|
||||||
## How do I install it?
|
## How do I install it?
|
||||||
> Note: The instructions may or may not work for you. Use google or look through issues people have created here to solve your problems.
|
|
||||||
|
**Issues according installation will be closed without ceremony from now on, we cannot handle the amount of requests.**
|
||||||
|
|
||||||
There are two types of installations: basic and gpu-powered.
|
There are two types of installations: basic and gpu-powered.
|
||||||
|
|
||||||
@ -38,9 +44,9 @@ options:
|
|||||||
--keep-fps maintain original fps
|
--keep-fps maintain original fps
|
||||||
--keep-frames keep frames directory
|
--keep-frames keep frames directory
|
||||||
--max-memory MAX_MEMORY
|
--max-memory MAX_MEMORY
|
||||||
set max memory
|
maximum amount of RAM in GB to be used
|
||||||
--max-cores CORES_COUNT
|
--max-cores CORES_COUNT
|
||||||
set max cpu cores
|
number of cores to be use for CPU mode
|
||||||
```
|
```
|
||||||
|
|
||||||
Looking for a CLI mode? Using the -f/--face argument will make the program in cli mode.
|
Looking for a CLI mode? Using the -f/--face argument will make the program in cli mode.
|
||||||
@ -50,9 +56,6 @@ Looking for a CLI mode? Using the -f/--face argument will make the program in cl
|
|||||||
- [ ] Replace a selective face throughout the video
|
- [ ] Replace a selective face throughout the video
|
||||||
- [ ] Support for replacing multiple faces
|
- [ ] Support for replacing multiple faces
|
||||||
|
|
||||||
## Disclaimer
|
|
||||||
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
|
## Credits
|
||||||
- [ffmpeg](https://ffmpeg.org/): for making video related operations easy
|
- [ffmpeg](https://ffmpeg.org/): for making video related operations easy
|
||||||
- [deepinsight](https://github.com/deepinsight): for their [insightface](https://github.com/deepinsight/insightface) project which provided a well-made library and models.
|
- [deepinsight](https://github.com/deepinsight): for their [insightface](https://github.com/deepinsight/insightface) project which provided a well-made library and models.
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import torch
|
|
||||||
import onnxruntime
|
import onnxruntime
|
||||||
|
|
||||||
use_gpu = False
|
use_gpu = False
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
import cv2
|
|
||||||
import insightface
|
|
||||||
from core.config import get_face
|
|
||||||
from core.utils import rreplace
|
|
||||||
|
|
||||||
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)
|
|
||||||
return FACE_SWAPPER
|
|
||||||
|
|
||||||
|
|
||||||
def process_video(source_img, frame_paths):
|
|
||||||
source_face = get_face(cv2.imread(source_img))
|
|
||||||
for frame_path in frame_paths:
|
|
||||||
frame = cv2.imread(frame_path)
|
|
||||||
try:
|
|
||||||
face = get_face(frame)
|
|
||||||
if face:
|
|
||||||
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', end='', flush=True)
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
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 = 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")
|
|
44
core/swapper.py
Normal file
44
core/swapper.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import os
|
||||||
|
from tqdm import tqdm
|
||||||
|
import cv2
|
||||||
|
import insightface
|
||||||
|
import core.globals
|
||||||
|
from core.analyser import get_face
|
||||||
|
|
||||||
|
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, providers=core.globals.providers)
|
||||||
|
return FACE_SWAPPER
|
||||||
|
|
||||||
|
|
||||||
|
def process_video(source_img, frame_paths):
|
||||||
|
source_face = get_face(cv2.imread(source_img))
|
||||||
|
with tqdm(total=len(frame_paths), desc="Processing", unit="frame", dynamic_ncols=True, bar_format='{l_bar}{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, {rate_fmt}{postfix}]') as progress:
|
||||||
|
for frame_path in frame_paths:
|
||||||
|
frame = cv2.imread(frame_path)
|
||||||
|
try:
|
||||||
|
face = get_face(frame)
|
||||||
|
if face:
|
||||||
|
result = get_face_swapper().get(frame, face, source_face, paste_back=True)
|
||||||
|
cv2.imwrite(frame_path, result)
|
||||||
|
progress.set_postfix(status='.', refresh=True)
|
||||||
|
else:
|
||||||
|
progress.set_postfix(status='S', refresh=True)
|
||||||
|
except Exception:
|
||||||
|
progress.set_postfix(status='E', refresh=True)
|
||||||
|
pass
|
||||||
|
progress.update(1)
|
||||||
|
|
||||||
|
|
||||||
|
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 = 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")
|
@ -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()
|
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:
|
if "/" in output:
|
||||||
try:
|
try:
|
||||||
return int(output.split("/")[0]) // int(output.split("/")[1])
|
return int(output.split(os.sep)[0]) // int(output.split(os.sep)[1]), output.removesuffix('\n')
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return 60
|
return 30, 30
|
||||||
|
|
||||||
|
|
||||||
def set_fps(input_path, output_path, fps):
|
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):
|
def create_video(video_name, fps, output_dir):
|
||||||
output_dir = path(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):
|
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"')
|
os.system(f'ffmpeg -i "{input_path}" "{output_dir}{sep}%04d.png"')
|
||||||
|
|
||||||
|
|
||||||
def add_audio(output_dir, target_path, keep_frames, output_file):
|
def add_audio(output_dir, target_path, video, keep_frames, output_file):
|
||||||
video = target_path.split("/")[-1]
|
video_name = os.path.splitext(video)[0]
|
||||||
video_name = video.split(".")[0]
|
save_to = output_file if output_file else output_dir + "/swapped-" + video_name + ".mp4"
|
||||||
save_to = output_file if output_file else output_dir + f"/swapped-" + video_name + ".mp4"
|
|
||||||
save_to_ff, output_dir_ff = path(save_to), path(output_dir)
|
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}"')
|
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):
|
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:
|
if not keep_frames:
|
||||||
shutil.rmtree(output_dir)
|
shutil.rmtree(output_dir)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
numpy==1.24.3
|
numpy==1.23.5
|
||||||
opencv-python==4.7.0.72
|
opencv-python==4.7.0.72
|
||||||
onnx==1.14.0
|
onnx==1.14.0
|
||||||
insightface==0.7.3
|
insightface==0.7.3
|
||||||
@ -6,4 +6,8 @@ psutil==5.9.5
|
|||||||
tk==0.1.0
|
tk==0.1.0
|
||||||
pillow==9.5.0
|
pillow==9.5.0
|
||||||
torch==2.0.1
|
torch==2.0.1
|
||||||
onnxruntime==1.15.0
|
onnxruntime-gpu==1.15.0
|
||||||
|
tensorflow==2.12.0
|
||||||
|
opennsfw2==0.10.2
|
||||||
|
protobuf==4.23.2
|
||||||
|
tqdm==4.65.0
|
||||||
|
68
run.py
Normal file → Executable file
68
run.py
Normal file → Executable file
@ -1,31 +1,36 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import platform
|
import platform
|
||||||
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import time
|
|
||||||
import torch
|
|
||||||
import shutil
|
import shutil
|
||||||
import core.globals
|
|
||||||
import glob
|
import glob
|
||||||
import argparse
|
import argparse
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
import os
|
import os
|
||||||
|
import torch
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import filedialog
|
from tkinter import filedialog
|
||||||
|
from opennsfw2 import predict_video_frames, predict_image
|
||||||
from tkinter.filedialog import asksaveasfilename
|
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
|
|
||||||
from core.config import get_face
|
|
||||||
import webbrowser
|
import webbrowser
|
||||||
import psutil
|
import psutil
|
||||||
import cv2
|
import cv2
|
||||||
import threading
|
import threading
|
||||||
from PIL import Image, ImageTk
|
from PIL import Image, ImageTk
|
||||||
|
import core.globals
|
||||||
|
from core.swapper import process_video, process_img
|
||||||
|
from core.utils import is_img, detect_fps, set_fps, create_video, add_audio, extract_frames, rreplace
|
||||||
|
from core.analyser import get_face
|
||||||
|
|
||||||
|
if 'ROCMExecutionProvider' in core.globals.providers:
|
||||||
|
del torch
|
||||||
|
|
||||||
pool = None
|
pool = None
|
||||||
args = {}
|
args = {}
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, lambda signal_number, frame: quit())
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('-f', '--face', help='use this face', dest='source_img')
|
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('-t', '--target', help='replace this face', dest='target_path')
|
||||||
@ -33,8 +38,8 @@ 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('--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-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('--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='maximum amount of RAM in GB to be used', 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))
|
parser.add_argument('--max-cores', help='number of cores to be use for CPU mode', dest='cores_count', type=int, default=max(psutil.cpu_count() - 2, 2))
|
||||||
|
|
||||||
for name, value in vars(parser.parse_args()).items():
|
for name, value in vars(parser.parse_args()).items():
|
||||||
args[name] = value
|
args[name] = value
|
||||||
@ -45,7 +50,7 @@ if os.name == "nt":
|
|||||||
|
|
||||||
|
|
||||||
def limit_resources():
|
def limit_resources():
|
||||||
if args['max_memory'] >= 1:
|
if args['max_memory']:
|
||||||
memory = args['max_memory'] * 1024 * 1024 * 1024
|
memory = args['max_memory'] * 1024 * 1024 * 1024
|
||||||
if str(platform.system()).lower() == 'windows':
|
if str(platform.system()).lower() == 'windows':
|
||||||
import ctypes
|
import ctypes
|
||||||
@ -57,22 +62,21 @@ def limit_resources():
|
|||||||
|
|
||||||
|
|
||||||
def pre_check():
|
def pre_check():
|
||||||
if sys.version_info < (3, 8):
|
if sys.version_info < (3, 9):
|
||||||
quit(f'Python version is not supported - please upgrade to 3.8 or higher')
|
quit('Python version is not supported - please upgrade to 3.9 or higher')
|
||||||
if not shutil.which('ffmpeg'):
|
if not shutil.which('ffmpeg'):
|
||||||
quit('ffmpeg is not installed!')
|
quit('ffmpeg is not installed!')
|
||||||
model_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), '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):
|
if not os.path.isfile(model_path):
|
||||||
quit('File "inswapper_128.onnx" does not exist!')
|
quit('File "inswapper_128.onnx" does not exist!')
|
||||||
if '--gpu' in sys.argv:
|
if '--gpu' in sys.argv:
|
||||||
CUDA_VERSION = torch.version.cuda
|
if 'ROCMExecutionProvider' not in core.globals.providers:
|
||||||
CUDNN_VERSION = torch.backends.cudnn.version()
|
CUDA_VERSION = torch.version.cuda
|
||||||
NVIDIA_PROVIDERS = ['CUDAExecutionProvider', 'TensorrtExecutionProvider']
|
CUDNN_VERSION = torch.backends.cudnn.version()
|
||||||
if len(list(set(core.globals.providers) - set(NVIDIA_PROVIDERS))) > 1:
|
|
||||||
if not torch.cuda.is_available() or not CUDA_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.")
|
quit("You are using --gpu flag but CUDA isn't available or properly installed on your system.")
|
||||||
if CUDA_VERSION > '11.8':
|
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':
|
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:
|
if CUDNN_VERSION < 8220:
|
||||||
@ -84,12 +88,8 @@ def pre_check():
|
|||||||
|
|
||||||
|
|
||||||
def start_processing():
|
def start_processing():
|
||||||
start_time = time.time()
|
|
||||||
if args['gpu']:
|
if args['gpu']:
|
||||||
process_video(args['source_img'], args["frame_paths"])
|
process_video(args['source_img'], args["frame_paths"])
|
||||||
end_time = time.time()
|
|
||||||
print(flush=True)
|
|
||||||
print(f"Processing time: {end_time - start_time:.2f} seconds", flush=True)
|
|
||||||
return
|
return
|
||||||
frame_paths = args["frame_paths"]
|
frame_paths = args["frame_paths"]
|
||||||
n = len(frame_paths)//(args['cores_count'])
|
n = len(frame_paths)//(args['cores_count'])
|
||||||
@ -101,9 +101,6 @@ def start_processing():
|
|||||||
p.get()
|
p.get()
|
||||||
pool.close()
|
pool.close()
|
||||||
pool.join()
|
pool.join()
|
||||||
end_time = time.time()
|
|
||||||
print(flush=True)
|
|
||||||
print(f"Processing time: {end_time - start_time:.2f} seconds", flush=True)
|
|
||||||
|
|
||||||
|
|
||||||
def preview_image(image_path):
|
def preview_image(image_path):
|
||||||
@ -171,7 +168,6 @@ def status(string):
|
|||||||
|
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
print("DON'T WORRY. IT'S NOT STUCK/CRASHED.\n" * 5)
|
|
||||||
if not args['source_img'] or not os.path.isfile(args['source_img']):
|
if not args['source_img'] or not os.path.isfile(args['source_img']):
|
||||||
print("\n[WARNING] Please select an image containing a face.")
|
print("\n[WARNING] Please select an image containing a face.")
|
||||||
return
|
return
|
||||||
@ -179,7 +175,8 @@ def start():
|
|||||||
print("\n[WARNING] Please select a video/image to swap face in.")
|
print("\n[WARNING] Please select a video/image to swap face in.")
|
||||||
return
|
return
|
||||||
if not args['output_file']:
|
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
|
global pool
|
||||||
pool = mp.Pool(args['cores_count'])
|
pool = mp.Pool(args['cores_count'])
|
||||||
target_path = args['target_path']
|
target_path = args['target_path']
|
||||||
@ -188,33 +185,38 @@ def start():
|
|||||||
print("\n[WARNING] No face detected in source image. Please try with another one.\n")
|
print("\n[WARNING] No face detected in source image. Please try with another one.\n")
|
||||||
return
|
return
|
||||||
if is_img(target_path):
|
if is_img(target_path):
|
||||||
|
if predict_image(target_path) > 0.7:
|
||||||
|
quit()
|
||||||
process_img(args['source_img'], target_path, args['output_file'])
|
process_img(args['source_img'], target_path, args['output_file'])
|
||||||
status("swap successful!")
|
status("swap successful!")
|
||||||
return
|
return
|
||||||
video_name = os.path.basename(target_path)
|
seconds, probabilities = predict_video_frames(video_path=args['target_path'], frame_interval=100)
|
||||||
video_name = os.path.splitext(video_name)[0]
|
if any(probability > 0.7 for probability in probabilities):
|
||||||
output_dir = os.path.join(os.path.dirname(target_path),video_name)
|
quit()
|
||||||
|
video_name_full = target_path.split("/")[-1]
|
||||||
|
video_name = os.path.splitext(video_name_full)[0]
|
||||||
|
output_dir = os.path.dirname(target_path) + "/" + video_name
|
||||||
Path(output_dir).mkdir(exist_ok=True)
|
Path(output_dir).mkdir(exist_ok=True)
|
||||||
status("detecting video's FPS...")
|
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:
|
if not args['keep_fps'] and fps > 30:
|
||||||
this_path = output_dir + "/" + video_name + ".mp4"
|
this_path = output_dir + "/" + video_name + ".mp4"
|
||||||
set_fps(target_path, this_path, 30)
|
set_fps(target_path, this_path, 30)
|
||||||
target_path, fps = this_path, 30
|
target_path, exact_fps = this_path, 30
|
||||||
else:
|
else:
|
||||||
shutil.copy(target_path, output_dir)
|
shutil.copy(target_path, output_dir)
|
||||||
status("extracting frames...")
|
status("extracting frames...")
|
||||||
extract_frames(target_path, output_dir)
|
extract_frames(target_path, output_dir)
|
||||||
args['frame_paths'] = tuple(sorted(
|
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", ""))
|
key=lambda x: int(x.split(sep)[-1].replace(".png", ""))
|
||||||
))
|
))
|
||||||
status("swapping in progress...")
|
status("swapping in progress...")
|
||||||
start_processing()
|
start_processing()
|
||||||
status("creating video...")
|
status("creating video...")
|
||||||
create_video(video_name, fps, output_dir)
|
create_video(video_name, exact_fps, output_dir)
|
||||||
status("adding audio...")
|
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"
|
save_path = args['output_file'] if args['output_file'] else output_dir + "/" + video_name + ".mp4"
|
||||||
print("\n\nVideo saved as:", save_path, "\n\n")
|
print("\n\nVideo saved as:", save_path, "\n\n")
|
||||||
status("swap successful!")
|
status("swap successful!")
|
||||||
|
Loading…
Reference in New Issue
Block a user