从接口名称而不是相机编号创建 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/video0
、dev/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的主要内容,如果未能解决你的问题,请参考以下文章
Android:从相机返回后创建新活动,而不是返回到以前的活动