QOpenGLWidget视频画面上绘制矩形框

一、QPainter绘制

在QOpenGLWidget中可以绘制,并且和OpenGL的内容叠在一起。paintGL里面绘制完视频后,解锁资源,再用QPainter绘制矩形框。这种方式灵活性最好。

void VideoGLWidget::paintGL() {glClear(GL_COLOR_BUFFER_BIT);m_program.bind();//绘制视频数据// 解绑VAOglBindVertexArray(0);m_program.release();// ----------------- 绘制矩形框 -----------------QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);painter.setPen(QPen(QColor(Qt::red), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));QRectF drawRect = QRectF(0, 0, width() * 0.5, height() * 0.5);painter.drawRect(drawRect);painter.end();
}

二、OpenGL绘制

通过不同的QOpenGLShaderProgram,可以指定不同的着色器程序来实现矩形的绘制。
1)边框颜色参数要通过Uniform传递给OpenGL的片段着色器。
2)动态矩形顶点缓冲更新,坐标归一化到OpenGL坐标系,顶点数据更新VBO

void VideoGLWidget::updateRectBuffer() {if (m_rects.isEmpty()) return;// 将 QRectF 转换为归一化坐标(-1 到 1)QVector<float> vertices;for (const QRectF &rect : m_rects) {float x1 = (rect.x() / m_videoSize.width()) * 2 - 1;float y1 = 1 - (rect.y() / m_videoSize.height()) * 2;float x2 = ((rect.x() + rect.width()) / m_videoSize.width()) * 2 - 1;float y2 = 1 - ((rect.y() + rect.height()) / m_videoSize.height()) * 2;// 每个矩形由 4 条线段组成(每条线段 2 个点)vertices << x1 << y1 << x2 << y1;  // 上边vertices << x2 << y1 << x2 << y2;  // 右边vertices << x2 << y2 << x1 << y2;  // 下边vertices << x1 << y2 << x1 << y1;  // 左边}// 更新 VBOglBindBuffer(GL_ARRAY_BUFFER, m_rectVBO);glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.constData(), GL_DYNAMIC_DRAW);
}

头文件 VideoGLWidget.h‌ 

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>class VideoGLWidget : public QOpenGLWidget, protected QOpenGLFunctions {
public:explicit VideoGLWidget(QWidget *parent = nullptr);~VideoGLWidget();// 更新视频帧(假设帧格式为 RGB32)void updateVideoFrame(const QImage &frame);// 更新动态矩形框列表(坐标相对于视频帧尺寸)void updateRects(const QList<QRectF> &rects);protected:void initializeGL() override;void paintGL() override;void resizeGL(int w, int h) override;private:// OpenGL 资源QOpenGLShaderProgram *m_videoShader; // 视频渲染着色器QOpenGLShaderProgram *m_rectShader;   // 矩形框渲染着色器QOpenGLTexture *m_videoTexture;       // 视频纹理GLuint m_rectVBO;                     // 矩形顶点缓冲对象QSize m_videoSize;                    // 视频帧尺寸QList<QRectF> m_rects;                // 当前矩形框列表// 顶点数据相关void initRectBuffer();void updateRectBuffer();
};

实现文件 VideoGLWidget.cpp 

OpenGL初始化

VideoGLWidget::VideoGLWidget(QWidget *parent) : QOpenGLWidget(parent), m_videoTexture(nullptr), m_rectVBO(0) {// 启用自动更新setAutoFillBackground(false);
}VideoGLWidget::~VideoGLWidget() {makeCurrent();delete m_videoTexture;delete m_videoShader;delete m_rectShader;glDeleteBuffers(1, &m_rectVBO);doneCurrent();
}void VideoGLWidget::initializeGL() {initializeOpenGLFunctions();glClearColor(0.0f, 0.0f, 0.0f, 1.0f);// 初始化视频渲染着色器m_videoShader = new QOpenGLShaderProgram(this);m_videoShader->addShaderFromSourceCode(QOpenGLShader::Vertex,"attribute vec4 vertexIn;""attribute vec2 texCoordIn;""varying vec2 texCoord;""void main() {""    gl_Position = vertexIn;""    texCoord = texCoordIn;""}");m_videoShader->addShaderFromSourceCode(QOpenGLShader::Fragment,"varying vec2 texCoord;""uniform sampler2D videoTexture;""void main() {""    gl_FragColor = texture2D(videoTexture, texCoord);""}");m_videoShader->link();// 初始化矩形框渲染着色器m_rectShader = new QOpenGLShaderProgram(this);m_rectShader->addShaderFromSourceCode(QOpenGLShader::Vertex,"attribute vec2 position;""void main() {""    gl_Position = vec4(position, 0.0, 1.0);""}");m_rectShader->addShaderFromSourceCode(QOpenGLShader::Fragment,"uniform vec4 color;""void main() {""    gl_FragColor = color;""}");m_rectShader->link();// 初始化矩形顶点缓冲glGenBuffers(1, &m_rectVBO);
}

视频帧更新与纹理上传

void VideoGLWidget::updateVideoFrame(const QImage &frame) {makeCurrent();// 首次创建或尺寸变化时重新创建纹理if (!m_videoTexture || m_videoTexture->size() != frame.size()) {delete m_videoTexture;m_videoTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);m_videoTexture->setFormat(QOpenGLTexture::RGB8_UNorm);m_videoTexture->setSize(frame.width(), frame.height());m_videoTexture->allocateStorage();m_videoSize = frame.size();}// 上传帧数据到纹理(假设帧为 RGB32 格式)m_videoTexture->bind();glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame.width(), frame.height(),GL_BGRA, GL_UNSIGNED_BYTE, frame.bits());update();
}void VideoGLWidget::updateRects(const QList<QRectF> &rects) {m_rects = rects;updateRectBuffer(); // 更新顶点数据update();
}

动态矩形顶点缓冲更新

void VideoGLWidget::updateRectBuffer() {if (m_rects.isEmpty()) return;// 将 QRectF 转换为归一化坐标(-1 到 1)QVector<float> vertices;for (const QRectF &rect : m_rects) {float x1 = (rect.x() / m_videoSize.width()) * 2 - 1;float y1 = 1 - (rect.y() / m_videoSize.height()) * 2;float x2 = ((rect.x() + rect.width()) / m_videoSize.width()) * 2 - 1;float y2 = 1 - ((rect.y() + rect.height()) / m_videoSize.height()) * 2;// 每个矩形由 4 条线段组成(每条线段 2 个点)vertices << x1 << y1 << x2 << y1;  // 上边vertices << x2 << y1 << x2 << y2;  // 右边vertices << x2 << y2 << x1 << y2;  // 下边vertices << x1 << y2 << x1 << y1;  // 左边}// 更新 VBOglBindBuffer(GL_ARRAY_BUFFER, m_rectVBO);glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.constData(), GL_DYNAMIC_DRAW);
}

‌渲染主循环

void VideoGLWidget::paintGL() {glClear(GL_COLOR_BUFFER_BIT);// 渲染视频帧if (m_videoTexture) {m_videoShader->bind();m_videoTexture->bind();// 顶点坐标和纹理坐标(全屏四边形)static const GLfloat vertexData[] = {-1.0f, -1.0f, 0.0f, 0.0f,1.0f, -1.0f, 1.0f, 0.0f,-1.0f,  1.0f, 0.0f, 1.0f,1.0f,  1.0f, 1.0f, 1.0f};// 设置顶点属性glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), vertexData);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), vertexData + 2);glEnableVertexAttribArray(0);glEnableVertexAttribArray(1);// 绘制全屏四边形glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);m_videoShader->release();}// 渲染动态矩形框if (!m_rects.isEmpty()) {m_rectShader->bind();glBindBuffer(GL_ARRAY_BUFFER, m_rectVBO);// 设置颜色(红色,50%透明度)m_rectShader->setUniformValue("color", QVector4D(1.0f, 0.0f, 0.0f, 0.5f));// 设置顶点属性glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);glEnableVertexAttribArray(0);// 绘制线段(每个矩形 4 条边,每条边 2 个顶点)glLineWidth(2.0f);glDrawArrays(GL_LINES, 0, m_rects.size() * 8); // 4边 * 2点 = 8点/矩形m_rectShader->release();}
}

 使用示例

// 在主窗口或控制器中
void MainWindow::onNewVideoFrame(const QImage &frame) {m_videoWidget->updateVideoFrame(frame);
}void MainWindow::onDetectionResult(const QList<QRectF> &rects) {m_videoWidget->updateRects(rects);
}

异步纹理上传,避免在主线程阻塞:

// 在单独线程处理视频解码
void DecoderThread::run() {while (running) {QImage frame = decodeFrame();QMetaObject::invokeMethod(m_videoWidget, "updateVideoFrame", Qt::QueuedConnection, Q_ARG(QImage, frame));}
}

三、实例代码

1、视频画面暂时使用图片纹理代替,矩形框支持OPianter和OpenGL方式。效果:

2、 工程代码

QOpenGLWidget绘制框代码下载

 

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

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

相关文章

蓝桥杯备考:真题之飞机降落(暴搜+小贪心)

我们最多有十架飞机&#xff0c;可以选择dfs暴力搜索&#xff0c;枚举每种情况 那么&#xff0c;我们降落的时候怎么确定新的起点也就是newend呢&#xff1f; 如果飞机飞到机场的时刻是大于原来的end的&#xff0c;我们就让tili作为newend 否则&#xff0c;我们就让end作为ne…

解决 Element UI 嵌套弹窗的状态管理问题!!!

解决 Element UI 嵌套弹窗的状态管理问题 &#x1f527; 问题描述 ❓ 在使用 Element UI 开发一个多层嵌套弹窗功能时&#xff0c;遇到了以下问题&#xff1a; 弹窗只能打开一次&#xff0c;第二次点击无法打开 &#x1f6ab;收到 Vue 警告&#xff1a;避免直接修改 prop 值…

实时图像处理:让你的应用更智能

一、项目背景 在数字化飞速发展的今天&#xff0c;图像处理技术已成为众多领域不可或缺的核心组件。从医疗影像的精准诊断&#xff0c;到自动驾驶汽车对道路环境的实时感知&#xff0c;再到安防系统中对异常行为的迅速捕捉&#xff0c;实时图像处理正以惊人的速度改变着我们的…

AWVS中lodash如何验证

作为一名漏扫攻城狮&#xff0c;时不时会在AWVS中看到lodash这个漏洞&#xff0c;但是我只管导出报告&#xff0c;该怎么验证呢&#xff1f; 验证POC 下面就是用于验证的POC&#xff0c;把这个html中的src进行修改为扫描的网站中的lodash.min.js然后浏览器打开 <!DOCTYPE …

【算法学习计划】贪心算法(上)

目录 前言&#xff08;什么是贪心&#xff09; leetcode 860.柠檬水找零 leetcode 2208.将数组和减半的最少操作次数 leetcode 179.最大数 leetcode 376.摆动序列 leetcode 300.最长递增子序列 leetcode 334.递增的三元子序列 leetcode 674.最长连续递增序列 leetcode …

Ubuntu 22.04 安装向日葵远程控制

1. 前言 由于公司客户的服务器用是图形化桌面&#xff0c;所以我们需要一个远程控制工具来控制服务器&#xff0c;目前市面上两款比较热门的控制软件就是ToDesk和向日葵了&#xff0c;我们今天就来学习一下向日葵的使用 2. 下载软件 前往向日葵官网下载 向日葵远程控制app官…

Linux网络编程(七)——套接字的多种可选项

文章目录 7 套接字的多种可选项 7.1 套接字可选项和I/O缓冲大小 7.1.1 套接字多种可选项 7.1.2 getsockopt & setsockopt 7.1.3 SO_SNDBUF & SO_RCVBUF 7.2 地址再分配 SO_REUSEADDR 7.2.1 发生地址分配错误&#xff08;Binding Error&#xff09; 7.2.2 Time-…

使用 langchain_deepseek 实现自然语言转数据库查询SQL

文章目录 Github官网简介腾讯云DeepSeek APIDeepSeek APIChatDeepSeek安装相关库创建 .env 文件验证 API 接口 生成数据库查询SQL获取测试用数据库验证数据库查询生成数据库查询SQL Github https://github.com/langchain-ai/langchain 官网 https://python.langchain.com/do…

2025年具有AI招聘管理系统选型及攻略分享

2025年&#xff0c;人工智能的深度渗透让招聘管理系统的竞争从“功能堆砌”转向“智能密度”的较量。企业若想在这场人才争夺战中胜出&#xff0c;选对招聘管理系统已不再是“加分项”&#xff0c;而是“生死线”。 然而&#xff0c;市面上的招聘系统五花八门&#xff0c;从老牌…

vue 自定义 tabs 控件,可自动左右滑动使得选中项居中显示

效果图如下&#xff1a; 录屏如下&#xff1a; tabs录屏 控件用法如下&#xff1a; <navi-tabs :data"tabs" changeTab"changeTab"></navi-tabs>import NaviTabs from "/components/navi-tabs";components: { NaviTabs },tabs: [{ …

HarmonyOS:解决UIAbility调用terminateSelf()后设置不保留最近任务列表中的快照

一、概述 在HarmonyOS应用开发中&#xff0c;UIAbilityContext的terminateSelf()方法被用来结束当前的UIAbility实例。 如果希望在调用terminateSelf()后&#xff0c;让应用在最近任务列表中不保留快照&#xff0c;可以通过在module.json5配置文件中配置removeMissionAfterTe…

el-table下的复选框关联勾选

效果展示&#xff1a; <el-table style"height: 500px;" :data"tableData" border empty-text"暂无数据" v-loading"loading":header-cell-style"{ text-align: center }" :cell-style"{ text-align: center }"…

langchain+ollama+deepseek的部署(win)

ANACONDA 安装 官网&#xff1a;Download Anaconda Distribution | Anaconda 配置系统环境 在系统变量中配置 检查是否配置成功 通过 cmd 窗口输入&#xff1a; conda info 如图&#xff1a;表示成功 配置你的虚拟环境 二、安装 ollama allama 安装 官网地址&#xff1a…

深入理解椭圆曲线密码学(ECC)与区块链加密

椭圆曲线密码学&#xff08;ECC&#xff09;在现代加密技术中扮演着至关重要的角色&#xff0c;广泛应用于区块链、数字货币、数字签名等领域。由于其在提供高安全性和高效率上的优势&#xff0c;椭圆曲线密码学成为了数字加密的核心技术之一。本文将详细介绍椭圆曲线的基本原理…

SQL Server 2008安装教程

目录 一.安装SQL Server 二.安装SQL Server Management Studio 三.使用SQL Server Management Studio 一.安装SQL Server 官网下载:SQL Server 下载 | Microsoft 1.选择安装中的全新安装如下图 2.功能选择 3.实例配置 4.后面一直下一步到数据库引擎配置 密码自己设置 系统…

Microi吾码界面设计引擎之基础组件用法大全【内置组件篇·中】

&#x1f380;&#x1f380;&#x1f380; microi-pageengine 界面引擎系列 &#x1f380;&#x1f380;&#x1f380; 一、Microi吾码&#xff1a;一款高效、灵活的低代码开发开源框架【低代码框架】 二、Vue3项目快速集成界面引擎 三、Vue3 界面设计插件 microi-pageengine …

如何在 Windows 上安装并使用 Postman?

Postman 是一个功能强大的API测试工具&#xff0c;它可以帮助程序员更轻松地测试和调试 API。在本文中&#xff0c;我们将讨论如何在 Windows 上安装和使用 Postman。 Windows 如何安装和使用 Postman 教程&#xff1f;

便携版:随时随地,高效处理 PDF 文件

PDF-XChange Editor Plus 便携版是一款功能强大且极其实用的 PDF 阅读与编辑工具。它不仅支持快速浏览 PDF 文件&#xff0c;还提供了丰富的编辑功能&#xff0c;让用户可以轻松处理 PDF 文档。经过大神优化处理&#xff0c;这款软件已经变得十分轻便&#xff0c;非常适合需要随…

MCP Server 实现一个 天气查询

​ Step1. 环境配置 安装 uv curl -LsSf https://astral.sh/uv/install.sh | shQuestion: 什么是 uv 呢和 conda 比有什么区别&#xff1f; Answer: 一个用 Rust 编写的超快速 (100x) Python 包管理器和环境管理工具&#xff0c;由 Astral 开发。定位为 pip 和 venv 的替代品…

MySQL执行计划

MySQL 的 执行计划&#xff08;Execution Plan&#xff09; 是优化器根据 SQL 语句生成的查询执行路径的详细说明。通过分析执行计划&#xff0c;可以了解 MySQL 如何处理 SQL 查询&#xff08;如索引使用情况、表连接顺序等&#xff09;&#xff0c;进而优化查询性能。 1. 获…