[英]Convert 16-bit grayscale to QImage
我正在开发基于PyQt4 GUI的基于传感器的Python应用程序。 传感器正在生成16位测量结果...每“行”有256个16位“像素”。 通过获得256行来获得正方形“图像”,从而得到一个(256,256)个16位数字的Numpy数组。 我只是想将其显示为灰度图像。 传感器循环在QThread中运行,并发出QImage信号。 信号连接到一个插槽,该插槽通过将数据打包到32位RGB图像中来呈现数据。 当然,要将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(尽管np.int32看起来也可以工作),才能最终在QImage中声明。 如果我仅将倒数第二个数组声明为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位时,它看起来像:
当将最小值和最大值映射为(0,255)时,它看起来像:
要将8bit图像转换为32bit,您只需调用img_8bit.repeat(4)
,它将重复每个字节4次,因此可以将内存视为uint32缓冲区。 由于您是通过Format_RGB32
而不是Format_ARGB32
创建QImage
的,因此不使用最高有效字节。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.