在Python中枚举摄影机
问题描述
我在枚举多个操作系统上的Python中的摄像头时遇到一些问题。
以下是我尝试过的一些方法:
import cv2 as cv
num = 0
while 1:
cap = cv.VideoCapture(num)
if cap.isOpened():
# working capture
num += 1
else:
break
使用OpenCV的缺点是OpenCV不提供任何友好的显示名称。此外,在相机上枚举速度很慢,因为您需要实际打开和关闭相机以检查它是否为有效的相机。
我也尝试过使用像PyPylon和pyuvc这样的库。它们有效,但仅适用于特定品牌。
我对堆栈溢出做了一些研究,有些人建议将Python的GStreamer绑定作为一种可能的独立于操作系统的解决方案。这就是我到目前为止所拥有的。
import pgi
pgi.require_version("Gtk", "3.0")
pgi.require_version("Gst", "1.0")
pgi.require_version("GstVideo", "1.0")
from pgi.repository import Gtk, GObject, Gst, GstVideo
Gst.init("")
dm = Gst.DeviceMonitor()
dm.set_show_all_devices(True)
dm.start()
print("Displaying devices.")
for device in dm.get_devices():
print(device.get_display_name())
print("Displaying providers.")
for provider in dm.get_providers():
print(provider)
dm.stop()
这是我得到的输出:
Displaying devices.
papalook Microphone
DisplayPort
HDMI
Built-in Output
Built-in Microph
Displaying providers.
osxaudiodeviceprovider
出于某种原因,我没有收到任何网络摄像头,只有音频设备。 你知道我做错了什么吗? 有什么不同的方法我应该采取吗? 谢谢。
解决方案
我最近遇到了这个问题,甚至没有意识到它有多难! 在这里分享我的解决方案,希望能对某些人有所帮助。
正如已经指出的,没有以跨平台的方式实现这一点的简单方法,我们仍然需要编写特定于平台的代码。 我的解决方案实际上是这里提供的一些方法的组合,所以让我们将其细分。1.获取摄像头的索引
我们要解决的第一件事是有多少摄像设备连接到计算机。 我们可以使用OpenCV进行此操作,也可以使用上面已经提到的方法。
2.Linux
Linux将有关视频设备的信息存储在/sys/class/video4linux
因为我们知道每个摄像头的索引,所以我们可以这样做来获取额外的信息。
cat /sys/class/video4linux/video1/name
3.Windows
Windows通过也称为WinRT的Windows Runtime提供了一系列有用的API。 Microsoft为此提供了Python library,要获取摄像头信息,我们需要使用DevicesEnumeration接口。4.MacOS
对于MacOS,我们可以使用与Linux类似的方法。似乎ioreg和system_profiler命令可以提供摄像机名称信息。 不幸的是,我没有MacOS系统来测试这一点,所以我留下了一个TODO。如果有人可以尝试并分享它,那就太好了。
这是我的代码。
import asyncio
import platform
import subprocess
import cv2
if platform.system() == 'Windows':
import winrt.windows.devices.enumeration as windows_devices
VIDEO_DEVICES = 4
class Camera:
def __init__(self):
self.cameras = []
def get_camera_info(self) -> list:
self.cameras = []
camera_indexes = self.get_camera_indexes()
if len(camera_indexes) == 0:
return self.cameras
self.cameras = self.add_camera_information(camera_indexes)
return self.cameras
def get_camera_indexes(self):
index = 0
camera_indexes = []
max_numbers_of_cameras_to_check = 10
while max_numbers_of_cameras_to_check > 0:
capture = cv2.VideoCapture(index)
if capture.read()[0]:
camera_indexes.append(index)
capture.release()
index += 1
max_numbers_of_cameras_to_check -= 1
return camera_indexes
# TODO add MacOS specific implementations
def add_camera_information(self, camera_indexes: list) -> list:
platform_name = platform.system()
cameras = []
if platform_name == 'Windows':
cameras_info_windows = asyncio.run(self.get_camera_information_for_windows())
for camera_index in camera_indexes:
camera_name = cameras_info_windows.get_at(camera_index).name.replace('
', '')
cameras.append({'camera_index': camera_index, 'camera_name': camera_name})
return cameras
if platform_name == 'Linux':
for camera_index in camera_indexes:
camera_name = subprocess.run(['cat', '/sys/class/video4linux/video{}/name'.format(camera_index)],
stdout=subprocess.PIPE).stdout.decode('utf-8')
camera_name = camera_name.replace('
', '')
cameras.append({'camera_index': camera_index, 'camera_name': camera_name})
return cameras
async def get_camera_information_for_windows(self):
return await windows_devices.DeviceInformation.find_all_async(VIDEO_DEVICES)
camera = Camera()
相关文章