class ROIDisplayItem(HasTraits): roi = Instance(ROI) selected = Bool(False) slicer = Instance(Slicer) pixmap = Instance(QPixmap, default=None) pixmapitem = Instance(QGraphicsPixmapItem, default=None) def __init__(self, graphics, slicer, **kwargs): self._graphics = graphics self.slicer = slicer super(ROIDisplayItem, self).__init__(**kwargs) def destroy(self): self._graphics.scene().removeItem(self.pixmapitem) @on_trait_change('roi') def _roi_changed(self, obj, name, old, new): if old is not None: self._graphics.scene().removeItem(self.pixmapitem) self.pixmapitem = None self.pixmap = None if new is not None: self.pixmapitem = QGraphicsPixmapItem() self._set_pixmap_from_roi(new) self._graphics.scene().addItem(self.pixmapitem) @on_trait_change('roi:updated,roi:visible,slicer:slc,selected') def _roi_updated(self): self._set_pixmap_from_roi(self.roi) def _set_pixmap_from_roi(self, roi): if roi.visible: color = _display_color(roi.color, self.selected) else: color = QColor(Qt.transparent) self.pixmap = _ndarray_to_arraypixmap(roi.mask[self.slicer.slc.view_slice], color.toTuple()) self.pixmapitem.setPixmap(self.pixmap) self.pixmapitem.setZValue(_foreground_roi_z if self.selected else _background_roi_z)
class ArrayGraphicsView(QGraphicsView): '''ArrayGraphicsView is used for viewing a numpy array. TODO: * When image is loaded it should be zoomed to fit the window * Maximum zoom should be based on pixel size ''' mousemoved = Signal(object) mousewheeled = Signal(object) mousedoubleclicked = Signal(object) mousepressed = Signal(object) mousereleased = Signal(object) mouse_entered = Signal(object) mouse_left = Signal(object) key_pressed = Signal(object) def __init__(self): super(ArrayGraphicsView, self).__init__() self.setViewportUpdateMode(self.FullViewportUpdate) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.pixmapItem = QGraphicsPixmapItem() self.setScene(QGraphicsScene()) self.scene().addItem(self.pixmapItem) self.setBackgroundBrush(QBrush(Qt.black)) self.setMouseTracking(True) def mouseevent_to_item_coords(self, ev): sp = self.mapToScene(ev.pos()) p = self.pixmapItem.mapFromScene(sp) return (p.x(), p.y()) def enterEvent(self, ev): super(ArrayGraphicsView, self).enterEvent(ev) self.mouse_entered.emit(ev) def leaveEvent(self, ev): super(ArrayGraphicsView, self).leaveEvent(ev) self.mouse_left.emit(ev) def mouseReleaseEvent(self, ev): super(ArrayGraphicsView, self).mouseReleaseEvent(ev) self.mousereleased.emit(ev) def mousePressEvent(self, ev): super(ArrayGraphicsView, self).mousePressEvent(ev) self.mousepressed.emit(ev) def mouseMoveEvent(self, ev): super(ArrayGraphicsView, self).mouseMoveEvent(ev) self.mousemoved.emit(ev) def mouseDoubleClickEvent(self, ev): super(ArrayGraphicsView, self).mouseDoubleClickEvent(ev) self.mousedoubleclicked.emit(ev) def wheelEvent(self, ev): self.mousewheeled.emit(ev) def keyPressEvent(self, ev): super(ArrayGraphicsView, self).keyPressEvent(ev) self.key_pressed.emit(ev) def setPixmap(self, pixmap): '''Set the array to be viewed. Args: array (numpy array): the array to be viewed This will remove the previous array but maintain the previous scaling as well as the panned position. ''' self.pixmap = pixmap self.pixmapItem.setPixmap(self.pixmap) # Constrain scene to be the boundary of the pixmap pad = 5 r = self.pixmapItem.boundingRect() r = QRectF(r.left()-pad,r.top()-pad,r.width()+2*pad,r.height()+2*pad) self.setSceneRect(r) def fitView(self): self.fitInView(self.sceneRect(), Qt.KeepAspectRatio)