Jetson TX1开发中V4L2+OpenCV3.1以MJPG格式读取USB摄像头图像并实时显示的示例分析
Jetson TX1是一款强大的开发板,配备了8 core ARM Cortex-A57 CPU以及256 core Maxwell GPU,可以用于各种深度学习、图像处理等应用。在开发过程中,使用摄像头进行图像采集和处理是常见的需求之一。本文将介绍如何使用V4L2和OpenCV3.1来读取USB摄像头以MJPG格式格式化并实时显示。
V4L2(Video for Linux Two)是一个视频设备驱动和API的框架,用于在Linux系统下的视频采集和输出。在Jetson TX1开发板上,可以通过V4L2库来直接访问USB摄像头,并进行视频流捕获和处理。
首先,需要安装V4L2库和OpenCV3.1。可以通过以下命令来安装:
sudo apt-get install libv4l-dev
sudo apt-get install libopencv-dev
安装完成后,可以开始编写代码。下面是一个基本的实现示例:
1.包含所需库头文件
#include <opencv2/opencv.hpp>
#include <linux/videodev2.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
2.定义常数
#define WIDTH 640
#define HEIGHT 480
#define FPS 30
3.打开设备
int dev_fd;
dev_fd = open("/dev/video0", O_RDWR | O_NONBLOCK);
if (dev_fd == -1)
{
std::cout << "Open Error" << std::endl;
return -1;
}
4.设置格式和帧率
v4l2_capability capability;
v4l2_fmtdesc format;
v4l2_format streamFormat = {0};
v4l2_streamparm streamParam = {0};
if (ioctl(dev_fd, VIDIOC_QUERYCAP, &capability) < 0)
{
std::cout << "V4L2: can't get device capbility" << std::endl;
return -1;
}
format.index = 0;
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(dev_fd, VIDIOC_ENUM_FMT, &format) == 0)
{
std::cout << "V4L2: " << format.description << std::endl;
format.index++;
}
streamFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
streamFormat.fmt.pix.width = WIDTH;
streamFormat.fmt.pix.height = HEIGHT;
streamFormat.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
streamFormat.fmt.pix.field = V4L2_FIELD_ANY;
if (ioctl(dev_fd, VIDIOC_S_FMT, &streamFormat) < 0)
{
std::cout << "V4L2: set format error" << std::endl;
return -1;
}
memset(&streamParam, 0, sizeof(streamParam));
streamParam.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
streamParam.parm.capture.timeperframe.numerator = 1;
streamParam.parm.capture.timeperframe.denominator = FPS;
if (ioctl(dev_fd, VIDIOC_S_PARM, &streamParam) < 0)
{
std::cout << "V4L2: set fps error" << std::endl;
return -1;
}
5.配置内存映射缓冲区
v4l2_requestbuffers requestbuffers = {0};
v4l2_buffer querybuffer = {0};
char *buffer = NULL;
requestbuffers.count = 1;
requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
requestbuffers.memory = V4L2_MEMORY_MMAP;
if (ioctl(dev_fd, VIDIOC_REQBUFS, &requestbuffers) < 0)
{
std::cout << "V4L2: request buffers error" << std::endl;
return -1;
}
querybuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
querybuffer.memory = V4L2_MEMORY_MMAP;
querybuffer.index = 0;
if (ioctl(dev_fd, VIDIOC_QUERYBUF, &querybuffer) < 0)
{
std::cout << "V4L2: query buffer error" << std::endl;
return -1;
}
buffer = (char *)mmap(NULL, querybuffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, querybuffer.m.offset);
if (buffer == MAP_FAILED)
{
std::cout << "V4L2: buffer mmap error" << std::endl;
return -1;
}
6.开始采集并处理图像
for (int i = 0; i < 10; i++)
{
memset(&querybuffer, 0, sizeof(querybuffer));
querybuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
querybuffer.memory = V4L2_MEMORY_MMAP;
querybuffer.index = 0;
if (ioctl(dev_fd, VIDIOC_QBUF, &querybuffer) < 0) // 将缓冲区入队
{
std::cout << "V4L2: Query buffer error" << std::endl;
return -1;
}
if (ioctl(dev_fd, VIDIOC_STREAMON, &querybuffer.type) < 0) // 开始采集
{
std::cout << "V4L2: Stream on error" << std::endl;
return -1;
}
if (ioctl(dev_fd, VIDIOC_DQBUF, &querybuffer) < 0) // 将缓冲区出队
{
std::cout << "V4L2: Dequeue buffer error" << std::endl;
return -1;
}
Mat img = Mat(HEIGHT, WIDTH, CV_8UC3, buffer);
imshow("camera", img);
waitKey();
if (ioctl(dev_fd, VIDIOC_STREAMOFF, &querybuffer.type) < 0) // 结束采集
{
std::cout << "V4L2: Stream off error" << std::endl;
return -1;
}
}
7.释放资源
munmap(buffer, querybuffer.length);
close(dev_fd);
通过以上代码,可以实现从USB摄像头读取数据并实时处理和显示。其中,V4L2库提供了许多函数和接口,可以方便地进行格式设置、缓冲区管理和视频流控制等操作。
需要注意的是,本文中仅介绍了基本的V4L2和OpenCV3.1的使用方法。在实际开发中,还需要考虑很多其他因素,例如图像质量、帧率、延迟、实时性等。同时,还需要注意保证摄像头的兼容性和稳定性,以确保应用的稳定性和优良性。
总之,Jetson TX1的强大性能和丰富的开发工具,为图像处理、深度学习等领域提供了丰富的可能性,在实际开发中可以从多个角度进行优化和调试,以实现更加高效和优秀的应用效果。
