def testOrthoZ(self): grid = DataGrid((GRIDSIZE, GRIDSIZE, GRIDSIZE), np.identity(4)) plane = OrthoSlice(grid, ZAXIS, SLICEPOS) self.assertEquals(tuple(plane.origin), (0, 0, SLICEPOS)) self.assertEquals(len(plane.basis), 2) self.assertTrue((0, 1, 0) in plane.basis) self.assertTrue((1, 0, 0) in plane.basis)
def testOrthoReversed(self): grid = DataGrid((GRIDSIZE, GRIDSIZE, GRIDSIZE), np.identity(4)) plane = OrthoSlice(grid, YAXIS, SLICEPOS) # Invert Z axis affine = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, GRIDSIZE - 1], [0, 0, 0, 1]]) datagrid = DataGrid((GRIDSIZE, GRIDSIZE, GRIDSIZE), affine) YD, XD, ZD = np.meshgrid(range(GRIDSIZE), range(GRIDSIZE), range(GRIDSIZE)) xdata, _, _, _ = NumpyData(XD, name="test", grid=datagrid).slice_data(plane) ydata, _, _, _ = NumpyData(YD, name="test", grid=datagrid).slice_data(plane) zdata, _, transv, offset = NumpyData(ZD, name="test", grid=datagrid).slice_data(plane) # Reversal is reflected in the transformation self.assertTrue(np.all(transv == [[1, 0], [0, -1]])) self.assertTrue(np.all(ydata == SLICEPOS)) for x in range(GRIDSIZE): self.assertTrue(np.all(xdata[x, :] == x)) self.assertTrue(np.all(zdata[:, x] == x))
def update(self): """ Update the ortho view """ if not self.isVisible(): return # Get the current position and slice self.focus_pos = self.ivl.focus() # Adjust axis scaling to that of the viewing grid spacing = self.ivl.grid.spacing self.vb.setAspectLocked(True, ratio=(spacing[self.xaxis] / spacing[self.yaxis])) self._update_labels() self._update_crosshairs() self._update_arrows() if self.force_redraw or self.focus_pos[ self. zaxis] != self.slice_z or self.slice_vol != self.focus_pos[3]: self.slice_z = self.focus_pos[self.zaxis] self.slice_vol = self.focus_pos[3] self.slice_plane = OrthoSlice(self.ivl.grid, self.zaxis, self.focus_pos[self.zaxis]) self.force_redraw = False for view in self._data_views: view.redraw(self.vb, self.slice_plane, self.slice_vol)
def _update_slice(self): self._slicez = self._ivl.focus()[self.zaxis] self._vol = self._ivl.focus()[3] self._plane = OrthoSlice(self._ivl.grid, self.zaxis, self._slicez) for view in self._data_views.values(): view.plane = self._plane view.vol = self._vol self.debug("set slice: %f %i", self._slicez, self._vol)
def testHighRes(self): grid = DataGrid((GRIDSIZE, GRIDSIZE, GRIDSIZE), np.identity(4)) plane = OrthoSlice(grid, YAXIS, SLICEPOS) data = np.random.rand(GRIDSIZE * 2, GRIDSIZE * 2, GRIDSIZE * 2) datagrid = DataGrid((GRIDSIZE * 2, GRIDSIZE * 2, GRIDSIZE * 2), np.identity(4) / 2) qpd = NumpyData(data, name="test", grid=datagrid) qpd.slice_data(plane)
def testOrthoY(self): grid = DataGrid((GRIDSIZE, GRIDSIZE, GRIDSIZE), np.identity(4)) YD, XD, ZD = np.meshgrid(range(GRIDSIZE), range(GRIDSIZE), range(GRIDSIZE)) plane = OrthoSlice(grid, YAXIS, SLICEPOS) self.assertEquals(tuple(plane.origin), (0, SLICEPOS, 0)) self.assertEquals(len(plane.basis), 2) self.assertTrue((1, 0, 0) in plane.basis) self.assertTrue((0, 0, 1) in plane.basis)
def testGenericZ(self): trans = np.array([[0.3, 0.2, 1.7, 0], [0.1, 2.1, 0.11, 0], [2.2, 0.7, 0.3, 0], [0, 0, 0, 1]]) grid = DataGrid((GRIDSIZE, GRIDSIZE, GRIDSIZE), trans) origin = list(SLICEPOS * trans[:3, 2]) plane = OrthoSlice(grid, ZAXIS, SLICEPOS) self.assertAlmostEquals(list(plane.origin), origin) self.assertEquals(len(plane.basis), 2) self.assertTrue(tuple(trans[:3, 0]) in plane.basis) self.assertTrue(tuple(trans[:3, 1]) in plane.basis)
def testOrtho(self): grid = DataGrid((GRIDSIZE, GRIDSIZE, GRIDSIZE), np.identity(4)) YD, XD, ZD = np.meshgrid(range(GRIDSIZE), range(GRIDSIZE), range(GRIDSIZE)) plane = OrthoSlice(grid, YAXIS, SLICEPOS) xdata, _, _, _ = NumpyData(XD, name="test", grid=grid).slice_data(plane) ydata, _, _, _ = NumpyData(YD, name="test", grid=grid).slice_data(plane) zdata, _, _, _ = NumpyData(ZD, name="test", grid=grid).slice_data(plane) self.assertTrue(np.all(ydata == SLICEPOS)) for x in range(GRIDSIZE): self.assertTrue(np.all(xdata[x, :] == x)) self.assertTrue(np.all(zdata[:, x] == x))
def testOrthoOffset(self): grid = DataGrid((GRIDSIZE, GRIDSIZE, GRIDSIZE), np.identity(4)) plane = OrthoSlice(grid, YAXIS, SLICEPOS) # Offset X axis affine = np.array([[1, 0, 0, 2], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) datagrid = DataGrid((GRIDSIZE, GRIDSIZE, GRIDSIZE), affine) YD, XD, ZD = np.meshgrid(range(GRIDSIZE), range(GRIDSIZE), range(GRIDSIZE)) xdata, _, _, _ = NumpyData(XD, name="test", grid=datagrid).slice_data(plane) ydata, _, _, _ = NumpyData(YD, name="test", grid=datagrid).slice_data(plane) zdata, _, transv, offset = NumpyData(ZD, name="test", grid=datagrid).slice_data(plane) self.assertTrue(np.all(ydata == SLICEPOS)) for x in range(GRIDSIZE): self.assertTrue(np.all(xdata[x, :] == x)) self.assertTrue(np.all(zdata[:, x] == x))
def run(self, options): data_name = options.pop('data', None) output_name = options.pop('output-name', None) if data_name is None: data_items = self.ivm.data.keys() elif isinstance(data_name, six.string_types): data_items = [ data_name, ] if output_name is None: output_name = "%s_stats" % data_name else: data_items = data_name data_items = [self.ivm.data[name] for name in data_items] if output_name is None: output_name = "stats" roi_name = options.pop('roi', None) roi = None if roi_name is not None: roi = self.ivm.rois[roi_name] slice_dir = options.pop('slice-dir', None) slice_pos = options.pop('slice-pos', 0) sl = None if slice_dir is not None: sl = OrthoSlice(self.ivm.main.grid, slice_dir, slice_pos) vol = options.pop('vol', None) no_extra = options.pop('no-extras', False) exact_median = options.pop('exact-median', False) self.model.clear() self.model.setVerticalHeaderItem(0, QtGui.QStandardItem("Mean")) self.model.setVerticalHeaderItem(1, QtGui.QStandardItem("Median")) self.model.setVerticalHeaderItem(2, QtGui.QStandardItem("STD")) self.model.setVerticalHeaderItem(3, QtGui.QStandardItem("Min")) self.model.setVerticalHeaderItem(4, QtGui.QStandardItem("Max")) col = 0 for data in data_items: stats, roi_labels = self.get_summary_stats( data, roi, slice_loc=sl, vol=vol, exact_median=exact_median) for ii in range(len(stats['mean'])): self.model.setHorizontalHeaderItem( col, QtGui.QStandardItem("%s\n%s" % (data.name, roi_labels[ii]))) self.model.setItem(0, col, QtGui.QStandardItem(sf(stats['mean'][ii]))) self.model.setItem( 1, col, QtGui.QStandardItem(sf(stats['median'][ii]))) self.model.setItem(2, col, QtGui.QStandardItem(sf(stats['std'][ii]))) self.model.setItem(3, col, QtGui.QStandardItem(sf(stats['min'][ii]))) self.model.setItem(4, col, QtGui.QStandardItem(sf(stats['max'][ii]))) col += 1 if not no_extra: self.ivm.add_extra(output_name, table_to_extra(self.model, output_name))
def __init__(self, ivl, ivm, ax_map, ax_labels): """ :param ivl: Viewer :param ivm: ImageVolumeManagement :param ax_map: Sequence defining the x, y, z axis of the slice viewer in terms of RAS axis sequence indexes :param ax_labels: Sequence of labels for the RAS axes """ LogSource.__init__(self) pg.GraphicsView.__init__(self) self._ivl = ivl self.ivm = ivm self.xaxis, self.yaxis, self.zaxis = ax_map self._slicez = 0 self._vol = 0 self._plane = OrthoSlice(self._ivl.grid, self.zaxis, self._slicez) self._main_view = None self._dragging = False self._arrow_items = [] self._data_views = {} self.debug("axes=%i, %i, %i", self.xaxis, self.yaxis, self.zaxis) # View box to display graphics items self._viewbox = pg.ViewBox(name="view%i" % self.zaxis, border=pg.mkPen((0x6c, 0x6c, 0x6c), width=2.0)) self._viewbox.setAspectLocked(True) self._viewbox.setBackgroundColor([0, 0, 0]) self._viewbox.enableAutoRange() self.setCentralItem(self._viewbox) # Crosshairs self._vline = pg.InfiniteLine(angle=90, movable=False) self._vline.setZValue(2 * MAX_NUM_DATA_SETS) self._vline.setPen( pg.mkPen((0, 255, 0), width=1.0, style=QtCore.Qt.DashLine)) self._hline = pg.InfiniteLine(angle=0, movable=False) self._hline.setZValue(2 * MAX_NUM_DATA_SETS) self._hline.setPen( pg.mkPen((0, 255, 0), width=1.0, style=QtCore.Qt.DashLine)) self._viewbox.addItem(self._vline, ignoreBounds=True) self._viewbox.addItem(self._hline, ignoreBounds=True) # Dummy image item which enables us to translate click co-ordinates # into image space co-ordinates even when there is no data in the view self._dummy = pg.ImageItem() self._dummy.setVisible(False) self._viewbox.addItem(self._dummy, ignoreBounds=True) # Static labels for the view directions self._labels = [] for axis in [self.xaxis, self.yaxis]: self._labels.append(QtGui.QLabel(ax_labels[axis][0], parent=self)) self._labels.append(QtGui.QLabel(ax_labels[axis][1], parent=self)) for label in self._labels: label.setAttribute(QtCore.Qt.WA_TranslucentBackground) self._grid_changed(self._ivl.grid) self._focus_changed(self._ivl.focus()) self._update_crosshairs() self._update_orientation() # Connect to signals from the parent viewer self._ivl.sig_grid_changed.connect(self._grid_changed) self._ivl.sig_focus_changed.connect(self._focus_changed) self._ivl.sig_arrows_changed.connect(self._arrows_changed) self._ivl.opts.sig_changed.connect(self._view_opts_changed) # Connect to data change signals self.ivm.sig_all_data.connect(self._data_changed) self.ivm.sig_main_data.connect(self._main_data_changed) # Need to intercept the default resize event # FIXME why can't call superclass method normally? self.resizeEventOrig = self.resizeEvent self.resizeEvent = self._window_resized