From 60eb59fc32e8f2de8fa123b854344d8c33e656b4 Mon Sep 17 00:00:00 2001 From: bartool Date: Mon, 18 May 2026 16:09:23 +0200 Subject: [PATCH] test pyuvc --- notes/pyuvc_ex2.txt | 239 ++++++++++++++++++++++++++++++++++++++++++++ test_opencv.py | 140 ++++++++++++++++++++++++++ test_pyuvc_ex1.py | 48 +++++++++ test_pyuvc_ex2.py | 103 +++++++++++++++++++ 4 files changed, 530 insertions(+) create mode 100644 notes/pyuvc_ex2.txt create mode 100644 test_opencv.py create mode 100644 test_pyuvc_ex1.py create mode 100644 test_pyuvc_ex2.py diff --git a/notes/pyuvc_ex2.txt b/notes/pyuvc_ex2.txt new file mode 100644 index 0000000..f44bca6 --- /dev/null +++ b/notes/pyuvc_ex2.txt @@ -0,0 +1,239 @@ +(.venv-mac-uvc) rafalkaczka@Mac-mini-Rafal duck-preview % sudo $(which python) test_pyuvc_ex2.py +[11:11:55] DEBUG Searching CameraSpec(name='HD USB CAMERA', width=1280, height=720, fps=30, test_pyuvc_ex2.py:65 + bandwidth_factor=2.0)... + DEBUG Found match by name test_pyuvc_ex2.py:68 + DEBUG Found device that mached uid: 20:10 test_pyuvc_ex2.py:69 + DEBUG Device info: {'name': 'HD USB CAMERA', 'manufacturer': '4K USB CAMERA', test_pyuvc_ex2.py:69 + 'serialNumber': '01.00.00', 'idProduct': 791, 'idVendor': 13028, + 'device_address': 10, 'bus_number': 20, 'uid': '20:10'} +libusb: info [darwin_detach_kernel_driver] no capture entitlements. may not be able to detach the kernel driver for this device + DEBUG Device '20:10' opended. test_pyuvc_ex2.py:69 + DEBUG Capture(name='HD USB CAMERA' manufacturer='4K USB CAMERA' test_pyuvc_ex2.py:69 + serialNumber='01.00.00' idProduct=791 idVendor=13028 device_address=10 + bus_number=20 uid='20:10') - all camera modes: [CameraMode(width=3840, + height=2160, fps=30, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=3840, height=2160, fps=25, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=3840, height=2160, + fps=20, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=3840, height=2160, fps=15, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=3840, height=2160, + fps=10, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=3840, height=2160, fps=5, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1920, height=1080, + fps=30, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1920, height=1080, fps=25, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1920, height=1080, + fps=20, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1920, height=1080, fps=15, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1920, height=1080, + fps=10, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1920, height=1080, fps=5, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=2592, height=1944, + fps=30, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=2592, height=1944, fps=25, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=2592, height=1944, + fps=20, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=2592, height=1944, fps=15, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=2592, height=1944, + fps=10, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=2592, height=1944, fps=5, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=2048, height=1536, + fps=30, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=2048, height=1536, fps=25, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=2048, height=1536, + fps=20, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=2048, height=1536, fps=15, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=2048, height=1536, + fps=10, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=2048, height=1536, fps=5, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1600, height=1200, + fps=30, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1600, height=1200, fps=25, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1600, height=1200, + fps=20, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1600, height=1200, fps=15, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1600, height=1200, + fps=10, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1600, height=1200, fps=5, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1280, height=960, + fps=30, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1280, height=960, fps=25, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1280, height=960, + fps=20, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1280, height=960, fps=15, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1280, height=960, + fps=10, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1280, height=960, fps=5, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1280, height=720, + fps=30, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1280, height=720, fps=25, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1280, height=720, + fps=20, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1280, height=720, fps=15, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1280, height=720, + fps=10, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1280, height=720, fps=5, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1024, height=768, + fps=30, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1024, height=768, fps=25, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1024, height=768, + fps=20, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1024, height=768, fps=15, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=1024, height=768, + fps=10, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=1024, height=768, fps=5, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=800, height=600, + fps=30, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=800, height=600, fps=25, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=800, height=600, + fps=20, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=800, height=600, fps=15, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=800, height=600, + fps=10, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=800, height=600, fps=5, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=640, height=480, + fps=30, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=640, height=480, fps=25, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=640, height=480, + fps=20, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=640, height=480, fps=15, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=640, height=480, + fps=10, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=640, height=480, fps=5, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=320, height=240, + fps=30, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=320, height=240, fps=25, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=320, height=240, + fps=20, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=320, height=240, fps=15, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=320, height=240, + fps=10, format_native=7, format_name='MJPG', supported=True), + CameraMode(width=320, height=240, fps=5, format_native=7, + format_name='MJPG', supported=True), CameraMode(width=3840, height=2160, + fps=1, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=1920, height=1080, fps=3, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=2592, height=1944, + fps=1, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=2048, height=1536, fps=3, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=1600, height=1200, + fps=3, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=1280, height=960, fps=5, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=1280, height=720, + fps=10, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=1280, height=720, fps=5, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=1024, height=768, + fps=10, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=1024, height=768, fps=5, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=800, height=600, + fps=20, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=800, height=600, fps=15, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=800, height=600, + fps=10, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=800, height=600, fps=5, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=640, height=480, + fps=30, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=640, height=480, fps=25, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=640, height=480, + fps=20, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=640, height=480, fps=15, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=640, height=480, + fps=10, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=640, height=480, fps=5, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=320, height=240, + fps=30, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=320, height=240, fps=25, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=320, height=240, + fps=20, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=320, height=240, fps=15, format_native=3, + format_name='YUY2', supported=False), CameraMode(width=320, height=240, + fps=10, format_native=3, format_name='YUY2', supported=False), + CameraMode(width=320, height=240, fps=5, format_native=3, + format_name='YUY2', supported=False)] +[11:11:56] DEBUG Adding "Auto Exposure Mode" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Absolute Exposure Time" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Auto Focus" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Absolute Focus" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Zoom absolute control" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Pan control" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Tilt control" control. test_pyuvc_ex2.py:69 +libusb: warning [darwin_transfer_status] transfer error: device not responding (value = 0xe00002ed) + DEBUG Could not init Tilt control control! test_pyuvc_ex2.py:69 + DEBUG Control info: {'display_name': 'Tilt control', 'unit': 'input_terminal', test_pyuvc_ex2.py:69 + 'control_id': 13, 'bit_mask': 2048, 'offset': 4, 'data_len': 4, + 'buffer_len': 8, 'min_val': None, 'max_val': None, 'step': None, 'def_val': + None, 'd_type': , 'doc': 'Tilt (Absolute) Control.', + 'unit_id': 1} + DEBUG Traceback (most recent call last): test_pyuvc_ex2.py:69 + File "uvc_bindings.pyx", line 779, in + uvc_bindings.Capture._enumerate_controls + File "../../../pyuvc-source/controls.pxi", line 625, in + uvc_bindings.Control.__init__ + File "../../../pyuvc-source/controls.pxi", line 660, in + uvc_bindings.Control._uvc_get + Exception: Error: Input/output error + + DEBUG Adding "Backlight Compensation" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Brightness" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Contrast" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Gain" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Power Line frequency" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Hue" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Saturation" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Sharpness" control. test_pyuvc_ex2.py:69 + DEBUG Adding "Gamma" control. test_pyuvc_ex2.py:69 + DEBUG Adding "White Balance temperature" control. test_pyuvc_ex2.py:69 + DEBUG Adding "White Balance temperature,Auto" control. test_pyuvc_ex2.py:69 + DEBUG Setting mode: CameraMode(width=1280, height=720, fps=30, format_native=7, test_pyuvc_ex2.py:73 + format_name='MJPG', supported=True) + DEBUG Negotiated frame format: {'bmHint': 1, 'bFormatIndex': 1, 'bFrameIndex': 7, test_pyuvc_ex2.py:73 + 'dwFrameInterval': 333333, 'wKeyFrameRate': 0, 'wPFrameRate': 0, + 'wCompQuality': 47, 'wCompWindowSize': 0, 'wDelay': 0, + 'dwMaxVideoFrameSize': 1843200, 'dwMaxPayloadTransferSize': 3060, + 'dwClockFrequency': 48000000, 'bmFramingInfo': 0, 'bPreferredVersion': 0, + 'bMinVersion': 0, 'bMaxVersion': 0, 'bInterfaceNumber': 1} + DEBUG Stream start. test_pyuvc_ex2.py:36 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +libusb: warning [darwin_abort_transfers] aborting all transactions on interface 1 pipe 1 +[11:13:41] DEBUG Stream stopped test_pyuvc_ex2.py:61 + DEBUG Stream closed test_pyuvc_ex2.py:61 + DEBUG Stream stop. test_pyuvc_ex2.py:61 +libusb: error [do_close] Device handle closed while transfer was still being processed, but the device is still connected as far as we know +libusb: error [do_close] A cancellation hasn't even been scheduled on the transfer for which the device is closing +[11:13:42] DEBUG UVC device closed. \ No newline at end of file diff --git a/test_opencv.py b/test_opencv.py new file mode 100644 index 0000000..0632019 --- /dev/null +++ b/test_opencv.py @@ -0,0 +1,140 @@ +import cv2 +import time +import sys + +# ========================= +# Otwieranie kamery +# ========================= +cap = cv2.VideoCapture(0, cv2.CAP_AVFOUNDATION) + +# Na macOS warto wymusić AVFoundation +# cap = cv2.VideoCapture(0, cv2.CAP_AVFOUNDATION) + +if not cap.isOpened(): + print("Nie można otworzyć kamery") + exit() + +ret, frame = cap.read() +if not ret: + print("nie ma obrazu") + cap.release() + cv2.destroyAllWindows() + sys.exit(0) + +print(f"{cap.get(cv2.CAP_PROP_BRIGHTNESS)}") +print(f"{cap.get(cv2.CAP_PROP_CONTRAST)}") +print(f"{cap.get(cv2.CAP_PROP_SATURATION)}") +print(f"{cap.get(cv2.CAP_PROP_HUE)}") +print(f"{cap.get(cv2.CAP_PROP_GAIN)}") + +print(f"{cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)}") +print(f"{cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)}") +print(f"{cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0.25)}") +time.sleep(0.5) +print(f"{cap.set(cv2.CAP_PROP_EXPOSURE, -1)}") + +# ========================= +# Lista parametrów OpenCV +# ========================= +camera_props = { + "BRIGHTNESS": cv2.CAP_PROP_BRIGHTNESS, + "CONTRAST": cv2.CAP_PROP_CONTRAST, + "SATURATION": cv2.CAP_PROP_SATURATION, + "HUE": cv2.CAP_PROP_HUE, + "GAIN": cv2.CAP_PROP_GAIN, + "EXPOSURE": cv2.CAP_PROP_EXPOSURE, + "SHARPNESS": getattr(cv2, "CAP_PROP_SHARPNESS", -1), + "GAMMA": getattr(cv2, "CAP_PROP_GAMMA", -1), + "AUTO_EXPOSURE": getattr(cv2, "CAP_PROP_AUTO_EXPOSURE", -1), + "WB_TEMPERATURE": getattr(cv2, "CAP_PROP_WB_TEMPERATURE", -1), +} + +# ========================= +# Okno i suwaki +# ========================= +cv2.namedWindow("camera") + +def nothing(x): + pass + +# Zakresy są orientacyjne +cv2.createTrackbar("brightness", "camera", 128, 255, nothing) +cv2.createTrackbar("contrast", "camera", 128, 255, nothing) +cv2.createTrackbar("saturation", "camera", 128, 255, nothing) +cv2.createTrackbar("hue", "camera", 128, 255, nothing) +cv2.createTrackbar("gain", "camera", 0, 255, nothing) +cv2.createTrackbar("exposure", "camera", 0, 255, nothing) + +# ========================= +# Pętla główna +# ========================= +while True: + + try: + # Odczyt suwaków + brightness = cv2.getTrackbarPos("brightness", "camera") + contrast = cv2.getTrackbarPos("contrast", "camera") + saturation = cv2.getTrackbarPos("saturation", "camera") + hue = cv2.getTrackbarPos("hue", "camera") + gain = cv2.getTrackbarPos("gain", "camera") + exposure = cv2.getTrackbarPos("exposure", "camera") + + # Ustawianie parametrów + print(f"{cap.set(cv2.CAP_PROP_BRIGHTNESS, brightness / 255.0)}") + print(f"{cap.set(cv2.CAP_PROP_CONTRAST, contrast / 255.0)}") + print(f"{cap.set(cv2.CAP_PROP_SATURATION, saturation / 255.0)}") + print(f"{cap.set(cv2.CAP_PROP_HUE, hue / 255.0)}") + print(f"{cap.set(cv2.CAP_PROP_GAIN, gain / 255.0)}") + + # Exposure często wymaga innych wartości + # cap.set(cv2.CAP_PROP_EXPOSURE, float(exposure)) + + # Odczyt klatki + ret, frame = cap.read() + + if not ret: + print("Błąd odczytu obrazu") + break + + # Wyświetlanie aktualnych wartości REALNIE ustawionych + y = 20 + for name, prop in camera_props.items(): + + if prop == -1: + continue + + value = cap.get(prop) + + text = f"{name}: {value:.3f}" + + cv2.putText( + frame, + text, + (10, y), + cv2.FONT_HERSHEY_SIMPLEX, + 0.5, + (0, 255, 0), + 1 + ) + + y += 20 + + cv2.imshow("camera", frame) + + key = cv2.waitKey(1) + + # ESC kończy + if key == 27: + break + except Exception: + print(f"exp:") + finally: + cap.release() + cv2.destroyAllWindows() + + +# ========================= +# Sprzątanie +# ========================= +cap.release() +cv2.destroyAllWindows() \ No newline at end of file diff --git a/test_pyuvc_ex1.py b/test_pyuvc_ex1.py new file mode 100644 index 0000000..ccc9250 --- /dev/null +++ b/test_pyuvc_ex1.py @@ -0,0 +1,48 @@ +import logging + +from rich import print +from rich.logging import RichHandler + + +def main(): + import uvc + + devices = uvc.device_list() + print("Available devices", devices) + + for device in devices: + + try: + cap = uvc.Capture(device["uid"]) + except uvc.DeviceNotFoundError: + continue + + print(f"{cap.name}") + + print("Available modes:") + for mode in cap.available_modes: + print( + f"MODE: {mode.width} x {mode.height} @ {mode.fps} ({mode.format_name})" + ) + + print("Iterating over frame sizes and rates") + for res in cap.frame_sizes: + cap.frame_size = res + for rate in cap.frame_rates: + cap.frame_rate = rate + print(f"RES/RATE: {res[0]} x {res[1]} @ {rate} Hz") + + cap.close() + + +if __name__ == "__main__": + # import os + # os.environ["LIBUSB_DEBUG"] = "0" + + logging.basicConfig( + level=logging.NOTSET, + handlers=[RichHandler(level="WARNING")], + format="%(message)s", + datefmt="[%X]", + ) + main() \ No newline at end of file diff --git a/test_pyuvc_ex2.py b/test_pyuvc_ex2.py new file mode 100644 index 0000000..31bc3c6 --- /dev/null +++ b/test_pyuvc_ex2.py @@ -0,0 +1,103 @@ +import logging +import os +import time +from typing import Iterable, NamedTuple, Optional + +import cv2 +import uvc.uvc_bindings as uvc +from rich.logging import RichHandler +from rich.traceback import install as install_rich_traceback + + +class CameraSpec(NamedTuple): + name: str + width: int + height: int + fps: int + bandwidth_factor: float = 2.0 + + +def main(camera_specs: Iterable[CameraSpec]): + devices = uvc.device_list() + cameras = {spec: init_camera_from_list(devices, spec) for spec in camera_specs} + if not all(cameras.values()): + raise RuntimeError( + "Could not initialize all specified cameras. Available: " + f"{[dev['name'] for dev in devices]}" + ) + + try: + keep_running = True + last_update = time.perf_counter() + + while keep_running: + for spec, cam in cameras.items(): + try: + frame = cam.get_frame(timeout=0.001) + except TimeoutError: + pass + # keep_running = False + # break + except uvc.InitError as err: + logging.debug(f"Failed to init {spec}: {err}") + keep_running = False + break + except uvc.StreamError as err: + logging.debug(f"Failed to get a frame for {spec}: {err}") + else: + data = frame.bgr if hasattr(frame, "bgr") else frame.gray + if frame.data_fully_received: + cv2.imshow(spec.name, data) + + if (time.perf_counter() - last_update) > 1 / 60: + if cv2.waitKey(1) & 0xFF == 27: + break + last_update = time.perf_counter() + + except KeyboardInterrupt: + pass + + for cam in cameras.values(): + cam.close() + + +def init_camera_from_list(devices, camera: CameraSpec) -> Optional[uvc.Capture]: + logging.debug(f"Searching {camera}...") + for device in devices: + if device["name"] == camera.name: + logging.debug(f"Found match by name") + capture = uvc.Capture(device["uid"]) + capture.bandwidth_factor = camera.bandwidth_factor + for mode in capture.available_modes: + if mode[:3] == camera[1:4]: # compare width, height, fps + capture.frame_mode = mode + return capture + else: + logging.warning( + f"None of the available modes matched: {capture.available_modes}" + ) + capture.close() + else: + logging.warning(f"No matching camera with name {camera.name!r} found") + + +if __name__ == "__main__": + os.environ["LIBUSB_DEBUG"] = "3" + install_rich_traceback() + logging.basicConfig( + level=logging.NOTSET, + handlers=[RichHandler(level="DEBUG")], + format="%(message)s", + datefmt="[%X]", + ) + # logging.getLogger("uvc").setLevel("INFO") + main( + [ + CameraSpec( + name="HD USB CAMERA", + width=1280, + height=720, + fps=30 + ) + ] + ) \ No newline at end of file