google colab
parent
4324b41b9e
commit
789b861504
|
@ -17,6 +17,7 @@ temp/
|
|||
venv/
|
||||
env/
|
||||
workflow/
|
||||
deepfake/
|
||||
gfpgan/
|
||||
models/inswapper_128.onnx
|
||||
models/GFPGANv1.4.pth
|
||||
|
|
64
README.md
64
README.md
|
@ -1,7 +1,7 @@
|
|||

|
||||
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This software is meant to be a productive contribution to the rapidly growing AI-generated media industry. It will help artists with tasks such as animating a custom character or using the character as a model for clothing etc.
|
||||
|
||||
The developers of this software are aware of its possible unethical applications and are committed to take preventative measures against them. It has a built-in check which prevents the program from working on inappropriate media including but not limited to nudity, graphic content, sensitive material such as war footage etc. We will continue to develop this project in the positive direction while adhering to law and ethics. This project may be shut down or include watermarks on the output if requested by law.
|
||||
|
@ -10,38 +10,43 @@ Users of this software are expected to use this software responsibly while abidi
|
|||
|
||||
## How do I install it?
|
||||
|
||||
|
||||
### Basic: It is more likely to work on your computer but it will also be very slow. You can follow instructions for the basic install (This usually runs via **CPU**)
|
||||
|
||||
#### 1.Setup your platform
|
||||
- python (3.10 recommended)
|
||||
- pip
|
||||
- git
|
||||
- [ffmpeg](https://www.youtube.com/watch?v=OlNWCpFdVMA)
|
||||
- [visual studio 2022 runtimes (windows)](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
|
||||
|
||||
- python (3.10 recommended)
|
||||
- pip
|
||||
- git
|
||||
- [ffmpeg](https://www.youtube.com/watch?v=OlNWCpFdVMA)
|
||||
- [visual studio 2022 runtimes (windows)](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
|
||||
|
||||
#### 2. Clone Repository
|
||||
|
||||
https://github.com/hacksider/Deep-Live-Cam.git
|
||||
|
||||
#### 3. Download Models
|
||||
|
||||
1. [GFPGANv1.4](https://huggingface.co/hacksider/deep-live-cam/resolve/main/GFPGANv1.4.pth)
|
||||
2. [inswapper_128_fp16.onnx](https://huggingface.co/hacksider/deep-live-cam/resolve/main/inswapper_128_fp16.onnx)
|
||||
1. [GFPGANv1.4](https://huggingface.co/hacksider/deep-live-cam/resolve/main/GFPGANv1.4.pth)
|
||||
2. [inswapper_128_fp16.onnx](https://huggingface.co/hacksider/deep-live-cam/resolve/main/inswapper_128_fp16.onnx)
|
||||
|
||||
Then put those 2 files on the "**models**" folder
|
||||
|
||||
#### 4. Install dependency
|
||||
We highly recommend to work with a `venv` to avoid issues.
|
||||
|
||||
We highly recommend to work with a `venv` to avoid issues.
|
||||
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
##### DONE!!! If you dont have any GPU, You should be able to run roop using `python run.py` command. Keep in mind that while running the program for first time, it will download some models which can take time depending on your network connection.
|
||||
|
||||
### *Proceed if you want to use GPU Acceleration
|
||||
### CUDA Execution Provider (Nvidia)*
|
||||
### \*Proceed if you want to use GPU Acceleration
|
||||
|
||||
1. Install [CUDA Toolkit 11.8](https://developer.nvidia.com/cuda-11-8-0-download-archive)
|
||||
|
||||
### CUDA Execution Provider (Nvidia)\*
|
||||
|
||||
1. Install [CUDA Toolkit 11.8](https://developer.nvidia.com/cuda-11-8-0-download-archive)
|
||||
2. Install dependencies:
|
||||
|
||||
|
||||
```
|
||||
pip uninstall onnxruntime onnxruntime-gpu
|
||||
|
@ -124,6 +129,7 @@ python run.py --execution-provider openvino
|
|||
```
|
||||
|
||||
## How do I use it?
|
||||
|
||||
> Note: When you run this program for the first time, it will download some models ~300MB in size.
|
||||
|
||||
Executing `python run.py` command will launch this window:
|
||||
|
@ -132,16 +138,39 @@ Executing `python run.py` command will launch this window:
|
|||
Choose a face (image with desired face) and the target image/video (image/video in which you want to replace the face) and click on `Start`. Open file explorer and navigate to the directory you select your output to be in. You will find a directory named `<video_title>` where you can see the frames being swapped in realtime. Once the processing is done, it will create the output file. That's it.
|
||||
|
||||
## For the webcam mode
|
||||
|
||||
Just follow the clicks on the screenshot
|
||||
|
||||
1. Select a face
|
||||
2. Click live
|
||||
3. Wait for a few seconds (it takes a longer time, usually 10 to 30 seconds before the preview shows up)
|
||||
|
||||

|
||||
|
||||
Just use your favorite screencapture to stream like OBS
|
||||
> Note: In case you want to change your face, just select another picture, the preview mode will then restart (so just wait a bit).
|
||||
## TO USE WITH GOOGLE COLAB
|
||||
|
||||
1. Upload the colab file in /google-colab/DeepLive_Google_Colab.ipynb to your google colab
|
||||
2. Follow the instructions to run the colab file.
|
||||
Note: For TCP Tunneling you can use either Ngrok or FRP.
|
||||
i. For Ngrok you would need an api key and payment details added to use the tcp connection
|
||||
ii. For FRP its free but you need to host the FRPS server on a VPS and replace '194.113.64.71' with your vps address
|
||||
3. Follow the image instruction to input the tcp address appropriately
|
||||
On Colab
|
||||
|
||||

|
||||
|
||||
On your Machine
|
||||
|
||||

|
||||
colab_instruction.png
|
||||
|
||||
4. For live Mode add the source image, enable Remote Processor,Fill the tcp correctly and click on live
|
||||
|
||||
5. For Image swap add the source and target image, enable Remote Processor, click on preview
|
||||
|
||||
Just use your favorite screencapture to stream like OBS
|
||||
|
||||
> Note: In case you want to change your face, just select another picture, the preview mode will then restart (so just wait a bit).
|
||||
|
||||
Additional command line arguments are given below. To learn out what they do, check [this guide](https://github.com/s0md3v/roop/wiki/Advanced-Options).
|
||||
|
||||
|
@ -167,6 +196,7 @@ options:
|
|||
Looking for a CLI mode? Using the -s/--source argument will make the run program in cli mode.
|
||||
|
||||
## Want the Next Update Now?
|
||||
|
||||
If you want the latest and greatest build, or want to see some new great features, go to our [experimental branch](https://github.com/hacksider/Deep-Live-Cam/tree/experimental) and experience what the contributors have given.
|
||||
|
||||
## Credits
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -34,7 +34,7 @@ def parse_args() -> None:
|
|||
program.add_argument('-s', '--source', help='select an source image', dest='source_path')
|
||||
program.add_argument('-t', '--target', help='select an target image or video', dest='target_path')
|
||||
program.add_argument('-o', '--output', help='select output file or directory', dest='output_path')
|
||||
program.add_argument('--frame-processor', help='pipeline of frame processors', dest='frame_processor', default=['face_swapper'], choices=['face_swapper', 'face_enhancer'], nargs='+')
|
||||
program.add_argument('--frame-processor', help='pipeline of frame processors', dest='frame_processor', default=['face_swapper'], choices=['face_swapper', 'face_enhancer','remote_processor'], nargs='+')
|
||||
program.add_argument('--keep-fps', help='keep original fps', dest='keep_fps', action='store_true', default=False)
|
||||
program.add_argument('--keep-audio', help='keep original audio', dest='keep_audio', action='store_true', default=True)
|
||||
program.add_argument('--keep-frames', help='keep temporary frames', dest='keep_frames', action='store_true', default=False)
|
||||
|
@ -74,7 +74,11 @@ def parse_args() -> None:
|
|||
modules.globals.fp_ui['face_enhancer'] = True
|
||||
else:
|
||||
modules.globals.fp_ui['face_enhancer'] = False
|
||||
|
||||
#for Remote tumbler:
|
||||
if 'remote_processor' in args.frame_processor:
|
||||
modules.globals.fp_ui['remote_processor'] = True
|
||||
else:
|
||||
modules.globals.fp_ui['remote_processor'] = False
|
||||
modules.globals.nsfw = False
|
||||
|
||||
# translate deprecated args
|
||||
|
|
|
@ -27,4 +27,7 @@ log_level = 'error'
|
|||
fp_ui: Dict[str, bool] = {}
|
||||
nsfw = None
|
||||
camera_input_combobox = None
|
||||
webcam_preview_running = False
|
||||
webcam_preview_running = False
|
||||
push_addr = None
|
||||
pull_addr = None
|
||||
push_addr_two = None
|
|
@ -1,3 +1,3 @@
|
|||
name = 'Deep Live Cam'
|
||||
version = '1.3.0'
|
||||
edition = 'Portable'
|
||||
version = '1.3.1'
|
||||
edition = 'Portable-Colab'
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
import zmq
|
||||
import cv2
|
||||
import modules.globals
|
||||
import numpy as np
|
||||
import threading
|
||||
import time
|
||||
import io
|
||||
from tqdm import tqdm
|
||||
from modules.typing import Face, Frame
|
||||
from typing import Any,List
|
||||
from modules.core import update_status
|
||||
from modules.utilities import conditional_download, resolve_relative_path, is_image, is_video
|
||||
import zlib
|
||||
import subprocess
|
||||
from cv2 import VideoCapture
|
||||
import queue
|
||||
NAME = 'DLC.REMOTE-PROCESSOR'
|
||||
|
||||
context = zmq.Context()
|
||||
|
||||
# Socket to send messages on
|
||||
def push_socket(address) -> zmq.Socket:
|
||||
sender_sock = context.socket(zmq.REQ)
|
||||
sender_sock.connect(address)
|
||||
return sender_sock
|
||||
def pull_socket(address) -> zmq.Socket:
|
||||
sender_sock = context.socket(zmq.REP)
|
||||
sender_sock.connect(address)
|
||||
return sender_sock
|
||||
|
||||
def pre_check() -> bool:
|
||||
if not modules.globals.push_addr and not modules.globals.pull_addr:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def pre_start() -> bool:
|
||||
if not is_image(modules.globals.target_path) and not is_video(modules.globals.target_path):
|
||||
update_status('Select an image or video for target path.', NAME)
|
||||
return False
|
||||
return True
|
||||
|
||||
def stream_frame(temp_frame: Frame,stream_out: subprocess.Popen[bytes],stream_in: subprocess.Popen[bytes]) -> Frame:
|
||||
temp_framex = swap_face_remote(temp_frame,stream_out,stream_in)
|
||||
|
||||
return temp_framex
|
||||
|
||||
def process_frame(source_frame: Frame, temp_frame: Frame)-> Frame:
|
||||
temp_framex = swap_frame_face_remote(source_frame,temp_frame)
|
||||
|
||||
return temp_framex
|
||||
def send_data(sender: zmq.Socket, face_bytes: bytes, metadata: dict, address: str) -> None:
|
||||
chunk_size = 1024*100
|
||||
total_chunk = len(face_bytes) // chunk_size + 1
|
||||
new_metadata = {'total_chunk': total_chunk}
|
||||
metadata.update(new_metadata)
|
||||
# Send metadata first
|
||||
sender.send_json(metadata)
|
||||
# Wait for acknowledgment for metadata
|
||||
ack = sender.recv_string()
|
||||
with tqdm(total=total_chunk, desc="Sending chunks", unit="chunk") as pbar:
|
||||
for i in range(total_chunk):
|
||||
chunk = face_bytes[i * chunk_size:(i + 1) * chunk_size]
|
||||
# Send the chunk
|
||||
sender.send(chunk)
|
||||
# Wait for acknowledgment after sending each chunk
|
||||
ack = sender.recv_string()
|
||||
pbar.set_postfix_str(f'Chunk {i + 1}/{total_chunk} ack: {ack}')
|
||||
pbar.update(1)
|
||||
|
||||
# Send a final message to indicate all chunks are sent
|
||||
sender.send(b"END")
|
||||
# Wait for the final reply
|
||||
final_reply_message = sender.recv_string()
|
||||
print(f"Received final reply: {final_reply_message}")
|
||||
|
||||
def send_source_frame(source_face: Frame)-> None:
|
||||
sender = push_socket(modules.globals.push_addr)
|
||||
source_face_bytes = source_face.tobytes()
|
||||
metadata = {
|
||||
'manyface':(modules.globals.many_faces),
|
||||
'dtype_source':str(source_face.dtype),
|
||||
'shape_source':source_face.shape,
|
||||
'size':'640x480',
|
||||
'fps':'60'
|
||||
#'shape_temp':temp_frame.shape
|
||||
}
|
||||
send_data(sender, source_face_bytes, metadata,modules.globals.push_addr)
|
||||
|
||||
def send_temp_frame(temp_face: Frame)-> None:
|
||||
sender = push_socket(modules.globals.push_addr_two)
|
||||
source_face_bytes = temp_face.tobytes()
|
||||
metadata = {
|
||||
'manyface':(modules.globals.many_faces),
|
||||
'dtype_temp':str(temp_face.dtype),
|
||||
'shape_temp':temp_face.shape,
|
||||
|
||||
#'shape_temp':temp_frame.shape
|
||||
}
|
||||
send_data(sender, source_face_bytes, metadata,modules.globals.push_addr)
|
||||
|
||||
def receive_processed_frame(output_queue: queue.Queue)-> None:
|
||||
while True:
|
||||
pull_socket_ = pull_socket(modules.globals.pull_addr)
|
||||
meta_data_json = pull_socket_.recv_json()
|
||||
print(meta_data_json)
|
||||
total_chunk = meta_data_json['total_chunk']
|
||||
# Send acknowledgment for metadata
|
||||
pull_socket_.send_string("ACK")
|
||||
# Receive the array bytes
|
||||
source_array_bytes =b''
|
||||
with tqdm(total=total_chunk, desc="Receiving chunks", unit="chunk") as pbar:
|
||||
for i in range(total_chunk):
|
||||
chunk = pull_socket_.recv()
|
||||
source_array_bytes += chunk
|
||||
pull_socket_.send_string(f"ACK {i + 1}/{total_chunk}")
|
||||
pbar.set_postfix_str(f'Chunk {i + 1}/{total_chunk}')
|
||||
pbar.update(1)
|
||||
|
||||
|
||||
end_message = pull_socket_.recv()
|
||||
if end_message == b"END":
|
||||
pull_socket_.send_string("Final ACK")
|
||||
|
||||
# Deserialize the bytes back to an ndarray
|
||||
source_array = np.frombuffer(source_array_bytes, dtype=np.dtype(meta_data_json['dtype_source'])).reshape(meta_data_json['shape_source'])
|
||||
|
||||
output_queue.put(source_array)
|
||||
break
|
||||
def send_streams(cap: VideoCapture) -> subprocess.Popen[bytes]:
|
||||
|
||||
ffmpeg_command = [
|
||||
'ffmpeg',
|
||||
'-f', 'rawvideo',
|
||||
'-pix_fmt', 'bgr24',
|
||||
'-s', f"{int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))}x{int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))}",
|
||||
'-r', str(int(cap.get(cv2.CAP_PROP_FPS))),
|
||||
'-i', '-',
|
||||
'-c:v', 'libx264',
|
||||
'-preset', 'ultrafast',
|
||||
'-tune', 'zerolatency',
|
||||
'-fflags', 'nobuffer',
|
||||
'-flags', 'low_delay',
|
||||
'-rtbufsize', '100M',
|
||||
'-f', 'mpegts', modules.globals.push_addr_two #'tcp://127.0.0.1:5552'
|
||||
]
|
||||
|
||||
|
||||
ffmpeg_process = subprocess.Popen(ffmpeg_command, stdin=subprocess.PIPE)
|
||||
return ffmpeg_process
|
||||
def recieve_streams(cap: VideoCapture)->subprocess.Popen[bytes]:
|
||||
ffmpeg_command_recie = [
|
||||
'ffmpeg',
|
||||
'-i',modules.globals.pull_addr, #'tcp://127.0.0.1:5553',
|
||||
'-f','rawvideo',
|
||||
'-pix_fmt','bgr24',
|
||||
'-s','960x540',#'640x480',
|
||||
'pipe:1'
|
||||
]
|
||||
|
||||
ffmpeg_process_com = subprocess.Popen(ffmpeg_command_recie, stdout=subprocess.PIPE)
|
||||
return ffmpeg_process_com
|
||||
|
||||
def write_to_stdin(queue: queue.Queue, stream_out: subprocess.Popen):
|
||||
|
||||
temp_frame = queue.get()
|
||||
temp_frame_bytes = temp_frame.tobytes()
|
||||
stream_out.stdin.write(temp_frame_bytes)
|
||||
def read_from_stdout(queue: queue.Queue, stream_in: subprocess.Popen, output_queue: queue.Queue):
|
||||
|
||||
raw_frame = stream_in.stdout.read(960 * 540 * 3)
|
||||
|
||||
|
||||
frame = np.frombuffer(raw_frame, dtype=np.uint8).reshape((540, 960, 3))
|
||||
output_queue.put(frame)
|
||||
def swap_face_remote(temp_frame: Frame,stream_out:subprocess.Popen[bytes],stream_in: subprocess.Popen[bytes]) -> Frame:
|
||||
input_queue = queue.Queue()
|
||||
output_queue = queue.Queue()
|
||||
|
||||
# Start threads for stdin and stdout
|
||||
write_thread = threading.Thread(target=write_to_stdin, args=(input_queue, stream_out))
|
||||
read_thread = threading.Thread(target=read_from_stdout, args=(input_queue, stream_in, output_queue))
|
||||
|
||||
write_thread.start()
|
||||
read_thread.start()
|
||||
|
||||
# Send the frame to the stdin thread
|
||||
input_queue.put(temp_frame)
|
||||
|
||||
# Wait for the processed frame from the stdout thread
|
||||
processed_frame = output_queue.get()
|
||||
|
||||
# Stop the threads
|
||||
input_queue.put(None)
|
||||
write_thread.join()
|
||||
read_thread.join()
|
||||
|
||||
return processed_frame
|
||||
|
||||
|
||||
def swap_frame_face_remote(source_frame: Frame,temp_frame: Frame) -> Frame:
|
||||
#input_queue = queue.Queue()
|
||||
output_queue = queue.Queue()
|
||||
|
||||
# Start threads for stdin and stdout
|
||||
write_thread = threading.Thread(target=send_source_frame, args=(source_frame,))
|
||||
write_thread_tw = threading.Thread(target=send_temp_frame, args=(temp_frame,))
|
||||
read_thread_ = threading.Thread(target=receive_processed_frame, args=(output_queue,))
|
||||
|
||||
write_thread.start()
|
||||
write_thread_tw.start()
|
||||
read_thread_.start()
|
||||
|
||||
# Send the frame to the stdin thread
|
||||
|
||||
# Wait for the processed frame from the stdout thread
|
||||
processed_frame = output_queue.get()
|
||||
|
||||
# Stop the threads
|
||||
write_thread.join()
|
||||
write_thread_tw.join()
|
||||
read_thread_.join()
|
||||
|
||||
return processed_frame
|
||||
|
||||
|
||||
def process_frames(source_path: str, temp_frame_paths: List[str], progress: Any = None) -> None:
|
||||
for temp_frame_path in temp_frame_paths:
|
||||
temp_frame = cv2.imread(temp_frame_path)
|
||||
result = process_frame(None, temp_frame)
|
||||
cv2.imwrite(temp_frame_path, result)
|
||||
if progress:
|
||||
progress.update(1)
|
||||
|
||||
|
||||
def process_image(source_path: str, target_path: str, output_path: str) -> None:
|
||||
target_frame = cv2.imread(target_path)
|
||||
result = process_frame(None, target_frame)
|
||||
cv2.imwrite(output_path, result)
|
||||
|
||||
|
||||
def process_video(source_path: str, temp_frame_paths: List[str]) -> None:
|
||||
modules.processors.frame.core.process_video(None, temp_frame_paths, process_frames)
|
164
modules/ui.py
164
modules/ui.py
|
@ -1,6 +1,8 @@
|
|||
import sys
|
||||
import os
|
||||
import webbrowser
|
||||
import customtkinter as ctk
|
||||
import tkinter as tk
|
||||
from typing import Callable, Tuple
|
||||
import cv2
|
||||
from PIL import Image, ImageOps
|
||||
|
@ -14,7 +16,7 @@ from modules.utilities import is_image, is_video, resolve_relative_path
|
|||
|
||||
ROOT = None
|
||||
ROOT_HEIGHT = 700
|
||||
ROOT_WIDTH = 600
|
||||
ROOT_WIDTH = 800
|
||||
|
||||
PREVIEW = None
|
||||
PREVIEW_MAX_HEIGHT = 700
|
||||
|
@ -62,47 +64,80 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
target_label.place(relx=0.6, rely=0.1, relwidth=0.3, relheight=0.25)
|
||||
|
||||
select_face_button = ctk.CTkButton(root, text='Select a face', cursor='hand2', command=lambda: select_source_path())
|
||||
select_face_button.place(relx=0.1, rely=0.4, relwidth=0.3, relheight=0.1)
|
||||
select_face_button.place(relx=0.1, rely=0.3, relwidth=0.3, relheight=0.1)
|
||||
|
||||
select_target_button = ctk.CTkButton(root, text='Select a target', cursor='hand2', command=lambda: select_target_path())
|
||||
select_target_button.place(relx=0.6, rely=0.4, relwidth=0.3, relheight=0.1)
|
||||
select_target_button.place(relx=0.6, rely=0.3, relwidth=0.3, relheight=0.1)
|
||||
|
||||
keep_fps_value = ctk.BooleanVar(value=modules.globals.keep_fps)
|
||||
keep_fps_checkbox = ctk.CTkSwitch(root, text='Keep fps', variable=keep_fps_value, cursor='hand2', command=lambda: setattr(modules.globals, 'keep_fps', not modules.globals.keep_fps))
|
||||
keep_fps_checkbox.place(relx=0.1, rely=0.6)
|
||||
keep_fps_checkbox.place(relx=0.1, rely=0.5)
|
||||
|
||||
keep_frames_value = ctk.BooleanVar(value=modules.globals.keep_frames)
|
||||
keep_frames_switch = ctk.CTkSwitch(root, text='Keep frames', variable=keep_frames_value, cursor='hand2', command=lambda: setattr(modules.globals, 'keep_frames', keep_frames_value.get()))
|
||||
keep_frames_switch.place(relx=0.1, rely=0.65)
|
||||
keep_frames_switch.place(relx=0.1, rely=0.55)
|
||||
|
||||
# for FRAME PROCESSOR ENHANCER tumbler:
|
||||
enhancer_value = ctk.BooleanVar(value=modules.globals.fp_ui['face_enhancer'])
|
||||
enhancer_switch = ctk.CTkSwitch(root, text='Face Enhancer', variable=enhancer_value, cursor='hand2', command=lambda: update_tumbler('face_enhancer',enhancer_value.get()))
|
||||
enhancer_switch.place(relx=0.1, rely=0.7)
|
||||
enhancer_switch.place(relx=0.1, rely=0.6)
|
||||
|
||||
remote_process_value = ctk.BooleanVar(value=modules.globals.fp_ui['remote_processor'])
|
||||
remote_process_switch = ctk.CTkSwitch(root, text='Remote Processor', variable=remote_process_value, cursor='hand2', command=lambda: update_tumbler('remote_processor',remote_process_value.get()))
|
||||
remote_process_switch.place(relx=0.1, rely=0.65)
|
||||
|
||||
def on_text_change(event=None):
|
||||
setattr(modules.globals, 'pull_addr', text_box_addr_in.get("1.0", tk.END).strip())
|
||||
|
||||
def on_text_change_out(event=None):
|
||||
setattr(modules.globals, 'push_addr', text_box_addr_out.get("1.0", tk.END).strip())
|
||||
def on_text_change_out_two(event=None):
|
||||
setattr(modules.globals, 'push_addr_two', text_box_addr_out_t.get("1.0", tk.END).strip())
|
||||
|
||||
keep_audio_value = ctk.BooleanVar(value=modules.globals.keep_audio)
|
||||
keep_audio_switch = ctk.CTkSwitch(root, text='Keep audio', variable=keep_audio_value, cursor='hand2', command=lambda: setattr(modules.globals, 'keep_audio', keep_audio_value.get()))
|
||||
keep_audio_switch.place(relx=0.6, rely=0.6)
|
||||
keep_audio_switch.place(relx=0.6, rely=0.5)
|
||||
|
||||
many_faces_value = ctk.BooleanVar(value=modules.globals.many_faces)
|
||||
many_faces_switch = ctk.CTkSwitch(root, text='Many faces', variable=many_faces_value, cursor='hand2', command=lambda: setattr(modules.globals, 'many_faces', many_faces_value.get()))
|
||||
many_faces_switch.place(relx=0.6, rely=0.65)
|
||||
many_faces_switch.place(relx=0.6, rely=0.55)
|
||||
|
||||
# nsfw_value = ctk.BooleanVar(value=modules.globals.nsfw)
|
||||
# nsfw_switch = ctk.CTkSwitch(root, text='NSFW', variable=nsfw_value, cursor='hand2', command=lambda: setattr(modules.globals, 'nsfw', nsfw_value.get()))
|
||||
# nsfw_switch.place(relx=0.6, rely=0.7)
|
||||
nsfw_value = ctk.BooleanVar(value=modules.globals.nsfw)
|
||||
nsfw_switch = ctk.CTkSwitch(root, text='NSFW', variable=nsfw_value, cursor='hand2', command=lambda: setattr(modules.globals, 'nsfw', nsfw_value.get()))
|
||||
nsfw_switch.place(relx=0.6, rely=0.6)
|
||||
|
||||
#Label a text box
|
||||
label = ctk.CTkLabel(root, text="In:")
|
||||
label.place(relx=0.1, rely=0.72, anchor=tk.E)
|
||||
#Label a text box
|
||||
label = ctk.CTkLabel(root, text="OutS:")
|
||||
label.place(relx=0.6, rely=0.72, anchor=tk.E)
|
||||
# Create a text box
|
||||
text_box_addr_in = ctk.CTkTextbox(root, width=200, height=10)
|
||||
text_box_addr_in.place(relx=0.1, rely=0.7)
|
||||
text_box_addr_in.bind("<KeyRelease>", on_text_change)
|
||||
|
||||
# Create a text box
|
||||
text_box_addr_out = ctk.CTkTextbox(root, width=100, height=10)
|
||||
text_box_addr_out.place(relx=0.6, rely=0.7)
|
||||
text_box_addr_out.bind("<KeyRelease>", on_text_change_out)
|
||||
|
||||
# Create a text box
|
||||
text_box_addr_out_t = ctk.CTkTextbox(root, width=100, height=10)
|
||||
text_box_addr_out_t.place(relx=0.8, rely=0.7)
|
||||
text_box_addr_out_t.bind("<KeyRelease>", on_text_change_out_two)
|
||||
|
||||
start_button = ctk.CTkButton(root, text='Start', cursor='hand2', command=lambda: select_output_path(start))
|
||||
start_button.place(relx=0.15, rely=0.80, relwidth=0.2, relheight=0.05)
|
||||
start_button.place(relx=0.15, rely=0.75, relwidth=0.2, relheight=0.05)
|
||||
|
||||
stop_button = ctk.CTkButton(root, text='Destroy', cursor='hand2', command=lambda: destroy())
|
||||
stop_button.place(relx=0.4, rely=0.80, relwidth=0.2, relheight=0.05)
|
||||
stop_button.place(relx=0.4, rely=0.75, relwidth=0.2, relheight=0.05)
|
||||
|
||||
preview_button = ctk.CTkButton(root, text='Preview', cursor='hand2', command=lambda: toggle_preview())
|
||||
preview_button.place(relx=0.65, rely=0.80, relwidth=0.2, relheight=0.05)
|
||||
preview_button.place(relx=0.65, rely=0.75, relwidth=0.2, relheight=0.05)
|
||||
|
||||
live_button = ctk.CTkButton(root, text='Live', cursor='hand2', command=lambda: webcam_preview())
|
||||
live_button.place(relx=0.40, rely=0.86, relwidth=0.2, relheight=0.05)
|
||||
live_button.place(relx=0.40, rely=0.85, relwidth=0.2, relheight=0.05)
|
||||
|
||||
status_label = ctk.CTkLabel(root, text=None, justify='center')
|
||||
status_label.place(relx=0.1, rely=0.9, relwidth=0.8)
|
||||
|
@ -235,15 +270,28 @@ def init_preview() -> None:
|
|||
def update_preview(frame_number: int = 0) -> None:
|
||||
if modules.globals.source_path and modules.globals.target_path:
|
||||
temp_frame = get_video_frame(modules.globals.target_path, frame_number)
|
||||
remote_process=False
|
||||
if modules.globals.nsfw == False:
|
||||
from modules.predicter import predict_frame
|
||||
if predict_frame(temp_frame):
|
||||
quit()
|
||||
for frame_processor in get_frame_processors_modules(modules.globals.frame_processors):
|
||||
temp_frame = frame_processor.process_frame(
|
||||
get_one_face(cv2.imread(modules.globals.source_path)),
|
||||
temp_frame
|
||||
)
|
||||
if 'remote_processor' in modules.globals.frame_processors :
|
||||
remote_process = True
|
||||
if frame_processor.__name__ =="modules.processors.frame.remote_processor":
|
||||
print('------- Remote Process ----------')
|
||||
source_data = cv2.imread(modules.globals.source_path)
|
||||
if not frame_processor.pre_check():
|
||||
print("No Input and Output Address")
|
||||
sys.exit()
|
||||
temp_frame=frame_processor.process_frame(source_data,temp_frame)
|
||||
|
||||
|
||||
if not remote_process:
|
||||
temp_frame = frame_processor.process_frame(
|
||||
get_one_face(cv2.imread(modules.globals.source_path)),
|
||||
temp_frame
|
||||
)
|
||||
image = Image.fromarray(cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB))
|
||||
image = ImageOps.contain(image, (PREVIEW_MAX_WIDTH, PREVIEW_MAX_HEIGHT), Image.LANCZOS)
|
||||
image = ctk.CTkImage(image, size=image.size)
|
||||
|
@ -257,6 +305,7 @@ def webcam_preview():
|
|||
global preview_label, PREVIEW
|
||||
|
||||
cap = cv2.VideoCapture(0) # Use index for the webcam (adjust the index accordingly if necessary)
|
||||
cap.set(cv2.CAP_PROP_BUFFERSIZE,3)
|
||||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 960) # Set the width of the resolution
|
||||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 540) # Set the height of the resolution
|
||||
cap.set(cv2.CAP_PROP_FPS, 60) # Set the frame rate of the webcam
|
||||
|
@ -270,30 +319,63 @@ def webcam_preview():
|
|||
frame_processors = get_frame_processors_modules(modules.globals.frame_processors)
|
||||
|
||||
source_image = None # Initialize variable for the selected face image
|
||||
remote_process=False # By default remote process is set to disabled
|
||||
stream_out = None # Both veriable stores the subprocess runned by ffmpeg
|
||||
stream_in = None
|
||||
|
||||
while True:
|
||||
ret, frame = cap.read()
|
||||
if not ret:
|
||||
break
|
||||
if 'remote_processor' in modules.globals.frame_processors :
|
||||
remote_modules = get_frame_processors_modules(['remote_processor'])
|
||||
source_data = cv2.imread(modules.globals.source_path)
|
||||
remote_modules[1].send_source_frame(source_data)
|
||||
#start ffmpeg stream out subprocess
|
||||
stream_out = remote_modules[1].send_streams(cap)
|
||||
#start ffmpeg stream In subprocess
|
||||
stream_in = remote_modules[1].recieve_streams(cap)
|
||||
|
||||
remote_process = True
|
||||
try:
|
||||
while True:
|
||||
ret, frame = cap.read()
|
||||
if not ret:
|
||||
break
|
||||
|
||||
# Select and save face image only once
|
||||
if source_image is None and modules.globals.source_path:
|
||||
source_image = get_one_face(cv2.imread(modules.globals.source_path))
|
||||
# Select and save face image only once
|
||||
if source_image is None and modules.globals.source_path:
|
||||
source_image = get_one_face(cv2.imread(modules.globals.source_path))
|
||||
|
||||
temp_frame = frame.copy() #Create a copy of the frame
|
||||
temp_frame = frame.copy() #Create a copy of the frame
|
||||
|
||||
for frame_processor in frame_processors:
|
||||
temp_frame = frame_processor.process_frame(source_image, temp_frame)
|
||||
for frame_processor in frame_processors:
|
||||
if remote_process:
|
||||
if frame_processor.__name__ =="modules.processors.frame.remote_processor":
|
||||
#print('------- Remote Process ----------')
|
||||
if not frame_processor.pre_check():
|
||||
print("No Input and Output Address")
|
||||
sys.exit()
|
||||
_frame = frame_processor.stream_frame(temp_frame,stream_out,stream_in)
|
||||
if _frame is not None:
|
||||
temp_frame = _frame
|
||||
|
||||
|
||||
image = cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB) # Convert the image to RGB format to display it with Tkinter
|
||||
image = Image.fromarray(image)
|
||||
image = ImageOps.contain(image, (PREVIEW_MAX_WIDTH, PREVIEW_MAX_HEIGHT), Image.LANCZOS)
|
||||
image = ctk.CTkImage(image, size=image.size)
|
||||
preview_label.configure(image=image)
|
||||
ROOT.update()
|
||||
|
||||
if PREVIEW.state() == 'withdrawn':
|
||||
break
|
||||
|
||||
cap.release()
|
||||
PREVIEW.withdraw() # Close preview window when loop is finished
|
||||
if not remote_process:
|
||||
temp_frame = frame_processor.process_frame(source_image, temp_frame)
|
||||
if not remote_process:
|
||||
image = cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB) # Convert the image to RGB format to display it with Tkinter
|
||||
image = Image.fromarray(image)
|
||||
image = ImageOps.contain(image, (PREVIEW_MAX_WIDTH, PREVIEW_MAX_HEIGHT), Image.LANCZOS)
|
||||
image = ctk.CTkImage(image, size=image.size)
|
||||
preview_label.configure(image=image)
|
||||
ROOT.update()
|
||||
elif _frame is not None:
|
||||
image = cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB) # Convert the image to RGB format to display it with Tkinter
|
||||
image = Image.fromarray(image)
|
||||
image = ImageOps.contain(image, (PREVIEW_MAX_WIDTH, PREVIEW_MAX_HEIGHT), Image.LANCZOS)
|
||||
image = ctk.CTkImage(image, size=image.size)
|
||||
preview_label.configure(image=image)
|
||||
ROOT.update()
|
||||
|
||||
if PREVIEW.state() == 'withdrawn':
|
||||
break
|
||||
finally:
|
||||
cap.release()
|
||||
PREVIEW.withdraw() # Close preview window when loop is finished
|
||||
|
|
|
@ -21,3 +21,4 @@ opennsfw2==0.10.2
|
|||
protobuf==4.23.2
|
||||
tqdm==4.66.4
|
||||
gfpgan==1.3.8
|
||||
zmq==26.1.0
|
Loading…
Reference in New Issue