Compare commits

..

3 Commits

Author SHA1 Message Date
Makaru 5dd6d1fe64 Fixed 0 Transparency
The error was caused by an erroneous designation of "face_swapper_enabled" in lieu of "fp_ui."
2025-01-15 02:53:11 +08:00
Makaru 9af216e819 Opacity Update
- Added 0 value, if it is set to 0, the face swapping will be disabled
2025-01-14 22:45:16 +08:00
Makaru 59d64d4b6a Added dropdown transparency 2025-01-13 01:23:58 +08:00
8 changed files with 150 additions and 275 deletions
+34 -137
View File
@@ -9,93 +9,52 @@
</p>
<p align="center">
<img src="media/demo.gif" alt="Demo GIF" width="800">
<img src="media/demo.gif" alt="Demo GIF">
<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.
This deepfake software is designed to be a productive tool for the AI-generated media industry. It can assist artists in animating custom characters, creating engaging content, and even using models for clothing design.
###### 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.
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.
###### 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.
- Ethical Use: 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.
## 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>
- Content Restrictions: The software includes built-in checks to prevent processing inappropriate media, such as nudity, graphic content, or sensitive material.
- Legal Compliance: We adhere to all relevant laws and ethical guidelines. If legally required, we may shut down the project or add watermarks to the output.
- User Responsibility: We are not responsible for end-user actions. Users must ensure their use of the software aligns with ethical standards and legal requirements.
By using this software, you agree to these terms and commit to using it in a manner that respects the rights and dignity of others.
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.
## Quick Start - Pre-built (Windows / Nvidia)
<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" />
##### This is the fastest build you can get if you have a discrete NVIDIA GPU.
###### These Pre-builts are perfect for non-technical users or those who don't have time to, or can't manually install all the requirements. Just a heads-up: this is an open-source project, so you can also install it manually.
## TLDR; Live Deepfake in just 3 Clicks
![easysteps](https://github.com/user-attachments/assets/af825228-852c-411b-b787-ffd9aac72fc6)
1. Select a face
2. Select which camera to use
3. Press live!
## Features & Uses - Everything is in real-time
## Features - Everything is real-time
### Mouth Mask
**Retain your original mouth for accurate movement using Mouth Mask**
**Retain your original mouth using Mouth Mask**
<p align="center">
<img src="media/ludwig.gif" alt="resizable-gif">
</p>
![resizable-gif](media/ludwig.gif)
### Face Mapping
**Use different faces on multiple subjects simultaneously**
**Use different faces on multiple subjects**
<p align="center">
<img src="media/streamers.gif" alt="face_mapping_source">
</p>
![face\_mapping\_source](media/streamers.gif)
### Your Movie, Your Face
**Watch movies with any face in real-time**
<p align="center">
<img src="media/movie.gif" alt="movie">
</p>
![movie](media/movie.gif)
### Live Show
## Benchmarks
**Run Live shows and performances**
**Nearly 0% detection!**
<p align="center">
<img src="media/live_show.gif" alt="show">
</p>
### Memes
**Create Your Most Viral Meme Yet**
<p align="center">
<img src="media/meme.gif" alt="show" width="450">
<br>
<sub>Created using Many Faces feature in Deep-Live-Cam</sub>
</p>
### Omegle
**Surprise people on Omegle**
<p align="center">
<video src="https://github.com/user-attachments/assets/2e9b9b82-fa04-4b70-9f56-b1f68e7672d0" width="450" controls></video>
</p>
![bench](media/deepwarebench.gif)
## Installation (Manual)
@@ -113,20 +72,19 @@ This is more likely to work on your computer but will be slower as it utilizes t
- Python (3.10 recommended)
- pip
- git
- [ffmpeg](https://www.youtube.com/watch?v=OlNWCpFdVMA) - ```iex (irm ffmpeg.tc.ht)```
- [ffmpeg](https://www.youtube.com/watch?v=OlNWCpFdVMA)
- [Visual Studio 2022 Runtimes (Windows)](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
**2. Clone the Repository**
```bash
git clone https://github.com/hacksider/Deep-Live-Cam.git
cd Deep-Live-Cam
https://github.com/hacksider/Deep-Live-Cam.git
```
**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_fp16.onnx)
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.
@@ -134,44 +92,14 @@ Place these files in the "**models**" folder.
We highly recommend using a `venv` to avoid issues.
For Windows:
```bash
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt
```
**For macOS:**
Apple Silicon (M1/M2/M3) requires specific setup:
**For macOS:** Install or upgrade the `python-tk` package:
```bash
# Install Python 3.10 (specific version is important)
brew install python@3.10
# Install tkinter package (required for the GUI)
brew install python-tk@3.10
# Create and activate virtual environment with Python 3.10
python3.10 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
```
** In case something goes wrong and you need to reinstall the virtual environment **
```bash
# Deactivate the virtual environment
rm -rf venv
# Reinstall the virtual environment
python -m venv venv
source venv/bin/activate
# install the dependencies again
pip install -r requirements.txt
```
**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).
@@ -180,7 +108,7 @@ pip install -r requirements.txt
**CUDA Execution Provider (Nvidia)**
1. Install [CUDA Toolkit 11.8.0](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
@@ -196,39 +124,19 @@ python run.py --execution-provider cuda
**CoreML Execution Provider (Apple Silicon)**
Apple Silicon (M1/M2/M3) specific installation:
1. Make sure you've completed the macOS setup above using Python 3.10.
2. Install dependencies:
1. Install dependencies:
```bash
pip uninstall onnxruntime onnxruntime-silicon
pip install onnxruntime-silicon==1.13.1
```
3. Usage (important: specify Python 3.10):
2. Usage:
```bash
python3.10 run.py --execution-provider coreml
python run.py --execution-provider coreml
```
**Important Notes for macOS:**
- You **must** use Python 3.10, not newer versions like 3.11 or 3.13
- Always run with `python3.10` command not just `python` if you have multiple Python versions installed
- If you get error about `_tkinter` missing, reinstall the tkinter package: `brew reinstall python-tk@3.10`
- If you get model loading errors, check that your models are in the correct folder
- If you encounter conflicts with other Python versions, consider uninstalling them:
```bash
# List all installed Python versions
brew list | grep python
# Uninstall conflicting versions if needed
brew uninstall --ignore-dependencies python@3.11 python@3.13
# Keep only Python 3.10
brew cleanup
```
**CoreML Execution Provider (Apple Legacy)**
1. Install dependencies:
@@ -273,6 +181,7 @@ pip install onnxruntime-openvino==1.15.0
```bash
python run.py --execution-provider openvino
```
</details>
## Usage
@@ -293,19 +202,6 @@ python run.py --execution-provider openvino
- Use a screen capture tool like OBS to stream.
- To change the face, select a new source image.
## Tips and Tricks
Check out these helpful guides to get the most out of Deep-Live-Cam:
- [Unlocking the Secrets to the Perfect Deepfake Image](https://deeplivecam.net/index.php/blog/tips-and-tricks/unlocking-the-secrets-to-the-perfect-deepfake-image) - Learn how to create the best deepfake with full head coverage
- [Video Call with DeepLiveCam](https://deeplivecam.net/index.php/blog/tips-and-tricks/video-call-with-deeplivecam) - Make your meetings livelier by using DeepLiveCam with OBS and meeting software
- [Have a Special Guest!](https://deeplivecam.net/index.php/blog/tips-and-tricks/have-a-special-guest) - Tutorial on how to use face mapping to add special guests to your stream
- [Watch Deepfake Movies in Realtime](https://deeplivecam.net/index.php/blog/tips-and-tricks/watch-deepfake-movies-in-realtime) - See yourself star in any video without processing the video
- [Better Quality without Sacrificing Speed](https://deeplivecam.net/index.php/blog/tips-and-tricks/better-quality-without-sacrificing-speed) - Tips for achieving better results without impacting performance
- [Instant Vtuber!](https://deeplivecam.net/index.php/blog/tips-and-tricks/instant-vtuber) - Create a new persona/vtuber easily using Metahuman Creator
Visit our [official blog](https://deeplivecam.net/index.php/blog/tips-and-tricks) for more tips and tutorials.
## Command Line Arguments (Unmaintained)
```
@@ -321,6 +217,7 @@ options:
--many-faces process every face
--map-faces map source target faces
--mouth-mask mask the mouth region
--nsfw-filter filter the NSFW image or video
--video-encoder {libx264,libx265,libvpx-vp9} adjust output video encoder
--video-quality [0-51] adjust output video quality
--live-mirror the live camera display as you see it in the front-facing camera frame
@@ -378,4 +275,4 @@ Looking for a CLI mode? Using the -s/--source argument will make the run program
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=hacksider/deep-live-cam&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=hacksider/deep-live-cam&type=Date" />
</picture>
</a>
</a>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 MiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 MiB

+12 -12
View File
@@ -39,13 +39,13 @@ def get_many_faces(frame: Frame) -> Any:
return None
def has_valid_map() -> bool:
for map in modules.globals.source_target_map:
for map in modules.globals.souce_target_map:
if "source" in map and "target" in map:
return True
return False
def default_source_face() -> Any:
for map in modules.globals.source_target_map:
for map in modules.globals.souce_target_map:
if "source" in map:
return map['source']['face']
return None
@@ -53,7 +53,7 @@ def default_source_face() -> Any:
def simplify_maps() -> Any:
centroids = []
faces = []
for map in modules.globals.source_target_map:
for map in modules.globals.souce_target_map:
if "source" in map and "target" in map:
centroids.append(map['target']['face'].normed_embedding)
faces.append(map['source']['face'])
@@ -64,10 +64,10 @@ def simplify_maps() -> Any:
def add_blank_map() -> Any:
try:
max_id = -1
if len(modules.globals.source_target_map) > 0:
max_id = max(modules.globals.source_target_map, key=lambda x: x['id'])['id']
if len(modules.globals.souce_target_map) > 0:
max_id = max(modules.globals.souce_target_map, key=lambda x: x['id'])['id']
modules.globals.source_target_map.append({
modules.globals.souce_target_map.append({
'id' : max_id + 1
})
except ValueError:
@@ -75,14 +75,14 @@ def add_blank_map() -> Any:
def get_unique_faces_from_target_image() -> Any:
try:
modules.globals.source_target_map = []
modules.globals.souce_target_map = []
target_frame = cv2.imread(modules.globals.target_path)
many_faces = get_many_faces(target_frame)
i = 0
for face in many_faces:
x_min, y_min, x_max, y_max = face['bbox']
modules.globals.source_target_map.append({
modules.globals.souce_target_map.append({
'id' : i,
'target' : {
'cv2' : target_frame[int(y_min):int(y_max), int(x_min):int(x_max)],
@@ -96,7 +96,7 @@ def get_unique_faces_from_target_image() -> Any:
def get_unique_faces_from_target_video() -> Any:
try:
modules.globals.source_target_map = []
modules.globals.souce_target_map = []
frame_face_embeddings = []
face_embeddings = []
@@ -127,7 +127,7 @@ def get_unique_faces_from_target_video() -> Any:
face['target_centroid'] = closest_centroid_index
for i in range(len(centroids)):
modules.globals.source_target_map.append({
modules.globals.souce_target_map.append({
'id' : i
})
@@ -135,7 +135,7 @@ def get_unique_faces_from_target_video() -> Any:
for frame in tqdm(frame_face_embeddings, desc=f"Mapping frame embeddings to centroids-{i}"):
temp.append({'frame': frame['frame'], 'faces': [face for face in frame['faces'] if face['target_centroid'] == i], 'location': frame['location']})
modules.globals.source_target_map[i]['target_faces_in_frame'] = temp
modules.globals.souce_target_map[i]['target_faces_in_frame'] = temp
# dump_faces(centroids, frame_face_embeddings)
default_target_face()
@@ -144,7 +144,7 @@ def get_unique_faces_from_target_video() -> Any:
def default_target_face():
for map in modules.globals.source_target_map:
for map in modules.globals.souce_target_map:
best_face = None
best_frame = None
for frame in map['target_faces_in_frame']:
+3 -1
View File
@@ -9,7 +9,7 @@ file_types = [
("Video", ("*.mp4", "*.mkv")),
]
source_target_map = []
souce_target_map = []
simple_map = {}
source_path = None
@@ -41,3 +41,5 @@ show_mouth_mask_box = False
mask_feather_ratio = 8
mask_down_size = 0.50
mask_size = 1
opacity = 1.0
face_swapper_enabled = True
+16 -14
View File
@@ -4,7 +4,6 @@ import insightface
import threading
import numpy as np
import modules.globals
import logging
import modules.processors.frame.core
from modules.core import update_status
from modules.face_analyser import get_one_face, get_many_faces, default_source_face
@@ -15,6 +14,7 @@ from modules.utilities import (
is_video,
)
from modules.cluster_analysis import find_closest_centroid
from modules.globals import face_swapper_enabled, opacity
import os
FACE_SWAPPER = None
@@ -26,7 +26,6 @@ models_dir = os.path.join(
os.path.dirname(os.path.dirname(os.path.dirname(abs_dir))), "models"
)
def pre_check() -> bool:
download_directory_path = abs_dir
conditional_download(
@@ -94,11 +93,17 @@ def swap_face(source_face: Face, target_face: Face, temp_frame: Frame) -> Frame:
swapped_frame = draw_mouth_mask_visualization(
swapped_frame, target_face, mouth_mask_data
)
opacity = getattr(modules.globals, "opacity", 1.0)
swapped_frame = cv2.addWeighted(temp_frame, 1 - opacity, swapped_frame, opacity, 0)
return swapped_frame
def process_frame(source_face: Face, temp_frame: Frame) -> Frame:
if getattr(modules.globals, "opacity", 1.0) == 0:
return temp_frame
if modules.globals.color_correction:
temp_frame = cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB)
@@ -106,30 +111,27 @@ def process_frame(source_face: Face, temp_frame: Frame) -> Frame:
many_faces = get_many_faces(temp_frame)
if many_faces:
for target_face in many_faces:
if source_face and target_face:
temp_frame = swap_face(source_face, target_face, temp_frame)
else:
print("Face detection failed for target/source.")
temp_frame = swap_face(source_face, target_face, temp_frame)
else:
target_face = get_one_face(temp_frame)
if target_face and source_face:
if target_face:
temp_frame = swap_face(source_face, target_face, temp_frame)
else:
logging.error("Face detection failed for target or source.")
return temp_frame
def process_frame_v2(temp_frame: Frame, temp_frame_path: str = "") -> Frame:
if getattr(modules.globals, "opacity", 1.0) == 0:
return temp_frame
if is_image(modules.globals.target_path):
if modules.globals.many_faces:
source_face = default_source_face()
for map in modules.globals.source_target_map:
for map in modules.globals.souce_target_map:
target_face = map["target"]["face"]
temp_frame = swap_face(source_face, target_face, temp_frame)
elif not modules.globals.many_faces:
for map in modules.globals.source_target_map:
for map in modules.globals.souce_target_map:
if "source" in map:
source_face = map["source"]["face"]
target_face = map["target"]["face"]
@@ -138,7 +140,7 @@ def process_frame_v2(temp_frame: Frame, temp_frame_path: str = "") -> Frame:
elif is_video(modules.globals.target_path):
if modules.globals.many_faces:
source_face = default_source_face()
for map in modules.globals.source_target_map:
for map in modules.globals.souce_target_map:
target_frame = [
f
for f in map["target_faces_in_frame"]
@@ -150,7 +152,7 @@ def process_frame_v2(temp_frame: Frame, temp_frame_path: str = "") -> Frame:
temp_frame = swap_face(source_face, target_face, temp_frame)
elif not modules.globals.many_faces:
for map in modules.globals.source_target_map:
for map in modules.globals.souce_target_map:
if "source" in map:
target_frame = [
f
+79 -104
View File
@@ -7,7 +7,6 @@ from cv2_enumerate_cameras import enumerate_cameras # Add this import
from PIL import Image, ImageOps
import time
import json
import tkinterdnd2 as tkdnd
import modules.globals
import modules.metadata
from modules.face_analyser import (
@@ -28,6 +27,7 @@ from modules.utilities import (
)
from modules.video_capture import VideoCapturer
from modules.gettext import LanguageManager
from modules import globals
import platform
if platform.system() == "Windows":
@@ -135,65 +135,78 @@ def load_switch_states():
pass
def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd.TkinterDnD.Tk:
def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.CTk:
global source_label, target_label, status_label, show_fps_switch
load_switch_states()
ctk.deactivate_automatic_dpi_awareness()
ctk.set_appearance_mode("dark")
ctk.set_appearance_mode("system")
ctk.set_default_color_theme(resolve_relative_path("ui.json"))
root = tkdnd.TkinterDnD.Tk()
root = ctk.CTk()
root.minsize(ROOT_WIDTH, ROOT_HEIGHT)
root.title(
f"{modules.metadata.name} {modules.metadata.version} {modules.metadata.edition}"
)
root.configure(bg="#050505")
root.configure()
root.protocol("WM_DELETE_WINDOW", lambda: destroy())
main_frame = ctk.CTkFrame(root, fg_color="#181818", corner_radius=0)
main_frame.pack(fill="both", expand=True, padx=0, pady=0)
source_label = ctk.CTkLabel(main_frame, text=None)
source_label = ctk.CTkLabel(root, text=None)
source_label.place(relx=0.1, rely=0.1, relwidth=0.3, relheight=0.25)
source_label.drop_target_register(tkdnd.DND_FILES)
source_label.dnd_bind("<<Drop>>", lambda event: handle_drop_source(event))
target_label = ctk.CTkLabel(main_frame, text=None)
target_label = ctk.CTkLabel(root, text=None)
target_label.place(relx=0.6, rely=0.1, relwidth=0.3, relheight=0.25)
target_label.drop_target_register(tkdnd.DND_FILES)
target_label.dnd_bind("<<Drop>>", lambda event: handle_drop_target(event))
select_face_button = ctk.CTkButton(
main_frame, 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)
select_face_button.drop_target_register(tkdnd.DND_FILES)
select_face_button.dnd_bind("<<Drop>>", lambda event: handle_drop_source(event))
select_face_button.place(relx=0.1, rely=0.375, relwidth=0.3, relheight=0.1)
swap_faces_button = ctk.CTkButton(
main_frame, text="", cursor="hand2", command=lambda: swap_faces_paths()
root, text="", cursor="hand2", command=lambda: swap_faces_paths()
)
swap_faces_button.place(relx=0.45, rely=0.4, relwidth=0.1, relheight=0.1)
swap_faces_button.place(relx=0.45, rely=0.375, relwidth=0.1, relheight=0.1)
select_target_button = ctk.CTkButton(
main_frame,
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.drop_target_register(tkdnd.DND_FILES)
select_target_button.dnd_bind("<<Drop>>", lambda event: handle_drop_target(event))
select_target_button.place(relx=0.6, rely=0.375, relwidth=0.3, relheight=0.1)
transparency_values = ["0%","25%", "50%", "75%", "100%"]
transparency_var = ctk.StringVar(value="100%") # Default to 100%
def on_transparency_change(value: str):
percentage = int(value.strip('%'))
modules.globals.opacity = percentage / 100.0
if percentage == 0:
modules.globals.fp_ui["face_enhancer"] = False
update_status("Transparency set to 0% - Face swapping disabled.")
elif percentage == 100:
modules.globals.face_swapper_enabled = True
update_status("Transparency set to 100%.")
else:
modules.globals.face_swapper_enabled = True
update_status(f"Transparency set to {value}")
transparency_label = ctk.CTkLabel(root, text="Transparency:")
transparency_label.place(relx=0.1, rely=0.5, relwidth=0.2, relheight=0.05)
transparency_dropdown = ctk.CTkOptionMenu(
root,
values=transparency_values,
variable=transparency_var,
command=on_transparency_change,
)
transparency_dropdown.place(relx=0.35, rely=0.5, relwidth=0.25, relheight=0.05)
keep_fps_value = ctk.BooleanVar(value=modules.globals.keep_fps)
keep_fps_checkbox = ctk.CTkSwitch(
main_frame,
root,
text=_("Keep fps"),
variable=keep_fps_value,
cursor="hand2",
@@ -206,7 +219,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
keep_frames_value = ctk.BooleanVar(value=modules.globals.keep_frames)
keep_frames_switch = ctk.CTkSwitch(
main_frame,
root,
text=_("Keep frames"),
variable=keep_frames_value,
cursor="hand2",
@@ -219,7 +232,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
enhancer_value = ctk.BooleanVar(value=modules.globals.fp_ui["face_enhancer"])
enhancer_switch = ctk.CTkSwitch(
main_frame,
root,
text=_("Face Enhancer"),
variable=enhancer_value,
cursor="hand2",
@@ -232,7 +245,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
keep_audio_value = ctk.BooleanVar(value=modules.globals.keep_audio)
keep_audio_switch = ctk.CTkSwitch(
main_frame,
root,
text=_("Keep audio"),
variable=keep_audio_value,
cursor="hand2",
@@ -245,7 +258,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
many_faces_value = ctk.BooleanVar(value=modules.globals.many_faces)
many_faces_switch = ctk.CTkSwitch(
main_frame,
root,
text=_("Many faces"),
variable=many_faces_value,
cursor="hand2",
@@ -258,7 +271,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
color_correction_value = ctk.BooleanVar(value=modules.globals.color_correction)
color_correction_switch = ctk.CTkSwitch(
main_frame,
root,
text=_("Fix Blueish Cam"),
variable=color_correction_value,
cursor="hand2",
@@ -269,9 +282,13 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
)
color_correction_switch.place(relx=0.6, rely=0.70)
# nsfw_value = ctk.BooleanVar(value=modules.globals.nsfw_filter)
# nsfw_switch = ctk.CTkSwitch(root, text='NSFW filter', variable=nsfw_value, cursor='hand2', command=lambda: setattr(modules.globals, 'nsfw_filter', nsfw_value.get()))
# nsfw_switch.place(relx=0.6, rely=0.7)
map_faces = ctk.BooleanVar(value=modules.globals.map_faces)
map_faces_switch = ctk.CTkSwitch(
main_frame,
root,
text=_("Map faces"),
variable=map_faces,
cursor="hand2",
@@ -285,7 +302,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
show_fps_value = ctk.BooleanVar(value=modules.globals.show_fps)
show_fps_switch = ctk.CTkSwitch(
main_frame,
root,
text=_("Show FPS"),
variable=show_fps_value,
cursor="hand2",
@@ -298,7 +315,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
mouth_mask_var = ctk.BooleanVar(value=modules.globals.mouth_mask)
mouth_mask_switch = ctk.CTkSwitch(
main_frame,
root,
text=_("Mouth Mask"),
variable=mouth_mask_var,
cursor="hand2",
@@ -308,7 +325,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
show_mouth_mask_box_var = ctk.BooleanVar(value=modules.globals.show_mouth_mask_box)
show_mouth_mask_box_switch = ctk.CTkSwitch(
main_frame,
root,
text=_("Show Mouth Mask Box"),
variable=show_mouth_mask_box_var,
cursor="hand2",
@@ -319,22 +336,22 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
show_mouth_mask_box_switch.place(relx=0.6, rely=0.55)
start_button = ctk.CTkButton(
main_frame, 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(
main_frame, 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(
main_frame, 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(main_frame, 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()
@@ -343,7 +360,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
if not camera_names or camera_names[0] == "No cameras found":
camera_variable = ctk.StringVar(value="No cameras found")
camera_optionmenu = ctk.CTkOptionMenu(
main_frame,
root,
variable=camera_variable,
values=["No cameras found"],
state="disabled",
@@ -351,13 +368,13 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
else:
camera_variable = ctk.StringVar(value=camera_names[0])
camera_optionmenu = ctk.CTkOptionMenu(
main_frame, variable=camera_variable, values=camera_names
root, variable=camera_variable, values=camera_names
)
camera_optionmenu.place(relx=0.35, rely=0.86, relwidth=0.25, relheight=0.05)
live_button = ctk.CTkButton(
main_frame,
root,
text=_("Live"),
cursor="hand2",
command=lambda: webcam_preview(
@@ -377,11 +394,11 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> tkdnd
live_button.place(relx=0.65, rely=0.86, relwidth=0.2, relheight=0.05)
# --- End Camera Selection ---
status_label = ctk.CTkLabel(main_frame, text=None, justify="center")
status_label = ctk.CTkLabel(root, text=None, justify="center")
status_label.place(relx=0.1, rely=0.9, relwidth=0.8)
donate_label = ctk.CTkLabel(
main_frame, text="Deep Live Cam", justify="center", cursor="hand2"
root, text="Deep Live Cam", justify="center", cursor="hand2"
)
donate_label.place(relx=0.1, rely=0.95, relwidth=0.8)
donate_label.configure(
@@ -409,7 +426,7 @@ def analyze_target(start: Callable[[], None], root: ctk.CTk):
return
if modules.globals.map_faces:
modules.globals.source_target_map = []
modules.globals.souce_target_map = []
if is_image(modules.globals.target_path):
update_status("Getting unique faces")
@@ -418,8 +435,8 @@ def analyze_target(start: Callable[[], None], root: ctk.CTk):
update_status("Getting unique faces")
get_unique_faces_from_target_video()
if len(modules.globals.source_target_map) > 0:
create_source_target_popup(start, root, modules.globals.source_target_map)
if len(modules.globals.souce_target_map) > 0:
create_source_target_popup(start, root, modules.globals.souce_target_map)
else:
update_status("No faces found in target")
else:
@@ -708,21 +725,17 @@ def check_and_ignore_nsfw(target, destroy: Callable = None) -> bool:
def fit_image_to_size(image, width: int, height: int):
if width is None or height is None or width <= 0 or height <= 0:
if width is None and height is None:
return image
h, w, _ = image.shape
ratio_h = 0.0
ratio_w = 0.0
ratio_w = width / w
ratio_h = height / h
# Use the smaller ratio to ensure the image fits within the given dimensions
ratio = min(ratio_w, ratio_h)
# Compute new dimensions, ensuring they're at least 1 pixel
new_width = max(1, int(ratio * w))
new_height = max(1, int(ratio * h))
new_size = (new_width, new_height)
if width > height:
ratio_h = height / h
else:
ratio_w = width / w
ratio = max(ratio_w, ratio_h)
new_size = (int(ratio * w), int(ratio * h))
return cv2.resize(image, dsize=new_size)
@@ -803,12 +816,13 @@ def webcam_preview(root: ctk.CTk, camera_index: int):
return
create_webcam_preview(camera_index)
else:
modules.globals.source_target_map = []
modules.globals.souce_target_map = []
create_source_target_popup_for_webcam(
root, modules.globals.source_target_map, camera_index
root, modules.globals.souce_target_map, camera_index
)
def get_available_cameras():
"""Returns a list of available camera names and indices."""
if platform.system() == "Windows":
@@ -1014,6 +1028,7 @@ def create_source_target_popup_for_webcam(
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
@@ -1213,44 +1228,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
# New drop handler functions
def handle_drop_source(event):
"""Handle files dropped on source button or label"""
file_path = event.data
# On Windows, file paths may be enclosed in {}
if file_path.startswith("{") and file_path.endswith("}"):
file_path = file_path[1:-1]
if is_image(file_path):
modules.globals.source_path = file_path
global RECENT_DIRECTORY_SOURCE
RECENT_DIRECTORY_SOURCE = os.path.dirname(modules.globals.source_path)
image = render_image_preview(modules.globals.source_path, (200, 200))
source_label.configure(image=image)
else:
update_status("Please drop an image file for the source.")
def handle_drop_target(event):
"""Handle files dropped on target button or label"""
file_path = event.data
# On Windows, file paths may be enclosed in {}
if file_path.startswith("{") and file_path.endswith("}"):
file_path = file_path[1:-1]
if is_image(file_path) or is_video(file_path):
modules.globals.target_path = file_path
global RECENT_DIRECTORY_TARGET
RECENT_DIRECTORY_TARGET = os.path.dirname(modules.globals.target_path)
if is_image(file_path):
image = render_image_preview(modules.globals.target_path, (200, 200))
target_label.configure(image=image)
elif is_video(file_path):
video_frame = render_video_preview(file_path, (200, 200))
target_label.configure(image=video_frame)
else:
update_status("Please drop an image or video file for the target.")
return map
+6 -7
View File
@@ -1,7 +1,6 @@
--extra-index-url https://download.pytorch.org/whl/cu118
numpy>=1.23.5,<2
typing-extensions>=4.8.0
opencv-python==4.10.0.84
cv2_enumerate_cameras==1.1.15
onnx==1.16.0
@@ -9,14 +8,14 @@ insightface==0.7.3
psutil==5.9.8
tk==0.1.0
customtkinter==5.2.2
pillow==11.1.0
torch==2.5.1+cu118; sys_platform != 'darwin'
torch==2.5.1; sys_platform == 'darwin'
torchvision==0.20.1; sys_platform != 'darwin'
torchvision==0.20.1; sys_platform == 'darwin'
pillow==9.5.0
torch==2.0.1+cu118; sys_platform != 'darwin'
torch==2.0.1; sys_platform == 'darwin'
torchvision==0.15.2+cu118; sys_platform != 'darwin'
torchvision==0.15.2; sys_platform == 'darwin'
onnxruntime-silicon==1.16.3; sys_platform == 'darwin' and platform_machine == 'arm64'
onnxruntime-gpu==1.16.3; sys_platform != 'darwin'
tensorflow; sys_platform != 'darwin'
tensorflow==2.12.1; sys_platform != 'darwin'
opennsfw2==0.10.2
protobuf==4.23.2
tqdm==4.66.4