当前位置: 首页 > news >正文

一种高效绘制余晖波形的方法Qt/C++

一、什么是“余晖波形”?

“余晖波形”(afterglow / persistence waveform)是指在实时波形显示中保留上一帧或多帧的轨迹并使其逐渐衰退的视觉效果。类似示波器上“痕迹逐渐消失”的效果:

  • 能看到最新信号的同时,也能看见短期历史(轨迹),比单纯把历史点清掉再画更直观。

  • 常见于音频可视化、示波器、频谱可视化、监控仪表盘等场景。

实现上通常有两种思路:把历史数据一直保留并每帧重绘(昂贵),或者在画布上“叠加透明层”使旧像素逐帧衰减(高效且视觉平滑)。

二、QCustomPlot 的性能瓶颈

在一个包含 4 个通道、每个通道 5000 点(总计 20,000 点)的场景中,如果每帧都把数据传给 QCustomPlot 并调用完整重绘,会遇到以下问题:

  1. 整体重绘开销大:每次刷新都触发全窗口的完整绘制,哪怕只有部分数据更新,也会重新计算和渲染全部曲线。

  2. 频繁的内存分配和拷贝:每帧都要构造并传递大量点数据,增加了内存管理开销。

  3. 高层抽象带来的额外消耗:QCustomPlot 提供了丰富的数据和绘图管理功能,但这些便利在高频实时刷新时会成为性能负担。

结果就是 CPU 占用率高、界面刷新不流畅、容易出现掉帧。而且对于“余晖”这种需要保留历史痕迹的效果,每次都重绘所有历史数据本身就是多余的。

三、使用离屏缓冲 + alpha 淡化 + 增量绘制实现

3.1 本方法的主要优点

1)性能高效:避免每帧重建和绘制全部点数据,显著降低 CPU 与内存开销。

2)视觉流畅:通过淡化处理保留历史轨迹,波形变化连续自然,观察体验更接近示波器。

3)实现简洁:基于缓冲区叠加和局部更新即可实现,无需引入复杂的数据结构。

3.2 关键实现原理

1) 离屏缓冲

    绘制波形时,并不是直接在控件上重绘所有历史数据,而是使用一张缓冲图像(离屏画布)来保存已经绘制过的波形。这样,每一帧只需要把缓冲图像整体“贴”到窗口上即可,开销非常小。

    2) 淡化实现

      为了产生“余晖”效果,每一帧在缓冲图像上覆盖一层半透明的颜色,让旧的轨迹逐渐变浅。这样既能保留短时间的历史痕迹,又不会无限叠加造成画面污染。

      3) 增量更新

      每个波形通道都只生成和绘制最新的数据点,而不是每次都把整个通道的所有点重新绘制一遍。这样可以大幅减少绘制调用次数,提高帧率。

      3.3 关键代码展示

      void WaveformPlot::paintEvent(QPaintEvent* event) {QPainter p(this);p.setRenderHint(QPainter::Antialiasing);// 绘制背景p.fillRect(rect(), Qt::white);// 绘制缓冲图像中的波形p.drawImage(0, 0, m_buffer);// 绘制坐标轴drawAxes(p);
      }void WaveformPlot::updateWaveform() {// 对旧波形做淡化QPainter fadePainter(&m_buffer);// alpha 衰减fadePainter.fillRect(m_buffer.rect(), QColor(255, 255, 255, 30));fadePainter.end();QColor baseColors[4] = {QColor(0, 0, 255),   // 蓝QColor(255, 0, 0),   // 红QColor(0, 255, 0),   // 绿QColor(255, 128, 0)  // 橙};double newYMin = m_yMin;double newYMax = m_yMax;for (int i = 0; i < m_layers.size(); ++i) {auto wf = m_layers[i].waveform;// 生成最新波形数据wf->generate(m_layers[i].index, i);// 获取 Y 范围wf->getminmax(newYMin, newYMax);m_layers[i].index = (m_layers[i].index + 1) % m_maxCount;}// 如果数据超出原范围,就调整 Y 轴if (newYMin < m_yMin || newYMax > m_yMax) {m_yMin = newYMin;m_yMax = newYMax;// ==== 计算扩展后的 yMin/yMax ====double yRange = m_yMax - m_yMin;m_yMinExt = m_yMin - 0.2 * yRange;  // 下扩展 20%m_yMaxExt = m_yMax + 0.2 * yRange;  // 上扩展 20%}for (int i = 0; i < m_layers.size(); ++i) {auto wf = m_layers[i].waveform;// 绘制最新波形wf->draw(m_buffer, this, baseColors[i]);}// 触发 paintEventupdate();
      }

      3.4 资源占用展示

      绘制余晖波形过程中,资源占用情况如下图所示

      四、总结

      本文介绍的余晖波形绘制方法,最突出的优点如下:

      1、性能高效:避免每帧重建和绘制全部点数据,显著降低 CPU 与内存开销。

      2、视觉流畅:通过淡化处理保留历史轨迹,波形变化连续自然。

      但是也有一些缺点,比如:

      1、完全依靠painter绘制,交互性不如QCustomPlot

      2、由于历史波形数据通过离屏缓冲 + alpha 淡化实现,窗口大小变化时历史波形无法自适应变化,适合窗口大小固定的场景。


      文章转载自:

      http://tIFHX3sx.hhqtq.cn
      http://FPT1qSuT.hhqtq.cn
      http://bH4prwWe.hhqtq.cn
      http://2ng8d1rb.hhqtq.cn
      http://ZOJRGsDT.hhqtq.cn
      http://O1eazfok.hhqtq.cn
      http://hYAIgggJ.hhqtq.cn
      http://0UFh1Tr4.hhqtq.cn
      http://ts27Twhs.hhqtq.cn
      http://WOEC6iBN.hhqtq.cn
      http://SO5gaItD.hhqtq.cn
      http://OuRMD25K.hhqtq.cn
      http://lYULEyrO.hhqtq.cn
      http://m7s3kfYZ.hhqtq.cn
      http://Tv5EvSfa.hhqtq.cn
      http://4mjR2K1F.hhqtq.cn
      http://LBPkip1T.hhqtq.cn
      http://5n0P7hVI.hhqtq.cn
      http://qw1lGPnP.hhqtq.cn
      http://J6ZUEG8n.hhqtq.cn
      http://zs1BcJzp.hhqtq.cn
      http://gYrdwHDk.hhqtq.cn
      http://WiumbRN9.hhqtq.cn
      http://TFMNUZes.hhqtq.cn
      http://6vVJALIO.hhqtq.cn
      http://SAqcrbZ6.hhqtq.cn
      http://lPhz5v4H.hhqtq.cn
      http://Rr5OJoYe.hhqtq.cn
      http://6HbhBKkg.hhqtq.cn
      http://F13VDgG7.hhqtq.cn
      http://www.dtcms.com/a/374188.html

      相关文章:

    • 本地部署的Qwen3,测试不同数量并发请求的吞吐量
    • 【从零开始java学习|第十三篇】字符串究极知识总结
    • Linux内核进程管理子系统有什么第四十六回 —— 进程主结构详解(42)
    • Kafka 与 RocketMQ 核心概念与架构对比
    • 【检索通知】2025年IEEE第二届深度学习与计算机视觉国际会议检索
    • 2025年AC-DC电源模块选购指南与应用方案解析
    • LeetCode 面试经典 150 题:删除有序数组中的重复项 II(最多保留 2 次 + 通用 k 次解法详解)
    • 在OpenHarmony上适配图形显示【2】——调试display hdi的技巧
    • 在 JavaScript 中轻松实现 AES 加密与解密:从原理到实战
    • Mockoon:开源免费的本地Mock服务工具,提升前后端联调效率
    • C/C++圣诞树②
    • segYolo添加界面
    • 初学Transformer核心——注意力机制
    • 第9篇:Freqtrade量化交易之config.json 基础入门与初始化
    • 推荐系统学习笔记(十六)LHUC(PPNet)
    • 前端开发实战 主流前端开发工具对比与最佳实践
    • 淘宝 API 技术架构与实战指南:从实时数据流到 AIGC 融合的电商开发新范式
    • 基于AD9689BBPZ-2600 的高速数字采集 板卡
    • Transformer 模型:Attention is All You Need 的真正含义
    • BUU MISC(看心情写)
    • 第三方网站数据库测评:【源码级SQL注入与数据泄露风险全面测评】
    • 【Linux基础】parted命令详解:从入门到精通的磁盘分区管理完全指南
    • 实践《数字图像处理》之Canny边缘检测、霍夫变换与主动二值化处理在短线段清除应用中的实践
    • sim2real_动作迁移常用的方法和思路(比如bvh->robot)
    • 第六届机器学习与计算机应用国际学术会议
    • 正交匹配追踪(OMP)详解:压缩感知的基石算法
    • Github项目推荐:Made-With-ML 机器学习工程学习指南
    • 【Java实战㉞】从0到1:Spring Boot Web开发与接口设计实战
    • Python从入门到精通_01_python基础
    • 基于开源做的图片压缩工具