From 5003c043868b088fe0575c1fd23addbc8294f292 Mon Sep 17 00:00:00 2001
From: KRSHH <136873090+KRSHH@users.noreply.github.com>
Date: Sun, 29 Dec 2024 22:00:25 +0530
Subject: [PATCH 01/24] Added IShowSpeed's Testimonial
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 642db72..c4ef59f 100644
--- a/README.md
+++ b/README.md
@@ -231,6 +231,8 @@ 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
From 8be73689490959e2ed2fb0fc2dd2b56d73c07d20 Mon Sep 17 00:00:00 2001
From: KRSHH <136873090+KRSHH@users.noreply.github.com>
Date: Mon, 30 Dec 2024 15:51:46 +0530
Subject: [PATCH 02/24] Added URL to official website
---
modules/ui.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/ui.py b/modules/ui.py
index 33ded63..3a1d56b 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -371,7 +371,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
text_color=ctk.ThemeManager.theme.get("URL").get("text_color")
)
donate_label.bind(
- "", lambda event: webbrowser.open("https://paypal.me/hacksider")
+ "", lambda event: webbrowser.open("https://deeplivecam.net")
)
return root
From 60e82ea200fae3d75107816eca2794aec529305b Mon Sep 17 00:00:00 2001
From: Makaru
Date: Fri, 3 Jan 2025 20:26:54 +0800
Subject: [PATCH 03/24] Update requirements.txt
---
requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements.txt b/requirements.txt
index 7ce536f..c90be07 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -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 :: Compatible Cuda 12.1
cv2_enumerate_cameras==1.1.15
onnx==1.16.0
insightface==0.7.3
From 82d5d3491296459b1bb689bb37e773ee3cbdf494 Mon Sep 17 00:00:00 2001
From: Makaru
Date: Fri, 3 Jan 2025 20:42:38 +0800
Subject: [PATCH 04/24] Update requirements.txt
---
requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements.txt b/requirements.txt
index c90be07..0e6d2b2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
--extra-index-url https://download.pytorch.org/whl/cu118
numpy>=1.23.5,<2
-opencv-python==4.10.0.84 :: Compatible Cuda 12.1
+opencv-python==4.10.0.84 :: Update OpenCV-Python from version 4.8.1.78 to version 4.10.0.84 in order to ensure compatibility with Cuda 12.1.
cv2_enumerate_cameras==1.1.15
onnx==1.16.0
insightface==0.7.3
From 6219da4b1b74c6f415b48885b5c7a50d4677822d Mon Sep 17 00:00:00 2001
From: Kenneth Estanislao
Date: Fri, 3 Jan 2025 21:12:07 +0800
Subject: [PATCH 05/24] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index c4ef59f..734dd61 100644
--- a/README.md
+++ b/README.md
@@ -81,7 +81,7 @@ brew install python-tk@3.10
**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
From d8a5cdbc190727bfebf20bb878667ae36931a636 Mon Sep 17 00:00:00 2001
From: KRSHH <136873090+KRSHH@users.noreply.github.com>
Date: Fri, 3 Jan 2025 19:21:39 +0530
Subject: [PATCH 06/24] removed comment from requirements.txt
---
requirements.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/requirements.txt b/requirements.txt
index 0e6d2b2..6a6f2c6 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
--extra-index-url https://download.pytorch.org/whl/cu118
numpy>=1.23.5,<2
-opencv-python==4.10.0.84 :: Update OpenCV-Python from version 4.8.1.78 to version 4.10.0.84 in order to ensure compatibility with Cuda 12.1.
+opencv-python==4.10.0.84
cv2_enumerate_cameras==1.1.15
onnx==1.16.0
insightface==0.7.3
From 22940d1b9992e6a1f5f5b2d4a2ca4dcaa4ded883 Mon Sep 17 00:00:00 2001
From: Makaru
Date: Sun, 5 Jan 2025 18:29:01 +0800
Subject: [PATCH 07/24] Update ui.py
The following changes have been implemented:
-A "clear" button has been incorporated.
-The Source x Target Mapper window has been retained following the submission of data via the "submit" button.
---
modules/ui.py | 236 ++++++++++++++++++++------------------------------
1 file changed, 93 insertions(+), 143 deletions(-)
diff --git a/modules/ui.py b/modules/ui.py
index 3a1d56b..0fc8a0f 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -7,6 +7,7 @@ from cv2_enumerate_cameras import enumerate_cameras # Add this import
from PIL import Image, ImageOps
import time
import json
+
import modules.globals
import modules.metadata
from modules.face_analyser import (
@@ -25,11 +26,6 @@ from modules.utilities import (
resolve_relative_path,
has_image_extension,
)
-from modules.video_capture import VideoCapturer
-import platform
-
-if platform.system() == "Windows":
- from pygrabber.dshow_graph import FilterGraph
ROOT = None
POPUP = None
@@ -100,7 +96,7 @@ def save_switch_states():
"fp_ui": modules.globals.fp_ui,
"show_fps": modules.globals.show_fps,
"mouth_mask": modules.globals.mouth_mask,
- "show_mouth_mask_box": modules.globals.show_mouth_mask_box,
+ "show_mouth_mask_box": modules.globals.show_mouth_mask_box
}
with open("switch_states.json", "w") as f:
json.dump(switch_states, f)
@@ -122,9 +118,7 @@ def load_switch_states():
modules.globals.fp_ui = switch_states.get("fp_ui", {"face_enhancer": False})
modules.globals.show_fps = switch_states.get("show_fps", False)
modules.globals.mouth_mask = switch_states.get("mouth_mask", False)
- modules.globals.show_mouth_mask_box = switch_states.get(
- "show_mouth_mask_box", False
- )
+ modules.globals.show_mouth_mask_box = switch_states.get("show_mouth_mask_box", False)
except FileNotFoundError:
# If the file doesn't exist, use default values
pass
@@ -321,22 +315,18 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
camera_label.place(relx=0.1, rely=0.86, relwidth=0.2, relheight=0.05)
available_cameras = get_available_cameras()
- camera_indices, camera_names = available_cameras
-
- if not camera_names or camera_names[0] == "No cameras found":
- camera_variable = ctk.StringVar(value="No cameras found")
- camera_optionmenu = ctk.CTkOptionMenu(
- root,
- variable=camera_variable,
- values=["No cameras found"],
- state="disabled",
+ # Convert camera indices to strings for CTkOptionMenu
+ available_camera_indices, available_camera_strings = available_cameras
+ camera_variable = ctk.StringVar(
+ value=(
+ available_camera_strings[0]
+ if available_camera_strings
+ else "No cameras found"
)
- else:
- camera_variable = ctk.StringVar(value=camera_names[0])
- camera_optionmenu = ctk.CTkOptionMenu(
- root, variable=camera_variable, values=camera_names
- )
-
+ )
+ camera_optionmenu = ctk.CTkOptionMenu(
+ root, variable=camera_variable, values=available_camera_strings
+ )
camera_optionmenu.place(relx=0.35, rely=0.86, relwidth=0.25, relheight=0.05)
live_button = ctk.CTkButton(
@@ -345,16 +335,9 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
cursor="hand2",
command=lambda: webcam_preview(
root,
- (
- camera_indices[camera_names.index(camera_variable.get())]
- if camera_names and camera_names[0] != "No cameras found"
- else None
- ),
- ),
- state=(
- "normal"
- if camera_names and camera_names[0] != "No cameras found"
- else "disabled"
+ available_camera_indices[
+ available_camera_strings.index(camera_variable.get())
+ ],
),
)
live_button.place(relx=0.65, rely=0.86, relwidth=0.2, relheight=0.05)
@@ -371,7 +354,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
text_color=ctk.ThemeManager.theme.get("URL").get("text_color")
)
donate_label.bind(
- "", lambda event: webbrowser.open("https://deeplivecam.net")
+ "", lambda event: webbrowser.open("https://paypal.me/hacksider")
)
return root
@@ -412,8 +395,8 @@ def create_source_target_popup(
def on_submit_click(start):
if has_valid_map():
- POPUP.destroy()
- select_output_path(start)
+ simplify_maps()
+ update_pop_live_status("Mappings submitted successfully!")
else:
update_pop_status("Atleast 1 source with target is required!")
@@ -760,9 +743,15 @@ def update_preview(frame_number: int = 0) -> None:
def webcam_preview(root: ctk.CTk, camera_index: int):
+ global POPUP_LIVE
+
+ if POPUP_LIVE is not None and POPUP_LIVE.winfo_exists():
+ 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")
+ # No image selected
return
create_webcam_preview(camera_index)
else:
@@ -774,94 +763,40 @@ 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":
- try:
- graph = FilterGraph()
- devices = graph.get_input_devices()
+ camera_indices = []
+ camera_names = []
- # Create list of indices and names
- camera_indices = list(range(len(devices)))
- camera_names = devices
-
- # If no cameras found through DirectShow, try OpenCV fallback
- if not camera_names:
- # Try to open camera with index -1 and 0
- test_indices = [-1, 0]
- working_cameras = []
-
- for idx in test_indices:
- cap = cv2.VideoCapture(idx)
- if cap.isOpened():
- working_cameras.append(f"Camera {idx}")
- cap.release()
-
- if working_cameras:
- return test_indices[: len(working_cameras)], working_cameras
-
- # If still no cameras found, return empty lists
- if not camera_names:
- return [], ["No cameras found"]
-
- return camera_indices, camera_names
-
- except Exception as e:
- print(f"Error detecting cameras: {str(e)}")
- return [], ["No cameras found"]
- else:
- # Unix-like systems (Linux/Mac) camera detection
- camera_indices = []
- camera_names = []
-
- if platform.system() == "Darwin": # macOS specific handling
- # Try to open the default FaceTime camera first
- cap = cv2.VideoCapture(0)
- if cap.isOpened():
- 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)
- if cap.isOpened():
- camera_indices.append(i)
- camera_names.append(f"Camera {i}")
- cap.release()
- else:
- # Linux camera detection - test first 10 indices
- for i in range(10):
- cap = cv2.VideoCapture(i)
- if cap.isOpened():
- camera_indices.append(i)
- camera_names.append(f"Camera {i}")
- cap.release()
-
- if not camera_names:
- return [], ["No cameras found"]
-
- return camera_indices, camera_names
+ for camera in enumerate_cameras():
+ cap = cv2.VideoCapture(camera.index)
+ if cap.isOpened():
+ camera_indices.append(camera.index)
+ camera_names.append(camera.name)
+ cap.release()
+ return (camera_indices, camera_names)
def create_webcam_preview(camera_index: int):
global preview_label, PREVIEW
- cap = VideoCapturer(camera_index)
- if not cap.start(PREVIEW_DEFAULT_WIDTH, PREVIEW_DEFAULT_HEIGHT, 60):
- update_status("Failed to start camera")
- return
+ camera = cv2.VideoCapture(camera_index)
+ camera.set(cv2.CAP_PROP_FRAME_WIDTH, PREVIEW_DEFAULT_WIDTH)
+ camera.set(cv2.CAP_PROP_FRAME_HEIGHT, PREVIEW_DEFAULT_HEIGHT)
+ camera.set(cv2.CAP_PROP_FPS, 60)
preview_label.configure(width=PREVIEW_DEFAULT_WIDTH, height=PREVIEW_DEFAULT_HEIGHT)
+
PREVIEW.deiconify()
frame_processors = get_frame_processors_modules(modules.globals.frame_processors)
+
source_image = None
prev_time = time.time()
- fps_update_interval = 0.5
+ fps_update_interval = 0.5 # Update FPS every 0.5 seconds
frame_count = 0
fps = 0
- while True:
- ret, frame = cap.read()
+ while camera:
+ ret, frame = camera.read()
if not ret:
break
@@ -875,11 +810,6 @@ def create_webcam_preview(camera_index: int):
temp_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
)
- else:
- temp_frame = fit_image_to_size(
- temp_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
- )
-
if not modules.globals.map_faces:
if source_image is None and modules.globals.source_path:
source_image = get_one_face(cv2.imread(modules.globals.source_path))
@@ -892,6 +822,7 @@ def create_webcam_preview(camera_index: int):
temp_frame = frame_processor.process_frame(source_image, temp_frame)
else:
modules.globals.target_path = None
+
for frame_processor in frame_processors:
if frame_processor.NAME == "DLC.FACE-ENHANCER":
if modules.globals.fp_ui["face_enhancer"]:
@@ -930,7 +861,7 @@ def create_webcam_preview(camera_index: int):
if PREVIEW.state() == "withdrawn":
break
- cap.release()
+ camera.release()
PREVIEW.withdraw()
@@ -946,7 +877,6 @@ def create_source_target_popup_for_webcam(
def on_submit_click():
if has_valid_map():
- POPUP_LIVE.destroy()
simplify_maps()
create_webcam_preview(camera_index)
else:
@@ -957,16 +887,35 @@ def create_source_target_popup_for_webcam(
refresh_data(map)
update_pop_live_status("Please provide mapping!")
+ def on_clear_click():
+ for item in map:
+ if "source" in item:
+ item.pop("source")
+ if "target" in item:
+ item.pop("target")
+ refresh_data(map)
+ update_pop_live_status("Source and target images 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.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(),
+ state="normal",
+ )
+ clear_button.place(relx=0.4, rely=0.92, relwidth=0.15, relheight=0.05)
close_button = ctk.CTkButton(
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)
+
+ refresh_data(map)
def refresh_data(map: list):
@@ -1013,40 +962,36 @@ def refresh_data(map: list):
button.grid(row=id, column=3, padx=20, pady=10)
if "source" in item:
- image = Image.fromarray(
- cv2.cvtColor(item["source"]["cv2"], cv2.COLOR_BGR2RGB)
- )
- image = image.resize(
- (MAPPER_PREVIEW_MAX_WIDTH, MAPPER_PREVIEW_MAX_HEIGHT), Image.LANCZOS
- )
- tk_image = ctk.CTkImage(image, size=image.size)
-
- source_image = ctk.CTkLabel(
+ source_label = ctk.CTkLabel(
scrollable_frame,
- text=f"S-{id}",
+ text="",
width=MAPPER_PREVIEW_MAX_WIDTH,
height=MAPPER_PREVIEW_MAX_HEIGHT,
)
- source_image.grid(row=id, column=1, padx=10, pady=10)
- source_image.configure(image=tk_image)
+ source_label.grid(row=id, column=1, padx=10, pady=10)
+ else:
+ ctk.CTkLabel(
+ scrollable_frame,
+ text="No Source",
+ width=MAPPER_PREVIEW_MAX_WIDTH,
+ height=MAPPER_PREVIEW_MAX_HEIGHT,
+ ).grid(row=id, column=1, padx=10, pady=10)
if "target" in item:
- image = Image.fromarray(
- cv2.cvtColor(item["target"]["cv2"], cv2.COLOR_BGR2RGB)
- )
- image = image.resize(
- (MAPPER_PREVIEW_MAX_WIDTH, MAPPER_PREVIEW_MAX_HEIGHT), Image.LANCZOS
- )
- tk_image = ctk.CTkImage(image, size=image.size)
-
- target_image = ctk.CTkLabel(
+ target_label = ctk.CTkLabel(
scrollable_frame,
- text=f"T-{id}",
+ text="",
width=MAPPER_PREVIEW_MAX_WIDTH,
height=MAPPER_PREVIEW_MAX_HEIGHT,
)
- target_image.grid(row=id, column=4, padx=20, pady=10)
- target_image.configure(image=tk_image)
+ target_label.grid(row=id, column=4, padx=20, pady=10)
+ else:
+ ctk.CTkLabel(
+ scrollable_frame,
+ text="No Target",
+ width=MAPPER_PREVIEW_MAX_WIDTH,
+ height=MAPPER_PREVIEW_MAX_HEIGHT,
+ ).grid(row=id, column=4, padx=20, pady=10)
def update_webcam_source(
@@ -1069,6 +1014,11 @@ def update_webcam_source(
return map
else:
cv2_img = cv2.imread(source_path)
+
+ if cv2_img is None:
+ update_pop_live_status("Failed to load the selected image. Please try again.")
+ return map
+
face = get_one_face(cv2_img)
if face:
From 742bcab130343cb73eac3545b00c4882445a4560 Mon Sep 17 00:00:00 2001
From: Makaru
Date: Sun, 5 Jan 2025 20:19:36 +0800
Subject: [PATCH 08/24] Update ui.py
Added:
- try-finally Block: This makes sure the camera.release() is called no matter how the while loops end.
- Resource Cleanup: The finally block takes care of cleaning up resources to keep the application stable.
---
modules/ui.py | 114 +++++++++++++++++++++++++-------------------------
1 file changed, 58 insertions(+), 56 deletions(-)
diff --git a/modules/ui.py b/modules/ui.py
index 0fc8a0f..b637dc6 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -795,74 +795,76 @@ def create_webcam_preview(camera_index: int):
frame_count = 0
fps = 0
- while camera:
- ret, frame = camera.read()
- if not ret:
- break
+ try:
+ while camera:
+ ret, frame = camera.read()
+ if not ret:
+ break
- temp_frame = frame.copy()
+ temp_frame = frame.copy()
- if modules.globals.live_mirror:
- temp_frame = cv2.flip(temp_frame, 1)
+ if modules.globals.live_mirror:
+ temp_frame = cv2.flip(temp_frame, 1)
- if modules.globals.live_resizable:
- temp_frame = fit_image_to_size(
- temp_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
- )
+ if modules.globals.live_resizable:
+ temp_frame = fit_image_to_size(
+ temp_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
+ )
- if not modules.globals.map_faces:
- if source_image is None and modules.globals.source_path:
- source_image = get_one_face(cv2.imread(modules.globals.source_path))
+ if not modules.globals.map_faces:
+ if source_image is None and modules.globals.source_path:
+ source_image = get_one_face(cv2.imread(modules.globals.source_path))
- for frame_processor in frame_processors:
- if frame_processor.NAME == "DLC.FACE-ENHANCER":
- if modules.globals.fp_ui["face_enhancer"]:
- temp_frame = frame_processor.process_frame(None, temp_frame)
- else:
- temp_frame = frame_processor.process_frame(source_image, temp_frame)
- else:
- modules.globals.target_path = None
+ for frame_processor in frame_processors:
+ if frame_processor.NAME == "DLC.FACE-ENHANCER":
+ if modules.globals.fp_ui["face_enhancer"]:
+ temp_frame = frame_processor.process_frame(None, temp_frame)
+ else:
+ temp_frame = frame_processor.process_frame(source_image, temp_frame)
+ else:
+ modules.globals.target_path = None
- for frame_processor in frame_processors:
- if frame_processor.NAME == "DLC.FACE-ENHANCER":
- if modules.globals.fp_ui["face_enhancer"]:
+ for frame_processor in frame_processors:
+ if frame_processor.NAME == "DLC.FACE-ENHANCER":
+ if modules.globals.fp_ui["face_enhancer"]:
+ temp_frame = frame_processor.process_frame_v2(temp_frame)
+ else:
temp_frame = frame_processor.process_frame_v2(temp_frame)
- else:
- temp_frame = frame_processor.process_frame_v2(temp_frame)
- # Calculate and display FPS
- current_time = time.time()
- frame_count += 1
- if current_time - prev_time >= fps_update_interval:
- fps = frame_count / (current_time - prev_time)
- frame_count = 0
- prev_time = current_time
+ # Calculate and display FPS
+ current_time = time.time()
+ frame_count += 1
+ if current_time - prev_time >= fps_update_interval:
+ fps = frame_count / (current_time - prev_time)
+ frame_count = 0
+ prev_time = current_time
- if modules.globals.show_fps:
- cv2.putText(
- temp_frame,
- f"FPS: {fps:.1f}",
- (10, 30),
- cv2.FONT_HERSHEY_SIMPLEX,
- 1,
- (0, 255, 0),
- 2,
+ if modules.globals.show_fps:
+ cv2.putText(
+ temp_frame,
+ f"FPS: {fps:.1f}",
+ (10, 30),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 1,
+ (0, 255, 0),
+ 2,
+ )
+
+ image = cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB)
+ image = Image.fromarray(image)
+ image = ImageOps.contain(
+ image, (temp_frame.shape[1], temp_frame.shape[0]), Image.LANCZOS
)
+ image = ctk.CTkImage(image, size=image.size)
+ preview_label.configure(image=image)
+ ROOT.update()
- image = cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB)
- image = Image.fromarray(image)
- image = ImageOps.contain(
- image, (temp_frame.shape[1], temp_frame.shape[0]), Image.LANCZOS
- )
- image = ctk.CTkImage(image, size=image.size)
- preview_label.configure(image=image)
- ROOT.update()
+ if PREVIEW.state() == "withdrawn":
+ break
+ finally:
+ camera.release()
+ PREVIEW.withdraw()
- if PREVIEW.state() == "withdrawn":
- break
-
- camera.release()
- PREVIEW.withdraw()
def create_source_target_popup_for_webcam(
From a3469b7bd4fd5b516b855606a86291b0e303521f Mon Sep 17 00:00:00 2001
From: Makaru
Date: Mon, 6 Jan 2025 00:10:53 +0800
Subject: [PATCH 09/24] Update ui.py
Added:
- If you happen to turn off the map faces switch while the Source x Target Mapper window is open, the Source x Target Mapper window will close.
---
modules/ui.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/modules/ui.py b/modules/ui.py
index b637dc6..b58b9c6 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -256,6 +256,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
command=lambda: (
setattr(modules.globals, "map_faces", map_faces.get()),
save_switch_states(),
+ close_popup_if_switch_off()
),
)
map_faces_switch.place(relx=0.1, rely=0.75)
@@ -382,6 +383,15 @@ def analyze_target(start: Callable[[], None], root: ctk.CTk):
else:
select_output_path(start)
+def close_popup_if_switch_off():
+ global POPUP, POPUP_LIVE
+ if not modules.globals.map_faces:
+ 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 create_source_target_popup(
start: Callable[[], None], root: ctk.CTk, map: list
From f6abe502b667d6cbc3b290ace4f2ba7676606e29 Mon Sep 17 00:00:00 2001
From: Kenneth Estanislao
Date: Mon, 6 Jan 2025 00:26:55 +0800
Subject: [PATCH 10/24] Update README.md
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 734dd61..2d9c295 100644
--- a/README.md
+++ b/README.md
@@ -243,6 +243,7 @@ Looking for a CLI mode? Using the -s/--source argument will make the run program
- [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
+- [kier007](https://github.com/kier007) : for improving the user experience
- 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 ❤️
From 28513d6c1f69a32a2401c92915b108bacb29c704 Mon Sep 17 00:00:00 2001
From: Kenneth Estanislao
Date: Mon, 6 Jan 2025 00:27:45 +0800
Subject: [PATCH 11/24] Update metadata.py
---
modules/metadata.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/metadata.py b/modules/metadata.py
index 55b0050..6a507e3 100644
--- a/modules/metadata.py
+++ b/modules/metadata.py
@@ -1,3 +1,3 @@
name = 'Deep-Live-Cam'
-version = '1.7.5'
+version = '1.8'
edition = 'GitHub Edition'
From 6bf503e669cefce8b9412bced097878f44c0ebc8 Mon Sep 17 00:00:00 2001
From: KRSHH <136873090+KRSHH@users.noreply.github.com>
Date: Sun, 5 Jan 2025 23:02:41 +0530
Subject: [PATCH 12/24] Add download buttons for Windows and Mac
---
README.md | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 734dd61..d4e070c 100644
--- a/README.md
+++ b/README.md
@@ -23,11 +23,20 @@ We are aware of the potential for unethical applications and are committed to pr
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 (Windows / Nvidia)
+## Quick Start - Download Prebuilt
+
-[](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.
## Installation (Manual)
**Please be aware that the installation needs technical skills and is not for beginners, consider downloading the prebuilt.**
From b518f4337d880aa6b7a45dc3886cfeb510e6e403 Mon Sep 17 00:00:00 2001
From: Kenneth Estanislao
Date: Mon, 6 Jan 2025 14:14:04 +0800
Subject: [PATCH 13/24] Revert "Merge pull request #869 from kier007/patch-1"
This reverts commit b38ef624471d15cdb2a0faf2fb877130d1655d3e, reversing
changes made to c03f697729fa8649f58381ae0fd5c217afb18634.
---
modules/ui.py | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/modules/ui.py b/modules/ui.py
index b58b9c6..b637dc6 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -256,7 +256,6 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
command=lambda: (
setattr(modules.globals, "map_faces", map_faces.get()),
save_switch_states(),
- close_popup_if_switch_off()
),
)
map_faces_switch.place(relx=0.1, rely=0.75)
@@ -383,15 +382,6 @@ def analyze_target(start: Callable[[], None], root: ctk.CTk):
else:
select_output_path(start)
-def close_popup_if_switch_off():
- global POPUP, POPUP_LIVE
- if not modules.globals.map_faces:
- 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 create_source_target_popup(
start: Callable[[], None], root: ctk.CTk, map: list
From b38831dfdf4781678165aa4bf54e7ce382b6323a Mon Sep 17 00:00:00 2001
From: Kenneth Estanislao
Date: Mon, 6 Jan 2025 14:14:21 +0800
Subject: [PATCH 14/24] Revert "Merge pull request #868 from kier007/main"
This reverts commit c03f697729fa8649f58381ae0fd5c217afb18634, reversing
changes made to d8a5cdbc190727bfebf20bb878667ae36931a636.
---
modules/ui.py | 354 ++++++++++++++++++++++++++++----------------------
1 file changed, 201 insertions(+), 153 deletions(-)
diff --git a/modules/ui.py b/modules/ui.py
index b637dc6..3a1d56b 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -7,7 +7,6 @@ from cv2_enumerate_cameras import enumerate_cameras # Add this import
from PIL import Image, ImageOps
import time
import json
-
import modules.globals
import modules.metadata
from modules.face_analyser import (
@@ -26,6 +25,11 @@ from modules.utilities import (
resolve_relative_path,
has_image_extension,
)
+from modules.video_capture import VideoCapturer
+import platform
+
+if platform.system() == "Windows":
+ from pygrabber.dshow_graph import FilterGraph
ROOT = None
POPUP = None
@@ -96,7 +100,7 @@ def save_switch_states():
"fp_ui": modules.globals.fp_ui,
"show_fps": modules.globals.show_fps,
"mouth_mask": modules.globals.mouth_mask,
- "show_mouth_mask_box": modules.globals.show_mouth_mask_box
+ "show_mouth_mask_box": modules.globals.show_mouth_mask_box,
}
with open("switch_states.json", "w") as f:
json.dump(switch_states, f)
@@ -118,7 +122,9 @@ def load_switch_states():
modules.globals.fp_ui = switch_states.get("fp_ui", {"face_enhancer": False})
modules.globals.show_fps = switch_states.get("show_fps", False)
modules.globals.mouth_mask = switch_states.get("mouth_mask", False)
- modules.globals.show_mouth_mask_box = switch_states.get("show_mouth_mask_box", False)
+ modules.globals.show_mouth_mask_box = switch_states.get(
+ "show_mouth_mask_box", False
+ )
except FileNotFoundError:
# If the file doesn't exist, use default values
pass
@@ -315,18 +321,22 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
camera_label.place(relx=0.1, rely=0.86, relwidth=0.2, relheight=0.05)
available_cameras = get_available_cameras()
- # Convert camera indices to strings for CTkOptionMenu
- available_camera_indices, available_camera_strings = available_cameras
- camera_variable = ctk.StringVar(
- value=(
- available_camera_strings[0]
- if available_camera_strings
- else "No cameras found"
+ camera_indices, camera_names = available_cameras
+
+ if not camera_names or camera_names[0] == "No cameras found":
+ camera_variable = ctk.StringVar(value="No cameras found")
+ camera_optionmenu = ctk.CTkOptionMenu(
+ root,
+ variable=camera_variable,
+ values=["No cameras found"],
+ state="disabled",
)
- )
- camera_optionmenu = ctk.CTkOptionMenu(
- root, variable=camera_variable, values=available_camera_strings
- )
+ else:
+ camera_variable = ctk.StringVar(value=camera_names[0])
+ camera_optionmenu = ctk.CTkOptionMenu(
+ 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(
@@ -335,9 +345,16 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
cursor="hand2",
command=lambda: webcam_preview(
root,
- available_camera_indices[
- available_camera_strings.index(camera_variable.get())
- ],
+ (
+ camera_indices[camera_names.index(camera_variable.get())]
+ if camera_names and camera_names[0] != "No cameras found"
+ else None
+ ),
+ ),
+ state=(
+ "normal"
+ if camera_names and camera_names[0] != "No cameras found"
+ else "disabled"
),
)
live_button.place(relx=0.65, rely=0.86, relwidth=0.2, relheight=0.05)
@@ -354,7 +371,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
text_color=ctk.ThemeManager.theme.get("URL").get("text_color")
)
donate_label.bind(
- "", lambda event: webbrowser.open("https://paypal.me/hacksider")
+ "", lambda event: webbrowser.open("https://deeplivecam.net")
)
return root
@@ -395,8 +412,8 @@ def create_source_target_popup(
def on_submit_click(start):
if has_valid_map():
- simplify_maps()
- update_pop_live_status("Mappings submitted successfully!")
+ POPUP.destroy()
+ select_output_path(start)
else:
update_pop_status("Atleast 1 source with target is required!")
@@ -743,15 +760,9 @@ def update_preview(frame_number: int = 0) -> None:
def webcam_preview(root: ctk.CTk, camera_index: int):
- global POPUP_LIVE
-
- if POPUP_LIVE is not None and POPUP_LIVE.winfo_exists():
- POPUP_LIVE.focus()
- return
-
if not modules.globals.map_faces:
if modules.globals.source_path is None:
- # No image selected
+ update_status("Please select a source image first")
return
create_webcam_preview(camera_index)
else:
@@ -763,108 +774,164 @@ def webcam_preview(root: ctk.CTk, camera_index: int):
def get_available_cameras():
"""Returns a list of available camera names and indices."""
- camera_indices = []
- camera_names = []
+ if platform.system() == "Windows":
+ try:
+ graph = FilterGraph()
+ devices = graph.get_input_devices()
- for camera in enumerate_cameras():
- cap = cv2.VideoCapture(camera.index)
- if cap.isOpened():
- camera_indices.append(camera.index)
- camera_names.append(camera.name)
- cap.release()
- return (camera_indices, camera_names)
+ # Create list of indices and names
+ camera_indices = list(range(len(devices)))
+ camera_names = devices
+
+ # If no cameras found through DirectShow, try OpenCV fallback
+ if not camera_names:
+ # Try to open camera with index -1 and 0
+ test_indices = [-1, 0]
+ working_cameras = []
+
+ for idx in test_indices:
+ cap = cv2.VideoCapture(idx)
+ if cap.isOpened():
+ working_cameras.append(f"Camera {idx}")
+ cap.release()
+
+ if working_cameras:
+ return test_indices[: len(working_cameras)], working_cameras
+
+ # If still no cameras found, return empty lists
+ if not camera_names:
+ return [], ["No cameras found"]
+
+ return camera_indices, camera_names
+
+ except Exception as e:
+ print(f"Error detecting cameras: {str(e)}")
+ return [], ["No cameras found"]
+ else:
+ # Unix-like systems (Linux/Mac) camera detection
+ camera_indices = []
+ camera_names = []
+
+ if platform.system() == "Darwin": # macOS specific handling
+ # Try to open the default FaceTime camera first
+ cap = cv2.VideoCapture(0)
+ if cap.isOpened():
+ 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)
+ if cap.isOpened():
+ camera_indices.append(i)
+ camera_names.append(f"Camera {i}")
+ cap.release()
+ else:
+ # Linux camera detection - test first 10 indices
+ for i in range(10):
+ cap = cv2.VideoCapture(i)
+ if cap.isOpened():
+ camera_indices.append(i)
+ camera_names.append(f"Camera {i}")
+ cap.release()
+
+ if not camera_names:
+ return [], ["No cameras found"]
+
+ return camera_indices, camera_names
def create_webcam_preview(camera_index: int):
global preview_label, PREVIEW
- camera = cv2.VideoCapture(camera_index)
- camera.set(cv2.CAP_PROP_FRAME_WIDTH, PREVIEW_DEFAULT_WIDTH)
- camera.set(cv2.CAP_PROP_FRAME_HEIGHT, PREVIEW_DEFAULT_HEIGHT)
- camera.set(cv2.CAP_PROP_FPS, 60)
+ cap = VideoCapturer(camera_index)
+ if not cap.start(PREVIEW_DEFAULT_WIDTH, PREVIEW_DEFAULT_HEIGHT, 60):
+ update_status("Failed to start camera")
+ return
preview_label.configure(width=PREVIEW_DEFAULT_WIDTH, height=PREVIEW_DEFAULT_HEIGHT)
-
PREVIEW.deiconify()
frame_processors = get_frame_processors_modules(modules.globals.frame_processors)
-
source_image = None
prev_time = time.time()
- fps_update_interval = 0.5 # Update FPS every 0.5 seconds
+ fps_update_interval = 0.5
frame_count = 0
fps = 0
- try:
- while camera:
- ret, frame = camera.read()
- if not ret:
- break
+ while True:
+ ret, frame = cap.read()
+ if not ret:
+ break
- temp_frame = frame.copy()
+ temp_frame = frame.copy()
- if modules.globals.live_mirror:
- temp_frame = cv2.flip(temp_frame, 1)
+ if modules.globals.live_mirror:
+ temp_frame = cv2.flip(temp_frame, 1)
- if modules.globals.live_resizable:
- temp_frame = fit_image_to_size(
- temp_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
- )
-
- if not modules.globals.map_faces:
- if source_image is None and modules.globals.source_path:
- source_image = get_one_face(cv2.imread(modules.globals.source_path))
-
- for frame_processor in frame_processors:
- if frame_processor.NAME == "DLC.FACE-ENHANCER":
- if modules.globals.fp_ui["face_enhancer"]:
- temp_frame = frame_processor.process_frame(None, temp_frame)
- else:
- temp_frame = frame_processor.process_frame(source_image, temp_frame)
- else:
- modules.globals.target_path = None
-
- for frame_processor in frame_processors:
- if frame_processor.NAME == "DLC.FACE-ENHANCER":
- if modules.globals.fp_ui["face_enhancer"]:
- temp_frame = frame_processor.process_frame_v2(temp_frame)
- else:
- temp_frame = frame_processor.process_frame_v2(temp_frame)
-
- # Calculate and display FPS
- current_time = time.time()
- frame_count += 1
- if current_time - prev_time >= fps_update_interval:
- fps = frame_count / (current_time - prev_time)
- frame_count = 0
- prev_time = current_time
-
- if modules.globals.show_fps:
- cv2.putText(
- temp_frame,
- f"FPS: {fps:.1f}",
- (10, 30),
- cv2.FONT_HERSHEY_SIMPLEX,
- 1,
- (0, 255, 0),
- 2,
- )
-
- image = cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB)
- image = Image.fromarray(image)
- image = ImageOps.contain(
- image, (temp_frame.shape[1], temp_frame.shape[0]), Image.LANCZOS
+ if modules.globals.live_resizable:
+ temp_frame = fit_image_to_size(
+ temp_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
)
- image = ctk.CTkImage(image, size=image.size)
- preview_label.configure(image=image)
- ROOT.update()
- if PREVIEW.state() == "withdrawn":
- break
- finally:
- camera.release()
- PREVIEW.withdraw()
+ else:
+ temp_frame = fit_image_to_size(
+ temp_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
+ )
+ if not modules.globals.map_faces:
+ if source_image is None and modules.globals.source_path:
+ source_image = get_one_face(cv2.imread(modules.globals.source_path))
+
+ for frame_processor in frame_processors:
+ if frame_processor.NAME == "DLC.FACE-ENHANCER":
+ if modules.globals.fp_ui["face_enhancer"]:
+ temp_frame = frame_processor.process_frame(None, temp_frame)
+ else:
+ temp_frame = frame_processor.process_frame(source_image, temp_frame)
+ else:
+ modules.globals.target_path = None
+ for frame_processor in frame_processors:
+ if frame_processor.NAME == "DLC.FACE-ENHANCER":
+ if modules.globals.fp_ui["face_enhancer"]:
+ temp_frame = frame_processor.process_frame_v2(temp_frame)
+ else:
+ temp_frame = frame_processor.process_frame_v2(temp_frame)
+
+ # Calculate and display FPS
+ current_time = time.time()
+ frame_count += 1
+ if current_time - prev_time >= fps_update_interval:
+ fps = frame_count / (current_time - prev_time)
+ frame_count = 0
+ prev_time = current_time
+
+ if modules.globals.show_fps:
+ cv2.putText(
+ temp_frame,
+ f"FPS: {fps:.1f}",
+ (10, 30),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 1,
+ (0, 255, 0),
+ 2,
+ )
+
+ image = cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB)
+ image = Image.fromarray(image)
+ image = ImageOps.contain(
+ image, (temp_frame.shape[1], temp_frame.shape[0]), 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()
def create_source_target_popup_for_webcam(
@@ -879,6 +946,7 @@ def create_source_target_popup_for_webcam(
def on_submit_click():
if has_valid_map():
+ POPUP_LIVE.destroy()
simplify_maps()
create_webcam_preview(camera_index)
else:
@@ -889,35 +957,16 @@ def create_source_target_popup_for_webcam(
refresh_data(map)
update_pop_live_status("Please provide mapping!")
- def on_clear_click():
- for item in map:
- if "source" in item:
- item.pop("source")
- if "target" in item:
- item.pop("target")
- refresh_data(map)
- update_pop_live_status("Source and target images 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.1, rely=0.92, relwidth=0.2, relheight=0.05)
-
- clear_button = ctk.CTkButton(
- POPUP_LIVE,
- text="Clear",
- command=lambda: on_clear_click(),
- state="normal",
- )
- clear_button.place(relx=0.4, rely=0.92, relwidth=0.15, relheight=0.05)
+ add_button.place(relx=0.2, rely=0.92, relwidth=0.2, relheight=0.05)
close_button = ctk.CTkButton(
POPUP_LIVE, text="Submit", command=lambda: on_submit_click()
)
- close_button.place(relx=0.7, rely=0.92, relwidth=0.2, relheight=0.05)
-
- refresh_data(map)
+ close_button.place(relx=0.6, rely=0.92, relwidth=0.2, relheight=0.05)
def refresh_data(map: list):
@@ -964,36 +1013,40 @@ def refresh_data(map: list):
button.grid(row=id, column=3, padx=20, pady=10)
if "source" in item:
- source_label = ctk.CTkLabel(
+ image = Image.fromarray(
+ cv2.cvtColor(item["source"]["cv2"], cv2.COLOR_BGR2RGB)
+ )
+ image = image.resize(
+ (MAPPER_PREVIEW_MAX_WIDTH, MAPPER_PREVIEW_MAX_HEIGHT), Image.LANCZOS
+ )
+ tk_image = ctk.CTkImage(image, size=image.size)
+
+ source_image = ctk.CTkLabel(
scrollable_frame,
- text="",
+ text=f"S-{id}",
width=MAPPER_PREVIEW_MAX_WIDTH,
height=MAPPER_PREVIEW_MAX_HEIGHT,
)
- source_label.grid(row=id, column=1, padx=10, pady=10)
- else:
- ctk.CTkLabel(
- scrollable_frame,
- text="No Source",
- width=MAPPER_PREVIEW_MAX_WIDTH,
- height=MAPPER_PREVIEW_MAX_HEIGHT,
- ).grid(row=id, column=1, padx=10, pady=10)
+ source_image.grid(row=id, column=1, padx=10, pady=10)
+ source_image.configure(image=tk_image)
if "target" in item:
- target_label = ctk.CTkLabel(
+ image = Image.fromarray(
+ cv2.cvtColor(item["target"]["cv2"], cv2.COLOR_BGR2RGB)
+ )
+ image = image.resize(
+ (MAPPER_PREVIEW_MAX_WIDTH, MAPPER_PREVIEW_MAX_HEIGHT), Image.LANCZOS
+ )
+ tk_image = ctk.CTkImage(image, size=image.size)
+
+ target_image = ctk.CTkLabel(
scrollable_frame,
- text="",
+ text=f"T-{id}",
width=MAPPER_PREVIEW_MAX_WIDTH,
height=MAPPER_PREVIEW_MAX_HEIGHT,
)
- target_label.grid(row=id, column=4, padx=20, pady=10)
- else:
- ctk.CTkLabel(
- scrollable_frame,
- text="No Target",
- width=MAPPER_PREVIEW_MAX_WIDTH,
- height=MAPPER_PREVIEW_MAX_HEIGHT,
- ).grid(row=id, column=4, padx=20, pady=10)
+ target_image.grid(row=id, column=4, padx=20, pady=10)
+ target_image.configure(image=tk_image)
def update_webcam_source(
@@ -1016,11 +1069,6 @@ def update_webcam_source(
return map
else:
cv2_img = cv2.imread(source_path)
-
- if cv2_img is None:
- update_pop_live_status("Failed to load the selected image. Please try again.")
- return map
-
face = get_one_face(cv2_img)
if face:
From 7f38539508c2b542cb36abd1d869a0cdb79a684e Mon Sep 17 00:00:00 2001
From: KRSHH <136873090+KRSHH@users.noreply.github.com>
Date: Mon, 6 Jan 2025 17:51:00 +0530
Subject: [PATCH 15/24] Fix Grammar in README
---
README.md | 127 +++++++++++++++++++++++++++++-------------------------
1 file changed, 69 insertions(+), 58 deletions(-)
diff --git a/README.md b/README.md
index 40d5609..7a13c22 100644
--- a/README.md
+++ b/README.md
@@ -13,17 +13,16 @@
-
## 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.
-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.
+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.
-
## Quick Start - Download Prebuilt
+
-
## 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.**
Click to see the process
@@ -48,24 +47,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.
@@ -85,18 +84,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) 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
```
@@ -104,11 +105,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
```
@@ -116,11 +120,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
```
@@ -128,11 +135,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
```
@@ -140,41 +150,43 @@ 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
```
-
## 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.
+- 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
+## Features - Everything is real-time
### Mouth Mask
-**Retain your original mouth using Mouth Mask**
+**Retain your original mouth using Mouth Mask**

@@ -182,15 +194,14 @@ python run.py --execution-provider openvino
**Use different faces on multiple subjects**
-
+
### Your Movie, Your Face
-**Watch movies with any face in realtime**
+**Watch movies with any face in real-time**

-
## Benchmarks
**Nearly 0% detection!**
@@ -225,42 +236,42 @@ 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.**
- - [*"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
- - [*"This free AI tool lets you become anyone during video-calls"*](https://www.newsbytesapp.com/news/science/deep-live-cam-ai-impersonation-tool-goes-viral/story) - NewsBytes
- - [*"OK, this viral AI live stream software is truly terrifying"*](https://www.creativebloq.com/ai/ok-this-viral-ai-live-stream-software-is-truly-terrifying) - Creative Bloq
- - [*"Deepfake AI Tool Lets You Become Anyone in a Video Call With Single Photo"*](https://petapixel.com/2024/08/14/deep-live-cam-deepfake-ai-tool-lets-you-become-anyone-in-a-video-call-with-single-photo-mark-zuckerberg-jd-vance-elon-musk/) - PetaPixel
- - [*"Deep-Live-Cam Uses AI to Transform Your Face in Real-Time, Celebrities Included"*](https://www.techeblog.com/deep-live-cam-ai-transform-face/) - TechEBlog
- - [*"An AI tool that "makes you look like anyone" during a video call is going viral online"*](https://telegrafi.com/en/a-tool-that-makes-you-look-like-anyone-during-a-video-call-is-going-viral-on-the-Internet/) - Telegrafi
- - [*"This Deepfake Tool Turning Images Into Livestreams is Topping the GitHub Charts"*](https://decrypt.co/244565/this-deepfake-tool-turning-images-into-livestreams-is-topping-the-github-charts) - Emerge
- - [*"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
-
+**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
+- [\*"This free AI tool lets you become anyone during video-calls"\*](https://www.newsbytesapp.com/news/science/deep-live-cam-ai-impersonation-tool-goes-viral/story) - NewsBytes
+- [\*"OK, this viral AI live stream software is truly terrifying"\*](https://www.creativebloq.com/ai/ok-this-viral-ai-live-stream-software-is-truly-terrifying) - Creative Bloq
+- [\*"Deepfake AI Tool Lets You Become Anyone in a Video Call With Single Photo"\*](https://petapixel.com/2024/08/14/deep-live-cam-deepfake-ai-tool-lets-you-become-anyone-in-a-video-call-with-single-photo-mark-zuckerberg-jd-vance-elon-musk/) - PetaPixel
+- [\*"Deep-Live-Cam Uses AI to Transform Your Face in Real-Time, Celebrities Included"\*](https://www.techeblog.com/deep-live-cam-ai-transform-face/) - TechEBlog
+- [\*"An AI tool that "makes you look like anyone" during a video call is going viral online"\*](https://telegrafi.com/en/a-tool-that-makes-you-look-like-anyone-during-a-video-call-is-going-viral-on-the-Internet/) - Telegrafi
+- [\*"This Deepfake Tool Turning Images Into Livestreams is Topping the GitHub Charts"\*](https://decrypt.co/244565/this-deepfake-tool-turning-images-into-livestreams-is-topping-the-github-charts) - Emerge
+- [\*"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
-- [kier007](https://github.com/kier007) : for improving the user experience
-- 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
+- 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 🚀
From 75913c513ea90ea6688752bc5f47294dc08b0a85 Mon Sep 17 00:00:00 2001
From: KRSHH <136873090+KRSHH@users.noreply.github.com>
Date: Mon, 6 Jan 2025 18:02:51 +0530
Subject: [PATCH 16/24] Decreased Disclaimer's Font Size
---
README.md | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 7a13c22..4e87c45 100644
--- a/README.md
+++ b/README.md
@@ -13,13 +13,12 @@
-## Disclaimer
+## 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 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.
+###### 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.
+###### 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 - Download Prebuilt
From 09f03436399155b8168a7621d5cb371c03601700 Mon Sep 17 00:00:00 2001
From: KRSHH <136873090+KRSHH@users.noreply.github.com>
Date: Mon, 6 Jan 2025 18:16:44 +0530
Subject: [PATCH 17/24] Shifted features section under Quick start
---
README.md | 76 +++++++++++++++++++++++++++----------------------------
1 file changed, 38 insertions(+), 38 deletions(-)
diff --git a/README.md b/README.md
index 4e87c45..8fd92e5 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,32 @@
+## Features - Everything is real-time
+
+### 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 real-time**
+
+
+
+## Benchmarks
+
+**Nearly 0% detection!**
+
+
+
## Installation (Manual)
**Please be aware that the installation requires technical skills and is not for beginners. Consider downloading the prebuilt version.**
@@ -181,32 +207,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.
-## Features - Everything is real-time
-
-### 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 real-time**
-
-
-
-## Benchmarks
-
-**Nearly 0% detection!**
-
-
-
## Command Line Arguments (Unmaintained)
```
@@ -239,18 +239,18 @@ Looking for a CLI mode? Using the -s/--source argument will make the run program
**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
-- [\*"This free AI tool lets you become anyone during video-calls"\*](https://www.newsbytesapp.com/news/science/deep-live-cam-ai-impersonation-tool-goes-viral/story) - NewsBytes
-- [\*"OK, this viral AI live stream software is truly terrifying"\*](https://www.creativebloq.com/ai/ok-this-viral-ai-live-stream-software-is-truly-terrifying) - Creative Bloq
-- [\*"Deepfake AI Tool Lets You Become Anyone in a Video Call With Single Photo"\*](https://petapixel.com/2024/08/14/deep-live-cam-deepfake-ai-tool-lets-you-become-anyone-in-a-video-call-with-single-photo-mark-zuckerberg-jd-vance-elon-musk/) - PetaPixel
-- [\*"Deep-Live-Cam Uses AI to Transform Your Face in Real-Time, Celebrities Included"\*](https://www.techeblog.com/deep-live-cam-ai-transform-face/) - TechEBlog
-- [\*"An AI tool that "makes you look like anyone" during a video call is going viral online"\*](https://telegrafi.com/en/a-tool-that-makes-you-look-like-anyone-during-a-video-call-is-going-viral-on-the-Internet/) - Telegrafi
-- [\*"This Deepfake Tool Turning Images Into Livestreams is Topping the GitHub Charts"\*](https://decrypt.co/244565/this-deepfake-tool-turning-images-into-livestreams-is-topping-the-github-charts) - Emerge
-- [\*"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
+ - [*"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
+ - [*"This free AI tool lets you become anyone during video-calls"*](https://www.newsbytesapp.com/news/science/deep-live-cam-ai-impersonation-tool-goes-viral/story) - NewsBytes
+ - [*"OK, this viral AI live stream software is truly terrifying"*](https://www.creativebloq.com/ai/ok-this-viral-ai-live-stream-software-is-truly-terrifying) - Creative Bloq
+ - [*"Deepfake AI Tool Lets You Become Anyone in a Video Call With Single Photo"*](https://petapixel.com/2024/08/14/deep-live-cam-deepfake-ai-tool-lets-you-become-anyone-in-a-video-call-with-single-photo-mark-zuckerberg-jd-vance-elon-musk/) - PetaPixel
+ - [*"Deep-Live-Cam Uses AI to Transform Your Face in Real-Time, Celebrities Included"*](https://www.techeblog.com/deep-live-cam-ai-transform-face/) - TechEBlog
+ - [*"An AI tool that "makes you look like anyone" during a video call is going viral online"*](https://telegrafi.com/en/a-tool-that-makes-you-look-like-anyone-during-a-video-call-is-going-viral-on-the-Internet/) - Telegrafi
+ - [*"This Deepfake Tool Turning Images Into Livestreams is Topping the GitHub Charts"*](https://decrypt.co/244565/this-deepfake-tool-turning-images-into-livestreams-is-topping-the-github-charts) - Emerge
+ - [*"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
From d07d4a6a2699bbdda8b76bb27bdd95393e1d7865 Mon Sep 17 00:00:00 2001
From: Makaru
Date: Mon, 6 Jan 2025 23:31:33 +0800
Subject: [PATCH 18/24] Update ui.py
I pushed it to premain
---
modules/ui.py | 75 ++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 60 insertions(+), 15 deletions(-)
diff --git a/modules/ui.py b/modules/ui.py
index 3a1d56b..21446db 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -262,6 +262,7 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
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)
@@ -376,6 +377,15 @@ def create_root(start: Callable[[], None], destroy: Callable[[], None]) -> ctk.C
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,7 +411,7 @@ 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
@@ -470,7 +480,7 @@ def create_source_target_popup(
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
@@ -495,7 +505,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,
}
@@ -704,7 +714,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 +754,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 +770,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 +789,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 +837,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,7 +953,7 @@ 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
@@ -946,9 +964,9 @@ def create_source_target_popup_for_webcam(
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 +975,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.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()
)
- 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):
@@ -1050,7 +1095,7 @@ 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
@@ -1075,7 +1120,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,7 +1147,7 @@ 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
@@ -1127,7 +1172,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,
}
From d2aaf46e6978b35502a9513524f0cb0211e56f8c Mon Sep 17 00:00:00 2001
From: KRSHH <136873090+KRSHH@users.noreply.github.com>
Date: Mon, 6 Jan 2025 23:13:57 +0530
Subject: [PATCH 19/24] Change buttons
---
README.md | 15 +++------------
1 file changed, 3 insertions(+), 12 deletions(-)
diff --git a/README.md b/README.md
index 8fd92e5..01257a5 100644
--- a/README.md
+++ b/README.md
@@ -21,18 +21,9 @@
###### 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 - Download Prebuilt
-
-
-
-
+
+
+
## Features - Everything is real-time
From a834811974640ed1683912ba5c72891fdec223f5 Mon Sep 17 00:00:00 2001
From: KRSHH <136873090+KRSHH@users.noreply.github.com>
Date: Mon, 6 Jan 2025 23:23:19 +0530
Subject: [PATCH 20/24] Add URL to buttons
Forgot to add before (regarded)
---
README.md | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 01257a5..736260b 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,12 @@
## Quick Start - Download Prebuilt
## Features - Everything is real-time
From 2a7ae010a84149d8da50cff66569c152f6514251 Mon Sep 17 00:00:00 2001
From: KRSHH <136873090+KRSHH@users.noreply.github.com>
Date: Mon, 6 Jan 2025 23:53:18 +0530
Subject: [PATCH 21/24] Raised img Res
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 736260b..f1c19b7 100644
--- a/README.md
+++ b/README.md
@@ -20,13 +20,13 @@
###### 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 - Download Prebuilt
+## Quick Start - Pre-built
From 6e29e4061b83bb6ca5c8c6f1196d55bc462ec188 Mon Sep 17 00:00:00 2001
From: qitian
Date: Tue, 7 Jan 2025 13:39:56 +0800
Subject: [PATCH 22/24] merge from the source and little change
---
README.md | 2 +-
modules/ui.py | 84 +++++++++++++++++++++++++++------------------------
2 files changed, 45 insertions(+), 41 deletions(-)
diff --git a/README.md b/README.md
index f1c19b7..e48cf4c 100644
--- a/README.md
+++ b/README.md
@@ -274,4 +274,4 @@ Looking for a CLI mode? Using the -s/--source argument will make the run program
-
+
\ No newline at end of file
diff --git a/modules/ui.py b/modules/ui.py
index 21446db..8eb9289 100644
--- a/modules/ui.py
+++ b/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,7 +260,7 @@ 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: (
@@ -270,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: (
@@ -283,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()),
@@ -293,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(
@@ -303,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()
@@ -342,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,
@@ -416,7 +420,7 @@ def create_source_target_popup(
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()
@@ -440,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,
@@ -474,7 +478,7 @@ 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)
@@ -485,7 +489,7 @@ def update_popup_source(
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],
)
@@ -536,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)
@@ -552,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:
@@ -580,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],
)
@@ -623,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],
)
@@ -647,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",
@@ -655,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",
@@ -958,7 +962,7 @@ def create_source_target_popup_for_webcam(
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()
@@ -983,14 +987,14 @@ def create_source_target_popup_for_webcam(
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 = 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 = 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.7, rely=0.92, relwidth=0.2, relheight=0.05)
@@ -1033,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,
@@ -1050,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,
@@ -1100,7 +1104,7 @@ def update_webcam_source(
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],
)
@@ -1152,7 +1156,7 @@ def update_webcam_target(
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],
)
@@ -1195,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
\ No newline at end of file
From cab2efa200b3cb890b8b7acde4beae8b2a902bd7 Mon Sep 17 00:00:00 2001
From: Kenneth Estanislao
Date: Tue, 7 Jan 2025 13:48:42 +0800
Subject: [PATCH 23/24] Update README.md
added qitianai on the credits
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e48cf4c..bb960f4 100644
--- a/README.md
+++ b/README.md
@@ -256,6 +256,7 @@ Looking for a CLI mode? Using the -s/--source argument will make the run program
- [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 ❤️
@@ -274,4 +275,4 @@ Looking for a CLI mode? Using the -s/--source argument will make the run program
-
\ No newline at end of file
+
From 5132f86cdc9cb623014589c05cf164a9577d2b50 Mon Sep 17 00:00:00 2001
From: qitian
Date: Tue, 7 Jan 2025 14:04:18 +0800
Subject: [PATCH 24/24] add mutil language
---
locales/zh.json | 46 +++++++++++++++++++++++++
modules/core.py | 4 ++-
modules/gettext.py | 26 ++++++++++++++
modules/ui.py | 84 ++++++++++++++++++++++++----------------------
4 files changed, 119 insertions(+), 41 deletions(-)
create mode 100644 locales/zh.json
create mode 100644 modules/gettext.py
diff --git a/locales/zh.json b/locales/zh.json
new file mode 100644
index 0000000..c029898
--- /dev/null
+++ b/locales/zh.json
@@ -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 目标映射器已打开。"
+}
\ No newline at end of file
diff --git a/modules/core.py b/modules/core.py
index ee67402..b6ef9b8 100644
--- a/modules/core.py
+++ b/modules/core.py
@@ -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()
diff --git a/modules/gettext.py b/modules/gettext.py
new file mode 100644
index 0000000..0334102
--- /dev/null
+++ b/modules/gettext.py
@@ -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)
\ No newline at end of file
diff --git a/modules/ui.py b/modules/ui.py
index 21446db..8eb9289 100644
--- a/modules/ui.py
+++ b/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,7 +260,7 @@ 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: (
@@ -270,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: (
@@ -283,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()),
@@ -293,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(
@@ -303,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()
@@ -342,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,
@@ -416,7 +420,7 @@ def create_source_target_popup(
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()
@@ -440,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,
@@ -474,7 +478,7 @@ 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)
@@ -485,7 +489,7 @@ def update_popup_source(
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],
)
@@ -536,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)
@@ -552,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:
@@ -580,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],
)
@@ -623,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],
)
@@ -647,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",
@@ -655,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",
@@ -958,7 +962,7 @@ def create_source_target_popup_for_webcam(
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()
@@ -983,14 +987,14 @@ def create_source_target_popup_for_webcam(
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 = 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 = 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.7, rely=0.92, relwidth=0.2, relheight=0.05)
@@ -1033,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,
@@ -1050,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,
@@ -1100,7 +1104,7 @@ def update_webcam_source(
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],
)
@@ -1152,7 +1156,7 @@ def update_webcam_target(
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],
)
@@ -1195,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
\ No newline at end of file