예제 #1
0
class SliceableGraphicsView(GraphicsView, SlicingView):
    sigToggleHorizontalSlice = Signal(bool)
    sigToggleVerticalSlice = Signal(bool)
    sigToggleDepthSlice = Signal(bool)
    sigMakePrimary = Signal(object, object)
    sigCrosshairMoved = Signal()

    SUPPORTED_NDIM = 2

    def __init__(self, slice_direction, parent=None, xlink=None, ylink=None):
        super(SliceableGraphicsView, self).__init__(parent=parent)

        self.slice_direction = slice_direction

        self.setContentsMargins(0, 0, 0, 0)

        # Add axes
        self.view = SliceableAxes(slice_direction)
        self.view.axes["left"]["item"].setZValue(10)
        self.view.axes["top"]["item"].setZValue(10)
        self.setCentralItem(self.view)

        for sig in [
                'sigToggleVerticalSlice', 'sigToggleHorizontalSlice',
                'sigToggleDepthSlice', 'sigMakePrimary'
        ]:
            if hasattr(self.view, sig):
                getattr(self.view, sig).connect(getattr(self, sig))

        # Add imageitem
        self.image_item = ImageItem(axisOrder='row-major')
        self.image_item.setOpts()
        self.view.addItem(self.image_item)

        # add crosshair
        self.crosshair = BetterCrosshairROI((0, 0),
                                            parent=self.view,
                                            resizable=False)
        self.crosshair.sigMoved.connect(self.sigCrosshairMoved)
        self.view.getViewBox().addItem(self.crosshair)

        # find top-level parent NDImageView
        while not isinstance(parent, NDImageView):
            parent = parent.parent()

        # Initialize lut, levels
        self.image_item.setLevels(parent.levels, update=True)
        self.image_item.setLookupTable(parent.lut, update=True)

        # Link axes
        if ylink:
            self.view.vb.setYLink(ylink)
        if xlink:
            self.view.vb.setXLink(xlink)

    def setData(self, data):
        # Constrain squareness when units match
        is_square = data.dims[-2].split('(')[-1] == data.dims[-1].split(
            '(')[-1]
        self.view.vb.setAspectLocked(is_square)

        xvals = data.coords[data.dims[-1]]
        yvals = data.coords[data.dims[-2]]
        xmin = float(xvals.min())
        xmax = float(xvals.max())
        ymin = float(yvals.min())
        ymax = float(yvals.max())

        # Position the image according to coords
        shape = data.shape
        a = [(0, shape[-2]), (shape[-1], shape[-2]), (shape[-1], 0), (0, 0)]

        # b = [(ymin, xmax), (ymax, xmax), (ymax, xmin), (ymin, xmin)]
        if self.slice_direction in ['horizontal', 'depth']:
            b = [(xmin, ymin), (xmax, ymin), (xmax, ymax), (xmin, ymax)]
        elif self.slice_direction == 'vertical':
            b = [(xmax, ymax), (xmin, ymax), (xmin, ymin), (xmax, ymin)]

        quad1 = QPolygonF()
        quad2 = QPolygonF()
        for p, q in zip(a, b):
            quad1.append(QPointF(*p))
            quad2.append(QPointF(*q))

        transform = QTransform()
        QTransform.quadToQuad(quad1, quad2, transform)

        # Bind coords from the xarray to the timeline axis
        # super(SliceableGraphicsView, self).setImage(img, autoRange, autoLevels, levels, axes, np.asarray(img.coords[img.dims[0]]), pos, scale, transform, autoHistogramRange, levelMode)
        self.image_item.setImage(np.asarray(data), autoLevels=False)
        self.image_item.setTransform(transform)

        # Label the image axes
        self.view.setLabel('left', data.dims[-2])
        self.view.setLabel('bottom', data.dims[-1])

    def resetCrosshair(self):
        transform = self.image_item.viewTransform()
        new_pos = transform.map(self.image_item.boundingRect().center())
        self.crosshair.setPos(new_pos)
        # self.crosshair.sigMoved.emit(new_pos)

    def updateImage(self, autoHistogramRange=True):
        ## Redraw image on screen
        if self.image is None:
            return

        image = self.getProcessedImage()

        if autoHistogramRange:
            self.ui.histogram.setHistogramRange(self.levelMin, self.levelMax)

        # Transpose image into order expected by ImageItem
        if self.imageItem.axisOrder == 'col-major':
            axorder = ['t', 'x', 'y', 'c']
        else:
            axorder = ['t', 'y', 'x', 'c']
        axorder = [
            self.axes[ax] for ax in axorder if self.axes[ax] is not None
        ]
        ax_swap = [image.dims[ax_index] for ax_index in axorder]
        image = image.transpose(*ax_swap)

        # Select time index
        if self.axes['t'] is not None:
            self.ui.roiPlot.show()
            image = image[self.currentIndex]

        self.imageItem.updateImage(np.asarray(image))

    def updateCrosshair(self, x, y):
        self.crosshair.setPos(x, y)

    def quickMinMax(self, data):
        """
        Estimate the min/max values of *data* by subsampling. MODIFIED TO USE THE 99TH PERCENTILE instead of max.
        """
        if data is None:
            return 0, 0

        sl = slice(None, None, max(1, int(data.size // 1e6)))
        data = np.asarray(data[sl])

        levels = (np.nanmin(data),
                  np.nanpercentile(
                      np.where(data < np.nanmax(data), data, np.nanmin(data)),
                      99))

        return [levels]
예제 #2
0
class SliceableGraphicsView(GraphicsView):
    sigToggleHorizontalSlice = Signal(bool)
    sigToggleVerticalSlice = Signal(bool)
    sigMakePrimary = Signal(object, object)

    def __init__(self):
        super(SliceableGraphicsView, self).__init__()

        self.setContentsMargins(0, 0, 0, 0)

        # Add axes
        self.view = SliceableAxes()
        self.view.axes["left"]["item"].setZValue(10)
        self.view.axes["top"]["item"].setZValue(10)
        self.setCentralItem(self.view)
        self.view.sigToggleVerticalSlice.connect(self.sigToggleVerticalSlice)
        self.view.sigToggleHorizontalSlice.connect(self.sigToggleHorizontalSlice)
        self.view.sigMakePrimary.connect(self.sigMakePrimary)

        # Add imageitem
        self.image_item = ImageItem()
        self.view.addItem(self.image_item)

        # add crosshair
        self.crosshair = BetterCrosshairROI((0, 0), parent=self.view, resizable=False)
        self.view.getViewBox().addItem(self.crosshair)

    def setData(self, data):

        xvals = data.coords[data.dims[-1]]
        yvals = data.coords[data.dims[-2]]
        xmin = float(xvals.min())
        xmax = float(xvals.max())
        ymin = float(yvals.min())
        ymax = float(yvals.max())

        # Position the image according to coords
        shape = data.shape
        a = [(0, shape[-1]), (shape[-2] - 1, shape[-1]), (shape[-2] - 1, 1), (0, 1)]

        # b = [(ymin, xmax), (ymax, xmax), (ymax, xmin), (ymin, xmin)]
        b = [(xmax, ymin), (xmax, ymax), (xmin, ymax), (xmin, ymin)]

        quad1 = QPolygonF()
        quad2 = QPolygonF()
        for p, q in zip(a, b):
            quad1.append(QPointF(*p))
            quad2.append(QPointF(*q))

        transform = QTransform()
        QTransform.quadToQuad(quad1, quad2, transform)

        # Bind coords from the xarray to the timeline axis
        # super(SliceableGraphicsView, self).setImage(img, autoRange, autoLevels, levels, axes, np.asarray(img.coords[img.dims[0]]), pos, scale, transform, autoHistogramRange, levelMode)
        self.image_item.setImage(np.asarray(data), autoLevels=False)
        self.image_item.setTransform(transform)

        # Label the image axes
        self.view.setLabel('left', data.dims[-2])
        self.view.setLabel('bottom', data.dims[-1])

    def resetCrosshair(self):
        transform = self.image_item.viewTransform()
        new_pos = transform.map(self.image_item.boundingRect().center())
        self.crosshair.setPos(new_pos)
        self.crosshair.sigMoved.emit(new_pos)

    def updateImage(self, autoHistogramRange=True):
        ## Redraw image on screen
        if self.image is None:
            return

        image = self.getProcessedImage()

        if autoHistogramRange:
            self.ui.histogram.setHistogramRange(self.levelMin, self.levelMax)

        # Transpose image into order expected by ImageItem
        if self.imageItem.axisOrder == 'col-major':
            axorder = ['t', 'x', 'y', 'c']
        else:
            axorder = ['t', 'y', 'x', 'c']
        axorder = [self.axes[ax] for ax in axorder if self.axes[ax] is not None]
        ax_swap = [image.dims[ax_index] for ax_index in axorder]
        image = image.transpose(*ax_swap)

        # Select time index
        if self.axes['t'] is not None:
            self.ui.roiPlot.show()
            image = image[self.currentIndex]

        self.imageItem.updateImage(np.asarray(image))

    def quickMinMax(self, data):
        """
        Estimate the min/max values of *data* by subsampling. MODIFIED TO USE THE 99TH PERCENTILE instead of max.
        """
        if data is None:
            return 0, 0

        sl = slice(None, None, max(1, int(data.size // 1e6)))
        data = np.asarray(data[sl])

        levels = (np.nanmin(data), np.nanpercentile(np.where(data < np.nanmax(data), data, np.nanmin(data)), 99))

        return [levels]