【Qt从摄像头视频中获取数据】
有时候需要在视频上画图,所以需要能获取到每一帧视频数据。
以前从视频文件或视频流中得到帧,一般都是使用qt + ffmpeg或qt + vlc。
qt对显示处理视频大体有以下方法:
- QMediaPlayer + QVideoWidget
这种方法只适合简单的显示视频功能,不适合对视频进行处理(比如画图)
- QMediaPlayer + QGraphicsVideoItem + QGraphicsScene + QGraphicsView
这种方法功能强大,除了显示视频功能,还可以做复杂的图形处理(具体可以查看QGraphicsScene的使用)
- QMediaPlayer + QAbstractVideoSurface
这种方法比较简单,是我下面要介给的。可以获取到每一帧视频数据,基本可以实现与qt + ffmpeg或qt + vlc相同的效果。
自定义VideoSurface:
class VideoSurface : public QAbstractVideoSurface
{Q_OBJECTpublic:VideoSurface(QObject *parent = Q_NULLPTR);~VideoSurface();QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const;bool present(const QVideoFrame &frame);signals:void frameAvailable(QVideoFrame &frame);};
实现如下:
VideoSurface::VideoSurface(QObject *parent): QAbstractVideoSurface(parent)
{
}VideoSurface::~VideoSurface()
{
}QList<QVideoFrame::PixelFormat> VideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
{QList<QVideoFrame::PixelFormat> listPixelFormats;listPixelFormats << 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;//qDebug() << listPixelFormats;// Return the formats you will supportreturn listPixelFormats;
}bool VideoSurface::present(const QVideoFrame &frame)
{// Handle the frame and do your processingif (frame.isValid()){QVideoFrame cloneFrame(frame);emit frameAvailable(cloneFrame);return true;}return false;
}
看了上面的代码就知道,只需要外部连接frameAvailable信号就可以获取到每一帧数据。
具体使用:
QMediaPlayer *mediaPlayer = new QMediaPlayer;
VideoSurface *videoSurface = new VideoSurface;
mediaPlayer->setVideoOutput(videoSurface);
mediaPlayer->setMedia(QUrl("rtsp://admin:admin@192.168.1.112"));
mediaPlayer->play();
把frameAvailable信号与显示窗口的槽连接,比如:
connect(videoSurface, SIGNAL(frameAvailable(QVideoFrame &)), this, SLOT(ProcessFrame(QVideoFrame &)));
void QtVideoTest::ProcessFrame(QVideoFrame &frame)
{qDebug() << "=============ProcessFrame===============";qDebug() << "width : " << frame.width() << " height : " << frame.height();qDebug() << "start time : " << frame.startTime()/1000 << "ms";qDebug() << "end time : " << frame.endTime()/1000 << "ms";qDebug() << "pixelFormat :" << frame.pixelFormat();frame.map(QAbstractVideoBuffer::ReadOnly);QImage recvImage(frame.bits(), frame.width(), frame.height(), QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()));qDebug() << "frame data size :" << frame.mappedBytes();frame.unmap();
}
如上,QVideoFrame转QImage,拿QImage进行画图操作就简单了。
Qt6.2.3获取摄像头录制YUV文件,逐帧获取录制,使用QVideoSink
Qt6.2.3获取摄像头录制YUV文件,逐帧获取录制,使用QVideoSink
必须要使用到QVideoSink,相应的依赖模块有:QMediaCaptureSession、QMediaDevices、QCamera、QVideoFrame
具体的使用方法是:
1、创建一个QMediaCaptureSession:
QMediaCaptureSession m_captureSession;
2、设置摄像头:
m_captureSession.setCamera(new QCamera(QMediaDevices::defaultVideoInput()));
3、设置YUV逐帧输出:
m_captureSession.setVideoSink(new QVideoSink m_videoSink);
4、设置YUV格式:
void QVideoSink::setVideoFrame(const QVideoFrame &frame)
5、主动获取一帧YUV数据:
QVideoFrame QVideoSink::videoFrame() const
6、被动接收每一帧:
connect(m_videoSink, &QVideoSink::videoFrameChanged, YourClass, yourParseFunction);
7、获取帧数据:
videoFrame.map(QVideoFrame::ReadOnly);
m_file.write((const char *)videoFrame.bits(0和1), videoFrame.mappedBytes(0和1));
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QCameraFormat>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);m_camera = new QCamera(QMediaDevices::defaultVideoInput());m_captureSession.setCamera(m_camera);m_captureSession.setVideoSink(&m_videoSink);connect(&m_videoSink, &QVideoSink::videoFrameChanged, this, &MainWindow::on_frame_changed);m_camera->start();m_file.setFileName("test.nv12");m_file.open(QIODevice::WriteOnly | QIODevice::Truncate);
}MainWindow::~MainWindow()
{m_camera->stop();m_file.close();delete ui;
}void MainWindow::on_frame_changed(const QVideoFrame &frame)
{QVideoFrame videoFrame = frame;/*** 我的电脑上返回的格式是Format_NV12:18,每个像素1.5字节,一帧1382400字节,* 如果你需要用别的YUV或者RGB格式,则需要自己设置QVideoSink或者QCamera格式*/QVideoFrameFormat::PixelFormat pixelFormat = videoFrame.pixelFormat();int width = videoFrame.width();int height = videoFrame.height();int planeCount = videoFrame.planeCount();uchar *pdata = nullptr;int len = 0;videoFrame.map(QVideoFrame::ReadOnly);for (int i = 0; i < planeCount; i++) {pdata = videoFrame.bits(i);len = videoFrame.mappedBytes(i);m_file.write((const char *)pdata, len);}frame_num++;qDebug("%d, %d, %d, %d, %d, %p, %d", frame_num,pixelFormat, width, height, planeCount, pdata, len);videoFrame.unmap();
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QCamera>
#include <QMediaCaptureSession>
#include <QMediaDevices>
#include <QVideoSink>
#include <QVideoFrame>
#include <QFile>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:Ui::MainWindow *ui;QMediaCaptureSession m_captureSession;QVideoSink m_videoSink;QCamera *m_camera;QFile m_file;int frame_num = 0;private slots:void on_frame_changed(const QVideoFrame &frame); // 一帧视频到来的信号
};
#endif // MAINWINDOW_H
main.cpp:
/*** \brief Qt6.2.3要逐帧获取YUV需要使用QVideoSink和QMediaCaptureSession* \details 编译运行后,窗口弹出即开始录制YUV文件,关闭窗口后文件保存* \note 保存的文件在本工程文件夹上级目录中的debug*目录下的test.nv12* 我的电脑摄像头默认输出是YUV NV12格式1280 * 720* 播放方式是安装ffmpeg软件后,在test.nv12文件目录下使用命令:* ffplay -f rawvideo -pix_fmt nv12 -video_size 1280x720 test.nv12*/#include "mainwindow.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}
005_yuv_input_save_file.pro:
QT += core gui
QT += multimediagreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++17# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mainwindow.cppHEADERS += \mainwindow.hFORMS += \mainwindow.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
mainwindow.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>MainWindow</class><widget class="QMainWindow" name="MainWindow"><property name="geometry"><rect><x>0</x><y>0</y><width>800</width><height>600</height></rect></property><property name="windowTitle"><string>MainWindow</string></property><widget class="QWidget" name="centralwidget"><layout class="QVBoxLayout" name="verticalLayout"><item><widget class="QPushButton" name="pushButton"><property name="text"><string>窗口不要开太久!开几秒就够了,否则存储的YUV文件会把你的硬盘塞满!</string></property></widget></item></layout></widget><widget class="QMenuBar" name="menubar"><property name="geometry"><rect><x>0</x><y>0</y><width>800</width><height>22</height></rect></property></widget><widget class="QStatusBar" name="statusbar"/></widget><resources/><connections/>
</ui>
报错:`QVideoFrame::unmap() was called more times then QVideoFrame::map()
原因:格式对不上QVideoFrame转QImage格式对照表`
QVideoFrame Class
参考:QT——QCamera摄像头的切换、分辨率切换、截图显示
cv::QVideoFrame转QImage失败原因及解决方案
相关文章:
【Qt从摄像头视频中获取数据】
有时候需要在视频上画图,所以需要能获取到每一帧视频数据。 以前从视频文件或视频流中得到帧,一般都是使用qt ffmpeg或qt vlc。 qt对显示处理视频大体有以下方法: QMediaPlayer QVideoWidget 这种方法只适合简单的显示视频功能ÿ…...
视频截取中的UI小组件
引言 视频截取在社交类 APP 中十分常见。有了上传视频的功能,就不可避免地需要提供截取和编辑的选项。如果我们过度依赖第三方库,项目的代码可能会变得异常臃肿,因为这些库往往包含许多我们用不到的功能,而且它们的 UI 样式和功能…...
java设计模式--结构型模式
结构性模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式 适配器模式 适配器模式(Adapter Pattern) 充当两个不兼容接口之间的桥梁,属于结构型设计模式。目的是将一个类的接口转换为另一个接口&am…...
消息中间件:Kafka消息丢失与堆积问题分析与解决方案
消息中间件:Kafka消息丢失与堆积问题分析与解决方案 Kafka作为分布式消息系统,广泛应用于实时数据流处理、大数据分析等领域。然而,在实际应用中,Kafka可能会面临消息丢失和消息堆积的问题,这些问题如果得不到有效处理…...
mac终端代理配置指南
终端代理配置指南 在 macOS 中,你可以通过几种不同的方法来配置终端代理。这里介绍两种常见的设置方式:使用 alias 和 shell 函数。 方法 1:使用 Alias 配置代理 打开终端配置文件 默认情况下,macOS 终端使用的是 zsh。如果你的系…...
mbedTLS生成客户端,服务端密钥及CA证书
1. mbedTLS源码:https://github.com/Mbed-TLS/mbedtls.git 2. 生成步骤: 2.1 编译上述源码 2.2 生成CA私钥和自签名证书: 进入编译的build目录,比如:/mbedtls-development/build# 2.2.1生成CA私钥 执行下面的命令&…...
如何有效应对突发技术故障:以网易云音乐为例
引言 在互联网行业,任何一个在线服务都可能遭遇突发的技术故障。这些故障不仅影响用户体验,还可能对公司的品牌形象造成损害。因此,如何快速响应并高效解决这些问题成为了每一个开发团队的重要课题。本文将以网易云音乐在2024年8月19日下午遭…...
上传文件到github仓库
REF: https://blog.csdn.net/litianxiang_kaola/article/details/74075151 已有repository,往仓库里更新内容 点击gitlab里的clone 在git bash中使用git clone,这个时候会将网上的仓库下载到本地,你可以把想要更新的内容直接拖到仓库里 …...
clip-path实现图片边角的裁剪
img {clip-path: polygon(0 7px,7px 0,calc(100% - 20px) 0,100% 20px,100% 100%,16px 100%,0 calc(100% - 16px));}每一个逗号隔开的就是路径坐标 左上角的两个点 0 7px ,7px 0 右上角 calc(100% - 20px) 0,100% 20px 相当于通过这些点练成的线的圈起来的部分就是剩…...
【C++ Primer Plus习题】2.7
问题: 解答: #include <iostream> using namespace std;void print(int hour, int minute) {cout << "Time:" << hour << ":" << minute << endl; }int main() {int hour0;int minute 0;cout << "请输入…...
uboot中 fastboot udp 协议分析
注: 1. 本文所分析的fastboot源码不是android下的源码,而是恩智浦芯片厂商在IMX6UL芯片的uboot源码中自己实现的源码,二者不同,请读者注意区分。一些图片是网上找到的,出处不好注明,请见谅。 2. 分析fastbo…...
redis hash类型的命令
1.hset 格式: hset key field value [field value ...](value是字符串) 返回值:设置成功的键值对的个数 2.hget:获取键值对 格式:hget key field 3.hexists:判断hash中是否存在指定 格式:…...
【OpenCV】 中使用 Lucas-Kanade 光流进行对象跟踪和路径映射
文章目录 一、说明二、什么是Lucas-Kanade 方法三、Lucas-Kanade 原理四、代码实现4.1 第 1 步:用户在第一帧绘制一个矩形4.2 第 2 步:从图像中提取关键点4.3 第 3 步:跟踪每一帧的关键点 一、说明 本文针对基于光流法的目标追踪进行叙述&am…...
ES 支持乐观锁吗?如何实现的?
本篇主要介绍一下Elasticsearch的并发控制和乐观锁的实现原理,列举常见的电商场景,关系型数据库的并发控制、ES的并发控制实践。 并发场景 不论是关系型数据库的应用,还是使用Elasticsearch做搜索加速的场景,只要有数据更新&…...
前端宝典十一:前端工程化稳定性方案
一、工程化体系介绍 1、什么是前端工程化 前端工程化 前端 软件工程;前端工程化 将工程方法系统化地应用到前端开发中;前端工程化 系统、严谨、可量化的方法开发、运营和维护前端应用程序;前端工程化 基于业务诉求,梳理出最…...
yum 数据源的切换
本来准备安装一个ntp 服务器时间进行同步,但是使用yum install ntp -y 但是却失败了 原因是yum自带的镜像源不能用了,所以要想使用yum 多功能只能切换yum 对应的镜像源了 如果你的服务商是可以使用wget命令的: wget -O /etc/yum.repos.d/Ce…...
MySQL入门学习-命令行工具.mysqlbinlog
MySQL 命令行工具mysqlbinlog用于处理二进制日志文件。 一、关于mysqlbinlog工具的详细介绍: 1、命令行工具mysqlbinlog的特点和使用方法: - 特点: - 可以解析和查看二进制日志文件的内容。 - 支持多种输出格式,如文本、SQ…...
WARNING XXX is not overriding the create method in batch
WARNING XXX is not overriding the create method in batch api.modeldef create(self, vals):quvals[name]youqu self.env[crm.qu].sudo().search([(name, , qu),(shi_id,,vals[shi_id])])if len(youqu)>0:raise UserError(_("该区名已存在,无需再填加…...
使用预训练的 ONNX 格式的目标检测模型(基于 YOLOv8n-pose)姿态监测
具体步骤如下: 加载图像: 从指定路径读取一张图像(这里假设图像名为bus.jpg)。将图像从 BGR 颜色空间转换为 RGB 颜色空间。 图像预处理: 计算图像的高度、宽度,并确定其中的最大值作为新图像的边长。创建一…...
matlab实现模拟退火算法
模拟退火算法(Simulated Annealing, SA)是一种通用概率优化算法,用于在给定的大搜索空间内寻找问题的近似全局最优解。该算法灵感来源于物理学中固体物质的退火过程,其中温度逐渐降低,粒子逐渐趋于能量最低状态。 在M…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
