Beispiel #1
0
def test_screenshot(qtbot):
    "Test taking a screenshot"
    viewer = Viewer()
    view = viewer.window.qt_viewer
    qtbot.addWidget(view)

    np.random.seed(0)
    # Add image
    data = np.random.random((10, 15))
    viewer.add_image(data)

    # Add labels
    data = np.random.randint(20, size=(10, 15))
    viewer.add_labels(data)

    # Add points
    data = 20 * np.random.random((10, 2))
    viewer.add_points(data)

    # Add vectors
    data = 20 * np.random.random((10, 2, 2))
    viewer.add_vectors(data)

    # Add shapes
    data = 20 * np.random.random((10, 4, 2))
    viewer.add_shapes(data)

    # Take screenshot
    screenshot = viewer.screenshot()
    assert screenshot.ndim == 3

    # Close the viewer
    viewer.window.close()
Beispiel #2
0
def test_nD_shapes(qtbot):
    """Test adding vectors."""
    viewer = Viewer()
    view = viewer.window.qt_viewer
    qtbot.addWidget(view)

    np.random.seed(0)
    # create one random rectangle per "plane"
    planes = np.tile(np.arange(10).reshape((10, 1, 1)), (1, 4, 1))
    corners = np.random.uniform(0, 10, size=(10, 4, 2))
    data = np.concatenate((planes, corners), axis=2)
    viewer.add_shapes(data)
    assert np.all(
        [np.all(ld == d) for ld, d in zip(viewer.layers[0].data, data)]
    )
    assert len(viewer.layers) == 1
    assert view.layers.vbox_layout.count() == 2 * len(viewer.layers) + 2

    assert viewer.dims.ndim == 3
    assert view.dims.nsliders == viewer.dims.ndim
    assert np.sum(view.dims._displayed_sliders) == 1

    # Flip dims order displayed
    viewer.dims.order = [0, 2, 1]
    assert viewer.dims.order == [0, 2, 1]

    # Flip dims order including non-displayed
    viewer.dims.order = [1, 0, 2]
    assert viewer.dims.order == [1, 0, 2]

    # Close the viewer
    viewer.window.close()
Beispiel #3
0
def test_add_shapes(qtbot):
    """Test adding shapes."""
    viewer = Viewer()
    view = viewer.window.qt_viewer
    qtbot.addWidget(view)

    np.random.seed(0)
    data = 20 * np.random.random((10, 4, 2))
    viewer.add_shapes(data)
    assert np.all(viewer.layers[0].data == data)

    assert len(viewer.layers) == 1
    assert view.layers.vbox_layout.count() == 2 * len(viewer.layers) + 2

    assert viewer.dims.ndim == 2
    assert view.dims.nsliders == viewer.dims.ndim
    assert np.sum(view.dims._displayed_sliders) == 0

    # Switch to 3D rendering mode and back to 2D rendering mode
    viewer.dims.ndisplay = 3
    assert viewer.dims.ndisplay == 3
    viewer.dims.ndisplay = 2
    assert viewer.dims.ndisplay == 2

    # Close the viewer
    viewer.window.close()
Beispiel #4
0
    def __init__(
        self,
        viewer: Viewer,
        im_shape: tuple,
        cell_masks: list = [],
        initial_state: Union[str, np.ndarray] = "good",
        selection_layer_name: str = 'selected_cell',
        accepted_layer_name: str = 'accepted_mask',
        rejected_layer_name: str = 'rejected_mask',
        mode: str = 'all',
    ):
        self.selected_shapes = viewer.add_shapes(name=selection_layer_name)

        self.initialize_masks(
            viewer=viewer,
            im_shape=im_shape,
            cell_masks=cell_masks,
            initial_state=initial_state,
            accepted_layer_name=accepted_layer_name,
            rejected_layer_name=rejected_layer_name,
        )

        viewer.bind_key("t", self.toggle_selected_mask)

        self._mode = mode
Beispiel #5
0
def test_add_shapes(qtbot):
    """Test adding vectors."""
    viewer = Viewer()
    view = viewer.window.qt_viewer
    qtbot.addWidget(view)

    np.random.seed(0)
    data = 20 * np.random.random((10, 4, 2))
    viewer.add_shapes(data)
    assert np.all(viewer.layers[0].data == data)

    assert len(viewer.layers) == 1
    assert view.layers.vbox_layout.count() == 2 * len(viewer.layers) + 2

    assert viewer.dims.ndim == 2
    assert view.dims.nsliders == 0
    assert np.sum(view.dims._displayed) == 0

    # Close the viewer
    viewer.window.close()
Beispiel #6
0
def test_data_change_ndisplay_shapes(qtbot):
    """Test change data calls for shapes layer with ndisplay change."""
    viewer = Viewer()
    view = viewer.window.qt_viewer
    qtbot.addWidget(view)

    np.random.seed(0)
    data = 20 * np.random.random((10, 4, 3))
    layer = viewer.add_shapes(data)

    visual = view.layer_to_visual[layer]

    @patch.object(visual, '_on_data_change', wraps=visual._on_data_change)
    def test_ndisplay_change(mocked_method, ndisplay=3):
        viewer.dims.ndisplay = ndisplay
        mocked_method.assert_called_once()

    # Switch to 3D rendering mode and back to 2D rendering mode
    test_ndisplay_change(ndisplay=3)
    test_ndisplay_change(ndisplay=2)

    # Close the viewer
    viewer.window.close()
    # add the timeseries
    movie_layer = viewer.add_image(movie,
                                   name='timeseries',
                                   contrast_limits=(0.0, 600.0),
                                   colormap='gray')

    mean_layer = viewer.add_image(mean,
                                  name='mean',
                                  contrast_limits=(0.0, 600.0),
                                  colormap='gray',
                                  visible=False)
    #
    # lc_layer = viewer.add_image(localcorr, name='localcorr', contrast_limits=(0.35, 1.0), colormap='gray', visible=False)
    #
    # centers_layer = viewer.add_points(centers, name='centers', edge_width=0, face_color='green', visible=False, opacity=0.5)
    #
    shapes_layer = viewer.add_shapes(polygons,
                                     shape_type='polygon',
                                     edge_width=0,
                                     face_color='green',
                                     opacity=0.5,
                                     name='neurons',
                                     visible=False)
    #
    labels = label(mask)
    labels_layer = viewer.add_labels(labels, name='rois')

# polygons_edit = shapes_layer.data
# np.save('data/neurofinder/polygons_edit.npy', polygons_edit)
Beispiel #8
0
base_cols = ['red', 'green', 'blue', 'white']

colors = [base_cols[i] for i in id]

with gui_qt():
    # create an empty viewer
    viewer = Viewer()

    # add the images
    layer = viewer.add_image(tiles, name=slide_name, clim_range=[0, 255])

    # add borders
    viewer.add_shapes(np.array(shapes),
                      shape_type='rectangle',
                      face_color=[0, 0, 0, 0],
                      edge_color=colors,
                      edge_width=border * 2,
                      opacity=0.75,
                      name='annotation')

    viewer.layers.unselect_all()

    @viewer.bind_key('c')
    def cored(viewer):
        """Set the current annotation to cored
        """
        msg = 'cored'
        shapes = viewer.layers['annotation']
        shapes._data_view.update_edge_color(0,
                                            base_cols[annot_types.index(msg)])
        shapes.refresh()
Beispiel #9
0
shape_1 = np.array([[float(c.attrib['X']),
                     float(c.attrib['Y'])] for c in root[0][0][0]])
shape_2 = np.array([[float(c.attrib['X']),
                     float(c.attrib['Y'])] for c in root[0][1][0]])
tumors = [shape_1, shape_2]

#print([p.shape[:2] for p in pyramid])

with gui_qt():
    # create an empty viewer
    viewer = Viewer()

    # add the pyramid
    #viewer.open(file_name, layer_type='image', name='slide', multiscale=True, scale=[10, 10], translate=[1000, 100])
    #viewer.open(file_name, layer_type='image', name='slide', multiscale=True, scale=[10, 10])
    viewer.open(file_name,
                layer_type='image',
                name='H&E stained lymph node',
                multiscale=True)

    layer = viewer.layers[0]

    tumor_layer = viewer.add_shapes(tumors,
                                    shape_type='polygon',
                                    edge_width=50,
                                    edge_color='blue',
                                    face_color=[0, 0, 1, 0.5],
                                    opacity=0.5,
                                    name='Tumors')
def build_plugin_(viewer: Viewer) -> None:
    """
    This part of the code sort of ended up as the controller for the plugin.
    """
    # validate state
    image_layers = [l for l in viewer.layers if isinstance(l, Image)]
    if len(image_layers) < 1:
        return
    layer: Image = image_layers[0]  # the image to visualize is the first
    image: np.ndarray = layer.data
    if image.ndim != 3:
        return
    if image.shape[2] <= 1:
        return

    n_channels = image.shape[2]

    # set up dock widgets
    topograph_pixels = _TopographPixels(n_channels)
    topograph_cells = TopographCells()

    viewer.window.add_dock_widget(
        topograph_pixels.view, name="TopographPixels", area="right"
    )
    # viewer.window.add_dock_widget(topograph_cells, name='TopographCells', area='right')

    init_rect = np.asarray([[0, 0], [0, 500], [500, 500], [500, 0]])

    shapes_layer: Shapes = viewer.add_shapes(
        [init_rect],
        shape_type="rectangle",
        name="Annotations",
        ndim=2,
        edge_color=[(1, 1, 1, 1)],  # black
        face_color=[(0, 0, 0, 0)],  # clear
    )

    _shape: Optional[np.ndarray] = None

    def update_plots():
        # at least one rectangle
        shapes: List[np.ndarray] = shapes_layer.data
        shapes: List[np.ndarray] = [s for s in shapes if is_rectangle(s)]
        if len(shapes) == 0:
            return

        # check if it's changed at all
        shape: np.ndarray = shapes[0]
        nonlocal _shape
        if (shape == _shape).all():
            return
        _shape = np.copy(shape)

        # get shape extents
        ymin, ymax = shape[:, 0].min(), shape[:, 0].max()
        ymin, ymax = int(round(ymin)), int(round(ymax))
        # ymin, ymax = int(round(ymin)), int(round(ymax)) + 1

        xmin, xmax = shape[:, 1].min(), shape[:, 1].max()
        xmin, xmax = int(round(xmin)), int(round(xmax))
        # xmin, xmax = int(round(xmin)), int(round(xmax)) + 1

        # clip extents
        ymin = min(max(ymin, 0), image.shape[0])
        ymax = max(min(ymax, image.shape[0]), 0)

        xmin = min(max(xmin, 0), image.shape[1])
        xmax = max(min(xmax, image.shape[1]), 0)

        # get desired region of image
        region = image[ymin:ymax, xmin:xmax, :]
        topograph_pixels.plotLayout.updatePlots(region)

    def on_change(event: Event) -> None:
        event_type = getattr(event, "type", None)
        if event_type != "set_data":
            return

        update_plots()

    shapes_layer.events.connect(on_change)
    update_plots()
def build_plugin(viewer: Viewer) -> None:
    # prepare viewer window
    viewer.window.qt_viewer.layerButtons.deleteButton.setDisabled(True)

    # add annotation layer with a single window
    init_rect = np.asarray([[0, 0], [500, 0], [500, 500], [0, 500]])
    annotation_layer: Shapes = viewer.add_shapes(
        [init_rect],
        shape_type="rectangle",
        name="Annotations",
        ndim=2,
        edge_color=[(1, 1, 1, 1)],
        face_color=[(0, 0, 0, 0)],
    )

    topograph_pixels = TopographPixels(viewer.layers)
    dock_widget: QtViewerDockWidget = viewer.window.add_dock_widget(
        topograph_pixels.view, name="TopographPixels", area="right"
    )
    viewer.window._qt_window.resizeDocks([dock_widget], [300], Qt.Horizontal)

    # update annotation rectangle
    _rect: Optional[np.ndarray] = None

    def update_plots() -> None:
        """
        Note that all coordinate values are in world coordinates; they correspond to
        *microns*. It is the responsibility of whoever is interacting with the image to
        convert these values from microns to pixels.
        """

        # at least one rectangle
        shapes: List[np.ndarray] = annotation_layer.data
        rects: List[np.ndarray] = [s for s in shapes if is_rectangle(s)]
        if len(rects) == 0:
            return

        # did rect change?
        rect = rects[0]
        nonlocal _rect
        if (_rect == rect).all():
            return
        _rect = np.copy(rect)

        # polygon to rectangle
        ymin, ymax = rect[:, 0].min(), rect[:, 0].max()
        ymin, ymax = int(round(ymin)), int(round(ymax)) + 1

        xmin, xmax = rect[:, 1].min(), rect[:, 1].max()
        xmin, xmax = int(round(xmin)), int(round(xmax)) + 1

        topograph_pixels.update_plots(xmin, xmax, ymin, ymax)

    @thread_worker
    def run_update():
        topograph_pixels.runButton.setDisabled(True)
        topograph_pixels.runButton.setText("Running...")
        update_plots()
        topograph_pixels.runButton.setEnabled(True)
        topograph_pixels.runButton.setText("Update")

    def run():
        worker = run_update()
        worker.start()

    topograph_pixels.runButton.clicked.connect(run)

    # viewer.layers.events.moved.connect(update_plots)
    #
    # def on_change(event: Event) -> None:
    #     event_type = getattr(event, "type", None)
    #     if event_type != "set_data":
    #         return
    #
    #     update_plots()
    #
    # annotation_layer.events.connect(on_change)

    # updating edge width
    _edge_width: Optional[float] = None

    def update_edge_width() -> None:
        edge_width = min(5 / viewer.camera.zoom, 200)

        nonlocal _edge_width
        if _edge_width == edge_width:
            return
        _edge_width = edge_width

        # current_edge_width.setter from `shapes.py`
        annotation_layer._current_edge_width = edge_width
        for i in range(len(annotation_layer._data_view.shapes)):
            annotation_layer._data_view.update_edge_width(i, edge_width)
        annotation_layer.status = format_float(annotation_layer.current_edge_width)
        annotation_layer.events.edge_width()

    def on_camera_event(event: Event):
        if event.type != "zoom":
            return

        update_edge_width()

    viewer.camera.events.connect(on_camera_event)
    update_edge_width()