Qt:基于QQuickFramebufferObject显示QImage到QML中

GItHub地址

简介

本仓库实现了一个在QML框架中,显示QImage数据的QML控件,取名为JQImageItem

本控件针对的场合是需要显示并且频繁修改QImage的场景,例如视频显示。

提供了2个实现版本,一个是基于QQuickFramebufferObject(FBO)的JQImageItem,一个是基于QQuickPaintedItem的JQImageItem2。

在绝大多数场合下,FBO的实现性能要明显好于其他版本,因此如果你需要使用本仓库的控件,请使用这个版本。

代码基于纯Qt+OpenGL实现,开发时测试了2个Qt版本,分别是5.15.2和6.5.2,理论上其他Qt版本也能正常使用。

如何使用

在QML中,直接实例化控件,然后需要把控件的指针传回到C++,然后在C++端进行数据更新。实例化代码如下:

JQImageItem {id: imageItemanchors.fill: parent
}

如果要调整图片显示的大小,位置等属性,那么直接调整这个Item即可。

在C++端拿到指针后,调用setImage接口,可以把QImage数据设置到控件内,然后控件会显示这个QImage图片数据,代码如下:

imageItem->setImage( QImage( "C:/your/image/xxx.png" ) );

这个setImage接口是线程安全的,因此你可以在任何线程调用这个接口

为什么快?

要理解为什么本仓库的实现块,我们需要先理解3个常见的QImage显示方法

一般来说,在QML中显示一个QImage,有3个方法实现,他们分别如下:

  • QQuickImageProvider

    这是目前网上最多的实现方法,大致原理是把QImage图片数据通过图片显示的逻辑,传给QML。

    这个方法理论上是最慢的,因为这个逻辑下,需要把一个图片,完整的经过Qt的图片资源处理逻辑,才能显示到QML中。

    在Qt的设计初衷上,这个类根本不是给这个场景用的,因此大多数人的实现,都需要在QML端给url赋值随机数,或者一个自增变量,来避免URL相同而引起的图片不刷新问题。

    并且,这个逻辑下,会严重破坏QML的图片缓存逻辑(如果你不设置cache为false的话)。

    因此在频繁修改图片的需求下,这个实现方式,我是完全不推荐使用的。

  • QQuickPaintedItem

    这个类的实现,更加的贴近我们的使用场景,也不存在url这些对实现需求完全无用的中间参数变量等。

    这个类大致的流程是在C++端,通过QPainter绘制一个图片到QImage中,然后Qt会把这个QImage图片显示到QML上

    这个类的速度其实已经很快了,但是他还是存在一个额外的开销,就是QPainter的步骤。即使在分辨率,格式完全相同的情况下,QPainter绘制一个图片到QQuickPaintedItem内部的缓冲区,会存在至少一次的拷贝开销。

    不过这个类本身也有FBO的实现方式,可以说如果你的需求是QPainter绘制图表,或者其他内容的话,这就是最合适的实现。

  • QQuickFramebufferObject(FBO)

    分析我们的需求,目前已经有了一个QImage,QImage有完整封装好的图片数据,我们希望他可以直接传给OpenGL实现,没有其他的开销。那么此时,直接把这个图片数据,上传到OpenGL的纹理对象(QOpenGLTexture),然后直接绘制,那么这就是最快的方法。

    基于FBO显示图片的话,会比较复杂,大致流程是:

    • 创建自己的shader,只保留图片渲染需要的部分

    • 创建和图片渲染相关的VBO,VAO

    • 把图片根据需求,更新到纹理中

    • 在OpenGL的绘制回调中,调用所有的相关对象,完成图片绘制

    也就是说基于FBO的实现,虽然逻辑更复杂,代码更多,但是更精准的控制了相关资源的使用、创建和释放逻辑。因此获得了一定的性能优势。并且在分辨率和格式相同的情况下,纹理不需要重新分配显存空间,可以复用。

    换句话说,就是特化了QImage显示的场景,降低了控件的通用性以换取性能。

    另外这里还有一个重要的性能优势,就是图片分辨率小于控件分辨率时,不在C++端进行缩放,而是把小图片直接上传到纹理,然后由QpenGL在显示的时候完成缩放逻辑。

    基于FBO也有图片附件的显示方法,代码量更少。但是实测下来性能开销也很大,因此我自己重写了shader,没有使用图片附件的方法。

注1:图片附件的代码如下,有兴趣的小伙伴可以自行搜索下文档:glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0 );

注2:我们暂时不讨论AnimatedImage和VideoOutput,因为这2个控件有其他更精准的使用场景

关于测试代码

测试代码分为2部分,一个是QML部分,分别实例化了JQImageItem和JQImageItem2,鼠标点击切换,开发者们可以观察切换后,CPU和GPU占用情况的变化。

C++的Helper类,会起一个线程,以大约60FPS的速度在设置图片给JQImageItem,以模拟图片变化的场合。

测试数据会有一个缩放的效果,这个涉及到的图片序列已经在初始化的时候生成完毕,并且统一了分辨率。这样在测试代码运行过程中的开销,基本就只有渲染开销。

心得体会

就如同之前所说,特化代码,换取了性能优势。因此这个方法需要更多的代码量,以及OpenGL相关的知识,大部分开发者不会做到这一步。

对我而言,很久以前就有这个QImage的显示需求,我都是拿QQuickPaintedItem实现,即使知道了FBO可以更快,但是无奈没有相关的知识储备,一直没有做实现,一直到现在才把这个实现做了出来。

实现的代码量其实不大,前后加起来就是300行不到。但是我觉得这个功能真的很重要,因此直接开源,方便其他开发者们取用。

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

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

相关文章

STM32CubeIDE基础学习-软件安装,环境搭建

STM32CubeIDE基础学习-软件介绍及环境搭建步骤 文章目录 STM32CubeIDE基础学习-软件介绍及环境搭建步骤前言第1章 STM32CubeIDE 介绍1.1 软件描述1.2 软件支持的功能及特点 第2章 STM32CubeIDE 软件安装2.1 STM32CubeIDE 软件获取方法2.2 STM32CubeIDE 软件安装步骤2.2.1 错误安…

C++模板完整版

顾得泉:个人主页 个人专栏:《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂,年薪百万! 一、泛型编程 如何实现一个通用的交换函数呢? void Swap(int& left, int& right) {int temp left…

抖店入驻费用是多少?新手入驻都有哪些要求?2024费用明细!

我是电商珠珠 我做电商做了将近五年,做抖店做了三年多,期间还带着学员一起做店。 今天,就来给大家详细的讲一下在抖音开店,需要多少费用,最低需要投入多少。 1、营业执照200元左右 就拿个体店举例,在入…

hook函数——useReducer

目录 1.useReducer定义2.useReducer用法3.useState和useReducer区别 1.useReducer定义 const [state, dispatch] useReducer(reducer, initialArg, init?) reducer:用于更新 state 的纯函数。参数为 state 和 action,返回值是更新后的 state。state …

这波操作看麻了!十亿行数据,从71s到1.7s的优化之路。

节期间关注到了一个关于 Java 方面的比赛,很有意思。由于是开源的,我把项目拉下来试图学(白)习(嫖)别人的做题思路,在这期间一度让我产生了一个自我怀疑: 他们写的 Java 和我会的 Ja…

解锁软件管理新篇章,Allegro许可证使用规定全解

在数字化经济的时代,软件已经成为企业运营的关键要素。然而,软件的使用往往伴随着一系列的合规性问题,导致企业面临潜在的风险和成本。Allegro许可证作为业界领先的软件解决方案提供商,为企业提供全面的许可证使用规定&#xff0c…

每日一题——LeetCode1576.替换所有的问号

方法一 3个字母原则 把?替换为和他左右都不相等的字符,那么找3个字符abc,?总能替换为abc中的一个字符,遍历字符串找到所有?,再遍历abc把?替换为abc中的一个字符 var modifyString …

解析 openGauss 的 AutoVacuum 机制及优化策略

前言 在 openGauss 数据库中,AutoVacuum 机制是一个关键的自动化功能,用于管理表的空间和性能。AutoVacuum 通过定期清理过时数据和更新统计信息,帮助数据库管理员维护数据库的性能和稳定性。 为什么需要 AutoVacuum? 了解AutoV…

JAVA内存模型与JVM内存结构

注意区分Java内存模型(Java Memory Model,简称JMM)与Jvm内存结构,前者与多线程相关,后者与JVM内部存储相关。本文会对两者进行简单介绍。 一、JAVA内存模型(JMM) 1. 概念 说来话长,由于在不同硬件厂商和…

No matching version found for @babel/traverse@^7.24.0.

问题: npm安装 依赖失败,找不到所需依赖。 原因: npm镜像源中没有该依赖。(大概率是因为依赖最近刚更新,当前镜像源没有同步) 解决: 查看自己的npm镜像:npm config get registry…

机器学习-面经(part2)

3. 验证方式 3.1什么是过拟合?产生过拟合原因? 定义:指模型在训练集上的效果很好,在测试集上的预测效果很差 数据有噪声 训练数据不足,有限的训练数据 训练模型过度导致模型非常复杂3.2 如何避免过拟合问题? 3.3 什么是机器学习的欠拟合?产生原…

D4890可应用在对讲机上,采用 SOP8/MSOP8两种封装形式

D4890 目前客户主要使用在对讲机上,电压范围2.2V ~ 5.5V之间,输出功率(THDN1%)1.0W/8Ω 5.0V。采用 SOP8/MSOP8两种封装形式。 2、推荐的应用线路图如下: 3、实际测试输出波形如下(VCC4.5V&…

Web Component 转图片

一、HTML 转图片 目前,常见的开源的能够将 HTML 转换为图片有html2canvas、dom-to-image,大部分场景下,这些开源库都能很友好的处理。 HTML 转图片的实现原理,通常分为两种:svg 与 canvas。今天主要讨论下 svg 的场景…

Flutter中使用Dio库封装网络请求服务工具类

在Flutter应用程序中,进行网络请求是非常常见的任务。Dio是一个强大的、易于使用的Dart包,用于处理HTTP请求。本篇博客将介绍如何封装Dio库,以及如何在Flutter应用中进行网络请求并取消请求。 什么是Dio? Dio是一个基于Dart语言…

解决android studio build Output中文乱码

1.效果如下所示: 代码运行报错的时候,Build Output报的错误日志中中文部分出现乱码,导致看不到到底报的什么错。 2.解决办法如下: 点击Android studio开发工具栏的Help-Edit Custom VM Options....,Android studio会…

springboot微服务中集成了mybatis的服务引入了其他集成了mybatis的服务此时调用引入的服务中的某个mapper接口时报没有注入

在启动类上加引入的服务中的mapper路径,在配置文件中将mapperLocations的值改为classpath*:mapper/.xml: MapperScan(basePackages {"com.ruoyi..mapper"}) 和 mapperLocations: classpath*:mapper/*.xml 是 MyBatis 在 Spring Boot 中配置 M…

AutoGPT实现原理

AutoGPT是一种利用GPT-4模型的自动化任务处理系统,其主要特点包括任务分配、多模型协作、互联网访问和文件读写能力以及上下文联动记忆性。其核心思想是通过零样本学习(Zero Shot Learning)让GPT-4理解人类设定的角色和目标,并通过…

端口号被占用时的解决办法

1、查看端口占用的进程号 netstat -ano |findstr 8080 2、 找到占用端口的程序 tasklist |findstr 2264 3、kill端口 taskkill /pid 2264 /f

文物预防性保护方案整体结构及软件介绍

​文物预防性保护监测与调控系统整体是构架在商业级技术平台上的多层综合性应用,采用分布式部署的模块化设计,以智能监测终端及高精传感器为核心的感知系统。系统通过以下的层次结构协同工作完成全面的监控与调控功能: 1)系统依靠文物监测调控模型作为运行核心&…

基于springboot+vue的校园爱心捐赠互助管理系统(源码+论文)

目录 前言 一、功能设计 二、功能实现 三、库表设计 四、论文 前言 随着经济水平和生活水平的提高在校大学生在校需要处理的物品也在不断增加,同时校园内还存在很多贫困生,可以通过线上平台实现资源的整合和二次利用,通过线上平台求助信…