I implemented a very basic image viewer that is supposed to show a batch of image stacks that are synced together, meaning that the same slice number should be displayed for all stacks. The viewer runs very well, but I get a Segmentation fault (core dumped) after closing the application. I have been trying to fix this for a while now but don't find the mistake. Your help would be very much appreciated!
Here is my code. It runs out of the box (displays random noise).
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import sys
import numpy as np
class ImageViewer2DWidget(QtGui.QWidget):
def __init__(self, width=300, height=300):
QtGui.QWidget.__init__(self)
self.image = None
self.init(width, height)
def init(self, width, height):
self.rect = QtCore.QRect(0, 0, width, height)
self.imageItem = pg.ImageItem()
self.imageItem.setImage(None)
self.graphicsScene = pg.GraphicsScene()
self.graphicsScene.addItem(self.imageItem)
self.graphicsView = pg.GraphicsView()
self.graphicsView.setRenderHint(QtGui.QPainter.Antialiasing)
self.graphicsView.setScene(self.graphicsScene)
layout = QtGui.QHBoxLayout()
layout.addWidget(self.graphicsView)
self.setLayout(layout)
self.setMaximumSize(width, height)
self.setMinimumSize(width-10, height-10)
def setImage(self, image):
assert len(image.shape) == 2 or len(image.shape) == 3
if len(image.shape) == 4:
assert image.shape[-1] == 4
self.image = image
self.imageItem.setImage(self.image)
self.imageItem.setRect(self.rect)
def setLevels(self, levels, update=True):
self.imageItem.setLevels(levels, update)
class ImageSlicingWidget(ImageViewer2DWidget):
def __init__(self, width=300, height=300):
self.slice = 0
ImageViewer2DWidget.__init__(self, width, height)
def setImage(self, image):
assert len(image.shape) == 3 or len(image.shape) == 4
if len(image.shape) == 4:
assert image.shape[-1] == 4
self.image = image
self._updateImageSlice()
def _updateImageSlice(self):
self.imageItem.setImage(self.image[self.slice])
self.imageItem.setRect(self.rect)
def setSlice(self, slice):
slice = np.max((0, slice))
slice = np.min((slice, self.image.shape[0] - 1))
self.slice = slice
self._updateImageSlice()
def getSlice(self):
return self.slice
class BatchViewer(QtGui.QWidget):
def __init__(self, width=300, height=300):
QtGui.QWidget.__init__(self)
self.batch = None
self.width = width
self.height = height
self.slicingWidgets = {}
self._init_gui()
def setBatch(self, batch):
assert len(batch.shape) == 4
for v in self.slicingWidgets.values():
self._my_layout.removeWidget(v)
self.slicingWidgets = {}
self.batch = batch
for i in range(self.batch.shape[0]):
w = ImageSlicingWidget(self.width, self.height)
w.setImage(self.batch[i])
w.setLevels([self.batch[i].min(), self.batch[i].max()])
w.setSlice(0)
self._my_layout.addWidget(w)
self.slicingWidgets[i] = w
def _init_gui(self):
self._my_layout = QtGui.QHBoxLayout()
self.slicingWidgets = {}
self.setLayout(self._my_layout)
self.setWindowTitle("Batch Viewer")
def wheelEvent(self, QWheelEvent):
for v in self.slicingWidgets.values():
v.setSlice(v.getSlice() + QWheelEvent.delta()/120)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
sv = BatchViewer()
batch = np.random.random((5, 300, 300, 300))
sv.setBatch(batch)
sv.show()
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
app.exec_()
# import IPython
# IPython.embed()