当前位置: 首页 > news >正文

Linux下USB设备图像采集

操作系统 : Linux
采集方式 : v4l2(video4linux2)
设备目录 :/dev/video0

Linux系统
Linux采集的核心组件名称叫:v4l2即video4linux2的简称。是Linux中关于视频设备的内核驱动,在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头设备文件位置是/dev/video0。

查看相机设备

方法一,直接通过ls查看/dev/目录下设备列表

ls /dev/video*

方法二,通过ffmpeg的ffprobe命令来查看连接到系统中的摄像头设备:
FFmpeg命令行安装

 sudo apt-get install ffmpeg
ffprobe /dev/video0

在这里插入图片描述video0设备采集出来的裸帧格式是:yuyv422,帧率30fps,分辨率640x480,因此在保存摄像头数据的时候,先对yuyu422的格式进行变化,将其变换为yuv420p的格式,然后再进行编码保存为h264的文件。

v4l2 常用命令

获取设备列表

v4l2-ctl --list-devices
#List supported video formats and resolutions of default video device 
v4l2-ctl --list-formats-ext#List supported video formats and resolutions of a specific video device:
v4l2-ctl --list-formats-ext --device path/to/video_device
#eg:
v4l2-ctl --list-formats-ext --device /dev/video0#Get all details of a video device:
v4l2-ctl --all --device path/to/video_device
#eg:
v4l2-ctl --all --device /dev/video0#Capture a JPEG photo with a specific resolution from video device:
v4l2-ctl --device path/to/video_device --set-fmt-video=width=width,height=height,pixelformat=MJPG --stream-mmap --stream-to=path/to/output.jpg --stream-count=1
#eg:
v4l2-ctl --device /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=MJPG --stream-mmap --stream-to=/home/nvidia/Pictures/video0-output.jpg --stream-count=1#Capture a raw video stream from video device:
v4l2-ctl --device path/to/video_device --set-fmt-video=width=width,height=height,pixelformat=format --stream-mmap --stream-to=path/to/output --stream-count=number_of_frames_to_capture
#eg:
v4l2-ctl --device /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=MJPG --stream-mmap --stream-to=/home/nvidia/Pictures --stream-count=10#List all video device's controls and their values:
v4l2-ctl --list-ctrls --device /path/to/video_device
#eg:
v4l2-ctl --list-ctrls --device /dev/video0

测试相机可用性

$ cheese -d /dev/video0
$ ffplay -f v4l2 -input_format bayer_bggr16le -video_size 640x480 -i /dev/video0

代码

cmmon.h

#ifndef COMMON_H
#define COMMON_H#ifdef __cplusplus
extern "C" {
#endif
#include <linux/videodev2.h>//c varable
extern struct v4l2_fmtdesc fmtd[20];
extern unsigned char * displaybuf; //v4l2 video buffer
extern int current_video_state;
typedef struct buffer{void *start;unsigned int length;
}buffer;//define
#define SRC_WIDTH 1280
#define SRC_HEIGHT 720
#define DST_WIDTH 1280
#define DST_HEIGHT 720
#define NB_BUFFER 4#ifdef __cplusplus
}
#endif
#endif

v4l2.h

#ifndef V4L2_H
#define V4L2_H#include <fcntl.h>
#include <linux/fb.h>
#include <linux/videodev2.h>
#include <poll.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include "config.h"#ifdef __cplusplus
extern "C" {
#endif//function
int c_OpenDevice(char* video);
void c_CloseDevice(int videofd);
int c_FormatDevice(unsigned int pixformat, int videofd);
int c_RequestBuffer(buffer *vbuffer, int videofd);
int c_GetBuffer(unsigned char* yuvBuffer, buffer *vbuffer, int videofd);
void c_DeintDevice(int videofd, buffer *vbuffer);
void c_NV12_TO_RGB24(unsigned char *yuyv, unsigned char *rgb, int width, int height);
void c_yuyv_to_rgb(unsigned char *yuyvdata, unsigned char *rgbdata, int w, int h);//varable#ifdef __cplusplus
}
#endif
#endif

CAMERATHREAD1.H

#ifndef CAMERATHREAD1_H
#define CAMERATHREAD1_H#include <QObject>
#include <QThread>
#include <QDebug>class CameraThread1 : public QThread
{Q_OBJECT
public:CameraThread1();void run() override;void getCam1Buf();bool previewCam1 = true;QString camera1Dev="";signals:void showCamera1(unsigned char *buffer);
};#endif // CAMERATHREAD1_H

MAINWINDOW.H

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QLabel>
#include "common.h"
#include "camerathread1.h"QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();
void checkIspServer();private:Ui::MainWindow *ui;// QLabel *camera1;CameraThread1 *cameraThread1;Common common;public slots:void displayCam1Buf(unsigned char *buffer);

camerathread1.cpp

#include "camerathread1.h"
#include "v4l2.h"CameraThread1::CameraThread1()
{}void CameraThread1::run()
{msleep(200);getCam1Buf();
}void CameraThread1::getCam1Buf()
{unsigned char *yuvBuffer = (unsigned char*)malloc(SRC_WIDTH * SRC_HEIGHT * 3);unsigned char *rgbBuffer = (unsigned char*)malloc(SRC_WIDTH * SRC_HEIGHT * 3);buffer * vbuffer;vbuffer = (buffer*)calloc (NB_BUFFER, sizeof (*vbuffer));int fd = c_OpenDevice(camera1Dev.toLocal8Bit().data());if(fd < 0) return;c_FormatDevice(V4L2_PIX_FMT_YUYV, fd);c_RequestBuffer(vbuffer, fd);while (previewCam1) {if(c_GetBuffer(yuvBuffer, vbuffer, fd) != 0) return;//c_NV12_TO_RGB24(yuvBuffer, rgbBuffer, SRC_WIDTH, SRC_HEIGHT);c_yuyv_to_rgb(yuvBuffer, rgbBuffer, SRC_WIDTH, SRC_HEIGHT);emit showCamera1(rgbBuffer);msleep(1000/30);}//close camerac_DeintDevice(fd, vbuffer);c_CloseDevice(fd);
}

v4l2.c

#include "v4l2.h"int buf_type = -1;
int current_video_state = 0;struct v4l2_fmtdesc fmtd[];
struct v4l2_format format;unsigned char * displaybuf = NULL;
unsigned char * rgb24 = NULL;int c_OpenDevice(char *video)
{struct v4l2_capability cap;struct v4l2_fmtdesc fmtdesc;/* open video */int videofd = open(video, O_RDWR);if ( -1 == videofd ) {printf("Error: cannot open %s device\n",video);return videofd;}printf("The %s device was opened successfully.\n", video);/* check capability */memset(&cap, 0, sizeof(struct v4l2_capability));if ( ioctl(videofd, VIDIOC_QUERYCAP, &cap) < 0 ) {printf("Error: get capability.\n");goto fatal;}/* query all pixformat */if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE){buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;}else if(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE){buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;}else{printf("Error: application not support this device %s.\n",video);goto fatal;}memset(fmtd, 0, sizeof(fmtd));//note: nedd clean array first.fmtdesc.index=0;fmtdesc.type=buf_type;while(ioctl(videofd, VIDIOC_ENUM_FMT, &fmtdesc) != -1) {fmtd[fmtdesc.index] = fmtdesc;// printf("\t%d.%s\n",fmtdesc.index+1,fmtdesc.description);fmtdesc.index++;}return videofd;
fatal:c_CloseDevice(videofd);
}int c_FormatDevice(unsigned int pixformat, int videofd)
{/* set format */memset(&format, 0, sizeof(struct v4l2_format));format.type = buf_type;if (format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE){format.fmt.pix.width = SRC_WIDTH;format.fmt.pix.height = SRC_HEIGHT;format.fmt.pix.pixelformat = pixformat;format.fmt.pix.field = V4L2_FIELD_ANY;printf("VIDIO_S_FMT: type=%d, w=%d, h=%d, fmt=0x%x, field=%d\n",format.type, format.fmt.pix.width,format.fmt.pix.height, format.fmt.pix.pixelformat,format.fmt.pix.field);}else{format.fmt.pix_mp.width = SRC_WIDTH;format.fmt.pix_mp.height = SRC_HEIGHT;format.fmt.pix_mp.pixelformat = pixformat;format.fmt.pix_mp.field = V4L2_FIELD_ANY;printf(">> VIDIO_S_FMT: type=%d, w=%d, h=%d, fmt=0x%x, field=%d\n",format.type, format.fmt.pix_mp.width,format.fmt.pix_mp.height, format.fmt.pix_mp.pixelformat,format.fmt.pix_mp.field);}if (ioctl(videofd, VIDIOC_S_FMT, &format) < 0) {printf("Error: set format %d.\n", errno);return errno;}/* get format */if (ioctl(videofd, VIDIOC_G_FMT, &format) < 0) {printf("Error: get format %d.\n", errno);return errno;}printf("VIDIO_G_FMT: type=%d, w=%d, h=%d, fmt=0x%x, field=%d\n",format.type, format.fmt.pix.width,format.fmt.pix.height, format.fmt.pix.pixelformat,format.fmt.pix.field);return 0;
}int c_RequestBuffer(buffer *vbuffer, int videofd)
{struct v4l2_requestbuffers reqbuf;struct v4l2_buffer v4l2_buf;/* buffer preparation */memset(&reqbuf, 0, sizeof(struct v4l2_requestbuffers));reqbuf.count = NB_BUFFER;reqbuf.type = buf_type;reqbuf.memory = V4L2_MEMORY_MMAP;if (ioctl(videofd, VIDIOC_REQBUFS, &reqbuf) < 0) {printf("Error: request buffer error=%d.\n",errno);goto fatal;}//map buffersfor (unsigned int i = 0; i < reqbuf.count; i++) {memset(&v4l2_buf, 0, sizeof(struct v4l2_buffer));v4l2_buf.index = i;v4l2_buf.type = buf_type;v4l2_buf.memory = V4L2_MEMORY_MMAP;if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {struct v4l2_plane buf_planes[format.fmt.pix_mp.num_planes];v4l2_buf.m.planes = buf_planes;v4l2_buf.length = format.fmt.pix_mp.num_planes;}if (ioctl(videofd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) {printf("Error: query buffer %d.\n", errno);goto fatal;}if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {for (int j = 0; j < format.fmt.pix_mp.num_planes; j++) {vbuffer[i * format.fmt.pix_mp.num_planes + j].start= mmap(0, v4l2_buf.m.planes[j].length, PROT_READ,MAP_SHARED, videofd, v4l2_buf.m.planes[j].m.mem_offset);vbuffer[i * format.fmt.pix_mp.num_planes + j].length= v4l2_buf.m.planes[j].length;}}else{//V4L2_BUF_TYPE_VIDEO_CAPTUREvbuffer[i].start = mmap(0, v4l2_buf.length, PROT_READ, MAP_SHARED, videofd,v4l2_buf.m.offset);vbuffer[i].length = v4l2_buf.length;}if (vbuffer[i].start == MAP_FAILED) {printf("Error: mmap buffers.\n");goto fatal;}}//queue buffersfor (int i = 0; i < reqbuf.count; ++i) {memset(&v4l2_buf, 0, sizeof(struct v4l2_buffer));v4l2_buf.index = i;v4l2_buf.type = buf_type;v4l2_buf.memory = V4L2_MEMORY_MMAP;if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {struct v4l2_plane buf_planes[format.fmt.pix_mp.num_planes];v4l2_buf.m.planes = buf_planes;v4l2_buf.length = format.fmt.pix_mp.num_planes;}if (ioctl(videofd, VIDIOC_QBUF, &v4l2_buf) < 0) {printf("Error: queue buffers, ret:%d i:%d\n", errno, i);goto fatal;}}printf("Queue buf done.\n");//stream onif (ioctl(videofd, VIDIOC_STREAMON, &buf_type) < 0) {printf("Error: streamon failed erron = %d.\n",errno);goto fatal;}//open successcurrent_video_state = 1;return 0;fatal:printf("init camera fial!\n");current_video_state = 0;c_CloseDevice(videofd);return -1;
}int c_GetBuffer(unsigned char* yuvBuffer, buffer *vbuffer, int videofd)
{struct v4l2_buffer v4l2_buf;int buf_index = -1;int planes_num = format.fmt.pix_mp.num_planes;memset(yuvBuffer, 0, SRC_WIDTH * SRC_HEIGHT * 3);// dqbuf from video nodememset(&v4l2_buf, 0, sizeof(struct v4l2_buffer));v4l2_buf.type = buf_type;v4l2_buf.memory = V4L2_MEMORY_MMAP;if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {struct v4l2_plane planes[planes_num];v4l2_buf.m.planes = planes;v4l2_buf.length = planes_num;}if (ioctl(videofd, VIDIOC_DQBUF, &v4l2_buf) < 0) {printf("Error: dequeue buffer, errno %d\n", errno);return errno;}buf_index = v4l2_buf.index;if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {for(int i = 0;i < planes_num; i++){memcpy(yuvBuffer, vbuffer[buf_index].start, format.fmt.pix_mp.plane_fmt[i].sizeimage);}}else{// V4L2_BUF_TYPE_VIDEO_CAPTUREmemcpy(yuvBuffer, vbuffer[buf_index].start, format.fmt.pix.sizeimage);}if (ioctl(videofd, VIDIOC_QBUF, &v4l2_buf) < 0) {printf("Error: queue buffer.\n");return errno;}return 0;
}void c_CloseDevice(int videofd)
{close(videofd);
}void c_DeintDevice(int videofd, buffer *vbuffer)
{struct v4l2_requestbuffers v4l2_rb;//    if(current_video_state != 1)
//        return;if(ioctl(videofd, VIDIOC_STREAMOFF, &buf_type) < 0 ){printf("Error: stream close failed erron= %d\n", errno);return;}for (int i = 0; i < NB_BUFFER; i++){if((i < NB_BUFFER -1) && (vbuffer[i].length !=  vbuffer[i+1].length))munmap (vbuffer[i].start, vbuffer[i+1].length);//first buffer.length maybe not currentelsemunmap (vbuffer[i].start, vbuffer[i].length);}memset(&v4l2_rb, 0, sizeof(struct v4l2_requestbuffers));v4l2_rb.count = 0;v4l2_rb.type = buf_type;v4l2_rb.memory = V4L2_MEMORY_MMAP;if (ioctl(videofd, VIDIOC_REQBUFS, &v4l2_rb) < 0)printf("Error: release buffer error=%d.\n",errno);free(vbuffer);vbuffer=NULL;
}void c_NV12_TO_RGB24(unsigned char *data, unsigned char *rgb, int width, int height)
{int index = 0;unsigned char *ybase = data;unsigned char *ubase = &data[width * height];unsigned char Y, U, V;int R, G, B;for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {//YYYYYYYYUVUVY = ybase[x + y * width];U = ubase[y / 2 * width + (x / 2) * 2];V = ubase[y / 2 * width + (x / 2) * 2 + 1];R = Y + 1.4075 * (V - 128);G = Y - 0.3455 * (U - 128) - 0.7169 * (V - 128);B = Y + 1.779 * (U - 128);if(R > 255)R = 255;else if(R < 0)R = 0;if(G > 255)G = 255;else if(G < 0)G = 0;if(B > 255)B = 255;else if(B < 0)B = 0;rgb[index++] = R; //Rrgb[index++] = G; //Grgb[index++] = B; //B}}
}void c_yuyv_to_rgb(unsigned char *yuyvdata, unsigned char *rgbdata, int w, int h)
{int r1, g1, b1;int r2, g2, b2;for (int i = 0; i < w * h / 2; i++){char data[4];memcpy(data, yuyvdata + i * 4, 4);// Y0 U0 Y1 V1-->[Y0 U0 V1] [Y1 U0 v1]unsigned char Y0 = data[0];unsigned char U0 = data[1];unsigned char Y1 = data[2];unsigned char V1 = data[3];r1 = Y0 + 1.4075 * (V1-128); if(r1>255)r1=255; if(r1<0)r1=0;g1 =Y0 - 0.3455 * (U0-128) - 0.7169 * (V1-128); if(g1>255)g1=255; if(g1<0)g1=0;b1 = Y0 + 1.779 *(U0-128); if(b1>255)b1=255; if(b1<0)b1=0;r2 = Y1+1.4075* (V1-128) ;if(r2>255)r2=255; if(r2<0)r2=0;g2 = Y1- 0.3455 *(U0-128) - 0.7169*(V1-128); if(g2>255)g2=255;if(g2<0)g2=0;b2 = Y1+ 1.779 * (U0-128);if(b2>255)b2=255;if(b2<0)b2=0;rgbdata[i * 6 + 0] = r1;rgbdata[i * 6 + 1] = g1;rgbdata[i * 6 + 2] = b1;rgbdata[i * 6 + 3] = r2;rgbdata[i * 6 + 4] = g2;rgbdata[i * 6 + 5] = b2;}
}

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"#include <QDebug>
#include <QProcess>
#include <QStorageInfo>
#include <QDirIterator>
#include <libudev.h>
#include <QSocketNotifier>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);cameraThread1 = new CameraThread1;//cameraThread1->camera1Dev = "/dev/video-camera0";connect(cameraThread1, &CameraThread1::showCamera1, this, &MainWindow::displayCam1Buf);cameraThread1->start();}void MainWindow::displayCam1Buf(unsigned char *buffer)
{QImage img;QPixmap pixmap;img = QImage(buffer, 1280, 720, QImage::Format_RGB888);QPixmap scaledPixmap = pixmap.fromImage(img);ui->camera1->setPixmap(scaledPixmap);// qDebug("<<<<<< %s %d\n",__FILE__,__LINE__);
}MainWindow::~MainWindow()
{delete ui;
}

相关文章:

  • mysql编程--从入门到入土
  • PPT的精细化优化与提升策略
  • Kubernetes中的Java微服务部署策略
  • 【深度学习】python之人工智能应用篇——图像生成技术(一)
  • 大数据面试-Hive
  • 用Java获取键盘输入数的个十百位数
  • 线代的学习(矩阵)
  • c语言回顾-结构体(2)
  • C++设计模式之适配器模式
  • Ubuntu配置ssh+vnc(完整版)
  • 数据结构:为什么说链表是顺序表的升级版(c语言实现)
  • pgsql给单独数据库制定账号权限
  • Kotlin 中的内联函数
  • AI与音乐:共创未来乐章还是终结艺术的颂歌?
  • Docker容器导出导入
  • HTTP--网络协议分层,http历史(二)
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • JavaScript中的对象个人分享
  • Laravel Mix运行时关于es2015报错解决方案
  • LeetCode18.四数之和 JavaScript
  • node.js
  • rabbitmq延迟消息示例
  • REST架构的思考
  • Web设计流程优化:网页效果图设计新思路
  • 阿里研究院入选中国企业智库系统影响力榜
  • 技术发展面试
  • 提醒我喝水chrome插件开发指南
  • 学习ES6 变量的解构赋值
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • python最赚钱的4个方向,你最心动的是哪个?
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 交换综合实验一
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • # Redis 入门到精通(七)-- redis 删除策略
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • #数学建模# 线性规划问题的Matlab求解
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (1)常见O(n^2)排序算法解析
  • (1)无线电失控保护(二)
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (二)PySpark3:SparkSQL编程
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (九)One-Wire总线-DS18B20
  • (六)Hibernate的二级缓存
  • (七)Appdesigner-初步入门及常用组件的使用方法说明
  • (三)模仿学习-Action数据的模仿
  • (十) 初识 Docker file
  • (实测可用)(3)Git的使用——RT Thread Stdio添加的软件包,github与gitee冲突造成无法上传文件到gitee
  • (转)Android学习笔记 --- android任务栈和启动模式
  • .chm格式文件如何阅读
  • .NET C# 操作Neo4j图数据库
  • .NET关于 跳过SSL中遇到的问题
  • /bin、/sbin、/usr/bin、/usr/sbin
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析