最新更新 2016 年 3 月 29 日:
如果您复制粘贴以下代码,您应该会得到一个带有按钮的 pyqt 应用程序。如果单击它,您会在 ViewBox 中添加灰度。如果您重写声明 ARR_OFF
的位置,以便 ARR = plt.cm.jet(norm(ARR))
那么您会得到我遇到的错误。我想在 ViewBox 中将 ARR
显示为颜色图,因此我将其转换为 RGBA 数组。
import os, sys, matplotlib, matplotlib.pyplot
import numpy as np
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.widgets.GraphicsLayoutWidget import GraphicsLayoutWidget
import pyqtgraph as pg
import pyqtgraph.functions as fn
import matplotlib.pyplot as plt
N = 256
ARR = np.random.random((N,N))*255
norm = plt.Normalize()
ARR_OFF = plt.cm.jet(norm(ARR))
# Change ARR_OFF to ARR to see my problem
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUserInterface()
self.setupSignals()
def setupUserInterface(self):
""" Initialise the User Interface """
# Left frame
leftFrame = QtGui.QFrame()
leftFrameLayout = QtGui.QHBoxLayout()
leftFrame.setLayout(leftFrameLayout)
leftFrame.setLineWidth(0)
leftFrame.setFrameStyle(QtGui.QFrame.Panel)
leftFrameLayout.setContentsMargins(0,0,5,0)
# Left frame contents
self.viewMain = GraphicsLayoutWidget() # A GraphicsLayout within a GraphicsView
leftFrameLayout.addWidget(self.viewMain)
self.viewMain.setMinimumSize(200,200)
self.vb = MultiRoiViewBox(lockAspect=True,enableMenu=True)
self.viewMain.addItem(self.vb)
self.vb.enableAutoRange()
# Right frame
self.sidePanel = SidePanel(self)
# UI window (containing left and right frames)
UIwindow = QtGui.QWidget(self)
UIwindowLayout = QtGui.QHBoxLayout()
UIwindowSplitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
UIwindowLayout.addWidget(UIwindowSplitter)
UIwindow.setLayout(UIwindowLayout)
self.setCentralWidget(UIwindow)
UIwindowSplitter.addWidget(leftFrame)
UIwindowSplitter.addWidget(self.sidePanel)
self.setMinimumSize(600,500)
self.resize(self.minimumSize())
def setupSignals(self):
""" Setup signals """
self.sidePanel.buttImageAdd.clicked.connect(self.showImage)
def showImage(self,imageFilename):
""" Shows image in main view """
self.vb.showImage(ARR)
class ViewMode():
def __init__(self,id,cmap):
self.id = id
self.cmap = cmap
self.getLookupTable()
def getLookupTable(self):
lut = [ [ int(255*val) for val in self.cmap(i)[:3] ] for i in xrange(256) ]
lut = np.array(lut,dtype=np.ubyte)
self.lut = lut
class MultiRoiViewBox(pg.ViewBox):
def __init__(self,parent=None,border=None,lockAspect=False,enableMouse=True,invertY=False,enableMenu=True,name=None):
pg.ViewBox.__init__(self,parent,border,lockAspect,enableMouse,invertY,enableMenu,name)
self.img = None
self.NORMAL = ViewMode(0,matplotlib.cm.gray)
self.DEXA = ViewMode(1,matplotlib.cm.jet)
self.viewMode = self.NORMAL
def showImage(self,arr):
if arr==None:
self.img = None
return
if self.img==None:
self.img = pg.ImageItem(arr,autoRange=False,autoLevels=False)
self.addItem(self.img)
self.img.setImage(arr,autoLevels=False)
self.updateView()
def updateView(self):
self.background.setBrush(fn.mkBrush(self.viewMode.lut[0]))
self.background.show()
if self.img==None: return
else: self.img.setLookupTable(self.viewMode.lut)
from pyqtgraph.Qt import QtCore,QtGui
class SidePanel(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self,parent)
self.setMinimumWidth(250)
self.buttMinimumSize = QtCore.QSize(36,36)
self.setupImageToolbox()
sidePanelLayout = QtGui.QVBoxLayout()
sidePanelLayout.addWidget(self.imageToolbox)
sidePanelLayout.setContentsMargins(0,0,0,0)
self.setLayout(sidePanelLayout)
def setupImageToolbox(self):
# Image buttons
self.buttImageAdd = QtGui.QPushButton()
imageButtons = [self.buttImageAdd]
for i in xrange(len(imageButtons)):
image = imageButtons[i]
image.setMinimumSize(self.buttMinimumSize)
self.imageFileTools = QtGui.QFrame()
imageFileToolsLayout = QtGui.QHBoxLayout()
self.imageFileTools.setLayout(imageFileToolsLayout)
self.imageFileTools.setLineWidth(1)
self.imageFileTools.setFrameStyle(QtGui.QFrame.StyledPanel)
imageFileToolsLayout.addWidget(self.buttImageAdd)
# Image Toolbox (containing imageFileList + imageFileList buttons)
self.imageToolbox = QtGui.QFrame()
self.imageToolbox.setLineWidth(2)
self.imageToolbox.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised)
imageToolboxLayout = QtGui.QVBoxLayout()
self.imageToolbox.setLayout(imageToolboxLayout)
imageToolboxLayout.addWidget(self.imageFileTools)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
为方便起见的注释和引用
- plt.cm.jet
- 我知道 ImageView,它包含 ImageItem does indeed support RGBA 的 ViewBox
- 阅读ImageItem docs我发现要让 setImage 与 RGBA 配合使用,我只需向其传递一个数组,该数组的尺寸指定 RGBA channel
(numpy array) Specifies the image data. May be 2D (width, height) or 3D (width, height, RGBa). The array dtype must be integer or floating point of any bit depth. For 3D arrays, the third dimension must be of length 3 (RGB) or 4 (RGBA).
- 回溯不包含我的代码行。这是我在完整程序中看到的内容
回溯(最近一次调用最后一次):
File "/usr/lib/python2.7/dist-packages/pyqtgraph/graphicsItems/ImageItem.py", line 309, in paint
self.render()
File "/usr/lib/python2.7/dist-packages/pyqtgraph/graphicsItems/ImageItem.py", line 301, in render
argb, alpha = fn.makeARGB(image.transpose((1, 0, 2)[:image.ndim]), lut=lut, levels=self.levels)
File "/usr/lib/python2.7/dist-packages/pyqtgraph/functions.py", line 976, in makeARGB
imgData[..., i] = data[..., order[i]]
ValueError: could not broadcast input array from shape (256,256,4) into shape (256,256)
在此错误回溯之后,pyqt 应用程序不会崩溃并保持对其他操作的响应。但我的 ViewBox 仍然是黑的
在调用
updateView
之前,在showImage
的 dubug 控制台中,我看到以下内容,似乎表明一切正常。
>>> self.img <pyqtgraph.graphicsItems.ImageItem.ImageItem object at 0x7fc7140dbd60> >> arr.ndim 3
- 这让我认为问题出在
updateView
中。但这里的所有行都调用内置的 pyqtgraph 函数。 - 以下是我在调用
setLookupTable
之前在调试控制台中得到的内容
>>> fn <module 'pyqtgraph.functions' from '/usr/lib/python2.7/dist-packages/pyqtgraph/functions.pyc'> >>> self.viewMode.lut[0] array([0, 0, 0], dtype=uint8)
- 最后,这是我的完整应用程序的屏幕截图,以防您看到我看不到的内容。当然请注意,这适用于灰度。我非常感谢 Micheal Hogg让我根据自己的目的修改他的代码。
最佳答案
如果您自己将图像转换为 RGBA 数组,则不应为图像分配 LUT。否则,将通过在 makeARGB
中调用的 applyLookupTable
函数添加第五维。因此,解决方案的第一步是删除 MultiRoiViewBox.updateView
中的 self.img.setLookupTable(self.viewMode.lut)
。
此外,通过查看 makeARGB
中的以下几行,您可以看到 PyQtGraph 期望 RGBA 值在 0 到 255 的范围内
if lut is not None:
data = applyLookupTable(data, lut)
else:
if data.dtype is not np.ubyte:
data = np.clip(data, 0, 255).astype(np.ubyte)
但是,您使用 Matplotlib norm
来标准化 0 和 1 之间的值。因此,快速修复方法是将数组乘以 255
ARR = plt.cm.jet(norm(ARR)) * 255
但是,我可能不会像这样混合 MatPlotLib 和 PyQtGraph 以避免进一步的意外。此外,它可能会让其他程序员感到困惑,因此如果您这样做,请正确记录。
关于python - 如何将 RGB ImageItem 添加到 pyqtgraph ViewBox? ValueError : could not broadcast input array from shape (256, 256,4) 变为形状 (256,256),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36229937/