commit
ee19c5158a
158
README.md
158
README.md
|
@ -13,24 +13,52 @@
|
|||
<img src="media/avgpcperformancedemo.gif" alt="Performance Demo GIF">
|
||||
</p>
|
||||
|
||||
## Disclaimer
|
||||
###### This software is intended as a productive contribution to the AI-generated media industry. It aims to assist artists with tasks like animating custom characters or using them as models for clothing, etc.
|
||||
|
||||
## Disclaimer
|
||||
###### We are aware of the potential for unethical applications and are committed to preventative measures. A built-in check prevents the program from processing inappropriate media (nudity, graphic content, sensitive material like war footage, etc.). We will continue to develop this project responsibly, adhering to the law and ethics. We may shut down the project or add watermarks if legally required.
|
||||
|
||||
This software is intended as a productive contribution to the AI-generated media industry. It aims to assist artists with tasks like animating custom characters or using them as models for clothing, etc.
|
||||
###### Users are expected to use this software responsibly and legally. If using a real person's face, obtain their consent and clearly label any output as a deepfake when sharing online. We are not responsible for end-user actions.
|
||||
|
||||
We are aware of the potential for unethical applications and are committed to preventative measures. A built-in check prevents the program from processing inappropriate media (nudity, graphic content, sensitive material like war footage, etc.). We will continue to develop this project responsibly, adhering to law and ethics. We may shut down the project or add watermarks if legally required.
|
||||
## Quick Start - Pre-built
|
||||
<div align="center">
|
||||
<a href="https://hacksider.gumroad.com/l/vccdmm">
|
||||
<img src="https://github.com/user-attachments/assets/7d993b32-e3e8-4cd3-bbfb-a549152ebdd5" width="285" height="77" />
|
||||
</a>
|
||||
<a href="https://krshh.gumroad.com/l/Deep-Live-Cam-Mac">
|
||||
<img src="https://github.com/user-attachments/assets/d5d913b5-a7de-4609-96b9-979a5749a703" width="285" height="77" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
Users are expected to use this software responsibly and legally. If using a real person's face, obtain their consent and clearly label any output as a deepfake when sharing online. We are not responsible for end-user actions.
|
||||
## Features - Everything is real-time
|
||||
|
||||
### Mouth Mask
|
||||
|
||||
## Quick Start (Windows / Nvidia)
|
||||
**Retain your original mouth using Mouth Mask**
|
||||
|
||||
[](https://hacksider.gumroad.com/l/vccdmm)
|
||||

|
||||
|
||||
[Download latest pre-built version with CUDA support](https://hacksider.gumroad.com/l/vccdmm) - No Manual Installation/Downloading required and Early features testing.
|
||||
### Face Mapping
|
||||
|
||||
**Use different faces on multiple subjects**
|
||||
|
||||

|
||||
|
||||
### Your Movie, Your Face
|
||||
|
||||
**Watch movies with any face in real-time**
|
||||
|
||||

|
||||
|
||||
## Benchmarks
|
||||
|
||||
**Nearly 0% detection!**
|
||||
|
||||

|
||||
|
||||
## Installation (Manual)
|
||||
**Please be aware that the installation needs technical skills and is not for beginners, consider downloading the prebuilt.**
|
||||
|
||||
**Please be aware that the installation requires technical skills and is not for beginners. Consider downloading the prebuilt version.**
|
||||
|
||||
<details>
|
||||
<summary>Click to see the process</summary>
|
||||
|
@ -39,24 +67,24 @@ Users are expected to use this software responsibly and legally. If using a real
|
|||
|
||||
This is more likely to work on your computer but will be slower as it utilizes the CPU.
|
||||
|
||||
**1. Setup Your Platform**
|
||||
**1. Set up 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**
|
||||
**2. Clone the Repository**
|
||||
|
||||
```bash
|
||||
https://github.com/hacksider/Deep-Live-Cam.git
|
||||
```
|
||||
|
||||
**3. Download Models**
|
||||
**3. Download the 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.onnx) (Note: Use this [replacement version](https://github.com/facefusion/facefusion-assets/releases/download/models/inswapper_128.onnx) if you encounter issues)
|
||||
2. [inswapper\_128\_fp16.onnx](https://huggingface.co/hacksider/deep-live-cam/resolve/main/inswapper_128.onnx) (Note: Use this [replacement version](https://github.com/facefusion/facefusion-assets/releases/download/models/inswapper_128.onnx) if you encounter issues)
|
||||
|
||||
Place these files in the "**models**" folder.
|
||||
|
||||
|
@ -76,18 +104,20 @@ brew install python-tk@3.10
|
|||
|
||||
**Run:** If you don't have a GPU, you can run Deep-Live-Cam using `python run.py`. Note that initial execution will download models (~300MB).
|
||||
|
||||
|
||||
### GPU Acceleration
|
||||
### GPU Acceleration
|
||||
|
||||
**CUDA Execution Provider (Nvidia)**
|
||||
|
||||
1. Install [CUDA Toolkit 11.8](https://developer.nvidia.com/cuda-11-8-0-download-archive)
|
||||
1. Install [CUDA Toolkit 11.8](https://developer.nvidia.com/cuda-11-8-0-download-archive) or [CUDA Toolkit 12.1.1](https://developer.nvidia.com/cuda-12-1-1-download-archive)
|
||||
2. Install dependencies:
|
||||
|
||||
```bash
|
||||
pip uninstall onnxruntime onnxruntime-gpu
|
||||
pip install onnxruntime-gpu==1.16.3
|
||||
```
|
||||
|
||||
3. Usage:
|
||||
|
||||
```bash
|
||||
python run.py --execution-provider cuda
|
||||
```
|
||||
|
@ -95,11 +125,14 @@ python run.py --execution-provider cuda
|
|||
**CoreML Execution Provider (Apple Silicon)**
|
||||
|
||||
1. Install dependencies:
|
||||
|
||||
```bash
|
||||
pip uninstall onnxruntime onnxruntime-silicon
|
||||
pip install onnxruntime-silicon==1.13.1
|
||||
```
|
||||
|
||||
2. Usage:
|
||||
|
||||
```bash
|
||||
python run.py --execution-provider coreml
|
||||
```
|
||||
|
@ -107,11 +140,14 @@ python run.py --execution-provider coreml
|
|||
**CoreML Execution Provider (Apple Legacy)**
|
||||
|
||||
1. Install dependencies:
|
||||
|
||||
```bash
|
||||
pip uninstall onnxruntime onnxruntime-coreml
|
||||
pip install onnxruntime-coreml==1.13.1
|
||||
```
|
||||
|
||||
2. Usage:
|
||||
|
||||
```bash
|
||||
python run.py --execution-provider coreml
|
||||
```
|
||||
|
@ -119,11 +155,14 @@ python run.py --execution-provider coreml
|
|||
**DirectML Execution Provider (Windows)**
|
||||
|
||||
1. Install dependencies:
|
||||
|
||||
```bash
|
||||
pip uninstall onnxruntime onnxruntime-directml
|
||||
pip install onnxruntime-directml==1.15.1
|
||||
```
|
||||
|
||||
2. Usage:
|
||||
|
||||
```bash
|
||||
python run.py --execution-provider directml
|
||||
```
|
||||
|
@ -131,62 +170,37 @@ python run.py --execution-provider directml
|
|||
**OpenVINO™ Execution Provider (Intel)**
|
||||
|
||||
1. Install dependencies:
|
||||
|
||||
```bash
|
||||
pip uninstall onnxruntime onnxruntime-openvino
|
||||
pip install onnxruntime-openvino==1.15.0
|
||||
```
|
||||
|
||||
2. Usage:
|
||||
|
||||
```bash
|
||||
python run.py --execution-provider openvino
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
**1. Image/Video Mode**
|
||||
|
||||
- Execute `python run.py`.
|
||||
- Choose a source face image and a target image/video.
|
||||
- Click "Start".
|
||||
- The output will be saved in a directory named after the target video.
|
||||
- Execute `python run.py`.
|
||||
- Choose a source face image and a target image/video.
|
||||
- Click "Start".
|
||||
- The output will be saved in a directory named after the target video.
|
||||
|
||||
**2. Webcam Mode**
|
||||
|
||||
- Execute `python run.py`.
|
||||
- Select a source face image.
|
||||
- Click "Live".
|
||||
- Wait for the preview to appear (10-30 seconds).
|
||||
- Use a screen capture tool like OBS to stream.
|
||||
- To change the face, select a new source image.
|
||||
|
||||
## Features - Everything is realtime
|
||||
|
||||
### Mouth Mask
|
||||
|
||||
**Retain your original mouth using Mouth Mask**
|
||||
|
||||

|
||||
|
||||
### Face Mapping
|
||||
|
||||
**Use different faces on multiple subjects**
|
||||
|
||||

|
||||
|
||||
### Your Movie, Your Face
|
||||
|
||||
**Watch movies with any face in realtime**
|
||||
|
||||

|
||||
|
||||
|
||||
## Benchmarks
|
||||
|
||||
**Nearly 0% detection!**
|
||||
|
||||

|
||||
- Execute `python run.py`.
|
||||
- Select a source face image.
|
||||
- Click "Live".
|
||||
- Wait for the preview to appear (10-30 seconds).
|
||||
- Use a screen capture tool like OBS to stream.
|
||||
- To change the face, select a new source image.
|
||||
|
||||
## Command Line Arguments (Unmaintained)
|
||||
|
||||
|
@ -216,9 +230,9 @@ options:
|
|||
|
||||
Looking for a CLI mode? Using the -s/--source argument will make the run program in cli mode.
|
||||
|
||||
|
||||
## Press
|
||||
**We are always open to criticism and ready to improve, that's why we didn't cherrypick anything.**
|
||||
|
||||
**We are always open to criticism and are ready to improve, that's why we didn't cherry-pick anything.**
|
||||
|
||||
- [*"Deep-Live-Cam goes viral, allowing anyone to become a digital doppelganger"*](https://arstechnica.com/information-technology/2024/08/new-ai-tool-enables-real-time-face-swapping-on-webcams-raising-fraud-concerns/) - Ars Technica
|
||||
- [*"Thanks Deep Live Cam, shapeshifters are among us now"*](https://dataconomy.com/2024/08/15/what-is-deep-live-cam-github-deepfake/) - Dataconomy
|
||||
|
@ -231,24 +245,28 @@ Looking for a CLI mode? Using the -s/--source argument will make the run program
|
|||
- [*"New Real-Time Face-Swapping AI Allows Anyone to Mimic Famous Faces"*](https://www.digitalmusicnews.com/2024/08/15/face-swapping-ai-real-time-mimic/) - Digital Music News
|
||||
- [*"This real-time webcam deepfake tool raises alarms about the future of identity theft"*](https://www.diyphotography.net/this-real-time-webcam-deepfake-tool-raises-alarms-about-the-future-of-identity-theft/) - DIYPhotography
|
||||
- [*"That's Crazy, Oh God. That's Fucking Freaky Dude... That's So Wild Dude"*](https://www.youtube.com/watch?time_continue=1074&v=py4Tc-Y8BcY) - SomeOrdinaryGamers
|
||||
- [*"Alright look look look, now look chat, we can do any face we want to look like chat"*](https://www.youtube.com/live/mFsCe7AIxq8?feature=shared&t=2686) - IShowSpeed
|
||||
|
||||
## Credits
|
||||
|
||||
- [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. Please be reminded that the [use of the model is for non-commercial research purposes only](https://github.com/deepinsight/insightface?tab=readme-ov-file#license).
|
||||
- [havok2-htwo](https://github.com/havok2-htwo) : for sharing the code for webcam
|
||||
- [GosuDRM](https://github.com/GosuDRM) : for open version of roop
|
||||
- [pereiraroland26](https://github.com/pereiraroland26) : Multiple faces support
|
||||
- [vic4key](https://github.com/vic4key) : For supporting/contributing on this project
|
||||
- [KRSHH](https://github.com/KRSHH) : For his contributions
|
||||
- and [all developers](https://github.com/hacksider/Deep-Live-Cam/graphs/contributors) behind libraries used in this project.
|
||||
- Foot Note: Please be informed that the base author of the code is [s0md3v](https://github.com/s0md3v/roop)
|
||||
- All the wonderful users who helped making this project go viral by starring the repo ❤️
|
||||
- [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. Please be reminded that the [use of the model is for non-commercial research purposes only](https://github.com/deepinsight/insightface?tab=readme-ov-file#license).
|
||||
- [havok2-htwo](https://github.com/havok2-htwo): for sharing the code for webcam
|
||||
- [GosuDRM](https://github.com/GosuDRM): for the open version of roop
|
||||
- [pereiraroland26](https://github.com/pereiraroland26): Multiple faces support
|
||||
- [vic4key](https://github.com/vic4key): For supporting/contributing to this project
|
||||
- [kier007](https://github.com/kier007): for improving the user experience
|
||||
- [qitianai](https://github.com/qitianai): for multi-lingual support
|
||||
- and [all developers](https://github.com/hacksider/Deep-Live-Cam/graphs/contributors) behind libraries used in this project.
|
||||
- Footnote: Please be informed that the base author of the code is [s0md3v](https://github.com/s0md3v/roop)
|
||||
- All the wonderful users who helped make this project go viral by starring the repo ❤️
|
||||
|
||||
[](https://github.com/hacksider/Deep-Live-Cam/stargazers)
|
||||
|
||||
## Contributions
|
||||
|
||||

|
||||
|
||||
## Stars to the Moon 🚀
|
||||
|
||||
<a href="https://star-history.com/#hacksider/deep-live-cam&Date">
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"Source x Target Mapper": "Source x Target Mapper",
|
||||
"select an source image": "选择一个源图像",
|
||||
"Preview": "预览",
|
||||
"select an target image or video": "选择一个目标图像或视频",
|
||||
"save image output file": "保存图像输出文件",
|
||||
"save video output file": "保存视频输出文件",
|
||||
"select an target image": "选择一个目标图像",
|
||||
"source": "源",
|
||||
"Select a target": "选择一个目标",
|
||||
"Select a face": "选择一张脸",
|
||||
"Keep audio": "保留音频",
|
||||
"Face Enhancer": "面纹增强器",
|
||||
"Many faces": "多脸",
|
||||
"Show FPS": "显示帧率",
|
||||
"Keep fps": "保持帧率",
|
||||
"Keep frames": "保持帧数",
|
||||
"Fix Blueish Cam": "修复偏蓝的摄像头",
|
||||
"Mouth Mask": "口罩",
|
||||
"Show Mouth Mask Box": "显示口罩盒",
|
||||
"Start": "开始",
|
||||
"Live": "直播",
|
||||
"Destroy": "结束",
|
||||
"Map faces": "识别人脸",
|
||||
"Processing...": "处理中...",
|
||||
"Processing succeed!": "处理成功!",
|
||||
"Processing ignored!": "处理被忽略!",
|
||||
"Failed to start camera": "启动相机失败",
|
||||
"Please complete pop-up or close it.": "请先完成弹出窗口或者关闭它",
|
||||
"Getting unique faces": "获取独特面部",
|
||||
"Please select a source image first": "请先选择一个源图像",
|
||||
"No faces found in target": "目标图像中没有人脸",
|
||||
"Add": "添加",
|
||||
"Clear": "清除",
|
||||
"Submit": "确认",
|
||||
"Select source image": "请选取源图像",
|
||||
"Select target image": "请选取目标图像",
|
||||
"Please provide mapping!": "请提供映射",
|
||||
"Atleast 1 source with target is required!": "至少需要一个来源图像与目标图像相关!",
|
||||
"At least 1 source with target is required!": "至少需要一个来源图像与目标图像相关!",
|
||||
"Face could not be detected in last upload!": "最近上传的图像中没有检测到人脸!",
|
||||
"Select Camera:": "选择摄像头",
|
||||
"All mappings cleared!": "所有映射均已清除!",
|
||||
"Mappings successfully submitted!": "成功提交映射!",
|
||||
"Source x Target Mapper is already open.": "源 x 目标映射器已打开。"
|
||||
}
|
|
@ -44,6 +44,7 @@ def parse_args() -> None:
|
|||
program.add_argument('--mouth-mask', help='mask the mouth region', dest='mouth_mask', action='store_true', default=False)
|
||||
program.add_argument('--video-encoder', help='adjust output video encoder', dest='video_encoder', default='libx264', choices=['libx264', 'libx265', 'libvpx-vp9'])
|
||||
program.add_argument('--video-quality', help='adjust output video quality', dest='video_quality', type=int, default=18, choices=range(52), metavar='[0-51]')
|
||||
program.add_argument('-l', '--lang', help='Ui language', default="en")
|
||||
program.add_argument('--live-mirror', help='The live camera display as you see it in the front-facing camera frame', dest='live_mirror', action='store_true', default=False)
|
||||
program.add_argument('--live-resizable', help='The live camera frame is resizable', dest='live_resizable', action='store_true', default=False)
|
||||
program.add_argument('--max-memory', help='maximum amount of RAM in GB', dest='max_memory', type=int, default=suggest_max_memory())
|
||||
|
@ -78,6 +79,7 @@ def parse_args() -> None:
|
|||
modules.globals.max_memory = args.max_memory
|
||||
modules.globals.execution_providers = decode_execution_providers(args.execution_provider)
|
||||
modules.globals.execution_threads = args.execution_threads
|
||||
modules.globals.lang = args.lang
|
||||
|
||||
#for ENHANCER tumbler:
|
||||
if 'face_enhancer' in args.frame_processor:
|
||||
|
@ -253,5 +255,5 @@ def run() -> None:
|
|||
if modules.globals.headless:
|
||||
start()
|
||||
else:
|
||||
window = ui.init(start, destroy)
|
||||
window = ui.init(start, destroy, modules.globals.lang)
|
||||
window.mainloop()
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import json
|
||||
from pathlib import Path
|
||||
|
||||
class LanguageManager:
|
||||
def __init__(self, default_language="en"):
|
||||
self.current_language = default_language
|
||||
self.translations = {}
|
||||
self.load_language(default_language)
|
||||
|
||||
def load_language(self, language_code) -> bool:
|
||||
"""load language file"""
|
||||
if language_code == "en":
|
||||
return True
|
||||
try:
|
||||
file_path = Path(__file__).parent.parent / f"locales/{language_code}.json"
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
self.translations = json.load(file)
|
||||
self.current_language = language_code
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
print(f"Language file not found: {language_code}")
|
||||
return False
|
||||
|
||||
def _(self, key, default=None) -> str:
|
||||
"""get translate text"""
|
||||
return self.translations.get(key, default if default else key)
|
|
@ -1,3 +1,3 @@
|
|||
name = 'Deep-Live-Cam'
|
||||
version = '1.7.5'
|
||||
version = '1.8'
|
||||
edition = 'GitHub Edition'
|
||||
|
|
159
modules/ui.py
159
modules/ui.py
|
@ -26,6 +26,7 @@ from modules.utilities import (
|
|||
has_image_extension,
|
||||
)
|
||||
from modules.video_capture import VideoCapturer
|
||||
from modules.gettext import LanguageManager
|
||||
import platform
|
||||
|
||||
if platform.system() == "Windows":
|
||||
|
@ -63,6 +64,7 @@ RECENT_DIRECTORY_SOURCE = None
|
|||
RECENT_DIRECTORY_TARGET = None
|
||||
RECENT_DIRECTORY_OUTPUT = None
|
||||
|
||||
_ = None
|
||||
preview_label = None
|
||||
preview_slider = None
|
||||
source_label = None
|
||||
|
@ -77,9 +79,11 @@ target_label_dict_live = {}
|
|||
img_ft, vid_ft = modules.globals.file_types
|
||||
|
||||
|
||||
def init(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.CTk:
|
||||
global ROOT, PREVIEW
|
||||
def init(start: Callable[[], None], destroy: Callable[[], None], lang: str) -> ctk.CTk:
|
||||
global ROOT, PREVIEW, _
|
||||
|
||||
lang_manager = LanguageManager(lang)
|
||||
_ = lang_manager._
|
||||
ROOT = create_root(start, destroy)
|
||||
PREVIEW = create_preview(ROOT)
|
||||
|
||||
|
@ -154,7 +158,7 @@ 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()
|
||||
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)
|
||||
|
||||
|
@ -165,7 +169,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
|
||||
select_target_button = ctk.CTkButton(
|
||||
root,
|
||||
text="Select a target",
|
||||
text=_("Select a target"),
|
||||
cursor="hand2",
|
||||
command=lambda: select_target_path(),
|
||||
)
|
||||
|
@ -174,7 +178,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
keep_fps_value = ctk.BooleanVar(value=modules.globals.keep_fps)
|
||||
keep_fps_checkbox = ctk.CTkSwitch(
|
||||
root,
|
||||
text="Keep fps",
|
||||
text=_("Keep fps"),
|
||||
variable=keep_fps_value,
|
||||
cursor="hand2",
|
||||
command=lambda: (
|
||||
|
@ -187,7 +191,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
keep_frames_value = ctk.BooleanVar(value=modules.globals.keep_frames)
|
||||
keep_frames_switch = ctk.CTkSwitch(
|
||||
root,
|
||||
text="Keep frames",
|
||||
text=_("Keep frames"),
|
||||
variable=keep_frames_value,
|
||||
cursor="hand2",
|
||||
command=lambda: (
|
||||
|
@ -200,7 +204,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
enhancer_value = ctk.BooleanVar(value=modules.globals.fp_ui["face_enhancer"])
|
||||
enhancer_switch = ctk.CTkSwitch(
|
||||
root,
|
||||
text="Face Enhancer",
|
||||
text=_("Face Enhancer"),
|
||||
variable=enhancer_value,
|
||||
cursor="hand2",
|
||||
command=lambda: (
|
||||
|
@ -213,7 +217,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
keep_audio_value = ctk.BooleanVar(value=modules.globals.keep_audio)
|
||||
keep_audio_switch = ctk.CTkSwitch(
|
||||
root,
|
||||
text="Keep audio",
|
||||
text=_("Keep audio"),
|
||||
variable=keep_audio_value,
|
||||
cursor="hand2",
|
||||
command=lambda: (
|
||||
|
@ -226,7 +230,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
many_faces_value = ctk.BooleanVar(value=modules.globals.many_faces)
|
||||
many_faces_switch = ctk.CTkSwitch(
|
||||
root,
|
||||
text="Many faces",
|
||||
text=_("Many faces"),
|
||||
variable=many_faces_value,
|
||||
cursor="hand2",
|
||||
command=lambda: (
|
||||
|
@ -239,7 +243,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
color_correction_value = ctk.BooleanVar(value=modules.globals.color_correction)
|
||||
color_correction_switch = ctk.CTkSwitch(
|
||||
root,
|
||||
text="Fix Blueish Cam",
|
||||
text=_("Fix Blueish Cam"),
|
||||
variable=color_correction_value,
|
||||
cursor="hand2",
|
||||
command=lambda: (
|
||||
|
@ -256,12 +260,13 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
map_faces = ctk.BooleanVar(value=modules.globals.map_faces)
|
||||
map_faces_switch = ctk.CTkSwitch(
|
||||
root,
|
||||
text="Map faces",
|
||||
text=_("Map faces"),
|
||||
variable=map_faces,
|
||||
cursor="hand2",
|
||||
command=lambda: (
|
||||
setattr(modules.globals, "map_faces", map_faces.get()),
|
||||
save_switch_states(),
|
||||
close_mapper_window() if not map_faces.get() else None
|
||||
),
|
||||
)
|
||||
map_faces_switch.place(relx=0.1, rely=0.75)
|
||||
|
@ -269,7 +274,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
show_fps_value = ctk.BooleanVar(value=modules.globals.show_fps)
|
||||
show_fps_switch = ctk.CTkSwitch(
|
||||
root,
|
||||
text="Show FPS",
|
||||
text=_("Show FPS"),
|
||||
variable=show_fps_value,
|
||||
cursor="hand2",
|
||||
command=lambda: (
|
||||
|
@ -282,7 +287,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
mouth_mask_var = ctk.BooleanVar(value=modules.globals.mouth_mask)
|
||||
mouth_mask_switch = ctk.CTkSwitch(
|
||||
root,
|
||||
text="Mouth Mask",
|
||||
text=_("Mouth Mask"),
|
||||
variable=mouth_mask_var,
|
||||
cursor="hand2",
|
||||
command=lambda: setattr(modules.globals, "mouth_mask", mouth_mask_var.get()),
|
||||
|
@ -292,7 +297,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
show_mouth_mask_box_var = ctk.BooleanVar(value=modules.globals.show_mouth_mask_box)
|
||||
show_mouth_mask_box_switch = ctk.CTkSwitch(
|
||||
root,
|
||||
text="Show Mouth Mask Box",
|
||||
text=_("Show Mouth Mask Box"),
|
||||
variable=show_mouth_mask_box_var,
|
||||
cursor="hand2",
|
||||
command=lambda: setattr(
|
||||
|
@ -302,22 +307,22 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
show_mouth_mask_box_switch.place(relx=0.6, rely=0.55)
|
||||
|
||||
start_button = ctk.CTkButton(
|
||||
root, text="Start", cursor="hand2", command=lambda: analyze_target(start, root)
|
||||
root, text=_("Start"), cursor="hand2", command=lambda: analyze_target(start, root)
|
||||
)
|
||||
start_button.place(relx=0.15, rely=0.80, relwidth=0.2, relheight=0.05)
|
||||
|
||||
stop_button = ctk.CTkButton(
|
||||
root, text="Destroy", cursor="hand2", command=lambda: destroy()
|
||||
root, text=_("Destroy"), cursor="hand2", command=lambda: destroy()
|
||||
)
|
||||
stop_button.place(relx=0.4, rely=0.80, relwidth=0.2, relheight=0.05)
|
||||
|
||||
preview_button = ctk.CTkButton(
|
||||
root, text="Preview", cursor="hand2", command=lambda: toggle_preview()
|
||||
root, text=_("Preview"), cursor="hand2", command=lambda: toggle_preview()
|
||||
)
|
||||
preview_button.place(relx=0.65, rely=0.80, relwidth=0.2, relheight=0.05)
|
||||
|
||||
# --- Camera Selection ---
|
||||
camera_label = ctk.CTkLabel(root, text="Select Camera:")
|
||||
camera_label = ctk.CTkLabel(root, text=_("Select Camera:"))
|
||||
camera_label.place(relx=0.1, rely=0.86, relwidth=0.2, relheight=0.05)
|
||||
|
||||
available_cameras = get_available_cameras()
|
||||
|
@ -341,7 +346,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
|
||||
live_button = ctk.CTkButton(
|
||||
root,
|
||||
text="Live",
|
||||
text=_("Live"),
|
||||
cursor="hand2",
|
||||
command=lambda: webcam_preview(
|
||||
root,
|
||||
|
@ -371,11 +376,20 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
|
|||
text_color=ctk.ThemeManager.theme.get("URL").get("text_color")
|
||||
)
|
||||
donate_label.bind(
|
||||
"<Button>", lambda event: webbrowser.open("https://paypal.me/hacksider")
|
||||
"<Button>", lambda event: webbrowser.open("https://deeplivecam.net")
|
||||
)
|
||||
|
||||
return root
|
||||
|
||||
def close_mapper_window():
|
||||
global POPUP, POPUP_LIVE
|
||||
if POPUP and POPUP.winfo_exists():
|
||||
POPUP.destroy()
|
||||
POPUP = None
|
||||
if POPUP_LIVE and POPUP_LIVE.winfo_exists():
|
||||
POPUP_LIVE.destroy()
|
||||
POPUP_LIVE = None
|
||||
|
||||
|
||||
def analyze_target(start: Callable[[], None], root: ctk.CTk):
|
||||
if POPUP != None and POPUP.winfo_exists():
|
||||
|
@ -401,12 +415,12 @@ def analyze_target(start: Callable[[], None], root: ctk.CTk):
|
|||
|
||||
|
||||
def create_source_target_popup(
|
||||
start: Callable[[], None], root: ctk.CTk, map: list
|
||||
start: Callable[[], None], root: ctk.CTk, map: list
|
||||
) -> None:
|
||||
global POPUP, popup_status_label
|
||||
|
||||
POPUP = ctk.CTkToplevel(root)
|
||||
POPUP.title("Source x Target Mapper")
|
||||
POPUP.title(_("Source x Target Mapper"))
|
||||
POPUP.geometry(f"{POPUP_WIDTH}x{POPUP_HEIGHT}")
|
||||
POPUP.focus()
|
||||
|
||||
|
@ -430,7 +444,7 @@ def create_source_target_popup(
|
|||
|
||||
button = ctk.CTkButton(
|
||||
scrollable_frame,
|
||||
text="Select source image",
|
||||
text=_("Select source image"),
|
||||
command=lambda id=id: on_button_click(map, id),
|
||||
width=DEFAULT_BUTTON_WIDTH,
|
||||
height=DEFAULT_BUTTON_HEIGHT,
|
||||
|
@ -464,18 +478,18 @@ def create_source_target_popup(
|
|||
popup_status_label.grid(row=1, column=0, pady=15)
|
||||
|
||||
close_button = ctk.CTkButton(
|
||||
POPUP, text="Submit", command=lambda: on_submit_click(start)
|
||||
POPUP, text=_("Submit"), command=lambda: on_submit_click(start)
|
||||
)
|
||||
close_button.grid(row=2, column=0, pady=10)
|
||||
|
||||
|
||||
def update_popup_source(
|
||||
scrollable_frame: ctk.CTkScrollableFrame, map: list, button_num: int
|
||||
scrollable_frame: ctk.CTkScrollableFrame, map: list, button_num: int
|
||||
) -> list:
|
||||
global source_label_dict
|
||||
|
||||
source_path = ctk.filedialog.askopenfilename(
|
||||
title="select an source image",
|
||||
title=_("select an source image"),
|
||||
initialdir=RECENT_DIRECTORY_SOURCE,
|
||||
filetypes=[img_ft],
|
||||
)
|
||||
|
@ -495,7 +509,7 @@ def update_popup_source(
|
|||
x_min, y_min, x_max, y_max = face["bbox"]
|
||||
|
||||
map[button_num]["source"] = {
|
||||
"cv2": cv2_img[int(y_min) : int(y_max), int(x_min) : int(x_max)],
|
||||
"cv2": cv2_img[int(y_min): int(y_max), int(x_min): int(x_max)],
|
||||
"face": face,
|
||||
}
|
||||
|
||||
|
@ -526,7 +540,7 @@ def create_preview(parent: ctk.CTkToplevel) -> ctk.CTkToplevel:
|
|||
|
||||
preview = ctk.CTkToplevel(parent)
|
||||
preview.withdraw()
|
||||
preview.title("Preview")
|
||||
preview.title(_("Preview"))
|
||||
preview.configure()
|
||||
preview.protocol("WM_DELETE_WINDOW", lambda: toggle_preview())
|
||||
preview.resizable(width=True, height=True)
|
||||
|
@ -542,16 +556,16 @@ def create_preview(parent: ctk.CTkToplevel) -> ctk.CTkToplevel:
|
|||
|
||||
|
||||
def update_status(text: str) -> None:
|
||||
status_label.configure(text=text)
|
||||
status_label.configure(text=_(text))
|
||||
ROOT.update()
|
||||
|
||||
|
||||
def update_pop_status(text: str) -> None:
|
||||
popup_status_label.configure(text=text)
|
||||
popup_status_label.configure(text=_(text))
|
||||
|
||||
|
||||
def update_pop_live_status(text: str) -> None:
|
||||
popup_status_label_live.configure(text=text)
|
||||
popup_status_label_live.configure(text=_(text))
|
||||
|
||||
|
||||
def update_tumbler(var: str, value: bool) -> None:
|
||||
|
@ -570,7 +584,7 @@ def select_source_path() -> None:
|
|||
|
||||
PREVIEW.withdraw()
|
||||
source_path = ctk.filedialog.askopenfilename(
|
||||
title="select an source image",
|
||||
title=_("select an source image"),
|
||||
initialdir=RECENT_DIRECTORY_SOURCE,
|
||||
filetypes=[img_ft],
|
||||
)
|
||||
|
@ -613,7 +627,7 @@ def select_target_path() -> None:
|
|||
|
||||
PREVIEW.withdraw()
|
||||
target_path = ctk.filedialog.askopenfilename(
|
||||
title="select an target image or video",
|
||||
title=_("select an target image or video"),
|
||||
initialdir=RECENT_DIRECTORY_TARGET,
|
||||
filetypes=[img_ft, vid_ft],
|
||||
)
|
||||
|
@ -637,7 +651,7 @@ def select_output_path(start: Callable[[], None]) -> None:
|
|||
|
||||
if is_image(modules.globals.target_path):
|
||||
output_path = ctk.filedialog.asksaveasfilename(
|
||||
title="save image output file",
|
||||
title=_("save image output file"),
|
||||
filetypes=[img_ft],
|
||||
defaultextension=".png",
|
||||
initialfile="output.png",
|
||||
|
@ -645,7 +659,7 @@ def select_output_path(start: Callable[[], None]) -> None:
|
|||
)
|
||||
elif is_video(modules.globals.target_path):
|
||||
output_path = ctk.filedialog.asksaveasfilename(
|
||||
title="save video output file",
|
||||
title=_("save video output file"),
|
||||
filetypes=[vid_ft],
|
||||
defaultextension=".mp4",
|
||||
initialfile="output.mp4",
|
||||
|
@ -704,7 +718,7 @@ def render_image_preview(image_path: str, size: Tuple[int, int]) -> ctk.CTkImage
|
|||
|
||||
|
||||
def render_video_preview(
|
||||
video_path: str, size: Tuple[int, int], frame_number: int = 0
|
||||
video_path: str, size: Tuple[int, int], frame_number: int = 0
|
||||
) -> ctk.CTkImage:
|
||||
capture = cv2.VideoCapture(video_path)
|
||||
if frame_number:
|
||||
|
@ -744,7 +758,7 @@ def update_preview(frame_number: int = 0) -> None:
|
|||
if modules.globals.nsfw_filter and check_and_ignore_nsfw(temp_frame):
|
||||
return
|
||||
for frame_processor in get_frame_processors_modules(
|
||||
modules.globals.frame_processors
|
||||
modules.globals.frame_processors
|
||||
):
|
||||
temp_frame = frame_processor.process_frame(
|
||||
get_one_face(cv2.imread(modules.globals.source_path)), temp_frame
|
||||
|
@ -760,6 +774,13 @@ def update_preview(frame_number: int = 0) -> None:
|
|||
|
||||
|
||||
def webcam_preview(root: ctk.CTk, camera_index: int):
|
||||
global POPUP_LIVE
|
||||
|
||||
if POPUP_LIVE and POPUP_LIVE.winfo_exists():
|
||||
update_status("Source x Target Mapper is already open.")
|
||||
POPUP_LIVE.focus()
|
||||
return
|
||||
|
||||
if not modules.globals.map_faces:
|
||||
if modules.globals.source_path is None:
|
||||
update_status("Please select a source image first")
|
||||
|
@ -772,6 +793,7 @@ def webcam_preview(root: ctk.CTk, camera_index: int):
|
|||
)
|
||||
|
||||
|
||||
|
||||
def get_available_cameras():
|
||||
"""Returns a list of available camera names and indices."""
|
||||
if platform.system() == "Windows":
|
||||
|
@ -819,7 +841,7 @@ def get_available_cameras():
|
|||
camera_indices.append(0)
|
||||
camera_names.append("FaceTime Camera")
|
||||
cap.release()
|
||||
|
||||
|
||||
# On macOS, additional cameras typically use indices 1 and 2
|
||||
for i in [1, 2]:
|
||||
cap = cv2.VideoCapture(i)
|
||||
|
@ -935,20 +957,20 @@ def create_webcam_preview(camera_index: int):
|
|||
|
||||
|
||||
def create_source_target_popup_for_webcam(
|
||||
root: ctk.CTk, map: list, camera_index: int
|
||||
root: ctk.CTk, map: list, camera_index: int
|
||||
) -> None:
|
||||
global POPUP_LIVE, popup_status_label_live
|
||||
|
||||
POPUP_LIVE = ctk.CTkToplevel(root)
|
||||
POPUP_LIVE.title("Source x Target Mapper")
|
||||
POPUP_LIVE.title(_("Source x Target Mapper"))
|
||||
POPUP_LIVE.geometry(f"{POPUP_LIVE_WIDTH}x{POPUP_LIVE_HEIGHT}")
|
||||
POPUP_LIVE.focus()
|
||||
|
||||
def on_submit_click():
|
||||
if has_valid_map():
|
||||
POPUP_LIVE.destroy()
|
||||
simplify_maps()
|
||||
create_webcam_preview(camera_index)
|
||||
update_pop_live_status("Mappings successfully submitted!")
|
||||
create_webcam_preview(camera_index) # Open the preview window
|
||||
else:
|
||||
update_pop_live_status("At least 1 source with target is required!")
|
||||
|
||||
|
@ -957,16 +979,43 @@ def create_source_target_popup_for_webcam(
|
|||
refresh_data(map)
|
||||
update_pop_live_status("Please provide mapping!")
|
||||
|
||||
def on_clear_click():
|
||||
clear_source_target_images(map)
|
||||
refresh_data(map)
|
||||
update_pop_live_status("All mappings cleared!")
|
||||
|
||||
popup_status_label_live = ctk.CTkLabel(POPUP_LIVE, text=None, justify="center")
|
||||
popup_status_label_live.grid(row=1, column=0, pady=15)
|
||||
|
||||
add_button = ctk.CTkButton(POPUP_LIVE, text="Add", command=lambda: on_add_click())
|
||||
add_button.place(relx=0.2, rely=0.92, relwidth=0.2, relheight=0.05)
|
||||
add_button = ctk.CTkButton(POPUP_LIVE, text=_("Add"), command=lambda: on_add_click())
|
||||
add_button.place(relx=0.1, rely=0.92, relwidth=0.2, relheight=0.05)
|
||||
|
||||
clear_button = ctk.CTkButton(POPUP_LIVE, text=_("Clear"), command=lambda: on_clear_click())
|
||||
clear_button.place(relx=0.4, rely=0.92, relwidth=0.2, relheight=0.05)
|
||||
|
||||
close_button = ctk.CTkButton(
|
||||
POPUP_LIVE, text="Submit", command=lambda: on_submit_click()
|
||||
POPUP_LIVE, text=_("Submit"), command=lambda: on_submit_click()
|
||||
)
|
||||
close_button.place(relx=0.6, rely=0.92, relwidth=0.2, relheight=0.05)
|
||||
close_button.place(relx=0.7, rely=0.92, relwidth=0.2, relheight=0.05)
|
||||
|
||||
|
||||
|
||||
def clear_source_target_images(map: list):
|
||||
global source_label_dict_live, target_label_dict_live
|
||||
|
||||
for item in map:
|
||||
if "source" in item:
|
||||
del item["source"]
|
||||
if "target" in item:
|
||||
del item["target"]
|
||||
|
||||
for button_num in list(source_label_dict_live.keys()):
|
||||
source_label_dict_live[button_num].destroy()
|
||||
del source_label_dict_live[button_num]
|
||||
|
||||
for button_num in list(target_label_dict_live.keys()):
|
||||
target_label_dict_live[button_num].destroy()
|
||||
del target_label_dict_live[button_num]
|
||||
|
||||
|
||||
def refresh_data(map: list):
|
||||
|
@ -988,7 +1037,7 @@ def refresh_data(map: list):
|
|||
|
||||
button = ctk.CTkButton(
|
||||
scrollable_frame,
|
||||
text="Select source image",
|
||||
text=_("Select source image"),
|
||||
command=lambda id=id: on_sbutton_click(map, id),
|
||||
width=DEFAULT_BUTTON_WIDTH,
|
||||
height=DEFAULT_BUTTON_HEIGHT,
|
||||
|
@ -1005,7 +1054,7 @@ def refresh_data(map: list):
|
|||
|
||||
button = ctk.CTkButton(
|
||||
scrollable_frame,
|
||||
text="Select target image",
|
||||
text=_("Select target image"),
|
||||
command=lambda id=id: on_tbutton_click(map, id),
|
||||
width=DEFAULT_BUTTON_WIDTH,
|
||||
height=DEFAULT_BUTTON_HEIGHT,
|
||||
|
@ -1050,12 +1099,12 @@ def refresh_data(map: list):
|
|||
|
||||
|
||||
def update_webcam_source(
|
||||
scrollable_frame: ctk.CTkScrollableFrame, map: list, button_num: int
|
||||
scrollable_frame: ctk.CTkScrollableFrame, map: list, button_num: int
|
||||
) -> list:
|
||||
global source_label_dict_live
|
||||
|
||||
source_path = ctk.filedialog.askopenfilename(
|
||||
title="select an source image",
|
||||
title=_("select an source image"),
|
||||
initialdir=RECENT_DIRECTORY_SOURCE,
|
||||
filetypes=[img_ft],
|
||||
)
|
||||
|
@ -1075,7 +1124,7 @@ def update_webcam_source(
|
|||
x_min, y_min, x_max, y_max = face["bbox"]
|
||||
|
||||
map[button_num]["source"] = {
|
||||
"cv2": cv2_img[int(y_min) : int(y_max), int(x_min) : int(x_max)],
|
||||
"cv2": cv2_img[int(y_min): int(y_max), int(x_min): int(x_max)],
|
||||
"face": face,
|
||||
}
|
||||
|
||||
|
@ -1102,12 +1151,12 @@ def update_webcam_source(
|
|||
|
||||
|
||||
def update_webcam_target(
|
||||
scrollable_frame: ctk.CTkScrollableFrame, map: list, button_num: int
|
||||
scrollable_frame: ctk.CTkScrollableFrame, map: list, button_num: int
|
||||
) -> list:
|
||||
global target_label_dict_live
|
||||
|
||||
target_path = ctk.filedialog.askopenfilename(
|
||||
title="select an target image",
|
||||
title=_("select an target image"),
|
||||
initialdir=RECENT_DIRECTORY_SOURCE,
|
||||
filetypes=[img_ft],
|
||||
)
|
||||
|
@ -1127,7 +1176,7 @@ def update_webcam_target(
|
|||
x_min, y_min, x_max, y_max = face["bbox"]
|
||||
|
||||
map[button_num]["target"] = {
|
||||
"cv2": cv2_img[int(y_min) : int(y_max), int(x_min) : int(x_max)],
|
||||
"cv2": cv2_img[int(y_min): int(y_max), int(x_min): int(x_max)],
|
||||
"face": face,
|
||||
}
|
||||
|
||||
|
@ -1150,4 +1199,4 @@ def update_webcam_target(
|
|||
target_label_dict_live[button_num] = target_image
|
||||
else:
|
||||
update_pop_live_status("Face could not be detected in last upload!")
|
||||
return map
|
||||
return map
|
|
@ -1,7 +1,7 @@
|
|||
--extra-index-url https://download.pytorch.org/whl/cu118
|
||||
|
||||
numpy>=1.23.5,<2
|
||||
opencv-python==4.8.1.78
|
||||
opencv-python==4.10.0.84
|
||||
cv2_enumerate_cameras==1.1.15
|
||||
onnx==1.16.0
|
||||
insightface==0.7.3
|
||||
|
|
Loading…
Reference in New Issue