python 获取本地USB摄像头列表

python 获取本地USB摄像头列表

  • 介绍
  • WMI
  • AForge
  • 开启虚拟摄像头
      • OBS
      • pyvirtualcam
  • 其他

介绍

最近想写IM聊天室,需要了解一些基础,顺便打算把以前挖的坑给填了。
在去年有水一篇:《Python Opencv暴力获取所有相机》
这份代码是我前年写的,当时是项目需要,语言用的就是Python,由于当时就只知道Python中可以用OpenCV调用摄像头,并且网上千篇一律都是用OpenCV调用摄像头,我不排斥技术,我排斥的是这些文章重复率太高了,甚至里面存在bug,但是没人点出来。(这个bug指的是opencv调用摄像头后无法修改摄像头参数)

如果你用特殊的搜索方式,可能也查不到如何获取摄像头信息,除非你用全英文搜索。

还有个前置知识,摄像头是存在多种协议的,像笔记本一般使用的都是USB摄像头,这个就可以直接用OpenCV调用,但像GIGE网络摄像头,OpenCV就不兼容,并且我觉得OpenCV调用摄像头稳定性很差,但我们追求能用就行,不那么讲究。

我运行的环境都是在Windows10+Python3.7下,并且使用的库也是Windows特有,关于其他操作就不清楚了。

WMI

pip install wmi

WMI可以获取Windows系统的硬件信息(硬盘分区、使用情况,内存大小,CPU型号)、当前运行的进程、自启动程序及位置、系统的版本等。

import wmi
info = wmi.WMI()
wql = "Select * From Win32_USBControllerDevice"
for item in info.query(wql):
    a = item.Dependent.PNPClass
    b = item.Dependent.Name.upper()
    if (a.upper() == 'MEDIA' or a.upper() == 'CAMERA') and 'AUDIO' not in b:
        print(item.Dependent)

打印信息:
python 获取本地USB摄像头列表_第1张图片
获取这么多信息,缺点很明显就是慢。
通过select语法,可以从进程、驱动中筛选符合的信息。
但是这个库也存在问题,我的笔记本获取到重复的摄像头,但也不排除是我操作有问题。

代码参考来源

AForge

这个是C#的库,以前做C#连接摄像头的时候有用到过,功能可以看百度百科AForge。
优点(可能还有别的,暂时没发现):

  • 自带界面控件,可以绑定handle来相机显示刷新。
  • 获取摄像头的信息非常快
  • 能够调用虚拟摄像头
  • 能够获取到USB摄像头支持的参数列表
    参数列表就是下面这些,分辨率从小到大排序,[size()-1]就是相机支持的最大分辨率。
    python 获取本地USB摄像头列表_第2张图片
    首先打开Visual Studio中的C#项目,右键引用,点击管理NuGet程序包。
    python 获取本地USB摄像头列表_第3张图片
    下载几个dll库,我的建议是全下以备不时之需。
    python 获取本地USB摄像头列表_第4张图片
    在你的C#项目目录下,有个packages,里面能找到下载好的动态库,然后把每个文件夹中的lib中的文件拷贝到 你的python项目目录下的lib文件夹中。
    python 获取本地USB摄像头列表_第5张图片
    python安装pythonnet,我用的是2.5.2,官方2022版正式版还没出,alpha3.0加入了一些优化,比如修复了无法用动态导入库函数的问题,由于目前用不到,可以不用更新。
pip install pythonnet

python执行代码,os.getcwd 就是你的python运行目录,要把上面提到的库拷贝到该目录下的lib文件夹中。

import clr  # pip install pythonnet
import sys
import os
# 加载当前文件路径,这样才能使用clr.AddReference
sys.path.append(os.getcwd() + '\lib')
clr.AddReference("AForge")
clr.AddReference("AForge.Video.DirectShow")
from AForge.Video.DirectShow import *

videoDevices = FilterInfoCollection(FilterCategory.VideoInputDevice)
for item in videoDevices:
    print(item.Name)
    print(item.MonikerString)
    videoSource = VideoCaptureDevice(item.MonikerString)
    for cap in videoSource.VideoCapabilities:
        print(cap.FrameSize, cap.FrameRate)

获取速度非常快。
你可能要问,我只需要"AForge.Video.DirectShow.dll",为什么还要加载"AForge.dll",答案就是pythonnet还有很多bug,有时候检测命名空间会有问题,能运行是好事,报错就要找不停的找缺什么文件。
(如果你的dll文件一起的目录下有.pdb文件,记得要一起拷贝过去)

开启虚拟摄像头

OBS

设置中修改基础分辨率和输出分辨率,基础分辨率>=输出分辨率
基础分辨率是主机分辨率,越大电脑越卡。
输出分辨率是接收方接收到的分辨率,越小越模糊。
python 获取本地USB摄像头列表_第6张图片
启动虚拟摄像头,如果是捕获显示器可能会出现接收失败的情况,这个就需要点击激活视频采集设备,等接受成功就可以取消激活。
在这里插入图片描述
我的笔记本上使用4k虚拟摄像头。

  • 如果用C#接收并显示,延迟在至多400ms以内,延迟非常低。
  • 如果用python调用C#,要经过多层格式转换,单线程的延迟在10秒。
    我测试了,opencv是无法调用虚拟摄像头,因此还要继续查py有没有其他库能调用虚拟摄像头。

pyvirtualcam

没什么好讲的,就是开启前要确保OBS的虚拟摄像头是关闭的,否则会因为冲突无法开启。

pip install pyvirtualcam
import pyvirtualcam
import numpy as np
with pyvirtualcam.Camera(width=1280, height=720, fps=30) as cam:
    print(f'Using virtual camera: {cam.device}')
    frame = np.zeros((cam.height, cam.width, 3), np.uint8)
    while True:
        frame[:] = cam.frames_sent % 255
        cam.send(frame)
        cam.sleep_until_next_frame()

其他

Python的话,像ffmpeg也能够调用摄像头,但是我没有研究过如何用它调用摄像头,留个坑。

C++和C#还有其他能够调用摄像头的库,并且获取摄像头信息,可以用类似第二个方法一样实现。

GIGE摄像头连接,我有用过海康威视和basler相机的库,都是用C#连接。目前是没有这两种相机所以没法测试,basler的pylon库貌似只能兼容自家相机,海康威视的MVS库能兼容basler的但是摄像头参数名称不一样,所以如果做通用的可以考虑只使用海康威视的库。

如果读者知道其他Py连接摄像头的库,可以在评论区留言,或许我之后会写个Demo。

你可能感兴趣的:(windows,C#,Python,后端,图像处理,python,c#)