Linux QT 使用V4L2打开摄像头获取图像

46 篇文章 2 订阅
46 篇文章 0 订阅

理论部分网上有,直接上程序,亲测可用:

h文件

#ifndef V4L2_H
#define V4L2_H

#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

using namespace std;

#define IMAGE_W 640
#define IMAGE_H 480

#define FREAM_NUM 4

//映射每个缓冲帧
struct buffer
{
    void* start;
    size_t length;
};

class V4L2
{
public:
    V4L2();

    int V4L2Init(string port);

    int V4L2Data(unsigned char *bufData);

    void V4L2Close();

private:
    void yuv_to_rgb(unsigned char* yuv, unsigned char *rgb);

    int fd;
    struct buffer buffers[FREAM_NUM];
    unsigned int m_buffers; //帧缓冲区数量
};

#endif // V4L2_H

cpp文件:将输出的yuv转成rgb在界面上显示

#include "v4l2.h"

V4L2::V4L2()
{
    fd = -1;
}

int V4L2::V4L2Init(string port)
{
    //打开摄像头
    fd = open(port.c_str(), O_RDWR, 0777);
    if(fd < 0) {
        cout<<"open camera error!!!"<<endl;
        return -1;
    }

    //查询视频设备的能力
    struct v4l2_capability cap;
    memset(&cap, 0, sizeof(cap));
    if(ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
        cout<<"cap error !!!"<<endl;
        return -1;
    }

    if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) != V4L2_CAP_VIDEO_CAPTURE)
    {
        cout<<"Device: supports capture error."<<endl;
        return -1;
    }

    if ((cap.capabilities & V4L2_CAP_STREAMING) != V4L2_CAP_STREAMING)
    {
        cout<<"Device: supports streaming error."<<endl;
        return -1;
    }


    //设置视频采集的参数
    //1.设置视频的制式
    //2.设置视频图像的采集窗口大小
    //3.设置视频的格式
    struct v4l2_format fmt;
    memset(&fmt, 0, sizeof(fmt));
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = IMAGE_W;
    fmt.fmt.pix.height = IMAGE_H;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
    if(ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
        cout<<"camera set format error!!!"<<endl;
        return -1;
    }
    //4.设置视频的帧率
    struct v4l2_streamparm parm;
    memset(&parm, 0, sizeof(parm));
    parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    parm.parm.capture.timeperframe.numerator = 1;
    parm.parm.capture.timeperframe.denominator = 10;
    parm.parm.capture.capturemode = 0;
    if(ioctl(fd, VIDIOC_S_PARM, &parm) < 0) {
        cout<<"camera set streamparm error!!!"<<endl;
        m_cameraConnectFlag = false;
        return -1;
    }
    //5.设置视频的旋转方式

    //申请若干个帧缓冲区,一般不小于3个
    //查询帧缓冲区在内核空间中的长度和偏移量
    struct v4l2_requestbuffers req;
    memset(&req, 0, sizeof(req));
    req.count = FREAM_NUM;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    if(-1 == (ioctl(fd, VIDIOC_REQBUFS, &req))) {
        cout<<"camera malloc requestbuffers error!!!"<<endl;
        return -1;
    }

    for(m_buffers = 0; m_buffers < req.count; ++ m_buffers) {
        struct v4l2_buffer buf;
        memset(&buf, 0, sizeof(buf));
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = m_buffers;
        if(-1 == (ioctl(fd, VIDIOC_QUERYBUF, &buf))) {
            cout<<"camera buffer error!!!"<<endl;
            return -1;
        }
        buffers[m_buffers].length = buf.length;
        buffers[m_buffers].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
        if(buffers[m_buffers].start == MAP_FAILED) {
            cout<<"camera mmap error!!!"<<endl;
            return -1;
        }
    }

    //开启视频采集
    enum v4l2_buf_type type;
    for(unsigned int i=0;i<m_buffers;i++) {
        struct v4l2_buffer buf;
        memset(&buf, 0, sizeof(buf));
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = i;
        if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))
            cout<<"camera qbuf error!!!"<<endl;
    }
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if(-1 == ioctl(fd, VIDIOC_STREAMON, &type)) {
        cout<<"camera stream on error!!!"<<endl;
    }

    return 0;
}

int V4L2::V4L2Data(unsigned char* bufData)
{
    struct v4l2_buffer buf;
    memset(&buf, 0, sizeof(buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    if(-1 == ioctl(fd, VIDIOC_DQBUF, &buf)) {
        cout<<"camera dqbuf error!!!"<<endl;
        return -1;
    }

    //数据处理
    unsigned char temp[buf.bytesused];//[buffers[buf.index].length];
    memcpy(temp, buffers[buf.index].start, buf.bytesused);//buffers[buf.index].length);
    yuv_to_rgb(temp, bufData);

    if(-1 == ioctl(fd, VIDIOC_QBUF, &buf)) {
        cout<<"camera qbuf error!!!"<<endl;
        return -1;
    }

    return 0;
}

void V4L2::V4L2Close()
{
    //关闭视频采集
    enum v4l2_buf_type type;
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if(-1 == (ioctl(fd, VIDIOC_STREAMOFF, &type))) {
        cout<<"camera stream off error!!!"<<endl;
        return;
    }

    //释放内存
    for(unsigned int i=0;i<m_buffers;i++) {
        if(-1 == munmap(buffers[i].start, buffers[i].length))
            cout<<"camera munmap error!!!"<<endl;
    }

    close(fd);
}

void V4L2::yuv_to_rgb(unsigned char *yuv, unsigned char *rgb)
{
    unsigned int i;
    unsigned char* y0 = yuv + 0;
    unsigned char* u0 = yuv + 1;
    unsigned char* y1 = yuv + 2;
    unsigned char* v0 = yuv + 3;

    unsigned  char* r0 = rgb + 0;
    unsigned  char* g0 = rgb + 1;
    unsigned  char* b0 = rgb + 2;
    unsigned  char* r1 = rgb + 3;
    unsigned  char* g1 = rgb + 4;
    unsigned  char* b1 = rgb + 5;

    float rt0 = 0, gt0 = 0, bt0 = 0, rt1 = 0, gt1 = 0, bt1 = 0;

    for(i = 0; i <= (IMAGE_W * IMAGE_H) / 2 ;i++)
    {
        bt0 = 1.164 * (*y0 - 16) + 2.018 * (*u0 - 128);
        gt0 = 1.164 * (*y0 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
        rt0 = 1.164 * (*y0 - 16) + 1.596 * (*v0 - 128);

        bt1 = 1.164 * (*y1 - 16) + 2.018 * (*u0 - 128);
        gt1 = 1.164 * (*y1 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
        rt1 = 1.164 * (*y1 - 16) + 1.596 * (*v0 - 128);


        if(rt0 > 250)      rt0 = 255;
        if(rt0< 0)        rt0 = 0;

        if(gt0 > 250)     gt0 = 255;
        if(gt0 < 0)    gt0 = 0;

        if(bt0 > 250)    bt0 = 255;
        if(bt0 < 0)    bt0 = 0;

        if(rt1 > 250)    rt1 = 255;
        if(rt1 < 0)    rt1 = 0;

        if(gt1 > 250)    gt1 = 255;
        if(gt1 < 0)    gt1 = 0;

        if(bt1 > 250)    bt1 = 255;
        if(bt1 < 0)    bt1 = 0;

        *r0 = (unsigned char)rt0;
        *g0 = (unsigned char)gt0;
        *b0 = (unsigned char)bt0;

        *r1 = (unsigned char)rt1;
        *g1 = (unsigned char)gt1;
        *b1 = (unsigned char)bt1;

        yuv = yuv + 4;
        rgb = rgb + 6;
        if(yuv == NULL)
            break;

        y0 = yuv;
        u0 = yuv + 1;
        y1 = yuv + 2;
        v0 = yuv + 3;

        r0 = rgb + 0;
        g0 = rgb + 1;
        b0 = rgb + 2;
        r1 = rgb + 3;
        g1 = rgb + 4;
        b1 = rgb + 5;
    }
}

具体工程文件:https://download.csdn.net/download/yuchunhai321/12154142

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是一个使用QTLinux系统中使用V4L2读取摄像头图像流数据的例程: ```c++ #include <QCoreApplication> #include <QDebug> #include <QImage> #include <QTimer> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/videodev2.h> #include <errno.h> #include <unistd.h> #define CAMERA_DEVICE "/dev/video0" // 摄像头设备路径 #define IMAGE_WIDTH 640 // 图像宽度 #define IMAGE_HEIGHT 480 // 图像高度 #define BUFFER_COUNT 4 // 缓存帧数 int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); int camera_fd = open(CAMERA_DEVICE, O_RDWR); // 打开摄像头设备 if (camera_fd == -1) { qCritical() << "Open camera device failed:" << strerror(errno); return -1; } // 设置摄像头参数 struct v4l2_capability cap; struct v4l2_format fmt; struct v4l2_requestbuffers reqbuf; struct v4l2_buffer buf; ioctl(camera_fd, VIDIOC_QUERYCAP, &cap); if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { qCritical() << "Device is not a video capture device"; return -1; } fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = IMAGE_WIDTH; fmt.fmt.pix.height = IMAGE_HEIGHT; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; fmt.fmt.pix.field = V4L2_FIELD_ANY; ioctl(camera_fd, VIDIOC_S_FMT, &fmt); reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbuf.memory = V4L2_MEMORY_MMAP; reqbuf.count = BUFFER_COUNT; ioctl(camera_fd, VIDIOC_REQBUFS, &reqbuf); struct buffer { void *start; size_t length; } buffers[BUFFER_COUNT]; for (int i = 0; i < BUFFER_COUNT; ++i) { buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; ioctl(camera_fd, VIDIOC_QUERYBUF, &buf); buffers[i].length = buf.length; buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, camera_fd, buf.m.offset); ioctl(camera_fd, VIDIOC_QBUF, &buf); } enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(camera_fd, VIDIOC_STREAMON, &type); // 定时器读取图像 QTimer timer; QObject::connect(&timer, &QTimer::timeout, [&](){ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ioctl(camera_fd, VIDIOC_DQBUF, &buf); QImage image((uchar*)buffers[buf.index].start, IMAGE_WIDTH, IMAGE_HEIGHT, QImage::Format_RGB888); image = image.rgbSwapped(); // 颜色转换 image.save("image.jpg"); // 保存图像 ioctl(camera_fd, VIDIOC_QBUF, &buf); }); timer.start(1000 / 25); // 25帧每秒 return a.exec(); } ``` 注意:上述代码仅供参考,具体实现可能需要根据不同的硬件和系统做出一些调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值