Pygrabber only for Windows

pull/844/head
KRSHH 2024-12-16 18:41:39 +05:30
parent c72582506d
commit a9e8f27360
2 changed files with 77 additions and 48 deletions

View File

@ -27,6 +27,7 @@ from modules.utilities import (
has_image_extension, has_image_extension,
) )
from modules.video_capture import VideoCapturer from modules.video_capture import VideoCapturer
import platform
ROOT = None ROOT = None
POPUP = None POPUP = None
@ -771,39 +772,57 @@ def webcam_preview(root: ctk.CTk, camera_index: int):
def get_available_cameras(): def get_available_cameras():
"""Returns a list of available camera names and indices.""" """Returns a list of available camera names and indices."""
try: if platform.system() == "Windows":
graph = FilterGraph() try:
devices = graph.get_input_devices() graph = FilterGraph()
devices = graph.get_input_devices()
# Create list of indices and names # Create list of indices and names
camera_indices = list(range(len(devices))) camera_indices = list(range(len(devices)))
camera_names = devices camera_names = devices
# If no cameras found through DirectShow, try OpenCV fallback # If no cameras found through DirectShow, try OpenCV fallback
if not camera_names: if not camera_names:
# Try to open camera with index -1 and 0 # Try to open camera with index -1 and 0
test_indices = [-1, 0] test_indices = [-1, 0]
working_cameras = [] working_cameras = []
for idx in test_indices: for idx in test_indices:
cap = cv2.VideoCapture(idx) cap = cv2.VideoCapture(idx)
if cap.isOpened(): if cap.isOpened():
working_cameras.append(f"Camera {idx}") working_cameras.append(f"Camera {idx}")
cap.release() cap.release()
if working_cameras: if working_cameras:
return test_indices[: len(working_cameras)], 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: if not camera_names:
return [], ["No cameras found"] return [], ["No cameras found"]
return camera_indices, camera_names 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): def create_webcam_preview(camera_index: int):
global preview_label, PREVIEW global preview_label, PREVIEW

View File

@ -1,13 +1,16 @@
import cv2 import cv2
import numpy as np import numpy as np
from pygrabber.dshow_graph import FilterGraph
import threading
from typing import Optional, Tuple, Callable 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: class VideoCapturer:
def __init__(self, device_index: int): def __init__(self, device_index: int):
self.graph = FilterGraph()
self.device_index = device_index self.device_index = device_index
self.frame_callback = None self.frame_callback = None
self._current_frame = None self._current_frame = None
@ -15,35 +18,42 @@ class VideoCapturer:
self.is_running = False self.is_running = False
self.cap = None self.cap = None
# Verify device exists # Initialize Windows-specific components if on Windows
devices = self.graph.get_input_devices() if platform.system() == "Windows":
if self.device_index >= len(devices): self.graph = FilterGraph()
raise ValueError( # Verify device exists
f"Invalid device index {device_index}. Available devices: {len(devices)}" 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: def start(self, width: int = 960, height: int = 540, fps: int = 60) -> bool:
"""Initialize and start video capture""" """Initialize and start video capture"""
try: try:
# Try different capture methods in order if platform.system() == "Windows":
capture_methods = [ # Windows-specific capture methods
(self.device_index, cv2.CAP_DSHOW), # Try DirectShow first capture_methods = [
(self.device_index, cv2.CAP_ANY), # Then try default backend (self.device_index, cv2.CAP_DSHOW), # Try DirectShow first
(-1, cv2.CAP_ANY), # Try -1 as fallback (self.device_index, cv2.CAP_ANY), # Then try default backend
(0, cv2.CAP_ANY), # Finally try 0 without specific 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: for dev_id, backend in capture_methods:
try: try:
self.cap = cv2.VideoCapture(dev_id, backend) self.cap = cv2.VideoCapture(dev_id, backend)
if self.cap.isOpened(): if self.cap.isOpened():
break break
self.cap.release() self.cap.release()
except Exception: except Exception:
continue 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(): 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 # Configure format
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width) self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)