通常,如果你只是想打开UVC(web camera)并显示数据的话,那最简单的方式就是使用类似下面的代码,

class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = nullptr):QWidget(parent),ui(new Ui::Widget){ui->setupUi(this);mCamera = new QCamera(this);mCameraViewfinder = new QCameraViewfinder(this);mCameraImageCapture = new QCameraImageCapture(mCamera, this);mLayout = new QVBoxLayout;mCamera->setViewfinder(mCameraViewfinder);mLayout->addWidget(mCameraViewfinder);mLayout->setMargin(0);ui->scrollArea->setLayout(mLayout);}~Widget(){...};private slots:void on_captureButton_clicked(){...};void on_stopButton_clicked(){...};void on_playButton_clicked(){...};private:Ui::Widget *ui;QCamera *mCamera;QCameraViewfinder *mCameraViewfinder;QCameraImageCapture *mCameraImageCapture;QVBoxLayout *mLayout;
};

如果使用QGraphicsView和QGraphicsScene的方式,则通常用QGraphicsVideoItem会更合适,

和前面的代码类似,

QGraphicsView* gView = NULL;
QGraphicsScene* gScene = NULL;
QGraphicsVideoItem* gVideoItem = NULL;mCamera = new QCamera(this);gScene = new QGraphicsScene(0, 0, 800, 600);gView = new QGraphicsView;gView->setScene(gScene);ui->gridLayout->addWidget(gView); //setCentralWidget(view);gVideoItem = new GraphVideoItem;mCamera->setViewfinder(gVideoItem);gVideoItem->setSize(QSizeF(800, 600));gVideoItem->setPos(0, 0);gScene->addItem(gVideoItem);

以上的问题是,如果我们 需要把每一帧数据收集起来,例如压缩成mp4,或者通过网络发送出去,或者需要对他进行视觉图形处理(这在机器视觉中是必须的),那就必须想办法把每一帧图像转变成QImage才行。

这里我就不讲理论了,我把这个写成了一个简单易用的头文件,除了QT之外,没有任何其他依赖。如果想看完整的demo,请参考链接:

https://github.com/SpaceView/WebCamera_to_QImage_for_Qt

如果只想用到这个类,可以直接看下面的源码(源码是参考了附录【1】的源码并进行了一些修改,同时也修复了一些不同版本引发的BUG),如下,

#ifndef WEBCAME_H
#define WEBCAME_H#include <QObject>
#include <QAbstractVideoSurface>
#include <QCamera>
#include <QCameraInfo>
#include <QVideoFrame>
#include <QMetaEnum>
#include <QImage>#include <QDebug>struct CameraInfo
{QString      identify;    /* Identify of device (maybe a device path) */QString      description; /* For display */QList<QSize> resolutionList;QStringList  formatList;
};enum FormatType {MJPEG,YUYV
};struct Format {int w;int h;FormatType imageFormat;int frameRate;
};static QImage imageFromVideoFrame(const QVideoFrame& buffer)
{QImage img;QVideoFrame frame(buffer);  // make a copy we can call map (non-const) onframe.map(QAbstractVideoBuffer::ReadOnly);QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat());// BUT the frame.pixelFormat() is QVideoFrame::Format_Jpeg, and this is// mapped to QImage::Format_Invalid by// QVideoFrame::imageFormatFromPixelFormatif (imageFormat != QImage::Format_Invalid) {img = QImage(frame.bits(),frame.width(),frame.height(),// frame.bytesPerLine(),imageFormat);} else {// e.g. JPEGint nbytes = frame.mappedBytes();img = QImage::fromData(frame.bits(), nbytes);}frame.unmap();return img;
}class WebCameraCapture : public QAbstractVideoSurface
{Q_OBJECT
public:enum PixelFormat {Format_Invalid,Format_ARGB32,Format_ARGB32_Premultiplied,Format_RGB32,Format_RGB24,Format_RGB565,Format_RGB555,Format_ARGB8565_Premultiplied,Format_BGRA32,Format_BGRA32_Premultiplied,Format_BGR32,Format_BGR24,Format_BGR565,Format_BGR555,Format_BGRA5658_Premultiplied,Format_AYUV444,Format_AYUV444_Premultiplied,Format_YUV444,Format_YUV420P,Format_YV12,Format_UYVY,Format_YUYV,Format_NV12,Format_NV21,Format_IMC1,Format_IMC2,Format_IMC3,Format_IMC4,Format_Y8,Format_Y16,Format_Jpeg,Format_CameraRaw,Format_AdobeDng,#ifndef Q_QDOCNPixelFormats,
#endifFormat_User = 1000};Q_ENUM(PixelFormat)explicit WebCameraCapture(QObject *parent = 0) : QAbstractVideoSurface(parent){}QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const override{Q_UNUSED(handleType);return QList<QVideoFrame::PixelFormat>()<< QVideoFrame::Format_ARGB32<< QVideoFrame::Format_ARGB32_Premultiplied<< QVideoFrame::Format_RGB32<< QVideoFrame::Format_RGB24<< QVideoFrame::Format_RGB565<< QVideoFrame::Format_RGB555<< QVideoFrame::Format_ARGB8565_Premultiplied<< QVideoFrame::Format_BGRA32<< QVideoFrame::Format_BGRA32_Premultiplied<< QVideoFrame::Format_BGR32<< QVideoFrame::Format_BGR24<< QVideoFrame::Format_BGR565<< QVideoFrame::Format_BGR555<< QVideoFrame::Format_BGRA5658_Premultiplied<< QVideoFrame::Format_AYUV444<< QVideoFrame::Format_AYUV444_Premultiplied<< QVideoFrame::Format_YUV444<< QVideoFrame::Format_YUV420P<< QVideoFrame::Format_YV12<< QVideoFrame::Format_UYVY<< QVideoFrame::Format_YUYV<< QVideoFrame::Format_NV12<< QVideoFrame::Format_NV21<< QVideoFrame::Format_IMC1<< QVideoFrame::Format_IMC2<< QVideoFrame::Format_IMC3<< QVideoFrame::Format_IMC4<< QVideoFrame::Format_Y8<< QVideoFrame::Format_Y16<< QVideoFrame::Format_Jpeg<< QVideoFrame::Format_CameraRaw<< QVideoFrame::Format_AdobeDng;}bool present(const QVideoFrame &frame) override{if (frame.isValid()) {/*//NOTE: for version > 5.15.x;QImage image = frame.image(); // This function was introduced in Qt 5.15.QImage::Format ifmt = image.format();qDebug() << ifmt;emit frameAvailable(image);*/QImage image = imageFromVideoFrame(frame);emit frameAvailable(image);return true;}return false;}signals:void frameAvailable(QImage& image);};class WebCamera : public QObject
{Q_OBJECT
public:explicit WebCamera(QCameraInfo cameraInfo = QCameraInfo::defaultCamera(), QObject *parent = 0) : QObject(parent){m_started = false;m_camera = NULL;m_cameraCapture = NULL;if (cameraInfo.isNull()) {qDebug() << __LINE__ << __FUNCTION__;return;}m_cameraDeviceInfo = cameraInfo;m_cameraFormat.w = 640;m_cameraFormat.h = 480;m_cameraFormat.frameRate = 15;m_cameraFormat.imageFormat = MJPEG;m_cameraCapture = new WebCameraCapture;connect(m_cameraCapture, SIGNAL(frameAvailable(QImage&)), this, SLOT(grabImage(QImage&)));m_cameraPixelFormatEnum = QMetaEnum::fromType<WebCameraCapture::PixelFormat>();}~WebCamera(){if (m_camera != NULL) {delete m_camera;m_camera = NULL;}if (m_cameraCapture != NULL) {delete m_cameraCapture;m_cameraCapture = NULL;}}static QList<CameraInfo> queryCameraDevices(){QList<CameraInfo> result;QList<QCameraInfo> infos = QCameraInfo::availableCameras();foreach (QCameraInfo each, infos) {CameraInfo info;info.identify = each.deviceName();info.description = each.description();result.append(info);}return result;}bool selectCamera(const QString &cameraIdentify){bool restart = false;if (isStarted()) {CloseCamera();restart = true;}if (m_camera) {delete m_camera;m_camera = NULL;}m_cameraDeviceInfo = QCameraInfo(cameraIdentify.toLatin1());m_camera = new QCamera(m_cameraDeviceInfo);m_camera->setViewfinder(m_cameraCapture);/* Set the same format for new device */setCameraFormat(m_cameraFormat);if (restart) {OpenCamera();}return true;}CameraInfo queryCameraInfo(){queryCaps();return m_cameraInfo;}Format getCameraFormat(){QCameraViewfinderSettings set;set = m_camera->viewfinderSettings();m_cameraFormat.w = set.resolution().width();m_cameraFormat.h = set.resolution().height();m_cameraFormat.frameRate = set.minimumFrameRate();switch (set.pixelFormat()) {case QVideoFrame::Format_Jpeg:m_cameraFormat.imageFormat = MJPEG;break;case QVideoFrame::Format_YUYV:m_cameraFormat.imageFormat = YUYV;break;default:break;}return m_cameraFormat;}bool setCameraFormat(Format &format){m_cameraFormat = format;QCameraViewfinderSettings set;switch (format.imageFormat) {case MJPEG:set.setPixelFormat(QVideoFrame::Format_Jpeg);break;case YUYV:set.setPixelFormat(QVideoFrame::Format_YUYV);break;}set.setResolution(m_cameraFormat.w, m_cameraFormat.h);//QCamera can change formats dynamically,//    it will use default format when unsupported format is set.m_camera->setViewfinderSettings(set);return true;}bool OpenCamera(int index = 0){Q_UNUSED(index) // for compatibilityif (m_started) {return false;}else {if (m_cameraDeviceInfo.isNull()) {return false;}else {if(NULL==m_camera){m_camera = new QCamera(m_cameraDeviceInfo);}m_camera->setViewfinder(m_cameraCapture);m_camera->start();m_started = true;}}return true;}bool CloseCamera(){m_camera->stop();m_started = false;return true;}bool isStarted(){return m_started;}bool capture(QString filePath){if (! m_started) {return false;}return m_image.save(filePath, "jpg");}private:void queryCaps(){QList<QVideoFrame::PixelFormat> cameraFormat;m_cameraInfo.resolutionList = m_camera->supportedViewfinderResolutions();cameraFormat = m_camera->supportedViewfinderPixelFormats();m_cameraInfo.formatList.clear();for (int i = 0; i < cameraFormat.length(); i++) {m_cameraInfo.formatList.append(m_cameraPixelFormatEnum.valueToKey(cameraFormat.at(i)));}}private slots:void grabImage(QImage& image){//qDebug() << image.isNull();//m_image = image.mirrored(false, true);m_image = image;emit onImageOutput(image);}signals:void onImageOutput(QImage& image);private:QCamera *m_camera = NULL;WebCameraCapture *m_cameraCapture;QCameraInfo   m_cameraDeviceInfo;CameraInfo    m_cameraInfo;Format        m_cameraFormat;bool      m_started;QImage    m_image;QMetaEnum m_cameraPixelFormatEnum;
};#endif // WEBCAME_H

怎么使用?

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();void onImageReceive(QImage& image);public slots:void onOpenCamera();void onCloseCamera();void onGrabImage();private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "WebCamera.h"#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>QGraphicsView* gView = NULL;
QGraphicsScene* gScene = NULL;
WebCamera *gCam = NULL;
QGraphicsPixmapItem* gItem = NULL;MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);connect(ui->btnOpenCamera, &QPushButton::clicked, this, &MainWindow::onOpenCamera);connect(ui->btnCloseCamera, &QPushButton::clicked, this, &MainWindow::onCloseCamera);connect(ui->btnGrabImage, &QPushButton::clicked, this, &MainWindow::onGrabImage);gCam = new WebCamera();connect(gCam, &WebCamera::onImageOutput, this, &MainWindow::onImageReceive);gScene = new QGraphicsScene(0, 0, 800, 600);gView = new QGraphicsView;gView->setScene(gScene);ui->gridLayout_cam->addWidget(gView); //setCentralWidget(view);gItem = new QGraphicsPixmapItem;gScene->addItem(gItem);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::onImageReceive(QImage& image)
{if(gScene){gScene->setSceneRect(image.rect());}if(gItem){gItem->setPixmap(QPixmap::fromImage(image));}
}void MainWindow::onOpenCamera()
{gCam->OpenCamera();
}void MainWindow::onCloseCamera()
{gCam->CloseCamera();
}void MainWindow::onGrabImage()
{}

附录【1】

源码来源:  基于QAbstractVideoSurface实现的摄像头数据帧的捕捉_QAbstractVideoSurface-直播技术代码类资源-CSDN下载

本文结束

Qt开发高级进阶: WebCamera(UVC)摄像头使用QAbstractVideoSurface捕获视频帧到QImage相关推荐

  1. Qt开发高级进阶:如何拷贝生成后的文件到特定文件夹

    Qt编译成功后,当很多项目联合调试的时候,经常要拷贝文件. 先给出参考地址: qt - QMake - how to copy a file to the output - Stack Overflo ...

  2. Android开发高级进阶内涵段子APP项目实战视频教程

    Android开发高级进阶内涵段子APP项目实战课程视频教程下载.本课程带你从框架入手,开启我们的Android进阶之旅,开始写一步一步完善整个项目. 项目目录: 01.Android进阶之旅与你同行 ...

  3. Android app应用开发高级进阶系列专栏解读

    1.前言 在从事android app开发的几年里,最开始接触做android 都是从app开发开始做的,在做app的这几年中把积累下来的做的一些功能,都整理出来了作为自己的技术资料,在以后开发类似的 ...

  4. QT界面中实现视频帧显示的多种方法及应用

    QT界面中实现视频帧显示的多种方法及应用 (一) 引言 1.1 视频帧在QT界面中的应用场景 1.2 不同方法的性能和适用性分析 1.2.1 使用QLabel和QPixmap 1.2.2 使用QPai ...

  5. UVC摄像头开发(三)

    本次主要记录QT以及QML显示UVC摄像头采集图像以及期间可靠性崩溃和刷新频率问题 在开发UVC摄像头过程中,开始直接将图像显示在FrameBuffer上面,该方式很多猿兄已经写过了方式方法,大家搜一 ...

  6. c语言 虚拟摄像头设备_Windows下虚拟UVC摄像头开发演示

    最近在windows10 x64下开发了一个USB虚拟总线驱动,该驱动可接收上位机的指令动态创建或卸载UVC摄像头. UVC摄像头的数据通过上位机下发给驱动,驱动再给视频播放软件,这样就可以实现视频的 ...

  7. Windows下 QT 使用directdshow对UVC摄像头控制

    QT使用QCamera配合QCameraViewfinder就可以显示UVC摄像头图像 (详细看QT示例,搜索camera) 如果需要UVC原始数据就使用QVideoProbe 但是QT没有做对UVC ...

  8. Windows下虚拟UVC摄像头开发演示

    最近在windows10 x64下开发了一个USB虚拟总线驱动,该驱动可接收上位机的指令动态创建或卸载UVC摄像头. UVC摄像头的数据通过上位机下发给驱动,驱动再给视频播放软件,这样就可以实现视频的 ...

  9. C/C++Linux服务器开发高级架构师/Linux后台开发架构师丨高级进阶学习

    01 课程介绍 [录播]课程介绍(66分钟) 免费试学 [录播]磁盘存储链式的B树与B+树(131分钟) 免费试学 免费学习视频链接点击:C/C++Linux服务器开发高级架构师/Linux后台架构师 ...

最新文章

  1. C#项目中关于多个程序集下App.config文件的问题
  2. 【python3的学习之路九】函数式编程
  3. python版本升级及pip部署方法
  4. linux shell 判断文件是否存在
  5. 方正计算机软件保护进超级用户,超级用户权限补丁(SuperSU Pro)含刷机包
  6. 智慧北京02_初步ui框架_ 主界面_viewPager事件_xUtils_slidingMenu_网络缓存_数据传递...
  7. 学python电脑要装什么_初学 Python 需要安装哪些软件?
  8. 浅析 Python 的类、继承和多态
  9. YzmCMSV3.1 | 代码审计
  10. JBoss环境搭建及部署Web项目
  11. 触摸屏软键盘怎么调出来_触摸屏专用虚拟键盘下载
  12. 简单的数据库造数据方法
  13. 计蒜客习题:农场看守
  14. 显示计算机配置的命令是,查看电脑配置命令
  15. laravel框架的whereIn条件或者where条件里面的in条件怎么写
  16. android 百度唤醒,Android百度语音唤醒(has no license,错误码11002)
  17. 全局配置遮罩层(VUE Element Ui)
  18. 红蓝对抗-红蓝对抗经验总结
  19. IT人才外包的驻场外派流程是怎样的?
  20. Android 简单的计算器实现

热门文章

  1. STM32F103芯片FSMC使用外扩SRAM芯片
  2. DynamicBone 飘带飘动风吹动效果
  3. Web入门之VScode基本操作,文本框、输入框、单选框、多选框、列表、插入图片、插入按钮及跳转网页和页面
  4. HP MSA存储 raid组坏了2块硬盘的数据恢复方法
  5. 多语言 cocos 国家列表
  6. 使用浏览器调试前端的必备技巧
  7. 上学还是坐牢?百年老校“监控”学生惹争议
  8. 输入汉字自动转为拼音(jsp实现方式)
  9. 跨境电商——产品漂洋过海的底层逻辑
  10. linux 终端分屏命令vsp