在 PyQt5 中,处理 160*120 位图流并实时显示,是添加 BMP 头文件快还是直接绘点快?如何实现 50FPS?
null
在 PyQt5 中,处理 160*120 位图流并实时显示,是添加 BMP 头文件快还是直接绘点快?如何实现 50FPS?
在PyQt5里处理160x120的位图流,直接绘点(QPainter.drawPoint)比添加BMP头再显示快得多。BMP头需要构造完整文件结构,涉及内存拷贝和格式解析,而直接绘点直接操作像素缓冲区。
要实现50FPS,关键是用QImage的scanLine直接写入像素数据,配合双缓冲避免闪烁。下面是完整实现:
import sys
import numpy as np
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QImage, QPainter, QColor
from PyQt5.QtCore import Qt, QTimer
class BitmapDisplay(QWidget):
def __init__(self):
super().__init__()
self.setFixedSize(160, 120)
# 创建QImage用于直接像素操作
self.image = QImage(160, 120, QImage.Format_RGB32)
self.image.fill(Qt.black)
# 双缓冲
self.buffer = QImage(160, 120, QImage.Format_RGB32)
# 模拟数据流 - 实际替换为你的位图数据
self.frame_count = 0
# 定时器实现50FPS (1000/50=20ms)
self.timer = QTimer()
self.timer.timeout.connect(self.update_frame)
self.timer.start(20) # 50FPS
def update_frame(self):
"""模拟生成新帧并更新显示"""
# 生成测试图像 - 实际替换为你的位图数据流
self.generate_test_frame()
# 触发重绘
self.update()
def generate_test_frame(self):
"""生成测试帧数据 - 直接操作QImage的像素缓冲区"""
self.frame_count += 1
# 直接访问QImage的缓冲区
for y in range(120):
scanline = self.image.scanLine(y)
# 将scanline转换为可操作的数组
# 注意:这里假设是32位RGB格式
for x in range(160):
# 计算像素位置(每个像素4字节)
pixel_pos = x * 4
# 生成一些变化的颜色
r = (x + self.frame_count) % 256
g = (y + self.frame_count * 2) % 256
b = (x + y + self.frame_count * 3) % 256
# 直接写入缓冲区(小端序:BGRA)
scanline[pixel_pos] = b # Blue
scanline[pixel_pos + 1] = g # Green
scanline[pixel_pos + 2] = r # Red
scanline[pixel_pos + 3] = 255 # Alpha
def paintEvent(self, event):
"""绘制图像 - 使用双缓冲避免闪烁"""
painter = QPainter(self)
# 先将图像绘制到缓冲区
buffer_painter = QPainter(self.buffer)
buffer_painter.drawImage(0, 0, self.image)
buffer_painter.end()
# 从缓冲区绘制到屏幕
painter.drawImage(0, 0, self.buffer)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = BitmapDisplay()
window.setWindowTitle('160x120 Bitmap Stream @50FPS')
window.show()
sys.exit(app.exec_())
核心优化点:
- 直接像素操作:通过
scanLine()直接访问QImage缓冲区,避免BMP头的构造和解析开销 - 双缓冲技术:先绘制到内存图像,再一次性绘制到屏幕,消除闪烁
- 定时器精确控制:20ms间隔实现50FPS
- 避免格式转换:直接使用RGB32格式,与显示设备格式匹配
如果你的原始数据是灰度图或其他格式,可以在generate_test_frame中直接转换,避免中间格式转换。对于160x120这种小分辨率,直接绘点完全能达到50FPS。
总结:直接操作像素缓冲区最快。
你这个像素是宇宙诞生之初的奇点吗?
用 Qt 做过类似的,我的图像是 8060 的,显示的时候放大到 480360,但是帧率低,30 左右,我是直接绘点,但是感觉现实图像的时候拖动窗口会有卡顿。如果不保存的话没必要处理成 bmp 吧,Qt 处理和显示图像效率好像不高
那用其他的图形库怎么样呢……
三个 byte 吧
其他库就没有研究过了,因为只是做个小工具,就怎么方便怎么来了
对 pyqt 不太了解,不过建议楼主做下测试,我是倾向于 bmp 可以更快的
首先,不需要非得是 bmp 文件,而是位图对象即可吧?先减少无畏的 io 时间
其次,ui 窗口上贴图乃至动画的方式,一般有高级的有底层的,底层的一般的内部实现都是直接调用 opengl 或 dx,让 gpu 直接处理,很快,而高级的一般是 cpu 再计算再处理,效率肯定要差不少,就好比 macos/ios 里 View 绘制用不用 CALayer。就贴图来讲,属于很远古的显卡就支持的功能,最早版本的 opengl 或 dx 就支持,pyqt 只要设计者合格,我相信会提供接近底层的贴图方法,那效率就应该远高于画像素,代码里自己折腾画图,跟 gpu 自己操作显存做与或运算来处理那效率差非常多的,当然,你的图并不大,或许目前主流电脑都可以满足你需求,我只是说我的经验和思路
好吧,我前面也写错了,一个像素 RGB 是 83 = 24 bits,写成 256 是脑子打结了
LZ 写成 160120*2bit 黑白图,就容易明白了
#2
你把这么简单的东西,说的如此深奥,我不会答啊
感谢…那我做下测试…
学识少,不太会描述问题…确实写成 1601202bit 容易理解多了。受教了…
160x120x1bpp -> 160x120 bits
2bpp 就成灰度图了。
U R right
单色是一位,两位是四色 CGA 了
pyqt 不懂
但 qtc++里 QImage::Format_Mono 和 QImage::Format_MonoLSB 可定义以 bit 表示 pixel 的图像
应该可以直接将原始数据流转成 QImage 然后显示
参考文档 http://doc.qt.io/qt-5/qimage.html#Format-enum
另外 50fps 帧率很高了,可能会考虑上 opengl,在 qt 里用它自己封装的 opengl 类不复杂,但 pyqt 可能编译的时候没有带 opengl 模块,这个自己斟酌吧
谢谢…我去看一下这个函数…
我昨晚想了想上位机刷新图像这么快看不出,应该 25fps 左右就差不多了。我再试试……

