103 lines
3.1 KiB
Python
103 lines
3.1 KiB
Python
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
|
|
)
|
|
]
|
|
) |