|
|
|
@ -28,7 +28,9 @@ ROOT_WIDTH = 600
|
|
|
|
|
|
|
|
|
|
|
|
PREVIEW = None
|
|
|
|
PREVIEW = None
|
|
|
|
PREVIEW_MAX_HEIGHT = 700
|
|
|
|
PREVIEW_MAX_HEIGHT = 700
|
|
|
|
PREVIEW_MAX_WIDTH = 1200
|
|
|
|
PREVIEW_MAX_WIDTH = 1200
|
|
|
|
|
|
|
|
PREVIEW_DEFAULT_WIDTH = 960
|
|
|
|
|
|
|
|
PREVIEW_DEFAULT_HEIGHT = 540
|
|
|
|
|
|
|
|
|
|
|
|
RECENT_DIRECTORY_SOURCE = None
|
|
|
|
RECENT_DIRECTORY_SOURCE = None
|
|
|
|
RECENT_DIRECTORY_TARGET = None
|
|
|
|
RECENT_DIRECTORY_TARGET = None
|
|
|
|
@ -42,6 +44,7 @@ status_label = None
|
|
|
|
|
|
|
|
|
|
|
|
img_ft, vid_ft = modules.globals.file_types
|
|
|
|
img_ft, vid_ft = modules.globals.file_types
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
camera = None
|
|
|
|
|
|
|
|
|
|
|
|
def check_camera_permissions():
|
|
|
|
def check_camera_permissions():
|
|
|
|
"""Check and request camera access permission on macOS."""
|
|
|
|
"""Check and request camera access permission on macOS."""
|
|
|
|
@ -184,7 +187,7 @@ def create_preview(parent: ctk.CTk) -> ctk.CTkToplevel:
|
|
|
|
preview.withdraw()
|
|
|
|
preview.withdraw()
|
|
|
|
preview.title('Preview')
|
|
|
|
preview.title('Preview')
|
|
|
|
preview.protocol('WM_DELETE_WINDOW', toggle_preview)
|
|
|
|
preview.protocol('WM_DELETE_WINDOW', toggle_preview)
|
|
|
|
preview.resizable(width=False, height=False)
|
|
|
|
preview.resizable(width=True, height=True)
|
|
|
|
|
|
|
|
|
|
|
|
preview_label = ctk.CTkLabel(preview, text=None)
|
|
|
|
preview_label = ctk.CTkLabel(preview, text=None)
|
|
|
|
preview_label.pack(fill='both', expand=True)
|
|
|
|
preview_label.pack(fill='both', expand=True)
|
|
|
|
@ -281,6 +284,11 @@ def toggle_preview() -> None:
|
|
|
|
init_preview()
|
|
|
|
init_preview()
|
|
|
|
update_preview()
|
|
|
|
update_preview()
|
|
|
|
PREVIEW.deiconify()
|
|
|
|
PREVIEW.deiconify()
|
|
|
|
|
|
|
|
global camera
|
|
|
|
|
|
|
|
if PREVIEW.state() == 'withdrawn':
|
|
|
|
|
|
|
|
if camera and camera.isOpened():
|
|
|
|
|
|
|
|
camera.release()
|
|
|
|
|
|
|
|
camera = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def init_preview() -> None:
|
|
|
|
def init_preview() -> None:
|
|
|
|
@ -320,11 +328,17 @@ def webcam_preview_loop(cap: cv2.VideoCapture, source_image: Any, frame_processo
|
|
|
|
|
|
|
|
|
|
|
|
temp_frame = frame.copy()
|
|
|
|
temp_frame = frame.copy()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if modules.globals.live_mirror:
|
|
|
|
|
|
|
|
temp_frame = cv2.flip(temp_frame, 1) # horizontal flipping
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if modules.globals.live_resizable:
|
|
|
|
|
|
|
|
temp_frame = fit_image_to_size(temp_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height())
|
|
|
|
|
|
|
|
|
|
|
|
for frame_processor in frame_processors:
|
|
|
|
for frame_processor in frame_processors:
|
|
|
|
temp_frame = frame_processor.process_frame(source_image, temp_frame)
|
|
|
|
temp_frame = frame_processor.process_frame(source_image, temp_frame)
|
|
|
|
|
|
|
|
|
|
|
|
image = Image.fromarray(cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB))
|
|
|
|
image = Image.fromarray(cv2.cvtColor(temp_frame, cv2.COLOR_BGR2RGB))
|
|
|
|
image = ImageOps.contain(image, (PREVIEW_MAX_WIDTH, PREVIEW_MAX_HEIGHT), Image.LANCZOS)
|
|
|
|
image = ImageOps.contain(image, (temp_frame.shape[1], temp_frame.shape[0]), Image.LANCZOS)
|
|
|
|
image = ctk.CTkImage(image, size=image.size)
|
|
|
|
image = ctk.CTkImage(image, size=image.size)
|
|
|
|
preview_label.configure(image=image)
|
|
|
|
preview_label.configure(image=image)
|
|
|
|
if virtual_cam:
|
|
|
|
if virtual_cam:
|
|
|
|
@ -337,6 +351,20 @@ def webcam_preview_loop(cap: cv2.VideoCapture, source_image: Any, frame_processo
|
|
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def fit_image_to_size(image, width: int, height: int):
|
|
|
|
|
|
|
|
if width is None and height is None:
|
|
|
|
|
|
|
|
return image
|
|
|
|
|
|
|
|
h, w, _ = image.shape
|
|
|
|
|
|
|
|
ratio_h = 0.0
|
|
|
|
|
|
|
|
ratio_w = 0.0
|
|
|
|
|
|
|
|
if width > height:
|
|
|
|
|
|
|
|
ratio_h = height / h
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
ratio_w = width / w
|
|
|
|
|
|
|
|
ratio = max(ratio_w, ratio_h)
|
|
|
|
|
|
|
|
new_size = (int(ratio * w), int(ratio * h))
|
|
|
|
|
|
|
|
return cv2.resize(image, dsize=new_size)
|
|
|
|
|
|
|
|
|
|
|
|
def webcam_preview(camera_name: str, virtual_cam_output: bool):
|
|
|
|
def webcam_preview(camera_name: str, virtual_cam_output: bool):
|
|
|
|
if modules.globals.source_path is None:
|
|
|
|
if modules.globals.source_path is None:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
@ -356,20 +384,21 @@ def webcam_preview(camera_name: str, virtual_cam_output: bool):
|
|
|
|
# Use OpenCV's camera index for cross-platform compatibility
|
|
|
|
# Use OpenCV's camera index for cross-platform compatibility
|
|
|
|
camera_index = get_camera_index_by_name(camera_name)
|
|
|
|
camera_index = get_camera_index_by_name(camera_name)
|
|
|
|
|
|
|
|
|
|
|
|
cap = cv2.VideoCapture(camera_index)
|
|
|
|
global camera
|
|
|
|
|
|
|
|
camera = cv2.VideoCapture(camera_index)
|
|
|
|
|
|
|
|
|
|
|
|
if not cap.isOpened():
|
|
|
|
if not camera.isOpened():
|
|
|
|
update_status(f"Error: Could not open camera {camera_name}")
|
|
|
|
update_status(f"Error: Could not open camera {camera_name}")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
|
|
|
|
camera.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
|
|
|
|
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
|
|
|
|
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
|
|
|
|
cap.set(cv2.CAP_PROP_FPS, FPS)
|
|
|
|
camera.set(cv2.CAP_PROP_FPS, FPS)
|
|
|
|
|
|
|
|
|
|
|
|
PREVIEW_MAX_WIDTH = WIDTH
|
|
|
|
PREVIEW_MAX_WIDTH = WIDTH
|
|
|
|
PREVIEW_MAX_HEIGHT = HEIGHT
|
|
|
|
PREVIEW_MAX_HEIGHT = HEIGHT
|
|
|
|
|
|
|
|
|
|
|
|
preview_label.configure(image=None)
|
|
|
|
preview_label.configure(width=PREVIEW_DEFAULT_WIDTH, height=PREVIEW_DEFAULT_HEIGHT)
|
|
|
|
PREVIEW.deiconify()
|
|
|
|
PREVIEW.deiconify()
|
|
|
|
|
|
|
|
|
|
|
|
frame_processors = get_frame_processors_modules(modules.globals.frame_processors)
|
|
|
|
frame_processors = get_frame_processors_modules(modules.globals.frame_processors)
|
|
|
|
@ -387,7 +416,7 @@ def webcam_preview(camera_name: str, virtual_cam_output: bool):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cap.release()
|
|
|
|
if camera: camera.release()
|
|
|
|
PREVIEW.withdraw()
|
|
|
|
PREVIEW.withdraw()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -420,8 +449,19 @@ def get_available_cameras():
|
|
|
|
elif device.deviceType() == "AVCaptureDeviceTypeContinuityCamera":
|
|
|
|
elif device.deviceType() == "AVCaptureDeviceTypeContinuityCamera":
|
|
|
|
print(f"Skipping Continuity Camera: {device.localizedName()}")
|
|
|
|
print(f"Skipping Continuity Camera: {device.localizedName()}")
|
|
|
|
elif platform.system() == 'Windows' or platform.system() == 'Linux':
|
|
|
|
elif platform.system() == 'Windows' or platform.system() == 'Linux':
|
|
|
|
# Use OpenCV to detect camera indexes
|
|
|
|
try:
|
|
|
|
devices = FilterGraph().get_input_devices()
|
|
|
|
devices = FilterGraph().get_input_devices()
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
|
|
# Use OpenCV to detect camera indexes
|
|
|
|
|
|
|
|
index = 0
|
|
|
|
|
|
|
|
devices = []
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
|
|
|
cap = cv2.VideoCapture(index)
|
|
|
|
|
|
|
|
if not cap.isOpened():
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
devices.append(f"Camera {index}")
|
|
|
|
|
|
|
|
cap.release()
|
|
|
|
|
|
|
|
index += 1
|
|
|
|
|
|
|
|
|
|
|
|
available_cameras = devices
|
|
|
|
available_cameras = devices
|
|
|
|
return available_cameras
|
|
|
|
return available_cameras
|
|
|
|
|