我正在开发基于 PyQt4 GUI 的基于传感器的 Python 应用程序。传感器正在生成 16 位测量值……每条“线”有 256 个 16 位“像素”。通过获得 256 行来获取一个正方形的“图像”,从而得到一个 (256,256) 个 16 位数字的 Numpy 数组。我只是想将其显示为灰度图像。传感器循环在 QThread 中运行并发出 QImage 信号。该信号连接到一个插槽,该插槽通过将数据打包成 32 位 RGB 图像来呈现主 GUI 中的数据。当然,要将 16 位灰度像素打包成 32 位 RGB 图像,我不得不将 16 位像素缩放为 8 位,并且会丢失大量动态范围。提供了一个 MWE,显示了我当前的策略(这显然不是我基于传感器的大型线程应用程序......它只是提取了显着部分)。
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Grayscale to RGB32 QPixmap tests
"""
import sys
import numpy as np
from PyQt4 import QtGui, QtCore
class PixmapTest(QtGui.QWidget):
def __init__(self):
super(PixmapTest, self).__init__()
self.initUI()
def initUI(self):
imglayout = QtGui.QHBoxLayout(self)
img_16bit = np.random.randint(0,65535,size=(256,256)).astype(np.uint32)
img_16bit_to_8bit = (img_16bit / 65535.0 * 255).astype(np.uint32)
packed_img_array = (255 << 24 | (img_16bit_to_8bit) << 16 | (img_16bit_to_8bit) << 8 | (img_16bit_to_8bit)).flatten()
img = QtGui.QImage(packed_img_array, 256, 256, QtGui.QImage.Format_RGB32)
pixmap = QtGui.QPixmap(img.scaledToWidth(img.width()*2))
imglabel = QtGui.QLabel(self)
imglabel.setPixmap(pixmap)
imglayout.addWidget(imglabel)
self.setLayout(imglayout)
self.move(300, 200)
self.setWindowTitle('QPixmap Test')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
form = PixmapTest()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
具体来说,我的问题是:
有没有更好的办法?解决方案必须保持“轻量级”(即 PyQt4 QImage/QPixmap)。我不能使用 Matplotlib 或任何重量级的东西,因为它太慢了。越接近原生 Python/Numpy 越好。我意识到这最终是 QImage 类的一个限制,但我希望有一个聪明的解决方案,我只是没有看到,让我保持我拥有的当前信号/插槽“接线”。
通过实验,我发现我必须将最终得到处理的所有数组声明为最终在 QImage 中作为 np.uint32 (尽管 np.int32 似乎也可以工作)。如果我只是将倒数第二个数组声明为 uint32/int32,则它不起作用。我不明白为什么。
我玩过改变亮度
Y' = 0.2126 * R + 0.7152 * G + 0.0722 * B
和其他类似的转换。可能在这里“抛光粪便”,但我想我会包括这个,因为 SX 上的其他答案似乎表明这很重要。尽管动态范围有所损失,但似乎可以像在我的 MWE 中那样简单地为 R、G、B 分配相同的值。
根据下面评论中的要求,这里是来自传感器的一些样本数据的直方图,用于说明动态范围: