From a9e8f273604140107cbbf03974e00655e963d447 Mon Sep 17 00:00:00 2001 From: KRSHH <136873090+KRSHH@users.noreply.github.com> Date: Mon, 16 Dec 2024 18:41:39 +0530 Subject: [PATCH] Pygrabber only for Windows --- modules/ui.py | 65 ++++++++++++++++++++++++++-------------- modules/video_capture.py | 60 +++++++++++++++++++++---------------- 2 files changed, 77 insertions(+), 48 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index a3fd725..25c7de0 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -27,6 +27,7 @@ from modules.utilities import ( has_image_extension, ) from modules.video_capture import VideoCapturer +import platform ROOT = None POPUP = None @@ -771,39 +772,57 @@ def webcam_preview(root: ctk.CTk, camera_index: int): def get_available_cameras(): """Returns a list of available camera names and indices.""" - try: - graph = FilterGraph() - devices = graph.get_input_devices() + if platform.system() == "Windows": + try: + graph = FilterGraph() + devices = graph.get_input_devices() - # Create list of indices and names - camera_indices = list(range(len(devices))) - camera_names = devices + # 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 = [] + # 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() + 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 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 = [] + + # Test the 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 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"] - def create_webcam_preview(camera_index: int): global preview_label, PREVIEW diff --git a/modules/video_capture.py b/modules/video_capture.py index dd55672..cab223d 100644 --- a/modules/video_capture.py +++ b/modules/video_capture.py @@ -1,13 +1,16 @@ import cv2 import numpy as np -from pygrabber.dshow_graph import FilterGraph -import threading from typing import Optional, Tuple, Callable +import platform +import threading + +# Only import Windows-specific library if on Windows +if platform.system() == "Windows": + from pygrabber.dshow_graph import FilterGraph class VideoCapturer: def __init__(self, device_index: int): - self.graph = FilterGraph() self.device_index = device_index self.frame_callback = None self._current_frame = None @@ -15,35 +18,42 @@ class VideoCapturer: self.is_running = False self.cap = None - # Verify device exists - devices = self.graph.get_input_devices() - if self.device_index >= len(devices): - raise ValueError( - f"Invalid device index {device_index}. Available devices: {len(devices)}" - ) + # Initialize Windows-specific components if on Windows + if platform.system() == "Windows": + self.graph = FilterGraph() + # Verify device exists + devices = self.graph.get_input_devices() + if self.device_index >= len(devices): + raise ValueError( + f"Invalid device index {device_index}. Available devices: {len(devices)}" + ) def start(self, width: int = 960, height: int = 540, fps: int = 60) -> bool: """Initialize and start video capture""" try: - # Try different capture methods in order - capture_methods = [ - (self.device_index, cv2.CAP_DSHOW), # Try DirectShow first - (self.device_index, cv2.CAP_ANY), # Then try default backend - (-1, cv2.CAP_ANY), # Try -1 as fallback - (0, cv2.CAP_ANY), # Finally try 0 without specific backend - ] + if platform.system() == "Windows": + # Windows-specific capture methods + capture_methods = [ + (self.device_index, cv2.CAP_DSHOW), # Try DirectShow first + (self.device_index, cv2.CAP_ANY), # Then try default backend + (-1, cv2.CAP_ANY), # Try -1 as fallback + (0, cv2.CAP_ANY), # Finally try 0 without specific backend + ] - for dev_id, backend in capture_methods: - try: - self.cap = cv2.VideoCapture(dev_id, backend) - if self.cap.isOpened(): - break - self.cap.release() - except Exception: - continue + for dev_id, backend in capture_methods: + try: + self.cap = cv2.VideoCapture(dev_id, backend) + if self.cap.isOpened(): + break + self.cap.release() + except Exception: + continue + else: + # Unix-like systems (Linux/Mac) capture method + self.cap = cv2.VideoCapture(self.device_index) if not self.cap or not self.cap.isOpened(): - raise RuntimeError("Failed to open camera with all available methods") + raise RuntimeError("Failed to open camera") # Configure format self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)