【问题标题】:How to correctly check if a camera is available?如何正确检查相机是否可用?
【发布时间】:2026-02-06 01:55:01
【问题描述】:

我正在使用 OpenCV 打开和读取多个网络摄像头。一切正常,但我似乎无法找到一种方法来知道相机是否可用。

我试过这段代码(cam 2 不存在):

import cv2
try:
    c = cv2.VideoCapture(2)
except:
    print "Cam 2 is invalid."

但这只会打印很多错误:

VIDEOIO ERROR: V4L: index 2 is not correct!
failed to open /usr/lib64/dri/hybrid_drv_video.so
Failed to wrapper hybrid_drv_video.so
failed to open /usr/lib64/dri/hybrid_drv_video.so
Failed to wrapper hybrid_drv_video.so
GStreamer Plugin: Embedded video playback halted; module v4l2src0 reported: Internal data stream error.
OpenCV Error: Unspecified error (GStreamer: unable to start pipeline
) in cvCaptureFromCAM_GStreamer, file /builddir/build/BUILD/opencv-3.2.0/modules/videoio/src/cap_gstreamer.cpp, line 832
VIDEOIO(cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L2, reinterpret_cast<char *>(index))): raised OpenCV exception:

/builddir/build/BUILD/opencv-3.2.0/modules/videoio/src/cap_gstreamer.cpp:832: error: (-2) GStreamer: unable to start pipeline
 in function cvCaptureFromCAM_GStreamer

OpenCV Error: Unspecified error (unicap: failed to get info for device
) in CvCapture_Unicap::initDevice, file /builddir/build/BUILD/opencv-3.2.0/modules/videoio/src/cap_unicap.cpp, line 139
VIDEOIO(cvCreateCameraCapture_Unicap(index)): raised OpenCV exception:

/builddir/build/BUILD/opencv-3.2.0/modules/videoio/src/cap_unicap.cpp:139: error: (-2) unicap: failed to get info for device
 in function CvCapture_Unicap::initDevice

CvCapture_OpenNI::CvCapture_OpenNI : Failed to enumerate production trees: Can't create any node of the requested type!
<VideoCapture 0x7fa5b5de0450>

不抛出异常。稍后使用c.read() 时,我确实得到False,但我想在程序的初始化阶段执行此操作。

那么,我如何找出我拥有的有效摄像机数量或检查某个数量是否“映射”到有效摄像机?

【问题讨论】:

  • "没有抛出异常":是的,因为你发现它们都没有处理。始终只捕获您愿意处理的异常。
  • @AndrasDeak print "Cam 2 is invalid" 从未显示。
  • 啊,这让它更有趣了(但我坚持我之前的说法)。那么......它打印什么样的错误?请阅读minimal reproducible exampleHow to Ask:P
  • @AndrasDeak 添加 import cv2 是制作此 MCV 所需的全部内容。我也添加了错误。
  • Úsing cv2.VideoCapture( invalid device number ) 不会引发异常。它构造了一个包含无效设备的&lt;VideoCapture object&gt;——如果你使用它,你会得到异常。测试 Nonenot IsOpen() 的构造对象以清除无效对象。有关代码示例,请参见答案。

标签: python opencv


【解决方案1】:

使用cv2.VideoCapture( invalid device number ) 不会引发异常。它构造了一个包含无效设备的&lt;VideoCapture object&gt; - 如果你使用它你会得到异常。

测试Nonenot isOpened() 的构造对象以清除无效对象。


对我来说这很有效(1 个笔记本电脑摄像头设备):

import cv2 as cv 

def testDevice(source):
   cap = cv.VideoCapture(source) 
   if cap is None or not cap.isOpened():
       print('Warning: unable to open video source: ', source)

testDevice(0) # no printout
testDevice(1) # prints message

输出为 1:

Warning: unable to open video source:  1

示例来自:https://github.com/opencv/opencv_contrib/blob/master/samples/python2/video.py 第 159 行

cap = cv.VideoCapture(source)
    if 'size' in params:
        w, h = map(int, params['size'].split('x'))
        cap.set(cv.CAP_PROP_FRAME_WIDTH, w)
        cap.set(cv.CAP_PROP_FRAME_HEIGHT, h)
if cap is None or not cap.isOpened():
    print 'Warning: unable to open video source: ', source

【讨论】:

  • “不存在的设备”是这个问题的核心:如何判断给定源 ID 的设备是否不可用。
  • @AndrasDeak 必须先安装 opencv 才能对其进行测试 - 对我来说它可以工作 - 不会崩溃
  • opencv_contrib 中的示例不检查cv2.VideoCapture() 是否返回None——它检查是否classes.get(params.get('class', None), VideoSynthBase) is None。查看全文:github.com/opencv/opencv_contrib/blob/…
  • 建议的解决方案不适用于点灰 (FLIR) 相机。我的cam.Init() 想法也没有在这里发布。
  • 我在实践中发现cv::VideoCapture() 确实在某些情况下会抛出异常(OpenCV 3.1.0,因为升级很困难)。当心。
【解决方案2】:

在 Linux 中可用的另一种解决方案是在 VideoCapture() 调用中使用 /dev/videoX 设备。插入摄像头后,设备就在那里。与glob()一起,获得所有摄像头是微不足道的:

import cv2, glob

for camera in glob.glob("/dev/video?"):
    c = cv2.VideoCapture(camera)

当然需要使用isOpened()c 进行检查,但您确定您只扫描可用的摄像头。

【讨论】:

    【解决方案3】:

    这里有一个“不工作”解决方案,可帮助您防止在这个陷阱中跌倒:

    import cv2 as cv
    import PySpin
    
    print (cv.__version__)
    
    # provided by Patrick Artner as solution to be working for other cameras than
    #                                                  those of Point Grey (FLIR).
    
    def testDevice(source):
       cap = cv.VideoCapture(source) 
       if cap is None or not cap.isOpened():
           print('Warning: unable to open video source: ', source)
    
    # ... PySpin / Spinnaker (wrapper/SDK libary) ...
    
    system   = PySpin.System.GetInstance()
    cam_list = system.GetCameras()
    
    cam = ''
    cam_num = 0
    
    for ID, cam in enumerate(cam_list):
        # Retrieve TL device nodemap
        if ID == cam_num:
            print ('Got cam')
            cam = cam
    
            cam.Init()
    
            # ... CV2 again ...
    
            for i in range(10):
                testDevice(i) # no printout
    

    【讨论】:

    • Point Grey FLIR 相机有什么特别之处?
    • 我也很困惑 - 这个解决方案是否适用于这种相机(使用 PySpin 包装器?)这种相机是否可以与 cv2 一起使用
    • 我还不知道,并在我们发言时试图弄清楚这一点。我已经从 PyCapture2 迁移到 PySpin,但失去了 cameraPowerON/OFF 等功能。我在另一个 Q/A 会话中描述了一个isValid() 测试,它或多或少地起到了作用(阅读:拼凑),但 read/writeRegister 函数在这里是一个失败的案例。据我现在所见,它们使用了 GENiCAM 结构化命名/框架,因此可以使用节点和活动相机实例(如提供的代码所示)。实际上,我有点惊讶 CV2 无法将手指放在镜头后面。
    • 也许您应该创建自己的问题 - 这似乎不是对原始帖子的答案。如果您想得到一些答案,您可能可以向how to detect amount of Pint Grey FLIR cameras 之类的人发布问题/自我回答......他们似乎有自己的自己的类型的API:flir.com/iis/machine-vision
    • 想象一下如果我们收集所有“不工作”的方式来做事作为对 SO 问题的答案...你的cam = cam 什么都不做 - 它将被循环中的下一个值 for ID, cam in enumerate(cam_list): 覆盖,并且只有 last 相机对象在其中 - 不是全部。你的意思很好,但我想这可能会得到 dv - 你会看到的。
    【解决方案4】:

    你可以试试这个代码:

    from __future__ import print_function
    import numpy as np
    import cv2
    
    # detect all connected webcams
    valid_cams = []
    for i in range(8):
        cap = cv2.VideoCapture(i)
        if cap is None or not cap.isOpened():
            print('Warning: unable to open video source: ', i)
        else:
            valid_cams.append(i)
    
    caps = []
    for webcam in valid_cams:
        caps.append(cv2.VideoCapture(webcam))
    
    while True:
        # Capture frame-by-frame
        for webcam in valid_cams:
            ret, frame = caps[webcam].read()
            # Display the resulting frame
            cv2.imshow('webcam'+str(webcam), frame)
        k = cv2.waitKey(1)
        if k == ord('q') or k == 27:
            break
    
    # When everything done, release the capture
    for cap in caps:
        cap.release()
    
    cv2.destroyAllWindows()
    

    【讨论】:

      最近更新 更多