【发布时间】:2012-03-20 20:01:03
【问题描述】:
我想将图像转换为 NumPy 数组到 PySide QPixmap,所以我可以显示它(编辑:在我的 PySide UI 中)。我已经找到了这个工具:qimage2ndarray,但它只适用于 PyQt4。我尝试对其进行更改以使其与 PySide 一起使用,但我必须更改该工具的 C 部分,而且我没有使用 C 的经验。我该怎么做或有其他选择吗?
【问题讨论】:
我想将图像转换为 NumPy 数组到 PySide QPixmap,所以我可以显示它(编辑:在我的 PySide UI 中)。我已经找到了这个工具:qimage2ndarray,但它只适用于 PyQt4。我尝试对其进行更改以使其与 PySide 一起使用,但我必须更改该工具的 C 部分,而且我没有使用 C 的经验。我该怎么做或有其他选择吗?
【问题讨论】:
另一种选择是只使用 PIL 库。
>>> import numpy as np
>>> import Image
>>> im = Image.fromarray(np.random.randint(0,256,size=(100,100,3)).astype(np.uint8))
>>> im.show()
您可以查看http://www.pyside.org/docs/pyside/PySide/QtGui/QImage.html 处的 QPixmap 构造函数。
看起来你应该可以直接在构造函数中使用 numpy 数组:
类 PySide.QtGui.QImage(数据、宽度、高度、格式)
格式参数是以下之一:http://www.pyside.org/docs/pyside/PySide/QtGui/QImage.html#PySide.QtGui.PySide.QtGui.QImage.Format。
因此,例如,您可以执行以下操作:
>>> a = np.random.randint(0,256,size=(100,100,3)).astype(np.uint32)
>>> b = (255 << 24 | a[:,:,0] << 16 | a[:,:,1] << 8 | a[:,:,2]).flatten() # pack RGB values
>>> im = PySide.QtGui.QImage(b, 100, 100, PySide.QtGui.QImage.Format_RGB32)
我没有安装 PySide,所以我没有对此进行测试。它可能不会按原样工作,但它可能会引导您朝着正确的方向前进。
【讨论】:
b = (255 << 24 | a[:,:,0] << 16 | a[:,:,1] << 8 | a[:,:,2]),它起作用了。非常感谢!
b=... 行,我根本不明白...:为什么是255、24、16、8?我猜它与 2^8、2^4、2^3 有关,但 24 呢?还有一个解释会很好,谢谢!
如果您自己创建数据,例如使用 numpy,我认为最快的方法是直接访问 QImage。您可以从缓冲区对象 QImage.bits() 创建一个 ndarray,使用 numpy 方法做一些工作,并在完成后从 QImage 创建一个 QPixmap。您也可以通过这种方式读取或修改现有的 QImage。
import numpy as np
from PySide.QtGui import QImage
img = QImage(30, 30, QImage.Format_RGB32)
imgarr = np.ndarray(shape=(30,30), dtype=np.uint32, buffer=img.bits())
# qt write, numpy read
img.setPixel(0, 0, 5)
print "%x" % imgarr[0,0]
# numpy write, qt read
imgarr[0,1] = 0xff000006
print "%x" % img.pixel(1,0)
确保数组不会比图像对象更长寿。如果需要,您可以使用更复杂的 dtype,例如用于单独访问 alpha、red、green 和 blue 位的记录数组(但要注意字节序)。
如果没有使用 numpy 计算像素值的有效方法,您还可以使用 scipy.weave 内联一些对 img.bits() 指向的数组进行操作的 C/C++ 代码。
如果您已经有一个 ARGB 格式的图像,那么按照之前的建议从数据创建 QImage 可能会更容易。
【讨论】:
除了@user545424 关于使用 PIL 的回答,如果你不想依赖 PIL,你可以直接从你的 np 数组手动构造你的 Image:
width = 100
height = 100
data = np.random.randint(0,256,size=(width,height,3)).astype(np.uint8)
img = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32)
for x in xrange(width):
for y in xrange(height):
img.setPixel(x, y, QtGui.QColor(*data[x][y]).rgb())
pix = QtGui.QPixmap.fromImage(img)
我敢肯定,使用 PIL,有一种方法可以将实际图像数据读入 QImage,但我会让 @user545424 解决该部分,因为它来自他的回答。 PIL自带ImageQt模块,方便直接转换Image -> QPixmap,可惜那是PyQt4 QPixmap,帮不上忙。
【讨论】:
ImageQt 与PySide 一起使用。您可以在import ImageQt 之前写sys.modules['PyQt4'] = PySide。示例代码:pastebin.com/DX2pbdpV。但我不知道什么更快。
如果 user545424 的答案没有按预期工作:您在图像中看到伪影,那么我建议您将参数更改为
PySide.QtGui.QImage.Format_ARGB32
a = np.random.randint(0,256,size=(100,100,3)).astype(np.uint32)
b = (255 << 24 | a[:,:,0] << 16 | a[:,:,1] << 8 | a[:,:,2]).flatten() # pack RGB values
im = PySide.QtGui.QImage(b, 100, 100, PySide.QtGui.QImage.Format_ARGB32)
【讨论】: