Broadcast virtual webcam

pull/768/head
KRSHH 2024-11-07 15:40:36 +05:30
parent 4aadfdf2ca
commit ceaf676b95
1 changed files with 129 additions and 113 deletions

View File

@ -7,7 +7,7 @@ from cv2_enumerate_cameras import enumerate_cameras # Add this import
from PIL import Image, ImageOps from PIL import Image, ImageOps
import time import time
import json import json
import pyvirtualcam
import modules.globals import modules.globals
import modules.metadata import modules.metadata
from modules.face_analyser import ( from modules.face_analyser import (
@ -779,140 +779,156 @@ def create_webcam_preview(camera_index: int):
camera.set(cv2.CAP_PROP_FRAME_WIDTH, PREVIEW_DEFAULT_WIDTH) 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_FRAME_HEIGHT, PREVIEW_DEFAULT_HEIGHT)
camera.set(cv2.CAP_PROP_FPS, 60) camera.set(cv2.CAP_PROP_FPS, 60)
camera.set(cv2.CAP_PROP_BUFFERSIZE, 2) # Slightly larger buffer for smoother frames camera.set(cv2.CAP_PROP_BUFFERSIZE, 2)
preview_label.configure(width=PREVIEW_DEFAULT_WIDTH, height=PREVIEW_DEFAULT_HEIGHT) # Get actual camera dimensions
PREVIEW.deiconify() width = int(camera.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(camera.get(cv2.CAP_PROP_FRAME_HEIGHT))
frame_processors = get_frame_processors_modules(modules.globals.frame_processors) # Initialize virtual camera with same dimensions
with pyvirtualcam.Camera(width=width, height=height, fps=30) as vcam:
print(f"Virtual camera created: {vcam.device}")
# Pre-load source face preview_label.configure(
source_face = ( width=PREVIEW_DEFAULT_WIDTH, height=PREVIEW_DEFAULT_HEIGHT
None )
if modules.globals.map_faces PREVIEW.deiconify()
else get_one_face(cv2.imread(modules.globals.source_path))
)
# Performance tracking frame_processors = get_frame_processors_modules(
prev_time = time.time() modules.globals.frame_processors
fps_update_interval = 0.5 )
frame_count = 0 source_face = (
fps = 0 None
if modules.globals.map_faces
else get_one_face(cv2.imread(modules.globals.source_path))
)
# Processing settings - adjusted for better quality # Performance tracking variables
process_scale = 0.75 # Increased base scale for better quality prev_time = time.time()
min_scale = 0.5 # Minimum allowed scale fps_update_interval = 0.5
max_scale = 1.0 # Maximum allowed scale frame_count = 0
skip_frames = 0 # Counter for frame skipping fps = 0
max_skip = 1 # Reduced max skip for smoother video process_scale = 0.75
target_fps = 24.0 # Slightly reduced target FPS for better quality min_scale = 0.5
min_process_time = 1.0 / target_fps max_scale = 1.0
scale_adjust_rate = 0.02 # More gradual scale adjustments skip_frames = 0
max_skip = 1
target_fps = 24.0
min_process_time = 1.0 / target_fps
scale_adjust_rate = 0.02
while camera.isOpened() and PREVIEW.state() != "withdrawn": while camera.isOpened() and PREVIEW.state() != "withdrawn":
ret, frame = camera.read() ret, frame = camera.read()
if not ret: if not ret:
break break
frame_count += 1 frame_count += 1
current_time = time.time() current_time = time.time()
elapsed_time = current_time - prev_time elapsed_time = current_time - prev_time
# Skip frames if processing is too slow if skip_frames > 0:
if skip_frames > 0: skip_frames -= 1
skip_frames -= 1 continue
continue
# Create processing copy if modules.globals.live_mirror:
if modules.globals.live_mirror: frame = cv2.flip(frame, 1)
frame = cv2.flip(frame, 1)
# Scale down for processing with better interpolation # Process frame
if process_scale != 1.0: try:
proc_frame = cv2.resize( if process_scale != 1.0:
frame, proc_frame = cv2.resize(
None, frame,
fx=process_scale, None,
fy=process_scale, fx=process_scale,
interpolation=cv2.INTER_AREA, fy=process_scale,
) interpolation=cv2.INTER_AREA,
else: )
proc_frame = frame.copy() else:
proc_frame = frame.copy()
# Process frame # Apply face swap processing
try: if not modules.globals.map_faces:
if not modules.globals.map_faces: for processor in frame_processors:
for processor in frame_processors: if processor.NAME == "DLC.FACE-ENHANCER":
if processor.NAME == "DLC.FACE-ENHANCER": if modules.globals.fp_ui["face_enhancer"]:
if modules.globals.fp_ui["face_enhancer"]: proc_frame = processor.process_frame(None, proc_frame)
proc_frame = processor.process_frame(None, proc_frame) else:
else: proc_frame = processor.process_frame(
proc_frame = processor.process_frame(source_face, proc_frame) source_face, proc_frame
else: )
for processor in frame_processors: else:
if processor.NAME == "DLC.FACE-ENHANCER": for processor in frame_processors:
if modules.globals.fp_ui["face_enhancer"]: if processor.NAME == "DLC.FACE-ENHANCER":
if modules.globals.fp_ui["face_enhancer"]:
proc_frame = processor.process_frame_v2(proc_frame)
else:
proc_frame = processor.process_frame_v2(proc_frame) proc_frame = processor.process_frame_v2(proc_frame)
else:
proc_frame = processor.process_frame_v2(proc_frame)
# Scale back up if needed, using better interpolation if process_scale != 1.0:
if process_scale != 1.0: proc_frame = cv2.resize(
proc_frame = cv2.resize( proc_frame,
(frame.shape[1], frame.shape[0]),
interpolation=cv2.INTER_LANCZOS4,
)
# Performance adjustments
process_time = time.time() - current_time
if process_time > min_process_time * 1.2:
process_scale = max(min_scale, process_scale - scale_adjust_rate)
skip_frames = min(max_skip, skip_frames + 1)
elif process_time < min_process_time * 0.8:
process_scale = min(max_scale, process_scale + scale_adjust_rate)
skip_frames = max(0, skip_frames - 1)
except Exception as e:
print(f"Frame processing error: {str(e)}")
proc_frame = frame
# Calculate FPS
if elapsed_time >= fps_update_interval:
fps = frame_count / elapsed_time
frame_count = 0
prev_time = current_time
if modules.globals.show_fps:
cv2.putText(
proc_frame, proc_frame,
(frame.shape[1], frame.shape[0]), f"FPS: {fps:.1f}",
interpolation=cv2.INTER_LANCZOS4, (10, 30),
cv2.FONT_HERSHEY_SIMPLEX,
1,
(0, 255, 0),
2,
) )
# More gradual performance-based scaling adjustments # Convert to RGB for both preview and virtual camera
process_time = time.time() - current_time if modules.globals.color_correction:
if process_time > min_process_time * 1.2: # Allow more tolerance output_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB)
process_scale = max(min_scale, process_scale - scale_adjust_rate) else:
skip_frames = min(max_skip, skip_frames + 1) output_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB)
elif process_time < min_process_time * 0.8:
process_scale = min(max_scale, process_scale + scale_adjust_rate)
skip_frames = max(0, skip_frames - 1)
except Exception as e: # Update preview
print(f"Frame processing error: {str(e)}") if modules.globals.live_resizable:
proc_frame = frame preview_frame = fit_image_to_size(
output_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
)
else:
preview_frame = output_frame
# Calculate and show FPS image = Image.fromarray(preview_frame)
if elapsed_time >= fps_update_interval: image = ctk.CTkImage(
fps = frame_count / elapsed_time image, size=(preview_frame.shape[1], preview_frame.shape[0])
frame_count = 0
prev_time = current_time
if modules.globals.show_fps:
cv2.putText(
proc_frame,
f"FPS: {fps:.1f}",
(10, 30),
cv2.FONT_HERSHEY_SIMPLEX,
1,
(0, 255, 0),
2,
) )
preview_label.configure(image=image)
# Update preview with better quality settings # Send to virtual camera
if modules.globals.live_resizable: vcam.send(output_frame)
proc_frame = fit_image_to_size( vcam.sleep_until_next_frame()
proc_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
)
# Improve color handling ROOT.update()
if modules.globals.color_correction:
proc_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB)
else:
proc_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB)
image = Image.fromarray(proc_frame) camera.release()
image = ctk.CTkImage(image, size=(proc_frame.shape[1], proc_frame.shape[0])) PREVIEW.withdraw()
preview_label.configure(image=image)
ROOT.update()
camera.release()
PREVIEW.withdraw()
def create_source_target_popup_for_webcam( def create_source_target_popup_for_webcam(