欢迎访问宙启技术站
智能推送

Jetson TX1开发中V4L2+OpenCV3.1以MJPG格式读取USB摄像头图像并实时显示的示例分析

发布时间:2023-05-16 03:33:39

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的强大性能和丰富的开发工具,为图像处理、深度学习等领域提供了丰富的可能性,在实际开发中可以从多个角度进行优化和调试,以实现更加高效和优秀的应用效果。