【问题标题】:OpenCV with multiple webcams - how to tell which camera is which in code?具有多个网络摄像头的 OpenCV - 如何在代码中判断哪个摄像头是哪个?
【发布时间】:2020-03-16 16:00:23
【问题描述】:

以前,我使用具有以太网连接和不同 IP 地址的工业相机来设置多个相机。现在我正在尝试使用 OpenCV 进行多摄像头设置,但我不确定如何将 OpenCV VideoCapture ID 匹配到某个摄像头。

我应该以我目前的情况为例,让我的问题更清楚。我目前连接了 3 个摄像头。如果这很重要,我正在使用 Ubuntu 18.04。这是我来自lsusb 的输出(除了我连接的 3 个罗技网络摄像头之外的所有内容都省略了):

$ lsusb
Bus 001 Device 013: ID 046d:0843 Logitech, Inc. Webcam C930e
Bus 001 Device 003: ID 046d:0843 Logitech, Inc. Webcam C930e
Bus 001 Device 006: ID 046d:0892 Logitech, Inc. OrbiCam

如您所见,我连接了 2 个C930es 和一个OrbiCam。基于这篇非常有用的帖子:

https://superuser.com/questions/902012/how-to-identify-usb-webcam-by-serial-number-from-the-linux-command-line

我发现我可以像这样获得摄像头的序列号:

$ sudo lsusb -v -d 046d:0843 | grep -i serial
  iSerial                 1 D2DF1D2E
  iSerial                 1 99A8F15E
$ sudo lsusb -v -d 046d:0892 | grep -i serial
  iSerial                 1 C83E952F

太好了,所以我现在有了一种方法,可以根据存储在摄像头内存中的序列号(D2DF1D2E99A8F15EC83E952F)来唯一地识别每个摄像头。

问题是,在OpenCV中打开网络摄像头连接是这样完成的:

vidCapForCamX = cv2.VideoCapture(OPEN_CV_VID_CAP_ID_FOR_CAM_X)
vidCapForCamY = cv2.VideoCapture(OPEN_CV_VID_CAP_ID_FOR_CAM_Y)
vidCapForCamZ = cv2.VideoCapture(OPEN_CV_VID_CAP_ID_FOR_CAM_Z)

其中相机 X、Y 和 Z 是我需要使用的 3 个相机,每个相机用于不同的确定目的,OPEN_CV_VID_CAP_ID_FOR_CAM_XYZ 是 OpenCV VideoCapture ID。现在,我通过以下手动过程将相机与 OpenCV VideoCapture ID 相关联:

1) 编写如下测试脚本:

# cam_test.py

import numpy as np
import cv2

cap = cv2.VideoCapture(4)

cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)


while True:
    # Capture frame-by-frame
    ret, frame = cap.read()

    # Display the resulting frame
    cv2.imshow('frame', frame)

    keyPress = cv2.waitKey(10)
    if keyPress == ord('q'):
        break
    # end if

# end while

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

2) 尝试为 VideoCapture 参数设置数字 0-99,直到找到我的 3 个附加摄像头的 3 个幻数。在我当前的示例中,它们是 0、2 和 4。

3) 每次找到有效的VideoCapture ID 时,在每个摄像头前挥手,直到我确定VideoCapture ID 用于哪个摄像头,然后写下我的项目中需要对应的摄像头,例如在我的情况下:

0 => serial D2DF1D2E => cam X
2 => serial 99A8F15E => cam Y
4 => serial C83E952F => cam Z

4) 编辑我的代码(或存储的配置文件或数据库字段),使凸轮 X 使用 VideoCapture ID 0,凸轮 Y 使用 VideoCapture ID 2,等等。

我应该澄清一下,摄像头 X、Y 和 Z 位于不同的位置并用于不同的目的,即如果我将 VideoCapture ID 4 用于摄像头 X,则应用程序将无法工作(它们必须以某种方式映射同上)。

显然,对于生产应用程序,此例程是不可接受的。

我意识到我可以这样做:

import cv2

openCvVidCapIds = []

for i in range(100):
    try:
        cap = cv2.VideoCapture(i)
        if cap is not None and cap.isOpened():
            openCvVidCapIds.append(i)
        # end if
    except:
        pass
    # end try
# end for

print(str(openCvVidCapIds))

要获得有效 OpenCV VideoCapture ID 的列表,但我仍然需要手动操作以确定每个摄像头对应的 OpenCV VideoCapture ID。

更糟糕的是,交换哪个摄像头连接到设备上的哪个物理端口会打乱 OpenCV VideoCapture ID,因此如果更改任何摄像头连接,或者添加或移除摄像头,则必须重复手动过程适用于所有相机。

所以我的问题是,是否有一些天才的方式(在代码中,而不是手动方式)来关联每个相机的序列号或其他存储的唯一 ID在凸轮的记忆中,OpenCV 似乎为VideoCapture ID 提供了神奇的数字?

换一种方式提出我的问题,我需要编写一个函数camSerialNumToOpenCvVidCapId,可以像这样使用:

vidCapForCamX = cv2.VideoCapture(camSerialNumToOpenCvVidCapId(D2DF1D2E))
vidCapForCamY = cv2.VideoCapture(camSerialNumToOpenCvVidCapId(99A8F15E))
vidCapForCamZ = cv2.VideoCapture(camSerialNumToOpenCvVidCapId(C83E952F))

这可能吗?如何做到这一点?

附:我对 OpenCV C++ 或 Python 很满意,任何有用的答案都将不胜感激。

--- 编辑---

这个问题:

OpenCV VideoCapture device index / device number

有一个与使用 Windows API 调用有关的响应(不接受),但我使用的是 Ubuntu。

--- 编辑2 ---

@ Micka,这是我在 /dev/ 中的摄像头:

$ ls -l /dev/video*
crw-rw----+ 1 root video 81, 0 Nov 20 12:26 /dev/video0
crw-rw----+ 1 root video 81, 1 Nov 20 12:26 /dev/video1
crw-rw----+ 1 root video 81, 2 Nov 20 12:26 /dev/video2
crw-rw----+ 1 root video 81, 3 Nov 20 12:26 /dev/video3
crw-rw----+ 1 root video 81, 4 Nov 20 12:26 /dev/video4
crw-rw----+ 1 root video 81, 5 Nov 20 12:26 /dev/video5

我不确定这是否有帮助

--- 编辑3 ---

在考虑了这一点之后,我真正需要的是 OpenCV 中的 cam 属性来唯一地识别每个相机。如上所述获得可用VideoCapture ID 列表后,如果有类似的属性:

serialNum = cv2.get(cv2.CAP_PROP_SERIAL_NUM)

那么这很容易,但似乎没有这样的属性或类似的东西(在检查了 cv2.CAP_PROP_* 的 PyCharm 自动完成并阅读了 VideoCapture 的 OpenCV 文档之后)。

【问题讨论】:

  • 这里列出了摄像机吗? /dev/video*
  • @Micka 我在问题描述中添加了你提到的信息,请看Edit2
  • afaik,您可以使用 VideoCapture(X) 捕获设备 videoX。现在,要查找 USB(带有序列号信息等)和 videoX 之间的映射,您可以尝试来自 superuser.com/questions/902012/… 的第二个答案

标签: opencv camera webcam


【解决方案1】:

对于您找到的解决方案,您需要 root 权限。在我使用 Ubuntu20 的设置中,这不是必需的:

udevadm info --name=/dev/video0

这会输出检测到的第一个摄像头的属性。通过“grep”管道过滤掉所有相机不同的特定属性,如“ID_SERIAL=”。然后,您可以使用 "cut" 删除此字符串 "ID_SERIAL=" 的开头并仅保留以下值:

udevadm info --name=/dev/video0 | grep ID_SERIAL= | cut -d "=" -f 2

在 Python 中,您可以运行外部命令来获取此信息,例如:

def get_cam_serial(cam_id):
    # Prepare the external command to extract serial number. 
    p = subprocess.Popen('udevadm info --name=/dev/video{} | grep ID_SERIAL= | cut -d "=" -f 2'.format(cam_id),
                         stdout=subprocess.PIPE, shell=True)

    # Run the command
    (output, err) = p.communicate()

    # Wait for it to finish
    p.status = p.wait()

    # Decode the output
    response = output.decode('utf-8')

    # The response ends with a new line so remove it
    return response.replace('\n', '')

要获取所有相机序列号,只需遍历多个相机 ID。在我的设置中,尝试摄像机 ID 0 和 1 瞄准同一台摄像机。 2 和 4 也以第二台摄像机为目标,因此循环可以有 2 步。提取所有 ID 后,将它们放入字典中,以便能够将凸轮 ID 与序列号相关联。完整的代码可以是:

serials = {}
FILTER = "ID_SERIAL="


def get_cam_serial(cam_id):
    p = subprocess.Popen('udevadm info --name=/dev/video{} | grep {} | cut -d "=" -f 2'.format(cam_id, FILTER),
                         stdout=subprocess.PIPE, shell=True)
    (output, err) = p.communicate()
    p.status = p.wait()
    response = output.decode('utf-8')
    return response.replace('\n', '')


for cam_id in range(0, 10, 2):
    serial = get_cam_serial(cam_id)
    if len(serial) > 6:
        serials[cam_id] = serial

print('Serial numbers:', serials)

【讨论】:

  • 如果您在解释代码,这将是一个更好的答案。
  • 有什么方法可以在 Windows 上做到这一点?
【解决方案2】:

做起来并不难。在 Linux 中浏览到目录

/dev/v4l/by-id/

此目录列出了连接到您系统的所有网络摄像头,名称如 usb-046d_081b_31296650-video-index0 复制此 ID 并以下列方式在您的代码中使用它:

cv::VideoCapture camera;
camera.open("/dev/v4l/by-id/usb-046d_081b_31296650-video-index0");

cv::Mat frame;
camera >> frame;

对于不同的相机,您可以先记下它们的 id,然后在代码中引用它们。

【讨论】:

  • 挑战有时可能在于在单个连接的相机暴露的多个 v4l 设备之间进行选择,其中一些不提供或不打算提供高质量的相机体验。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-12
  • 2015-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多