linux读取usb摄像头c++
时间: 2025-07-11 08:32:08 浏览: 12
<think>我们正在处理用户的问题:如何在Linux环境下使用C++读取USB摄像头的数据或视频流。根据引用[2]和[3],我们可以知道USB免驱摄像头通常遵循UVC(USBVideoClass)标准,因此我们可以使用支持UVC的库来读取摄像头数据。引用[2]提到了libuvc库,它是一个跨平台的库,用于访问UVC设备。引用[3]提到在Ubuntu下读取USB摄像头数据时遇到问题,并使用了特定程序,这也暗示了我们可以使用libuvc。因此,我们可以推荐使用libuvc库来读取USB摄像头的数据流。同时,OpenCV(如引用[1]所述)也是一个常用的选择,因为OpenCV提供了简单易用的接口来捕获摄像头视频流,并且它可能内部使用了V4L2(VideoforLinux2)驱动,而UVC摄像头在Linux下通常由V4L2驱动支持。所以,我们可以提供两种方法:方法一:使用OpenCV(简单,高级API)方法二:使用libuvc(更底层,直接控制UVC设备)由于用户明确要求使用C++,我们将提供两种方法的示例代码。注意:引用[1]中提到了在Ubuntu系统下分辨率采用相机的分辨率,我们在使用OpenCV时也可以设置分辨率。步骤:1.使用OpenCV:-安装OpenCV-编写代码:使用VideoCapture类捕获摄像头视频流2.使用libuvc:-安装libuvc-编写代码:初始化libuvc,打开设备,设置格式,开始传输,读取帧数据由于引用[1]提供了OpenCV的C++示例(虽然主要是关于保存视频流的,但捕获部分相同),我们可以参考。我们将分别给出两种方法的简要步骤和代码示例。注意:在Linux下,USB摄像头通常挂载在/dev/videoX(如/dev/video0)设备节点上。方法一:OpenCV安装OpenCV(假设用户已经安装,如果没有,需要先安装)代码示例:```cpp#include<opencv2/opencv.hpp>usingnamespacecv;intmain(){//打开摄像头,0通常是默认摄像头,如果是USB摄像头,可能是0或1,根据设备号VideoCapturecap(0);if(!cap.isOpened()){//如果打开失败,尝试设备1(如果0是内置摄像头,USB可能是1)cap.open(1);if(!cap.isOpened()){return-1;}}//设置分辨率(可选,如果不设置则使用默认分辨率)cap.set(CAP_PROP_FRAME_WIDTH,640);cap.set(CAP_PROP_FRAME_HEIGHT,480);Matframe;namedWindow("USBCamera",WINDOW_AUTOSIZE);while(true){cap>>frame;//从摄像头捕获一帧if(frame.empty())break;imshow("USBCamera",frame);if(waitKey(30)>=0)break;//按任意键退出}return0;}```方法二:使用libuvc安装libuvc(需要先安装libusb):sudoapt-getinstalllibusb-1.0-0-dev然后从github克隆libuvc并编译安装:https://github.com/libuvc/libuvc代码示例(参考libuvc示例):```cpp#include<libuvc/libuvc.h>#include<opencv2/opencv.hpp>//为了显示图像,也可以不用OpenCV而用其他方式intmain(){uvc_context_t*ctx;uvc_device_t*dev;uvc_device_handle_t*devh;uvc_stream_ctrl_tctrl;uvc_error_tres;//初始化libuvcres=uvc_init(&ctx,NULL);if(res<0){uvc_perror(res,"uvc_init");returnres;}//查找设备(根据厂商ID和产品ID,或者使用NULL表示任意设备)res=uvc_find_device(ctx,&dev,0,0,NULL);//0,0表示任意厂商和产品if(res<0){uvc_perror(res,"uvc_find_device");}else{//打开设备res=uvc_open(dev,&devh);if(res<0){uvc_perror(res,"uvc_open");}else{//打印设备信息uvc_print_diag(devh,stderr);//尝试设置流格式:这里设置为640x480的YUYV格式,30fpsres=uvc_get_stream_ctrl_format_size(devh,&ctrl,UVC_FRAME_FORMAT_YUYV,640,480,30);if(res<0){uvc_perror(res,"get_mode");}else{//开始流传输res=uvc_start_streaming(devh,&ctrl,[](uvc_frame_t*frame,void*ptr){//回调函数,当有新帧时被调用//这里将帧转换为OpenCV的Mat并显示cv::Matimg(frame->height,frame->width,CV_8UC2,frame->data);//注意:YUYV是2通道,需要转换为BGRcv::Matimg_bgr;cv::cvtColor(img,img_bgr,cv::COLOR_YUV2BGR_YUYV);cv::imshow("USBCamera(libuvc)",img_bgr);cv::waitKey(1);},nullptr,0);if(res<0){uvc_perror(res,"start_streaming");}else{//等待用户输入,然后停止std::cout<<"Streaming...PressEntertostop."<<std::endl;getchar();uvc_stop_streaming(devh);}}uvc_close(devh);}uvc_unref_device(dev);}uvc_exit(ctx);return0;}```注意:libuvc的回调函数中,我们使用了OpenCV来显示图像,因此需要链接OpenCV。如果不想依赖OpenCV,可以用其他方式显示或处理。两种方法比较:-OpenCV方法简单,但可能不够底层,控制能力有限。-libuvc方法更底层,可以直接控制UVC设备的各种参数,但需要安装额外的库。根据用户需求选择。此外,引用[3]中提到的问题(huffman表缺失)可能与特定摄像头格式有关,使用libuvc或OpenCV(其背后使用V4L2)通常能避免这种问题。最后,我们生成相关问题。</think>### Linux C++ 读取 USB 摄像头数据/视频流方法
在 Linux 环境下使用 C++ 读取 USB 摄像头数据主要有以下三种方法,按实现复杂度排序:
---
#### **方法 1:使用 OpenCV(推荐)**
最简方案,适合快速开发。OpenCV 通过 V4L2(Video for Linux)接口访问摄像头,支持 UVC 免驱设备[^2]。
```cpp
#include <opencv2/opencv.hpp>
using namespace cv;
int main() {
// 打开设备(0=默认摄像头,1=USB摄像头)
VideoCapture cap(1);
if (!cap.isOpened()) return -1;
// 设置分辨率(需设备支持)
cap.set(CAP_PROP_FRAME_WIDTH, 640);
cap.set(CAP_PROP_FRAME_HEIGHT, 480);
Mat frame;
while (true) {
cap >> frame; // 读取帧数据
if (frame.empty()) break;
imshow("USB Camera", frame);
if (waitKey(30) >= 0) break; // 按任意键退出
}
return 0;
}
```
**安装依赖**:
```bash
sudo apt install libopencv-dev # Ubuntu
```
**优点**:代码简洁,跨平台,自带图像处理功能
**缺点**:控制参数有限[^1]
---
#### **方法 2:使用 V4L2 API(原生 Linux 方案)**
直接调用 Linux 视频子系统接口,精细控制摄像头参数。
```cpp
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <unistd.h>
int main() {
const char* device = "/dev/video1"; // USB摄像头设备节点
int fd = open(device, O_RDWR);
// 设置采集格式
v4l2_format fmt = {};
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 640;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; // 常用格式
ioctl(fd, VIDIOC_S_FMT, &fmt);
// 申请缓冲区(完整代码需包含内存映射和队列管理)
v4l2_requestbuffers req = {};
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ioctl(fd, VIDIOC_REQBUFS, &req);
// 开始采集
v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd, VIDIOC_STREAMON, &type);
// 循环读取数据(伪代码)
while (true) {
v4l2_buffer buf = {};
// ... 出队缓冲区 -> 处理数据 -> 重新入队
}
close(fd);
return 0;
}
```
**关键步骤**:
1. 打开设备节点(`/dev/videoN`)
2. 设置格式(分辨率/像素格式)
3. 分配内存缓冲区
4. 启动流传输
5. 循环读取帧数据
**优点**:完全控制摄像头参数
**缺点**:代码复杂,需处理底层细节[^3]
---
#### **方法 3:使用 libuvc(专用 UVC 库)**
直接操作 UVC 协议,支持高级控制(如曝光、白平衡)[^2]。
```cpp
#include <libuvc/libuvc.h>
void frame_callback(uvc_frame_t *frame, void *ptr) {
// 在此处理帧数据(YUV/RGB格式)
}
int main() {
uvc_context_t *ctx;
uvc_device_t *dev;
uvc_device_handle_t *devh;
uvc_init(&ctx, NULL); // 初始化
uvc_find_device(ctx, &dev, 0, 0, NULL); // 查找设备
uvc_open(dev, &devh); // 打开设备
// 启动传输(YUYV格式, 640x480, 30fps)
uvc_start_streaming(devh, &ctrl, frame_callback, NULL, 0);
sleep(10); // 采集10秒
uvc_stop_streaming(devh);
uvc_close(devh);
uvc_exit(ctx);
return 0;
}
```
**安装依赖**:
```bash
sudo apt install libusb-1.0-0-dev
git clone https://github.com/libuvc/libuvc
cd libuvc && mkdir build && cd build
cmake .. && make && sudo make install
```
**优点**:精确控制 UVC 参数
**缺点**:需额外安装库
---
### **选择建议**
| 方法 | 适用场景 | 学习曲线 |
|------------|----------------------------------|----------|
| OpenCV | 快速原型开发,需要图像处理 | 低 |
| V4L2 API | 系统级开发,需极致性能/控制 | 高 |
| libuvc | 专业摄像头控制(曝光/焦点等) | 中 |
> **注意**:
> 1. USB 摄像头设备号可通过 `v4l2-ctl --list-devices` 查看
> 2. 分辨率支持需检查设备能力:`v4l2-ctl -d /dev/video1 --list-formats-ext`
> 3. 确保用户有设备访问权限(加入 `video` 用户组)
阅读全文
相关推荐

















