从接口名称而不是相机编号创建 openCV VideoCapture

Posted

技术标签:

【中文标题】从接口名称而不是相机编号创建 openCV VideoCapture【英文标题】:Create openCV VideoCapture from interface name instead of camera numbers 【发布时间】:2016-06-19 16:56:39 【问题描述】:

创建视频捕捉的正常方法是这样的:

cam = cv2.VideoCapture(n)

其中n对应/dev/video0dev/video1的数量

但是因为我正在构建一个机器人,它使用多个摄像头来处理不同的事情,所以我需要确保它被分配给正确的摄像头,我创建了 udev 规则,该规则可以创建带有指向正确端口的符号链接的设备,只要特定的摄像头已插入。

它们似乎正在工作,因为当我查看 /dev 目录时,我可以看到链接:

/dev/front_cam -> video1

但是我现在不确定如何实际使用它。

我以为我可以从文件名中打开它,就好像它是一个视频一样,但是cam = cv2.VideoCapture('/dev/front_cam') 不起作用。

cv2.VideoCapture('/dev/video1')也没有

它不会抛出错误,它会返回一个 VideoCapture 对象,只是不是打开的对象(cam.isOpened() 返回False)。

【问题讨论】:

你能从你的程序中读取符号链接,以便以编程方式获取字符串'/dev/video1'吗?如果是,您能否从该字符串 (1) 中提取数字并将其提供给您的 openCV 捕获对象? 我赞成你的问题,我认为这个问题很好。 【参考方案1】:
import re
import subprocess
import cv2
import os

device_re = re.compile("Bus\s+(?P<bus>\d+)\s+Device\s+(?P<device>\d+).+ID\s(?P<id>\w+:\w+)\s(?P<tag>.+)$", re.I)
df = subprocess.check_output("lsusb", shell=True)
for i in df.split('\n'):
    if i:
        info = device_re.match(i)
        if info:
            dinfo = info.groupdict()
            if "Logitech, Inc. Webcam C270" in dinfo['tag']:
                print "Camera found."
                bus = dinfo['bus']
                device = dinfo['device']
                break

device_index = None
for file in os.listdir("/sys/class/video4linux"):
    real_file = os.path.realpath("/sys/class/video4linux/" + file)
    print real_file
    print "/" + str(bus[-1]) + "-" + str(device[-1]) + "/"
    if "/" + str(bus[-1]) + "-" + str(device[-1]) + "/" in real_file:
        device_index = real_file[-1]
        print "Hurray, device index is " + str(device_index)


camera = cv2.VideoCapture(int(device_index))

while True:
    (grabbed, frame) = camera.read() # Grab the first frame
    cv2.imshow("Camera", frame)
    key = cv2.waitKey(1) & 0xFF

首先在 USB 设备列表中搜索所需的字符串。获取 BUS 和 DEVICE 编号。

在 video4linux 目录下找到符号链接。从 realpath 中提取设备索引并将其传递给 VideoCapture 方法。

【讨论】:

【参考方案2】:

我找到了一个较短的解决方案,而不是建议的解决方案,感觉有点老套。

我只是查看符号链接指向的位置,找到其中的整数,然后使用它。

import subprocess

cmd = "readlink -f /dev/CAMC"
process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)

# output of form /dev/videoX
out = process.communicate()[0]

# parse for ints
nums = [int(x) for x in out if x.isdigit()]

cap = cv2.VideoCapture(nums[0])

【讨论】:

【参考方案3】:

如果您知道相机的型号,可以在/dev/v4l/by-id/... 中查找。我们使用的是 HDMI-USB 视频转换器,我们像这样连接到它:

#! /usr/bin/env python
import os
import re
import cv2

DEFAULT_CAMERA_NAME = '/dev/v4l/by-id/usb-AVerMedia_Technologies__Inc._Live_Gamer_Portable_2_Plus_5500114600612-video-index0'

device_num = 0
if os.path.exists(DEFAULT_CAMERA_NAME):
    device_path = os.path.realpath(DEFAULT_CAMERA_NAME)
    device_re = re.compile("\/dev\/video(\d+)")
    info = device_re.match(device_path)
    if info:
        device_num = int(info.group(1))
        print("Using default video capture device on /dev/video" + str(device_num))
cap = cv2.VideoCapture(device_num)

这遵循指向/dev/video 名称的设备名称符号链接,然后将其解析为设备编号。

【讨论】:

【参考方案4】:

我的每个 video4linux 设备都会创建 2 个设备节点。例如,/dev/video0/dev/video1 都与我的内部网络摄像头有关。当我插入第二个 USB 网络摄像头时,/dev/video2/dev/video3 都会出现。但是,我只能使用每对中编号较小的设备进行视频捕获(即/dev/video0/dev/video2)。

我用udevadm monitor 观看了我的设备到达,然后用udevadm info --path=$PATH_FROM_UDEVADM_MONITOR --attribute-walk 检查了每个摄像头设备。用于视频采集的设备有ATTRindex=="0"

也许您无需尝试打开/dev/video1,只需打开/dev/video0

cam = cv2.CaptureVideo("/dev/video0")

【讨论】:

【参考方案5】:

其他答案中未探讨的一种可能性是使用 /sys/class/video4linux/video*/ 目录中的“名称”文件。

例子:

def get_camera(camera_name):
    cam_num = None
    for file in os.listdir("/sys/class/video4linux"):
        real_file = os.path.realpath("/sys/class/video4linux/" + file + "/name")
        with open(real_file, "rt") as name_file:
            name = name_file.read().rstrip()
        if camera_name in name:
            cam_num = int(re.search("\d+$", file).group(0))
            found = "FOUND!"
        else:
            found = "      "
        print("  -> ".format(found, file, name))
    return cam_num

这给出了:

get_camera('HUE')
FOUND! video1 -> HUE HD Pro Camera: HUE HD Pro C
    video0 -> HP HD Camera: HP HD Camera

【讨论】:

以上是关于从接口名称而不是相机编号创建 openCV VideoCapture的主要内容,如果未能解决你的问题,请参考以下文章

Symfony,如何显示对象的正常名称而不是实体编号

使用 OpenCV 检测指尖而不是人脸

Android:从相机返回后创建新活动,而不是返回到以前的活动

Xcode 查找错误的 OpenCV 库名称:2.4.dylib 而不是 2.4.5.dylib

将视频保存为输入而不是android中的相机

使用 opencv 从 3d 点创建全景图像