예제 #1
0
    def test_add_cell_info_multiple_frames(self):
        num_frames = 5
        labels = np.zeros((num_frames, 1, 1, 1))
        project = models.Project.create(DummyLoader(labels=labels))
        edit = label.Edit(project)
        cell_ids = edit.labels.cell_ids
        cell_info = edit.labels.cell_info

        cell = 1
        feature = 0

        # Add new label to all frames
        for frame in range(num_frames):
            edit.add_cell_info(cell, frame)
            assert cell in cell_ids[feature]
            assert cell_info[feature][cell] == {
                'label': 1,
                'frames': list(range(frame + 1)),
                'parent': None,
                'frame_div': None,
                'daughters': [],
                'capped': False,
            }
            assert edit.y_changed
            assert edit.labels_changed
예제 #2
0
def test_redo_frame_not_changed_in_next_action():
    """
    Tests redoing when a frame may not be stored in the next action.
    """
    # Create project with two frames
    project = models.Project.create(DummyLoader(raw=np.zeros((2, 1, 1, 1))))

    # Mock action on both frame
    for frame in project.label_frames:
        frame.frame[:] = 1
    project.create_memento('both_frames')
    project.update()
    # Mock action on first frame
    project.label_frames[0].frame[:] = 2
    project.create_memento('first_frame_only')
    project.update()
    # Undo both action
    project.undo()
    project.undo()
    # Redo first action
    project.redo()

    assert 0 not in project.label_array
    assert 2 not in project.label_array
    assert 1 in project.label_frames[0].frame
    assert 1 in project.label_frames[1].frame
예제 #3
0
def test_raw_frame_init():
    """Test constructing the raw frames for a project."""
    project = models.Project.create(DummyLoader())
    raw_frames = project.raw_frames
    for frame in raw_frames:
        assert len(frame.frame.shape) == 3  # Height, width, channels
        assert frame.frame_id is not None
예제 #4
0
 def test_export_npz(self, app, db_session):
     with app.app_context():
         db_session.autoflush = False
         project = models.Project.create(DummyLoader())
         exporter = exporters.Exporter(project, 'npz')
         file_ = exporter.export()
         assert isinstance(file_, io.BytesIO)
예제 #5
0
def test_label_frame_init():
    """Test constructing the label frames for a project."""
    project = models.Project.create(DummyLoader())

    label_frames = project.label_frames
    for frame in label_frames:
        assert frame.frame.ndim == 3  # Height, width, features
        assert frame.frame_id is not None
예제 #6
0
def test_get_max_label_two_frames():
    labels = np.array([[[[1]]], [[[2]]]])
    project = models.Project.create(DummyLoader(labels=labels))
    feature = 0
    project.feature = feature
    project.update()
    max_label = project.get_max_label(feature)
    assert max_label == 2
예제 #7
0
def test_get_max_label_all_ones():
    labels = np.ones((1, 1, 1, 1))
    project = models.Project.create(DummyLoader(labels=labels))
    feature = 0
    project.feature = feature
    project.update()
    max_label = project.get_max_label(feature)
    assert max_label == 1
예제 #8
0
 def test_export(self, mocker, app, db_session):
     with app.app_context():
         mocked = mocker.patch('boto3.s3.inject.upload_fileobj')
         db_session.autoflush = False
         project = models.Project.create(DummyLoader())
         exporter = exporters.S3Exporter(project, 'npz')
         exporter.export('test')
         mocked.assert_called()
예제 #9
0
def test_labels_init():
    """Test constructing the Labels row for a Project."""
    project = models.Project.create(DummyLoader())
    labels = project.labels

    assert len(labels.cell_ids) == project.num_features
    assert len(labels.cell_info) == project.num_features
    for feature in range(project.num_features):
        assert len(labels.cell_ids[feature]) == len(labels.cell_info[feature])
예제 #10
0
def test_redo_no_next_action():
    """Test redoing at the end of the action history."""
    project = models.Project.create(DummyLoader())
    action = project.action
    num_actions = project.num_actions

    project.redo()

    assert project.action is action
    assert project.num_actions == num_actions
예제 #11
0
def test_undo_no_previous_action():
    """Test undoing at the start of the action history."""
    project = models.Project.create(DummyLoader())
    action = project.action
    num_actions = project.num_actions

    project.undo()

    assert project.action is action
    assert project.num_actions == num_actions
예제 #12
0
def test_get_project():
    """
    Test getting a project from the Projects table.
    creates a project, then gets it again.
    """
    project = models.Project.create(DummyLoader())

    valid_id = project.token
    found_project = models.Project.get(valid_id)
    assert found_project == project
예제 #13
0
def test_frames_init():
    """Test that raw, and label frames within a project are all compatible."""
    project = models.Project.create(DummyLoader())

    raw_frames = project.raw_frames
    label_frames = project.label_frames
    assert len(raw_frames) == len(label_frames)
    for raw_frame, label_frame in zip(raw_frames, label_frames):
        assert raw_frame.frame.shape[:-1] == label_frame.frame.shape[:-1]
        assert raw_frame.frame_id == label_frame.frame_id
        assert raw_frame.project_id == label_frame.project_id
예제 #14
0
    def test_replace_with_parent_with_overlap(self, app):
        """
        Replaces daughter with parent when the daughter exists before the div.
        """
        labels = np.reshape([1, 2, 1, 2], (2, 2, 1, 1))
        cell_info = {
            0: {
                1: {
                    'capped': True,
                    'frame_div': 1,
                    'daughters': [2],
                    'parent': None,
                    'frames': [0, 1],
                },
                2: {
                    'capped': False,
                    'frame_div': None,
                    'daughters': [],
                    'parent': 1,
                    'frames': [0, 1],
                },
            }
        }
        loader = DummyLoader(labels=labels,
                             cell_info=cell_info,
                             path='test.trk')
        project = models.Project.create(loader)
        edit = label.Edit(project)

        daughter = 2
        expected_labels = np.reshape([1, 2, 1, 1], (2, 2, 1, 1))
        expected_cell_info = {
            0: {
                1: {
                    'capped': False,
                    'frame_div': None,
                    'daughters': [],
                    'parent': None,
                    'frames': [0, 1],
                },
                2: {
                    'capped': False,
                    'frame_div': None,
                    'daughters': [],
                    'parent': None,
                    'frames': [0],
                },
            }
        }

        with app.app_context():
            edit.action_replace_with_parent(daughter)
            np.testing.assert_equal(project.label_array, expected_labels)
            assert edit.tracks == expected_cell_info[0]
예제 #15
0
def test_undo(client):
    # Project not found
    response = client.post('/api/undo/0')
    assert response.status_code == 404

    # Create a project
    project = models.Project.create(DummyLoader())

    # Undo with no action to undo silently does nothing
    response = client.post('/api/undo/{}'.format(project.token))
    assert response.status_code == 200
예제 #16
0
def test_redo(client):
    # Project not found
    response = client.post('/api/redo/0')
    assert response.status_code == 404

    # Create a project
    project = models.Project.create(DummyLoader())

    # Redo with no action to redo silently does nothing
    response = client.post(f'/api/redo/{project.token}')
    assert response.status_code == 200
예제 #17
0
    def test_action_replace_single(self, app):
        # single 2 x 2 frame with two labels: 1s in top row, 2s in bottom
        labels = np.reshape([1, 1, 2, 2], (1, 2, 2, 1))
        project = models.Project.create(DummyLoader(labels=labels))
        edit = label.Edit(project)
        expected_labels = np.array([[[1], [1]], [[1], [1]]])

        cell1 = 1
        cell2 = 2
        with app.app_context():
            edit.action_replace_single(cell1, cell2)
            np.testing.assert_array_equal(edit.frame, expected_labels)
            assert 2 not in edit.tracks
예제 #18
0
    def test_action_dilate_other_labels_unchanged(self, app):
        """Tests that other labels not affected by dilating a label."""
        labels = np.reshape([1, 1, 2, 2], (1, 2, 2, 1))
        project = models.Project.create(DummyLoader(labels=labels))
        edit = label.Edit(project)

        cell = 1
        other_cell = 2

        with app.app_context():
            edit.action_dilate(cell)
            np.testing.assert_array_equal(labels[project.frame] == other_cell,
                                          edit.frame == other_cell)
예제 #19
0
def test_project_init():
    """
    Test constructor for Project table.
    """
    project = models.Project(DummyLoader())

    # Check columns filled in by constructor
    assert project.path is not None
    assert project.source is not None
    assert project.num_frames is not None
    assert project.height is not None
    assert project.width is not None
    assert project.num_channels is not None
    assert project.num_features is not None
예제 #20
0
    def test_action_erode_delete_label(self, app):
        """Tests that a label is correctly removed when eroding deletes all of its pixels."""
        labels = np.zeros((1, 3, 3, 1))
        labels[0, 1, 1, 0] = 1
        project = models.Project.create(DummyLoader(labels=labels))
        edit = label.Edit(project)

        cell = 1

        with app.app_context():
            edit.action_erode(cell)
            assert cell not in edit.frame
            assert cell not in project.labels.cell_ids[project.feature]
            assert cell not in project.labels.cell_info[project.feature]
예제 #21
0
    def test_track_replace_daughter_that_divides_with_parent(self, app):
        labels = np.reshape([1, 2, 3], (3, 1, 1, 1))
        cell_info = {
            0: {
                1: {
                    'capped': True,
                    'frame_div': 1,
                    'daughters': [2],
                    'parent': None,
                    'frames': [0],
                },
                2: {
                    'capped': True,
                    'frame_div': 2,
                    'daughters': [3],
                    'parent': 1,
                    'frames': [1],
                },
                3: {
                    'capped': False,
                    'frame_div': None,
                    'daughters': [],
                    'parent': 2,
                    'frames': [2],
                },
            }
        }
        project = models.Project.create(
            DummyLoader(labels=labels, cell_info=cell_info, path='test.trk'))
        edit = label.Edit(project)
        expected_labels = np.reshape([1, 1, 3], (3, 1, 1, 1))

        parent = 1
        daughter = 2
        granddaughter = 3

        with app.app_context():
            edit.action_replace_with_parent(daughter)
            tracks = edit.tracks
            parent_track = tracks[parent]
            granddaughter_track = tracks[granddaughter]
            assert daughter not in tracks
            assert parent_track['capped']
            assert parent_track['daughters'] == [3]
            assert parent_track['frame_div'] == 2
            assert parent_track['frames'] == [0, 1]
            assert granddaughter_track['parent'] == 1
            np.testing.assert_array_equal(edit.project.label_array,
                                          expected_labels)
예제 #22
0
    def test_action_active_contour_label_too_large(self, app):
        """Tests that a label that is larger than the raw objects is made
        smaller by active contouring."""
        raw = np.zeros((1, 10, 10, 1))
        labels = np.ones((1, 10, 10, 1))
        raw[0, 3:6, 3:6, 0] = 1
        project = models.Project.create(DummyLoader(raw=raw, labels=labels))
        edit = label.Edit(project)

        cell = 1

        with app.app_context():
            edit.action_active_contour(cell)
            assert int(
                (edit.frame == 1).sum()) < (labels[project.frame] == 1).sum()
예제 #23
0
def test_finish_project():
    """
    Test finishing a project.
    Checks that the project's relationship are also finished.
    """
    # create project
    project = models.Project.create(DummyLoader())

    project.finish()
    assert project.finished is not None
    assert project.labels.cell_ids is None
    assert project.labels.cell_info is None
    for raw, label in zip(project.raw_frames, project.label_frames):
        assert raw.frame is None
        assert label.frame is None
예제 #24
0
def test_get_labeled_array():
    """
    Test outlined label arrays to send to the front-end.
    """
    project = models.Project.create(DummyLoader())
    frame = 0
    feature = 0
    expected_frame = project.label_frames[frame].frame[..., feature]

    label_arr = project.get_labeled_array(frame, feature)

    assert label_arr.shape == (project.height, project.width)
    np.testing.assert_array_equal(label_arr[label_arr >= 0],
                                  expected_frame[label_arr >= 0])
    np.testing.assert_array_equal(label_arr[label_arr < 0],
                                  -expected_frame[label_arr < 0])
예제 #25
0
def test_add_channel(client):
    project = models.Project.create(DummyLoader(raw=np.zeros((1, 1, 1, 1))))

    npz = io.BytesIO()
    np.savez(npz, new_channel=np.ones((1, 1, 1, 1)))
    npz.seek(0)
    data = {'file': (npz, 'test.npz')}

    response = client.post(f'/api/raw/{project.token}',
                           data=data,
                           content_type='multipart/form-data')
    assert response.status_code == 200
    assert response.json.get('numChannels') == 2
    assert project.raw_array.shape == (1, 1, 1, 2)
    assert 0 in project.raw_array
    assert 1 in project.raw_array
예제 #26
0
    def test_action_handle_draw_add_label(self, app):
        """Adding a label with by drawing it in."""
        labels = np.reshape([0], (1, 1, 1, 1))
        project = models.Project.create(DummyLoader(labels=labels))
        edit = label.Edit(project)

        trace, foreground, background, brush_size = [(0, 0)], 1, 0, 1
        feature = 0
        expected_draw = np.reshape([1], (1, 1))

        with app.app_context():
            edit.action_handle_draw(trace, foreground, background, brush_size)
            np.testing.assert_array_equal(edit.frame[..., feature],
                                          expected_draw)
            assert foreground in edit.labels.cell_info[feature]
            assert foreground in edit.labels.cell_ids[feature]
예제 #27
0
    def test_action_active_contour_other_labels_unchanged(self, app):
        """
        Tests that other labels not affected by active contouring a label
        """
        labels = np.ones((1, 10, 10, 1))
        labels[:, 5:, :, :] = 2
        project = models.Project.create(DummyLoader(labels=labels))
        edit = label.Edit(project)

        cell = 1
        other_cell = 2

        with app.app_context():
            edit.action_active_contour(cell)
            np.testing.assert_array_equal(labels[project.frame] == other_cell,
                                          edit.frame == other_cell)
예제 #28
0
    def test_add_daughter_existing_division(self, app):
        # two 2 x 1 frames
        # one label in the first frame and two in the second frame
        labels = np.reshape([0, 1, 2, 3], (2, 2, 1, 1))
        cell_info = {
            0: {
                1: {
                    'capped': True,
                    'frame_div': 1,
                    'daughters': [2],
                    'parent': None
                },
                2: {
                    'capped': False,
                    'frame_div': None,
                    'daughters': [],
                    'parent': 1
                },
                3: {
                    'capped': False,
                    'frame_div': None,
                    'daughters': [],
                    'parent': None,
                },
            }
        }
        project = models.Project.create(
            DummyLoader(labels=labels, cell_info=cell_info, path='test.trk'))
        edit = label.Edit(project)

        parent = 1
        daughter = 2
        other_daughter = 3
        frame_div = 1

        with app.app_context():
            edit.action_add_daughter(parent, other_daughter)
            tracks = edit.tracks
            parent_track = tracks[parent]
            daughter_track = tracks[daughter]
            other_daughter_track = tracks[other_daughter]
            assert parent_track['capped']
            assert daughter in parent_track['daughters']
            assert other_daughter in parent_track['daughters']
            assert parent_track['frame_div'] == frame_div
            assert daughter_track['parent'] == parent
            assert other_daughter_track['parent'] == parent
예제 #29
0
    def test_action_flood_background(self, app):
        """Flooding background does NOT spread to diagonal areas."""
        # 3 x 3 frame with label in diamond shape
        labels = np.reshape([0, 1, 0, 1, 0, 1, 0, 1, 0], (1, 3, 3, 1))
        project = models.Project.create(DummyLoader(labels=labels))
        edit = label.Edit(project)

        flood_label, x_loc, y_loc = 2, 1, 1
        feature = 0
        expected_flood = np.reshape([0, 1, 0, 1, 2, 1, 0, 1, 0], (3, 3))

        with app.app_context():
            edit.action_flood(flood_label, x_loc, y_loc)
            np.testing.assert_array_equal(edit.frame[..., feature],
                                          expected_flood)
            assert edit.y_changed
            assert edit.labels_changed
예제 #30
0
    def test_action_swap_single_frame_with_label_not_in_frame(self, app):
        """Tests that swapping with a cell not in frame updates the cell info."""
        labels = np.reshape([1], (1, 1, 1, 1))
        project = models.Project.create(DummyLoader(labels=labels))
        edit = label.Edit(project)

        cell1 = 1
        cell2 = 2
        expected_labels = np.reshape([2], (1, 1, 1, 1))

        with app.app_context():
            edit.action_swap_single_frame(cell1, cell2)
            np.testing.assert_array_equal(project.label_array, expected_labels)
            assert edit.y_changed
            assert edit.labels_changed
            assert cell2 in edit.tracks
            assert cell1 not in edit.tracks