枚举Python中的相机

时间:2018-09-28 15:37:05

标签: python opencv gstreamer python-gstreamer

在使用多个操作系统的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

由于某种原因,我没有任何网络摄像头,只有音频设备。 关于我在做什么错的任何想法吗? 我应该采取任何其他方法吗? 谢谢。

2 个答案:

答案 0 :(得分:0)

对于Windows,您可以使用pygrabber库,它是一个纯python工具,可以从相机捕获照片并使用DirectShow和OpenCV进行简单的图像处理。它还枚举连接的网络摄像头,如下所示:

from __future__ import print_function
from pygrabber.dshow_graph import FilterGraph

graph = FilterGraph()
print(graph.get_input_devices())

我已经修改了该库以在Python 2和3下工作。 https://github.com/bunkahle/pygrabber

仅Python 3的原始源: https://github.com/andreaschiavinato/python_grabber

答案 1 :(得分:0)

我最近遇到了这个问题,甚至没有意识到它有多难! 在这里分享我的解决方案,希望对某人有所帮助。

正如已经指出的那样,以跨平台方式执行此操作没有简单的方法,我们仍然需要编写特定于平台的代码。 我的解决方案实际上是这里提供的一些方法的组合,所以让我们分解一下。

1.获取相机的索引

我们要解决的第一件事是有多少摄像头设备连接到计算机。 为此,我们可以使用 OpenCV 以及上面已经提到的方法。

2. Linux

Linux 将有关视频设备的信息存储在 /sys/class/video4linux 由于我们知道每个相机的索引,因此我们可以执行类似的操作来获取额外信息。

cat /sys/class/video4linux/video1/name

3.窗户

Windows 通过 Windows Runtime 也称为 WinRT 提供了大量有用的 API。 Microsoft 为此提供了一个 Python library,为了获取我们需要使用 DevicesEnumeration API 的相机信息。

4. macOS

对于 MacO,我们可以使用与 Linux 类似的方法。 ioregsystem_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('\n', '')
                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('\n', '')
                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()