具有多个网络摄像头的OpenCV-如何分辨代码中的哪个摄像头? [英] OpenCV with multiple webcams - how to tell which camera is which in code?

查看:282
本文介绍了具有多个网络摄像头的OpenCV-如何分辨代码中的哪个摄像头?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Previously I've used industrial cameras with Ethernet connections and distinct IP addresses for multiple camera setups. Now I'm attempting a multiple camera setup with OpenCV and I'm not sure how to match the OpenCV VideoCapture ID to a certain camera.

我可能应该以目前的情况为例,以使我的问题更加清楚.我目前已连接3台摄像机.如果有的话,我正在使用Ubuntu 18.04.这是我来自 lsusb 的输出(省略了我已连接的3个Logitech网络摄像头以外的所有内容):

I should probably use my current situation as an example to make my question more clear. I currently have 3 cameras connected. I'm using Ubuntu 18.04 if that matters. Here is my output from lsusb (omitting everything except the 3 Logitech webcams I have connected):

$ 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个 C930e 和一个 OrbiCam .基于这篇非常有帮助的帖子:

As you can see I have 2 C930es and one OrbiCam connected. Based on this very helpful post:

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

我发现我可以像这样获得凸轮的序列号:

I found I could get the serial number of the cams like so:

$ 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

太好了,所以我现在有一种方法可以根据存储在凸轮内存中的序列号( D2DF1D2E 99A8F15E C83E952F).

Great, so I now have a way to uniquely identify each camera based on the serial numbers stored in the cam's memory (D2DF1D2E, 99A8F15E, and C83E952F).

问题是,在OpenCV中打开网络摄像头连接的步骤如下:

The problem is, opening a webcam connection in OpenCV is done as follows:

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_X Y Z 是OpenCV VideoCapture ID.现在,我通过以下手动过程将摄像机与OpenCV VideoCapture ID关联起来:

Where camera X, Y, and Z are the 3 cameras I need to use, each for a different determined purpose, and OPEN_CV_VID_CAP_ID_FOR_CAM_X, Y, and Z are the OpenCV VideoCapture IDs. Right now, I'm relating cameras to the OpenCV VideoCapture IDs with the following manual process:

1)编写如下测试脚本:

1) Make a test script like this:

# 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.

2) Try numbers 0-99 for the VideoCapture parameter until I find the 3 magic numbers for my 3 attached cameras. In my current example they are 0, 2, and 4.

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

3) Each time I find a valid VideoCapture ID, wave my hand in front of each camera until I determine which one that VideoCapture ID is for, then write down which camera in my project that needs to correspond to, ex in my case:

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

4)编辑我的代码(或存储的配置文件或数据库字段),以便cam X使用 VideoCapture ID 0,cam Y使用 VideoCapture ID 2,依此类推.

4) Edit my code (or a stored config file or database field) so cam X uses VideoCapture ID 0, cam Y uses VideoCapture ID 2, etc.

我应该澄清一下,摄像机X,Y和Z处于不同的位置并且具有不同的用途,即,如果我将 VideoCapture ID 4用于cam X,则该应用程序将无法正常工作(它们必须按上述方式映射.)

I should clarify that cameras X, Y, and Z are in different positions and serve different purposes, i.e. if I use VideoCapture ID 4 for cam X the application wouldn't work (they have to be mapped a certain way as above).

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

Clearly for a production application this routine is not acceptable.

我意识到我可以做这样的事情:

I realize I can do something like this:

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.

To get a list of the valid OpenCV VideoCapture IDs, but I still have to do the manual hand wave thing to determine which OpenCV VideoCapture IDs corresponds to each camera.

更糟糕的是,交换将哪个摄像机连接到设备上的哪个物理端口会破坏OpenCV VideoCapture ID,因此,如果更改了任何摄像机连接,或者添加或删除了凸轮,必须对所有摄像机重复此过程.

To make matters worse, swapping which camera is connected to which physical port on a device shuffles the OpenCV VideoCapture IDs, so if any camera connection is changed, or a cam is added or removed the manual process has to be repeated for all cameras.

所以我的问题是 ,是否存在某种天才方法(以代码方式而非手动方式)来关联每个摄像机的序列号或存储的其他唯一ID在凸轮的内存中找到OpenCV似乎为 VideoCapture ID提供的幻数?

So my question is, is there some genius way (in code, not a manual way) to relate the serial number of each camera or some other unique ID stored in the cam's memory to the magic numbers that OpenCV seems to come up with for VideoCapture IDs?

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

To put my question another way, I need to write a function camSerialNumToOpenCvVidCapId that could be used like so:

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

这可能吗,怎么办?

P.S.我对OpenCV C ++或Python感到很满意,无论使用哪种方法,任何有用的答案都将不胜感激.

P.S. I'm comfortable with OpenCV C++ or Python, any helpful answers using either would be greatly appreciated.

-编辑---

这个问题:

OpenCV VideoCapture设备索引/设备号

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

Has a response (not accepted) that pertains to using Windows API calls, but I'm using Ubuntu.

-编辑2 ---

@ Micka,这是我在/dev/中的相机的所有物品:

@ Micka, here is what I have for cameras in /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列表之后,如果存在类似这样的属性:

After considering this some more what I really need is a cam property in OpenCV to identify each camera uniquely. After getting a list of available VideoCapture IDs as mentioned above, if there was a property like:

serialNum = cv2.get(cv2.CAP_PROP_SERIAL_NUM)

然后这很容易,但是似乎没有这样的属性或任何类似的东西(检查PyCharm自动完成 cv2.CAP_PROP _ * 并阅读OpenCV文档以获得之后VideoCapture ).

Then it would be easy, but there does not seem to be such a property or anything similar (after checking PyCharm auto-complete for cv2.CAP_PROP_* and reading the OpenCV docs for VideoCapture).

推荐答案

对于找到的解决方案,您需要root特权.在我使用Ubuntu20的安装程序中,这不是必需的:

For the solution you found, you need root privileges. On my setup with Ubuntu20 this is not required for:

udevadm info --name=/dev/video0

这将输出检测到的第一个摄像机的属性.通过"grep"管道将其通过管道传输以过滤出对于所有摄像机都不同的特定属性,例如"ID_SERIAL =".然后,您可以使用剪切"删除字符串"ID_SERIAL ="的开头并保留如下值:

This outputs properties of first camera detected. Pipe it through "grep" to filter out specific property that is different for all cameras like "ID_SERIAL=". You can then use "cut" to remove beginning of this string "ID_SERIAL=" and leave just the value like:

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

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

In Python you can run external command to get this info like:

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与序列号相关联.完整的代码可能是:

To acquire all the camera serial numbers, just loop through several camera ID's. On my setup trying camera ID 0 and 1 target the same camera. Also 2 and 4 target the second camera, so the loop can have 2 for step. Once all ID's are extracted, place them in a dictionary to be able to associate cam ID with serial number. The complete code could be:

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)

这篇关于具有多个网络摄像头的OpenCV-如何分辨代码中的哪个摄像头?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆