Qt QML实现视频帧提取

## 前言

视频帧率(Frame Rate)是指视频播放时每秒显示的画面帧数,通常用fps(Frames Per Second)来表示。视频是由一系列静止的图像帧组成的,而视频帧率则决定了这些图像帧在单位时间内播放的速度。较高的视频帧率可以提供更流畅的视频画面,而较低的视频帧率则可能导致画面卡顿和不连贯的情况

在实际的应用开发中,经常会遇到需要处理视频的情况,例如提取视频帧用于图像处理、分析等应用。本文将介绍如何利用Qt QML实现视频帧的提取,通过简单的代码示例将图片提取保存到本地中。

## 效果

先看运行效果:

## 正文

本示例通过QML实现UI,Qt5.15 cmake编译,使用多线程处理提取,保证UI主线程不会卡顿,将提取的图片保存到本地。

提取部分,关键代码:

void FrameExtractor::stopProcessing()
{qDebug() << "停止帧提取处理";m_running.store(0);// 清空队列,避免处理不必要的帧QMutexLocker locker(&m_mutex);if (!m_frameQueue.isEmpty()) {qDebug() << "清空帧队列,当前队列长度: " << m_frameQueue.size();m_frameQueue.clear();}// 唤醒等待中的线程m_condition.wakeOne();
}void FrameExtractor::processFrames()
{qDebug() << "开始处理视频帧";while (m_running.load()) {QVideoFrame frame;// 获取下一帧{QMutexLocker locker(&m_mutex);// 如果队列为空且没有更多帧,则结束处理if (m_frameQueue.isEmpty() && m_noMoreFrames.load()) {qDebug() << "队列为空且没有更多帧,结束处理";break;}// 如果队列为空,等待新帧if (m_frameQueue.isEmpty()) {qDebug() << "队列为空,等待新帧...";m_condition.wait(&m_mutex);qDebug() << "等待结束,继续处理";continue;}frame = m_frameQueue.dequeue();qDebug() << "从队列中获取一帧,当前队列长度: " << m_frameQueue.size();}// 处理帧if (frame.isValid()) {QVideoFrame cloneFrame(frame);if (cloneFrame.map(QAbstractVideoBuffer::ReadOnly)) {// 将视频帧转换为QImageQImage image;switch (cloneFrame.pixelFormat()) {case QVideoFrame::Format_RGB32:case QVideoFrame::Format_ARGB32:case QVideoFrame::Format_ARGB32_Premultiplied:image = QImage(cloneFrame.bits(),cloneFrame.width(),cloneFrame.height(),cloneFrame.bytesPerLine(),QImage::Format_RGB32);break;case QVideoFrame::Format_RGB24:image = QImage(cloneFrame.bits(),cloneFrame.width(),cloneFrame.height(),cloneFrame.bytesPerLine(),QImage::Format_RGB888);break;case QVideoFrame::Format_YUYV:case QVideoFrame::Format_UYVY:case QVideoFrame::Format_YUV420P:case QVideoFrame::Format_YV12:case QVideoFrame::Format_NV12:case QVideoFrame::Format_NV21:{// 对于YUV格式,需要进行颜色空间转换// 这里简化处理,将其转换为灰度图像qDebug() << "处理YUV格式视频帧: " << cloneFrame.pixelFormat() << "宽度: " << cloneFrame.width() << "高度: " << cloneFrame.height();// 安全地创建灰度图像image = QImage(cloneFrame.width(), cloneFrame.height(), QImage::Format_Grayscale8);// 只处理Y平面数据,避免访问UV平面导致的问题const uchar *bits = cloneFrame.bits();int bytesPerLine = cloneFrame.bytesPerLine();// 限制处理范围,避免越界访问int maxHeight = qMin(cloneFrame.height(), image.height());int maxWidth = qMin(cloneFrame.width(), image.width());try {for (int y = 0; y < maxHeight; ++y) {for (int x = 0; x < maxWidth; ++x) {// 只取Y分量作为灰度值uchar value = bits[y * bytesPerLine + x];image.setPixelColor(x, y, QColor(value, value, value));}}qDebug() << "YUV帧处理完成";} catch (const std::exception &e) {qDebug() << "处理YUV帧时发生异常: " << e.what();// 如果发生异常,创建一个空白图像image = QImage(cloneFrame.width(), cloneFrame.height(), QImage::Format_Grayscale8);image.fill(Qt::black);}break;}default:// 对于其他格式,尝试转换为RGB32image = QImage(cloneFrame.bits(),cloneFrame.width(),cloneFrame.height(),cloneFrame.bytesPerLine(),QImage::Format_RGB32).copy();break;}// 保存图像if (!image.isNull()) {QString fileName = QString("%1/frame_%2.jpg").arg(m_outputDir).arg(m_extractedCount, 6, 10, QChar('0'));qDebug() << "正在保存图像到: " << fileName;if (image.save(fileName, "JPG")) {m_extractedCount++;qDebug() << "图像保存成功,已提取: " << m_extractedCount << "/" << m_frameCount;emit progressUpdated(m_extractedCount, m_frameCount);} else {qDebug() << "图像保存失败: " << fileName;}} else {qDebug() << "无法保存空图像,跳过当前帧";}cloneFrame.unmap();}}}// 处理完成emit finished();
}

-----------------

本文代码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/35532.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LabVIEW压比调节器动态试验台

本案介绍了一种基于LabVIEW的压比调节器动态试验台的设计&#xff0c;通过实用的LabVIEW图形化编程语言&#xff0c;优化了数据采集与处理的整个流程。案例通过实际应用展示了设计的专业性与高效性&#xff0c;以及如何通过系统化的方法实现精确的动态测试和结果分析。 ​ 项目…

3.17学习总结 java数组

地址值&#xff1a; D&#xff1a;表示当前数组内元素元素是double类型的 索引>下标&#xff0c;从0开始 最大索引&#xff1a;数组长度-1 把数据存储到数组中&#xff0c;一旦覆盖之后&#xff0c;原来的数据就不存在了 数组的遍历&#xff1a; 遍历&#xff1a;是取…

Linux-数据结构-线性表-单链表

一.链表的概念 【1】线性表的链式存储 解决顺序存储的缺点&#xff0c;插入和删除&#xff0c;动态存储问题。 【2】特点&#xff1a; 线性表链式存储结构的特点是一组任意的存储单位存储线性表的数据元素&#xff0c;存储单元可以是连续的&#xff0c;也可以不连续。可以被存…

Apifox Helper 自动生成API接口文档

在我们开发过程中我们在编写请求地址和编写请求参数的时候特别花费时间耗费了我们很多时间&#xff0c;作为一个程序员&#xff0c;更应该把精力时间集中在开发上&#xff0c; Apifox Helper 是 Apifox 团队针对 IntelliJ IDEA 环境所推出的插件&#xff0c;可以在 IDEA 环境中…

【软考-架构】13.1、软件架构概述-构件技术

✨资料&文章更新✨ GitHub地址&#xff1a;https://github.com/tyronczt/system_architect 文章目录 ✨【重点】系统架构设计软件架构概述软件架构设计与生命周期构件&#x1f31f;软件架构风格数据流风格调用/返回风格独立构件风格虚拟机风格仓库风格闭环控制风格C2体系结…

C++特性——智能指针

为什么需要智能指针 对于定义的局部变量&#xff0c;当作用域结束之后&#xff0c;就会自动回收&#xff0c;这没有什么问题。 当时用new delete的时候&#xff0c;就是动态分配对象的时候&#xff0c;如果new了一个变量&#xff0c;但却没有delete&#xff0c;这会造成内存泄…

基于SpringBoot+Vue的幼儿园管理系统+LW示例参考

1.项目介绍 系统角色&#xff1a;管理员、教师、普通用户功能模块&#xff1a;用户管理、教师管理、班级管理、幼儿信息管理、会议记录管理、待办事项、职工考核、请假信息、缴费信息、体检管理、资源管理、原料管理、菜品信息管理等技术选型&#xff1a;SpringBoot&#xff0…

网络通信(传输层协议:TCP/IP ,UDP):

Socket是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端&#xff0c;提供了应用层进程利用网络协议交换数据的机制。 网络协议&#xff1a;一台电脑的数据怎么传递给另一台电脑&#xff0c;是由网络协议来规定的 端口号&#…

Qt之自定义界面组件 一

通过qt中的painter绘图事件绘制一个电池电量图的变化。效果如下图 创建一个基于界面widget工程&#xff0c;在wdiget界面添加一个widget界面,将添加的widget界面的类提升为Tbattery.在Tbattery类中重写painEvent电池电量代码 文件目录结构 主要部分代码 //Tbattery.cpp #inc…

AP AR

混淆矩阵 真实值正例真实值负例预测值正例TPFP预测值负例FNTN &#xff08;根据阈值预测&#xff09; P精确度计算&#xff1a;TP/(TPFP) R召回率计算&#xff1a;TP/(TPFN) AP 综合考虑P R 根据不同的阈值计算出不同的PR组合&#xff0c; 画出PR曲线&#xff0c;计算曲线…

学习单片机需要多长时间才能进行简单的项目开发?

之前有老铁问我&#xff0c;学单片机到底要多久&#xff0c;才能进行简单的项目开发&#xff1f;是三个月速成&#xff0c;还是三年磨一剑&#xff1f; 今天咱们就来聊聊这个话题&#xff0c;我不是什么高高在上的专家&#xff0c;就是个踩过无数坑、烧过几块板子的“技术老友”…

数学建模:MATLAB循环神经网络

一、简述 1.循环神经网络 循环神经网络&#xff08;RNN&#xff09;是一种用于处理序列数据的神经网络。不同于传统的前馈神经网络&#xff0c;RNN在隐藏层中加入了自反馈连接&#xff0c;使得网络能够对序列中的每个元素执行相同的操作&#xff0c;同时保持一个“记忆”状态…

《GitHub网路访问不稳定:解决办法》:此文为AI自动生成

《GitHub网路访问不稳定&#xff1a;解决办法》&#xff1a;此文为AI自动生成 GitHub 网路访问不稳定初现 在当今数字化时代&#xff0c;软件开发行业蓬勃发展&#xff0c;GitHub 作为全球最大的代码托管平台&#xff0c;已然成为无数开发者不可或缺的 “宝库”。它不仅汇聚了海…

SpringCloud 学习笔记2(Nacos)

Nacos Nacos 下载 Nacos Server 下载 | Nacos 官网 下载、解压、打开文件&#xff1a; 更改 Nacos 的启动方式 Nacos 的启动模式默认是集群模式。在学习时需要把他改为单机模式。 把 cluster 改为 standalone&#xff0c;记得保存&#xff01; 启动startup.cmd Ubuntu 启动…

在windows10系统上安装docker,然后在容器中运行GPU版本的Pytorch,并使用vscode连接该容器

一 . 安装Docker Desktop 首先打开网址https://docs.docker.com/desktop/install/windows-install/ 下载完后&#xff0c;双击下面的exe文件进行安装&#xff0c;默认情况下&#xff0c;Docker Desktop 安装在C:\Program Files\Docker\Docker 出现提示时&#xff0c;请确保…

AI入门7:python三种API方式调用本地Ollama+DeepSeek

回顾 书接上篇&#xff1a;各种方式搭建了本地知识库&#xff1a; AI入门&#xff1a;AI模型管家婆ollama的安装和使用-CSDN博客 AI入门2&#xff1a;本地AI部署&#xff0c;用ollama部署deepseek&#xff08;私有化部署&#xff09;-CSDN博客 AI入门3&#xff1a;给本地d…

Unity导出WebGL

在Build Settings页面中平台&#xff08;Platform&#xff09;切换到WebGL平台 如何没有安装WebGL扩展插件&#xff0c;点击下载&#xff08;Open Download Page&#xff09; 下载扩展安装文件WebGL-Support-for-Editor-2023.1.0f1c1.exe 下载地址&#xff1a; http://downlo…

深入理解静态与动态代理设计模式:从理论到实践

静态代理设计模式 1.为什么需要代理设计模式&#xff1f; javaEE分层开发中&#xff0c;哪个层次对于我们来讲最重要 DAO---->Service---->Controller JavaEE分层中&#xff0c;最为重要的是Service层 Service层包含了那些代码 Service层核心功能(几十行 上百代码) 额外…

4.JVM-垃圾回收介绍

记录个人学习中记录笔记&#xff0c;如有错误请您指正&#xff0c;谢谢&#x1f64f; 垃圾回收器发展史 传统垃圾回收: 分代回收 不同代有不同的垃圾回收机制 保底 标记清除算法 垃圾识别算法 引用计数法 缺陷:下图2 出现循环引用 无法解决 可达性分析 大部分(Java,pytho…

解决qt中自定插件加载失败,不显示问题。

这个问题断断续续搞了一天多&#xff0c;主要是版本不匹配问题。 我们先来看下 Based on Qt 6.6.0 → 说明 Qt Creator 本身 是基于 Qt 6.6.0 框架构建的。MSVC 2019, 64-bit → 说明 Qt Creator 是使用 Microsoft Visual C 2019 编译器&#xff08;64 位&#xff09; 编译的。…