python – 将16位灰度转换为QImage

我正在研究基于PyQt4 GUI的基于传感器的
Python应用程序.传感器正在生成16位测量…每个“线”256个16位“像素”.通过获得256行来获取正方形“图像”,得到16位数的(256,256)Numpy阵列.我只想将其显示为灰度图像.传感器循环在QThread中运行并发出QImage信号.信号连接到一个插槽,该插槽通过将数据打包成32位RGB图像来呈现主GUI中的数据.当然,为了将16位灰度像素打包成32位RGB图像,我不得不将16位像素缩放到8位,并且丢失了大量的动态范围.提供了一个显示我当前策略的MWE(这显然不是我更大的基于线程传感器的应用程序……它只是提取显着部分).请注意我是Python初学者,我正在尽我所能跟上…

#!/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类的限制,但我希望有一个聪明的解决方案我只是没有看到让我保持当前信号/插槽“接线”我有.
>通过实验,我发现我必须声明所有最终被处理的数组最终作为np.uint32在QImage中结束(尽管np.int32似乎也能正常工作).如果我只是将倒数第二个数组声明为uint32 / int32,它就不起作用.我不明白为什么.
>我用Y’= 0.2126 * R 0.7152 * G 0.0722 * B和其他类似的转换来改变亮度.可能在这里“抛光粪便”,但我认为我会包含这个,因为SX上的其他答案似乎表明这很重要.尽管失去了动态范围,但似乎可以简单地将相同的值分配给我的MWE中的R,G,B.

根据下面的评论中的要求,这里是来自传感器的一些样本数据的直方图,以说明动态范围:

最佳答案 这里我使用一些函数数据进行演示:

y, x = np.mgrid[-10:10:256j, -10:10:256j]
data = ((np.sin(y**2 + x**2) + 2) * 1000).astype(np.uint16)

img_8bit = (data / 256.0).astype(np.uint8) # use the high 8bit
img_8bit = ((data - data.min()) / (data.ptp() / 255.0)).astype(np.uint8) # map the data range to 0 - 255
img = QtGui.QImage(img_8bit.repeat(4), 256, 256, QtGui.QImage.Format_RGB32)

当使用高8位时,它看起来像:

当map min&最大值为(0,255),它看起来像:

要将8位图像转换为32位,您只需调用img_8bit.repeat(4),这将重复每个字节4次,因此可以将内存视为uint32缓冲区.由于您通过Format_RGB32而不是Format_ARGB32创建QImage,因此不使用最重要的字节.

点赞