Contents

使用 Docker 捕获 USB 摄像头图像

本文记录了如何使用 Python + OpenCV 检测并读取 USB 摄像头图像,并封装为 Docker 容器程序,确保设备正确挂载并可视化显示图像。


🧩 1. 背景与需求

在嵌入式、工业自动化、AI 图像处理等场景中,我们常常需要通过 USB 摄像头采集图像。将图像采集功能封装为 Docker 容器,有以下优点:

  • ✅ 运行环境独立、依赖隔离
  • ✅ 支持部署到各种设备(如工控机、NVIDIA Jetson、树莓派)
  • ✅ 易于远程管理、快速迁移

📸 2. 步骤总览

  1. 在宿主机中检测可用相机设备(如 /dev/video0, /dev/video2
  2. 封装 Docker 镜像并在容器中采集图像
  3. 通过 x11 挂载实现容器中 GUI 图像窗口显示
  4. 使用脚本统一启动流程

🧪 3. 相机设备检测(运行在宿主机)

文件:camera_detect.py

import cv2

def list_available_cameras(max_devices=10):
    available = []
    for index in range(max_devices):
        cap = cv2.VideoCapture(index)
        if cap is not None and cap.read()[0]:
            print(f"相机设备 {index} 可用")
            available.append(index)
        cap.release()
    return available

if __name__ == "__main__":
    cams = list_available_cameras()
    print(f"可用相机索引:{cams}")

或者使用命令行工具 v4l2-ctl 检测相机设备:

sudo apt install v4l-utils

for i in /dev/video*; do
  echo "检查 $i"
  v4l2-ctl --device=$i --all | grep "Video Capture"
done

🎯 使用方法:

python camera_detect.py

输出示例:

相机设备 0 可用
相机设备 2 可用
可用相机索引:[0, 2]

📷 4. 相机图像采集程序(Docker 内运行)

文件:camera_capture.py

import cv2

def capture_from_usb_camera(camera_index=0):
    cap = cv2.VideoCapture(camera_index)

    if not cap.isOpened():
        print(f"无法打开相机(设备索引 {camera_index})")
        return

    print("按 'q' 退出")
    while True:
        ret, frame = cap.read()
        if not ret:
            print("无法读取帧")
            break

        cv2.imshow('USB Camera', frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    capture_from_usb_camera()

🧱 5. Dockerfile 封装

FROM python:3.10-slim

# 安装必要库
RUN apt-get update && \
    apt-get install -y libgl1 libglib2.0-0 libsm6 libxext6 libxrender1 ffmpeg && \
    pip install opencv-python && \
    apt-get clean

# 拷贝程序
WORKDIR /app
COPY camera_capture.py .

# 默认启动
CMD ["python", "camera_capture.py"]

🛠 6. 构建镜像

docker build -t usb-camera-test .

🚀 7. 启动容器并挂载相机与显示

编写脚本:run.sh

#!/bin/bash

# 允许容器访问宿主 GUI
xhost +local:root

# 启动容器
docker run --rm -it \
  --device=/dev/video0:/dev/video0 \
  -e DISPLAY=$DISPLAY \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  usb-camera-app

可以将宿主机上的 /dev/video0 替换为实际的 USB 摄像头设备路径。例如,挂载 /dev/video2

docker run --rm -it \
  --device=/dev/video0:/dev/video0 \
  -e DISPLAY=$DISPLAY \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  usb-camera-app

💡 如果你有多个设备(如 /dev/video2),可以多次添加 --device=/dev/video2


🧠 8. 常见问题排查

问题可能原因解决方案
无法打开摄像头未挂载设备添加 --device=/dev/videoX
cv2.imshow() 无法显示容器内无法访问 X11添加 -e DISPLAY 和挂载 /tmp/.X11-unix,使用 xhost +local:root
缺少 libGL.so.1容器中图形依赖缺失安装 libgl1
宿主有 /dev/videoX 但 Docker 中打不开权限不足或未挂载--device 显式挂载

🌀 9. 可选增强

✅ 9.1 捕获图像并保存

将采集程序改为保存图像文件:

cv2.imwrite('frame.jpg', frame)

✅ 9.2 支持命令行指定相机索引

import sys
index = int(sys.argv[1]) if len(sys.argv) > 1 else 0
capture_from_usb_camera(index)

然后运行:

docker run ... usb-camera-test python camera_capture.py 2

✅ 10. 总结

本项目实现了:

  • 检测可用 USB 相机
  • 使用 OpenCV 获取实时图像
  • Docker 封装可移植部署
  • 正确挂载设备与显示,支持图形化窗口

📎 参考命令速查

# 检测可用摄像头
python camera_detect.py

# 构建 Docker 镜像
docker build -t usb-camera-test .

# 运行摄像头容器(GUI)
xhost +local:root
./run.sh