OpenCV无法同时开启4台USB摄像头问题求助
USB四摄像头同时开启时第四台无画面的解决方案
问题重现
通过USB集线器连接/dev/video4、/dev/video6、/dev/video8、/dev/video10四台USB摄像头,单独或同时开启三台均正常工作,但同时开启四台时第四台无法捕获画面。使用的OpenCV代码如下:
#include <opencv2/opencv.hpp> int main() { cv::VideoCapture cap1(10, cv::CAP_V4L); cap1.set(cv::CAP_PROP_FRAME_WIDTH, 352); cap1.set(cv::CAP_PROP_FRAME_HEIGHT, 288); cap1.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G')); cv::VideoCapture cap2(8, cv::CAP_V4L); cap2.set(cv::CAP_PROP_FRAME_WIDTH, 352); cap2.set(cv::CAP_PROP_FRAME_HEIGHT, 288); cap2.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G')); cv::VideoCapture cap3(6, cv::CAP_V4L2); cap3.set(cv::CAP_PROP_FRAME_WIDTH, 352); cap3.set(cv::CAP_PROP_FRAME_HEIGHT, 288); cap3.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G')); cv::VideoCapture cap4(4, cv::CAP_V4L2); cap4.set(cv::CAP_PROP_FRAME_WIDTH, 352); cap4.set(cv::CAP_PROP_FRAME_HEIGHT, 288); cap4.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G')); while (true) { cv::Mat img1, img2, img3, img4; cap1.grab(); cap1.retrieve(img1); cap2.grab(); cap2.retrieve(img2); cap3.grab(); cap3.retrieve(img3); cap4.grab(); cap4.retrieve(img4); if (img1.cols > 0) { cv::imshow("1", img1); cv::waitKey(50); } if (img2.cols > 0) { cv::imshow("2", img2); cv::waitKey(50); } if (img3.cols > 0) { cv::imshow("3", img3); cv::waitKey(50); } if (img4.cols > 0) { cv::imshow("4", img4); cv::waitKey(50); } } return 1; }
核心原因分析
- USB带宽瓶颈:USB集线器带宽共享,即使使用MJPEG压缩,四台摄像头同时传输的总带宽可能超过USB总线实际可用上限(尤其是USB 2.0总线)。
- 代码阻塞问题:循环中每个
imshow后调用waitKey(50)导致程序频繁阻塞,摄像头帧捕获线程无法及时获取数据,最终引发第四台摄像头超时无输出。 - 后端API混用:代码中混用
CAP_V4L和CAP_V4L2后端,存在兼容性冲突风险。 - 供电不足:无外接电源的USB集线器可能无法为四台摄像头提供足够电力,导致第四台无法正常启动。
解决方案
1. 优化USB带宽占用
- 降低帧率:为每个摄像头设置更低帧率,减少数据传输量:
cap1.set(cv::CAP_PROP_FPS, 10); cap2.set(cv::CAP_PROP_FPS, 10); cap3.set(cv::CAP_PROP_FPS, 10); cap4.set(cv::CAP_PROP_FPS, 10); - 进一步降低分辨率:尝试320x240或更低分辨率,减少单帧数据大小。
- 确认MJPEG格式生效:部分摄像头可能不支持强制设置MJPEG,会 fallback 到YUYV等未压缩格式,可通过以下命令查看摄像头支持的格式:
也可在代码中通过v4l2-ctl --list-formats-ext /dev/video4cap.get(cv::CAP_PROP_FOURCC)验证格式是否设置成功。
2. 修复代码阻塞问题
将waitKey移到循环末尾,仅调用一次,避免频繁阻塞:
while (true) { cv::Mat img1, img2, img3, img4; bool success1 = cap1.grab() && cap1.retrieve(img1); bool success2 = cap2.grab() && cap2.retrieve(img2); bool success3 = cap3.grab() && cap3.retrieve(img3); bool success4 = cap4.grab() && cap4.retrieve(img4); if (success1) cv::imshow("1", img1); if (success2) cv::imshow("2", img2); if (success3) cv::imshow("3", img3); if (success4) cv::imshow("4", img4); // 仅在循环末尾处理窗口事件,按ESC退出 if (cv::waitKey(1) == 27) break; }
3. 统一使用V4L2后端
将所有VideoCapture的后端统一改为cv::CAP_V4L2,避免API混用的兼容性问题:
cv::VideoCapture cap1(10, cv::CAP_V4L2); cv::VideoCapture cap2(8, cv::CAP_V4L2); cv::VideoCapture cap3(6, cv::CAP_V4L2); cv::VideoCapture cap4(4, cv::CAP_V4L2);
4. 检查集线器供电与带宽
- 使用带外接电源的USB 3.0集线器:USB 3.0提供更高带宽(5Gbps)和更稳定的供电,能更好支持多摄像头同时工作。
- 若使用USB 2.0集线器,确保总带宽不超总线限制:USB 2.0理论带宽480Mbps,实际可用约300-400Mbps,MJPEG格式下352x288@10fps单摄像头约3-5Mbps,四台总带宽远低于限制,但集线器质量差可能导致实际可用带宽不足。
5. 添加错误检查
在代码中添加摄像头初始化和帧捕获的错误检查,便于排查问题:
if (!cap1.isOpened()) { std::cerr << "Failed to open /dev/video10" << std::endl; return -1; } if (!cap2.isOpened()) { std::cerr << "Failed to open /dev/video8" << std::endl; return -1; } if (!cap3.isOpened()) { std::cerr << "Failed to open /dev/video6" << std::endl; return -1; } if (!cap4.isOpened()) { std::cerr << "Failed to open /dev/video4" << std::endl; return -1; }
6. 调整摄像头初始化顺序
尝试改变摄像头初始化顺序,比如先初始化/dev/video4,避免总线冲突:
cv::VideoCapture cap4(4, cv::CAP_V4L2); cv::VideoCapture cap3(6, cv::CAP_V4L2); cv::VideoCapture cap2(8, cv::CAP_V4L2); cv::VideoCapture cap1(10, cv::CAP_V4L2);
内容的提问来源于stack exchange,提问作者HC S
相关产品推荐
相关产品推荐

