mirror of
https://github.com/hacksider/Deep-Live-Cam.git
synced 2026-09-09 09:08:58 +02:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c54c8f3105 | ||
|
|
834bc43768 | ||
|
|
3b69413d61 | ||
|
|
07e2e960c8 | ||
|
|
ba27b75265 | ||
|
|
cfa8123b67 | ||
|
|
08b2dd2526 | ||
|
|
886e64b320 | ||
|
|
aa6f2cbade |
@@ -0,0 +1,16 @@
|
||||
name: ruff
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
ruff:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: astral-sh/ruff-action@v4.0.0
|
||||
with:
|
||||
version: "0.15.7"
|
||||
args: "check --output-format=github"
|
||||
@@ -30,7 +30,7 @@ By using this software, you agree to these terms and commit to using it in a man
|
||||
|
||||
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.
|
||||
|
||||
## Exclusive v2.7 beta Quick Start - Pre-built (Windows/Mac Silicon/CPU)
|
||||
## Exclusive v2.7 RC2 Quick Start - Pre-built (Windows/Mac Silicon/CPU)
|
||||
|
||||
<a href="https://deeplivecam.net/index.php/quickstart"> <img src="media/Download.png" width="285" height="77" />
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ if sys.platform == "win32":
|
||||
|
||||
import insightface
|
||||
from insightface.app import FaceAnalysis
|
||||
from insightface.utils import face_align
|
||||
from modules.processors.frame.face_swapper import _fast_paste_back
|
||||
from modules import platform_info
|
||||
|
||||
@@ -81,10 +80,14 @@ def capture_thread():
|
||||
try:
|
||||
capture_queue.put_nowait(frame)
|
||||
except queue.Full:
|
||||
try: capture_queue.get_nowait()
|
||||
except queue.Empty: pass
|
||||
try: capture_queue.put_nowait(frame)
|
||||
except queue.Full: pass
|
||||
try:
|
||||
capture_queue.get_nowait()
|
||||
except queue.Empty:
|
||||
pass
|
||||
try:
|
||||
capture_queue.put_nowait(frame)
|
||||
except queue.Full:
|
||||
pass
|
||||
|
||||
cap_t = threading.Thread(target=capture_thread, daemon=True)
|
||||
cap_t.start()
|
||||
|
||||
+38
-18
@@ -1,18 +1,38 @@
|
||||
import os
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
# Utility function to support unicode characters in file paths for reading
|
||||
def imread_unicode(path, flags=cv2.IMREAD_COLOR):
|
||||
return cv2.imdecode(np.fromfile(path, dtype=np.uint8), flags)
|
||||
|
||||
# Utility function to support unicode characters in file paths for writing
|
||||
def imwrite_unicode(path, img, params=None):
|
||||
root, ext = os.path.splitext(path)
|
||||
if not ext:
|
||||
ext = ".png"
|
||||
result, encoded_img = cv2.imencode(ext, img, params if params else [])
|
||||
result, encoded_img = cv2.imencode(f".{ext}", img, params if params is not None else [])
|
||||
encoded_img.tofile(path)
|
||||
return True
|
||||
return False
|
||||
import os
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
|
||||
# Utility function to support unicode characters in file paths for reading.
|
||||
# OpenCV's cv2.imread() encodes the path with the locale ANSI code page on
|
||||
# Windows, so it silently returns None for paths containing non-ASCII
|
||||
# characters (Chinese, Japanese, Cyrillic, accents, ...). Reading the bytes
|
||||
# through NumPy (which uses Python's unicode-aware file I/O) and decoding them
|
||||
# in memory sidesteps that limitation. Returns None on failure, matching
|
||||
# cv2.imread() so it stays a drop-in replacement.
|
||||
def imread_unicode(path, flags=cv2.IMREAD_COLOR):
|
||||
try:
|
||||
data = np.fromfile(path, dtype=np.uint8)
|
||||
if data.size == 0:
|
||||
return None
|
||||
return cv2.imdecode(data, flags)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
# Utility function to support unicode characters in file paths for writing.
|
||||
# cv2.imwrite() has the same ANSI-path limitation, so we encode the image in
|
||||
# memory and write the bytes out with NumPy's unicode-aware file I/O. Returns
|
||||
# True/False like cv2.imwrite() so it stays a drop-in replacement.
|
||||
def imwrite_unicode(path, img, params=None):
|
||||
try:
|
||||
root, ext = os.path.splitext(path)
|
||||
if not ext:
|
||||
ext = ".png"
|
||||
result, encoded_img = cv2.imencode(ext, img, params if params is not None else [])
|
||||
if not result:
|
||||
return False
|
||||
encoded_img.tofile(path)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import numpy as np
|
||||
from sklearn.cluster import KMeans
|
||||
from sklearn.metrics import silhouette_score
|
||||
from typing import Any
|
||||
|
||||
|
||||
|
||||
+2
-3
@@ -171,8 +171,6 @@ def limit_resources() -> None:
|
||||
# limit memory usage
|
||||
if modules.globals.max_memory:
|
||||
memory = modules.globals.max_memory * 1024 ** 3
|
||||
if platform.system().lower() == 'darwin':
|
||||
memory = modules.globals.max_memory * 1024 ** 6
|
||||
if platform.system().lower() == 'windows':
|
||||
import ctypes
|
||||
kernel32 = ctypes.windll.kernel32
|
||||
@@ -324,7 +322,8 @@ def start() -> None:
|
||||
def destroy(to_quit=True) -> None:
|
||||
if modules.globals.target_path:
|
||||
clean_temp(modules.globals.target_path)
|
||||
if to_quit: quit()
|
||||
if to_quit:
|
||||
quit()
|
||||
|
||||
|
||||
def run() -> None:
|
||||
|
||||
@@ -4,9 +4,8 @@ from typing import Any
|
||||
import insightface
|
||||
import threading
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
import modules.globals
|
||||
from modules import imread_unicode, imwrite_unicode
|
||||
from tqdm import tqdm
|
||||
from modules.typing import Frame
|
||||
from modules.cluster_analysis import find_cluster_centroids, find_closest_centroid
|
||||
@@ -255,8 +254,10 @@ def add_blank_map() -> Any:
|
||||
def get_unique_faces_from_target_image() -> Any:
|
||||
try:
|
||||
modules.globals.source_target_map = []
|
||||
target_frame = cv2.imread(modules.globals.target_path)
|
||||
target_frame = imread_unicode(modules.globals.target_path)
|
||||
many_faces = get_many_faces(target_frame)
|
||||
if many_faces is None:
|
||||
return None
|
||||
i = 0
|
||||
|
||||
for face in many_faces:
|
||||
@@ -289,8 +290,10 @@ def get_unique_faces_from_target_video() -> Any:
|
||||
|
||||
i = 0
|
||||
for temp_frame_path in tqdm(temp_frame_paths, desc="Extracting face embeddings from frames"):
|
||||
temp_frame = cv2.imread(temp_frame_path)
|
||||
temp_frame = imread_unicode(temp_frame_path)
|
||||
many_faces = get_many_faces(temp_frame)
|
||||
if many_faces is None:
|
||||
continue
|
||||
|
||||
for face in many_faces:
|
||||
face_embeddings.append(face.normed_embedding)
|
||||
@@ -340,7 +343,7 @@ def default_target_face():
|
||||
|
||||
x_min, y_min, x_max, y_max = best_face['bbox']
|
||||
|
||||
target_frame = cv2.imread(best_frame['location'])
|
||||
target_frame = imread_unicode(best_frame['location'])
|
||||
map['target'] = {
|
||||
'cv2' : target_frame[int(y_min):int(y_max), int(x_min):int(x_max)],
|
||||
'face' : best_face
|
||||
@@ -356,7 +359,7 @@ def dump_faces(centroids: Any, frame_face_embeddings: list):
|
||||
Path(temp_directory_path + f"/{i}").mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for frame in tqdm(frame_face_embeddings, desc=f"Copying faces to temp/./{i}"):
|
||||
temp_frame = cv2.imread(frame['location'])
|
||||
temp_frame = imread_unicode(frame['location'])
|
||||
|
||||
j = 0
|
||||
for face in frame['faces']:
|
||||
@@ -364,5 +367,5 @@ def dump_faces(centroids: Any, frame_face_embeddings: list):
|
||||
x_min, y_min, x_max, y_max = face['bbox']
|
||||
|
||||
if temp_frame[int(y_min):int(y_max), int(x_min):int(x_max)].size > 0:
|
||||
cv2.imwrite(temp_directory_path + f"/{i}/{frame['frame']}_{j}.png", temp_frame[int(y_min):int(y_max), int(x_min):int(x_max)])
|
||||
imwrite_unicode(temp_directory_path + f"/{i}/{frame['frame']}_{j}.png", temp_frame[int(y_min):int(y_max), int(x_min):int(x_max)])
|
||||
j += 1
|
||||
|
||||
@@ -21,7 +21,7 @@ from __future__ import annotations
|
||||
import os
|
||||
import cv2
|
||||
import numpy as np
|
||||
from typing import Tuple, Optional
|
||||
from typing import Tuple
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CUDA availability detection (evaluated once at import time)
|
||||
|
||||
@@ -392,7 +392,7 @@ def _decompose_split(model) -> bool:
|
||||
|
||||
# Collect all needed boundary constants
|
||||
for _, (a, b) in splits:
|
||||
ensure_const(f"_sp_s0", [0])
|
||||
ensure_const("_sp_s0", [0])
|
||||
ensure_const(f"_sp_s{a}", [a])
|
||||
ensure_const(f"_sp_s{a + b}", [a + b])
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ def load_frame_processor_module(frame_processor: str) -> Any:
|
||||
frame_processor_module = importlib.import_module(f'modules.processors.frame.{frame_processor}')
|
||||
for method_name in FRAME_PROCESSORS_INTERFACE:
|
||||
if not hasattr(frame_processor_module, method_name):
|
||||
print(f"Frame processor {frame_processor} is missing required method {method_name}")
|
||||
sys.exit()
|
||||
except ImportError:
|
||||
print(f"Frame processor {frame_processor} not found")
|
||||
@@ -59,7 +60,7 @@ def set_frame_processors_modules_from_ui(frame_processors: List[str]) -> None:
|
||||
current_processor_names = [proc.__name__.split('.')[-1] for proc in FRAME_PROCESSORS_MODULES]
|
||||
|
||||
for frame_processor, state in modules.globals.fp_ui.items():
|
||||
if state == True and frame_processor not in current_processor_names:
|
||||
if state and frame_processor not in current_processor_names:
|
||||
try:
|
||||
frame_processor_module = load_frame_processor_module(frame_processor)
|
||||
FRAME_PROCESSORS_MODULES.append(frame_processor_module)
|
||||
@@ -70,7 +71,7 @@ def set_frame_processors_modules_from_ui(frame_processors: List[str]) -> None:
|
||||
except Exception as e:
|
||||
print(f"Warning: Error loading frame processor {frame_processor} requested by UI state: {e}")
|
||||
|
||||
elif state == False and frame_processor in current_processor_names:
|
||||
elif not state and frame_processor in current_processor_names:
|
||||
try:
|
||||
module_to_remove = next((mod for mod in FRAME_PROCESSORS_MODULES if mod.__name__.endswith(f'.{frame_processor}')), None)
|
||||
if module_to_remove:
|
||||
@@ -125,7 +126,7 @@ def process_video_in_memory(source_path: str, target_path: str, fps: float) -> b
|
||||
Returns True on success, False on failure (caller should fall back to the
|
||||
disk-based pipeline).
|
||||
"""
|
||||
import cv2
|
||||
from modules import imread_unicode
|
||||
from modules.face_analyser import get_one_face
|
||||
from modules.utilities import (
|
||||
get_video_dimensions,
|
||||
@@ -138,7 +139,7 @@ def process_video_in_memory(source_path: str, target_path: str, fps: float) -> b
|
||||
# --- Pre-load source face (needed by face_swapper in simple mode) ---
|
||||
source_face = None
|
||||
if source_path and os.path.exists(source_path):
|
||||
source_img = cv2.imread(source_path)
|
||||
source_img = imread_unicode(source_path)
|
||||
if source_img is not None:
|
||||
source_face = get_one_face(source_img)
|
||||
del source_img
|
||||
|
||||
@@ -10,8 +10,9 @@ import onnxruntime
|
||||
|
||||
import modules.globals
|
||||
import modules.processors.frame.core
|
||||
from modules import imread_unicode, imwrite_unicode
|
||||
from modules.core import update_status
|
||||
from modules.face_analyser import get_one_face, get_many_faces
|
||||
from modules.face_analyser import get_many_faces
|
||||
from modules.typing import Frame, Face
|
||||
from modules.utilities import (
|
||||
is_image,
|
||||
@@ -407,7 +408,7 @@ def process_frames(
|
||||
progress.update(1)
|
||||
continue
|
||||
|
||||
temp_frame = cv2.imread(temp_frame_path)
|
||||
temp_frame = imread_unicode(temp_frame_path)
|
||||
if temp_frame is None:
|
||||
print(
|
||||
f"{NAME}: Warning: Failed to read frame {temp_frame_path}, skipping."
|
||||
@@ -417,7 +418,7 @@ def process_frames(
|
||||
continue
|
||||
|
||||
result_frame = process_frame(None, temp_frame)
|
||||
cv2.imwrite(temp_frame_path, result_frame)
|
||||
imwrite_unicode(temp_frame_path, result_frame)
|
||||
if progress:
|
||||
progress.update(1)
|
||||
|
||||
@@ -426,12 +427,12 @@ def process_image(
|
||||
source_path: str | None, target_path: str, output_path: str
|
||||
) -> None:
|
||||
"""Processes a single image file."""
|
||||
target_frame = cv2.imread(target_path)
|
||||
target_frame = imread_unicode(target_path)
|
||||
if target_frame is None:
|
||||
print(f"{NAME}: Error: Failed to read target image {target_path}")
|
||||
return
|
||||
result_frame = process_frame(None, target_frame)
|
||||
cv2.imwrite(output_path, result_frame)
|
||||
imwrite_unicode(output_path, result_frame)
|
||||
print(f"{NAME}: Enhanced image saved to {output_path}")
|
||||
|
||||
|
||||
|
||||
@@ -4,11 +4,9 @@ from typing import Any, List
|
||||
import os
|
||||
import threading
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
import modules.globals
|
||||
import modules.processors.frame.core
|
||||
from modules import imread_unicode, imwrite_unicode
|
||||
from modules.core import update_status
|
||||
from modules.face_analyser import get_one_face
|
||||
from modules.typing import Frame, Face
|
||||
@@ -103,24 +101,24 @@ def process_frames(
|
||||
source_path: str | None, temp_frame_paths: List[str], progress: Any = None
|
||||
) -> None:
|
||||
for temp_frame_path in temp_frame_paths:
|
||||
temp_frame = cv2.imread(temp_frame_path)
|
||||
temp_frame = imread_unicode(temp_frame_path)
|
||||
if temp_frame is None:
|
||||
if progress:
|
||||
progress.update(1)
|
||||
continue
|
||||
result = process_frame(None, temp_frame)
|
||||
cv2.imwrite(temp_frame_path, result)
|
||||
imwrite_unicode(temp_frame_path, result)
|
||||
if progress:
|
||||
progress.update(1)
|
||||
|
||||
|
||||
def process_image(source_path: str | None, target_path: str, output_path: str) -> None:
|
||||
target_frame = cv2.imread(target_path)
|
||||
target_frame = imread_unicode(target_path)
|
||||
if target_frame is None:
|
||||
print(f"{NAME}: Error: Failed to read target image {target_path}")
|
||||
return
|
||||
result_frame = process_frame(None, target_frame)
|
||||
cv2.imwrite(output_path, result_frame)
|
||||
imwrite_unicode(output_path, result_frame)
|
||||
print(f"{NAME}: Enhanced image saved to {output_path}")
|
||||
|
||||
|
||||
|
||||
@@ -4,11 +4,9 @@ from typing import Any, List
|
||||
import os
|
||||
import threading
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
import modules.globals
|
||||
import modules.processors.frame.core
|
||||
from modules import imread_unicode, imwrite_unicode
|
||||
from modules.core import update_status
|
||||
from modules.face_analyser import get_one_face
|
||||
from modules.typing import Frame, Face
|
||||
@@ -103,24 +101,24 @@ def process_frames(
|
||||
source_path: str | None, temp_frame_paths: List[str], progress: Any = None
|
||||
) -> None:
|
||||
for temp_frame_path in temp_frame_paths:
|
||||
temp_frame = cv2.imread(temp_frame_path)
|
||||
temp_frame = imread_unicode(temp_frame_path)
|
||||
if temp_frame is None:
|
||||
if progress:
|
||||
progress.update(1)
|
||||
continue
|
||||
result = process_frame(None, temp_frame)
|
||||
cv2.imwrite(temp_frame_path, result)
|
||||
imwrite_unicode(temp_frame_path, result)
|
||||
if progress:
|
||||
progress.update(1)
|
||||
|
||||
|
||||
def process_image(source_path: str | None, target_path: str, output_path: str) -> None:
|
||||
target_frame = cv2.imread(target_path)
|
||||
target_frame = imread_unicode(target_path)
|
||||
if target_frame is None:
|
||||
print(f"{NAME}: Error: Failed to read target image {target_path}")
|
||||
return
|
||||
result_frame = process_frame(None, target_frame)
|
||||
cv2.imwrite(output_path, result_frame)
|
||||
imwrite_unicode(output_path, result_frame)
|
||||
print(f"{NAME}: Enhanced image saved to {output_path}")
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import cv2
|
||||
import numpy as np
|
||||
from modules.typing import Face, Frame
|
||||
import modules.globals
|
||||
from modules.gpu_processing import gpu_gaussian_blur, gpu_resize, gpu_cvt_color
|
||||
from modules.gpu_processing import gpu_gaussian_blur, gpu_resize
|
||||
|
||||
def apply_color_transfer(source, target):
|
||||
"""
|
||||
|
||||
@@ -7,6 +7,7 @@ import numpy as np
|
||||
import platform
|
||||
import modules.globals
|
||||
import modules.processors.frame.core
|
||||
from modules import imread_unicode, imwrite_unicode
|
||||
from modules.core import update_status
|
||||
from modules.face_analyser import get_one_face, get_many_faces, default_source_face
|
||||
from modules.typing import Face, Frame
|
||||
@@ -16,7 +17,7 @@ from modules.utilities import (
|
||||
is_video,
|
||||
)
|
||||
from modules.cluster_analysis import find_closest_centroid
|
||||
from modules.gpu_processing import gpu_gaussian_blur, gpu_sharpen, gpu_add_weighted, gpu_resize, gpu_cvt_color
|
||||
from modules.gpu_processing import gpu_gaussian_blur, gpu_sharpen, gpu_add_weighted, gpu_resize
|
||||
import os
|
||||
from collections import deque
|
||||
import time
|
||||
@@ -680,7 +681,8 @@ def apply_post_processing(current_frame: Frame, swapped_face_bboxes: List[np.nda
|
||||
continue
|
||||
|
||||
face_region = processed_frame[y1:y2, x1:x2]
|
||||
if face_region.size == 0: continue
|
||||
if face_region.size == 0:
|
||||
continue
|
||||
|
||||
# Apply sharpening (GPU-accelerated when CUDA OpenCV is available)
|
||||
try:
|
||||
@@ -815,9 +817,11 @@ def process_frame_v2(temp_frame: Frame, temp_frame_path: str = "") -> Frame:
|
||||
else: # Single face or specific mapping
|
||||
for map_data in source_target_map:
|
||||
source_info = map_data.get("source", {})
|
||||
if not source_info: continue # Skip if no source info
|
||||
if not source_info:
|
||||
continue # Skip if no source info
|
||||
source_face = source_info.get("face")
|
||||
if not source_face: continue # Skip if no source defined for this map entry
|
||||
if not source_face:
|
||||
continue # Skip if no source defined for this map entry
|
||||
|
||||
if is_image(modules.globals.target_path):
|
||||
target_info = map_data.get("target", {})
|
||||
@@ -854,7 +858,8 @@ def process_frame_v2(temp_frame: Frame, temp_frame_path: str = "") -> Frame:
|
||||
if len(detected_faces) <= len(target_embeddings):
|
||||
# More targets defined than detected - match each detected face
|
||||
for detected_face in detected_faces:
|
||||
if detected_face.normed_embedding is None: continue
|
||||
if detected_face.normed_embedding is None:
|
||||
continue
|
||||
closest_idx, _ = find_closest_centroid(target_embeddings, detected_face.normed_embedding)
|
||||
if 0 <= closest_idx < len(source_faces):
|
||||
source_target_pairs.append((source_faces[closest_idx], detected_face))
|
||||
@@ -862,7 +867,8 @@ def process_frame_v2(temp_frame: Frame, temp_frame_path: str = "") -> Frame:
|
||||
# More faces detected than targets defined - match each target embedding to closest detected face
|
||||
detected_embeddings = [f.normed_embedding for f in detected_faces if f.normed_embedding is not None]
|
||||
detected_faces_with_embedding = [f for f in detected_faces if f.normed_embedding is not None]
|
||||
if not detected_embeddings: return processed_frame # No embeddings to match
|
||||
if not detected_embeddings:
|
||||
return processed_frame # No embeddings to match
|
||||
|
||||
for i, target_embedding in enumerate(target_embeddings):
|
||||
if 0 <= i < len(source_faces): # Ensure source face exists for this embedding
|
||||
@@ -912,7 +918,7 @@ def process_frames(
|
||||
# Log the error but allow proceeding; subsequent check will stop processing.
|
||||
else:
|
||||
try:
|
||||
source_img = cv2.imread(source_path)
|
||||
source_img = imread_unicode(source_path)
|
||||
if source_img is None:
|
||||
# Specific error for file reading failure
|
||||
update_status(f"Error reading source image file {source_path}. Please check the path and file integrity.", NAME)
|
||||
@@ -936,7 +942,7 @@ def process_frames(
|
||||
|
||||
# --- Stop processing entirely if in Simple Mode and source face is invalid ---
|
||||
if not use_v2 and source_face is None:
|
||||
update_status(f"Halting video processing: Invalid or no face detected in source image for simple mode.", NAME)
|
||||
update_status("Halting video processing: Invalid or no face detected in source image for simple mode.", NAME)
|
||||
if progress:
|
||||
# Ensure the progress bar completes if it was started
|
||||
remaining_updates = total_frames - progress.n if hasattr(progress, 'n') else total_frames
|
||||
@@ -952,14 +958,16 @@ def process_frames(
|
||||
# Read the target frame
|
||||
temp_frame = None
|
||||
try:
|
||||
temp_frame = cv2.imread(temp_frame_path)
|
||||
temp_frame = imread_unicode(temp_frame_path)
|
||||
if temp_frame is None:
|
||||
print(f"{NAME}: Error: Could not read frame: {temp_frame_path}, skipping.")
|
||||
if progress: progress.update(1)
|
||||
if progress:
|
||||
progress.update(1)
|
||||
continue # Skip this frame if read fails
|
||||
except Exception as read_e:
|
||||
print(f"{NAME}: Error reading frame {temp_frame_path}: {read_e}, skipping.")
|
||||
if progress: progress.update(1)
|
||||
if progress:
|
||||
progress.update(1)
|
||||
continue
|
||||
|
||||
# Select processing function and execute
|
||||
@@ -988,7 +996,7 @@ def process_frames(
|
||||
# Write the result back to the same frame path with optimized compression
|
||||
try:
|
||||
# Use PNG compression level 3 (faster) instead of default 9
|
||||
write_success = cv2.imwrite(temp_frame_path, result_frame, [cv2.IMWRITE_PNG_COMPRESSION, 3])
|
||||
write_success = imwrite_unicode(temp_frame_path, result_frame, [cv2.IMWRITE_PNG_COMPRESSION, 3])
|
||||
if not write_success:
|
||||
print(f"{NAME}: Error: Failed to write processed frame to {temp_frame_path}")
|
||||
except Exception as write_e:
|
||||
@@ -1018,7 +1026,7 @@ def process_image(source_path: str, target_path: str, output_path: str) -> None:
|
||||
|
||||
# Read target first
|
||||
try:
|
||||
target_frame = cv2.imread(target_path)
|
||||
target_frame = imread_unicode(target_path)
|
||||
if target_frame is None:
|
||||
update_status(f"Error: Could not read target image: {target_path}", NAME)
|
||||
return
|
||||
@@ -1037,7 +1045,7 @@ def process_image(source_path: str, target_path: str, output_path: str) -> None:
|
||||
|
||||
else: # Simple mode
|
||||
try:
|
||||
source_img = cv2.imread(source_path)
|
||||
source_img = imread_unicode(source_path)
|
||||
if source_img is None:
|
||||
update_status(f"Error: Could not read source image: {source_path}", NAME)
|
||||
return
|
||||
@@ -1053,7 +1061,7 @@ def process_image(source_path: str, target_path: str, output_path: str) -> None:
|
||||
|
||||
# Write the result if processing was successful
|
||||
if result is not None:
|
||||
write_success = cv2.imwrite(output_path, result)
|
||||
write_success = imwrite_unicode(output_path, result)
|
||||
if write_success:
|
||||
update_status(f"Output image saved to: {output_path}", NAME)
|
||||
else:
|
||||
@@ -1496,7 +1504,8 @@ def apply_color_transfer(source, target):
|
||||
if len(source.shape) == 2: # Grayscale
|
||||
source = cv2.cvtColor(source, cv2.COLOR_GRAY2BGR)
|
||||
source = np.clip(source, 0, 255).astype(np.uint8)
|
||||
if len(source.shape)!= 3 or source.shape[2]!= 3: raise ValueError("Conversion failed")
|
||||
if len(source.shape) != 3 or source.shape[2] != 3:
|
||||
raise ValueError("Conversion failed")
|
||||
except Exception:
|
||||
return source
|
||||
if len(target.shape) != 3 or target.shape[2] != 3 or target.dtype != np.uint8:
|
||||
@@ -1505,7 +1514,8 @@ def apply_color_transfer(source, target):
|
||||
if len(target.shape) == 2: # Grayscale
|
||||
target = cv2.cvtColor(target, cv2.COLOR_GRAY2BGR)
|
||||
target = np.clip(target, 0, 255).astype(np.uint8)
|
||||
if len(target.shape)!= 3 or target.shape[2]!= 3: raise ValueError("Conversion failed")
|
||||
if len(target.shape) != 3 or target.shape[2] != 3:
|
||||
raise ValueError("Conversion failed")
|
||||
except Exception:
|
||||
return source # Return original source if target invalid
|
||||
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Import the tkinter fix to patch the ScreenChanged error
|
||||
import tkinter_fix
|
||||
# Import the tkinter fix to patch the ScreenChanged error (module patches Tk on import)
|
||||
import tkinter_fix # noqa: F401
|
||||
|
||||
import core
|
||||
|
||||
|
||||
+5
-4
@@ -73,6 +73,7 @@ from modules.utilities import (
|
||||
is_image,
|
||||
is_video,
|
||||
)
|
||||
from modules import imread_unicode
|
||||
from modules.video_capture import VideoCapturer
|
||||
|
||||
if platform.system() == "Windows":
|
||||
@@ -988,7 +989,7 @@ class PreviewWindow(QWidget):
|
||||
from modules.processors.frame.core import get_frame_processors_modules as _gfpm
|
||||
for fp in _gfpm(modules.globals.frame_processors):
|
||||
temp_frame = fp.process_frame(
|
||||
get_one_face(cv2.imread(modules.globals.source_path)), temp_frame
|
||||
get_one_face(imread_unicode(modules.globals.source_path)), temp_frame
|
||||
)
|
||||
# Fit to current widget size while preserving aspect ratio.
|
||||
h, w = temp_frame.shape[:2]
|
||||
@@ -1071,7 +1072,7 @@ class _ProcessingWorker(QThread):
|
||||
and modules.globals.source_path != last_source_path
|
||||
):
|
||||
last_source_path = modules.globals.source_path
|
||||
source_image = get_one_face(cv2.imread(modules.globals.source_path))
|
||||
source_image = get_one_face(imread_unicode(modules.globals.source_path))
|
||||
|
||||
det_count += 1
|
||||
if det_count % det_interval == 0:
|
||||
@@ -1337,7 +1338,7 @@ class MapperDialog(QDialog):
|
||||
)
|
||||
if not path:
|
||||
return
|
||||
cv2_img = cv2.imread(path)
|
||||
cv2_img = imread_unicode(path)
|
||||
face = get_one_face(cv2_img)
|
||||
if face is None:
|
||||
self.set_status("Face could not be detected in last upload!")
|
||||
@@ -1442,7 +1443,7 @@ class LiveMapperDialog(QDialog):
|
||||
)
|
||||
if not path:
|
||||
return
|
||||
cv2_img = cv2.imread(path)
|
||||
cv2_img = imread_unicode(path)
|
||||
face = get_one_face(cv2_img)
|
||||
if face is None:
|
||||
self.set_status("Face could not be detected in last upload!")
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
import sys
|
||||
import time
|
||||
from typing import Optional, Tuple, Callable
|
||||
import platform
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
[tool.ruff]
|
||||
target-version = "py310"
|
||||
|
||||
[tool.ruff.lint]
|
||||
# Deterministic, low-risk rules enforced in CI. Other rules (F841, E402, F821)
|
||||
# surface real findings but require human judgement to fix safely, so they are
|
||||
# left out of the gate for now. Intentional side-effect imports should be
|
||||
# annotated with `# noqa: F401`.
|
||||
select = ["E701", "E711", "E712", "F401", "F541"]
|
||||
+3
-3
@@ -2,16 +2,16 @@ numpy>=1.23.5,<2
|
||||
typing-extensions>=4.8.0
|
||||
opencv-python==4.10.0.84
|
||||
cv2_enumerate_cameras==1.1.15
|
||||
onnx==1.18.0
|
||||
onnx==1.21.0
|
||||
insightface==0.7.3
|
||||
psutil==5.9.8
|
||||
PySide6>=6.7,<7
|
||||
pillow==12.1.1
|
||||
pillow==12.2.0
|
||||
tqdm>=4.65.0
|
||||
onnxruntime-silicon==1.16.3; sys_platform == 'darwin' and platform_machine == 'arm64'
|
||||
onnxruntime-gpu==1.23.2; sys_platform != 'darwin'
|
||||
tensorflow>=2.15.0; sys_platform != 'darwin'
|
||||
tensorflow>=2.15.0; sys_platform == 'darwin' and python_version < '3.13'
|
||||
opennsfw2==0.10.2
|
||||
protobuf==4.25.1
|
||||
protobuf==5.29.6
|
||||
pygrabber; sys_platform == 'win32'
|
||||
|
||||
Reference in New Issue
Block a user