Exemple #1
0
def test_label_mutability():
    dummy_video = Video(backend=MediaVideo)
    dummy_skeleton = Skeleton()
    dummy_instance = Instance(dummy_skeleton)
    dummy_frame = LabeledFrame(dummy_video, frame_idx=0, instances=[dummy_instance])

    labels = Labels()
    labels.append(dummy_frame)

    assert dummy_video in labels.videos
    assert dummy_video in labels
    assert dummy_skeleton in labels.skeletons
    assert dummy_skeleton in labels
    assert dummy_frame in labels.labeled_frames
    assert dummy_frame in labels
    assert (dummy_video, 0) in labels
    assert (dummy_video, 1) not in labels

    dummy_video2 = Video(backend=MediaVideo)
    dummy_skeleton2 = Skeleton(name="dummy2")
    dummy_instance2 = Instance(dummy_skeleton2)
    dummy_frame2 = LabeledFrame(dummy_video2, frame_idx=0, instances=[dummy_instance2])
    assert dummy_video2 not in labels
    assert dummy_skeleton2 not in labels
    assert dummy_frame2 not in labels

    labels.append(dummy_frame2)
    assert dummy_video2 in labels
    assert dummy_frame2 in labels

    labels.remove_video(dummy_video2)
    assert dummy_video2 not in labels
    assert dummy_frame2 not in labels
    assert len(labels.find(dummy_video2)) == 0

    assert len(labels) == 1
    labels.append(LabeledFrame(dummy_video, frame_idx=0))
    assert len(labels) == 1

    dummy_frames = [LabeledFrame(dummy_video, frame_idx=i) for i in range(10)]
    dummy_frames2 = [LabeledFrame(dummy_video2, frame_idx=i) for i in range(10)]

    for f in dummy_frames + dummy_frames2:
        labels.append(f)

    assert len(labels) == 20
    labels.remove_video(dummy_video2)
    assert len(labels) == 10

    assert len(labels.find(dummy_video)) == 10
    assert dummy_frame in labels
    assert all([label in labels for label in dummy_frames[1:]])

    assert dummy_video2 not in labels
    assert len(labels.find(dummy_video2)) == 0
    assert all([label not in labels for label in dummy_frames2])

    labels.remove_video(dummy_video)
    assert len(labels.find(dummy_video)) == 0
Exemple #2
0
def simple_predictions():

    video = Video.from_filename("video.mp4")

    skeleton = Skeleton()
    skeleton.add_node("a")
    skeleton.add_node("b")

    track_a = Track(0, "a")
    track_b = Track(0, "b")

    labels = Labels()

    instances = []
    instances.append(
        PredictedInstance(
            skeleton=skeleton,
            score=2,
            track=track_a,
            points=dict(a=PredictedPoint(1, 1, score=0.5),
                        b=PredictedPoint(1, 1, score=0.5)),
        ))
    instances.append(
        PredictedInstance(
            skeleton=skeleton,
            score=5,
            track=track_b,
            points=dict(a=PredictedPoint(1, 1, score=0.7),
                        b=PredictedPoint(1, 1, score=0.7)),
        ))

    labeled_frame = LabeledFrame(video, frame_idx=0, instances=instances)
    labels.append(labeled_frame)

    instances = []
    instances.append(
        PredictedInstance(
            skeleton=skeleton,
            score=3,
            track=track_a,
            points=dict(a=PredictedPoint(4, 5, score=1.5),
                        b=PredictedPoint(1, 1, score=1.0)),
        ))
    instances.append(
        PredictedInstance(
            skeleton=skeleton,
            score=6,
            track=track_b,
            points=dict(a=PredictedPoint(6, 13, score=1.7),
                        b=PredictedPoint(1, 1, score=1.0)),
        ))

    labeled_frame = LabeledFrame(video, frame_idx=1, instances=instances)
    labels.append(labeled_frame)

    return labels
Exemple #3
0
def test_duplicate_skeletons_serializing():
    vid = Video.from_filename("foo.mp4")

    skeleton_a = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")
    skeleton_b = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")

    lf_a = LabeledFrame(vid, frame_idx=2, instances=[Instance(skeleton_a)])
    lf_b = LabeledFrame(vid, frame_idx=3, instances=[Instance(skeleton_b)])

    new_labels = Labels(labeled_frames=[lf_a, lf_b])
    new_labels_json = new_labels.to_dict()
Exemple #4
0
    def _points_dict_to_array(
        points: Dict[Union[str, Node], Point], parray: PointArray, skeleton: Skeleton
    ):
        """
        Sets values in given :class:`PointsArray` from dictionary.

        Args:
            points: The dictionary of points. Keys can be either node
                names or :class:`Node`s, values are :class:`Point`s.
            parray: The :class:`PointsArray` which is being updated.
            skeleton: The :class:`Skeleton` which contains the nodes
                referenced in the dictionary of points.

        Raises:
            ValueError: If dictionary keys are not either all strings
                or all :class:`Node`s.

        Returns:
            None
        """

        # Check if the dict contains all strings
        is_string_dict = set(map(type, points)) == {str}

        # Check if the dict contains all Node objects
        is_node_dict = set(map(type, points)) == {Node}

        # If the user fed in a dict whose keys are strings, these are node names,
        # convert to node indices so we don't break references to skeleton nodes
        # if the node name is relabeled.
        if points and is_string_dict:
            points = {skeleton.find_node(name): point for name, point in points.items()}

        if not is_string_dict and not is_node_dict:
            raise ValueError(
                "points dictionary must be keyed by either strings "
                + "(node names) or Nodes."
            )

        # Get rid of the points dict and replace with equivalent point array.
        for node, point in points.items():
            # Convert PredictedPoint to Point if Instance
            if type(parray) == PointArray and type(point) == PredictedPoint:
                point = Point(
                    x=point.x, y=point.y, visible=point.visible, complete=point.complete
                )
            try:
                parray[skeleton.node_to_index(node)] = point
                # parray[skeleton.node_to_index(node.name)] = point
            except:
                pass
Exemple #5
0
def test_scalar_properties():
    # Scalar
    dummy_video = Video(backend=MediaVideo)
    dummy_skeleton = Skeleton()
    dummy_instance = Instance(dummy_skeleton)
    dummy_frame = LabeledFrame(dummy_video,
                               frame_idx=0,
                               instances=[dummy_instance])

    labels = Labels()
    labels.append(dummy_frame)

    assert labels.video == dummy_video
    assert labels.skeleton == dummy_skeleton

    # Empty
    labels = Labels()
    with pytest.raises(ValueError):
        labels.video
    with pytest.raises(ValueError):
        labels.skeleton

    # More than one video
    dummy_skeleton = Skeleton()
    labels = Labels()
    labels.append(
        LabeledFrame(Video(backend=MediaVideo),
                     frame_idx=0,
                     instances=[Instance(dummy_skeleton)]))
    labels.append(
        LabeledFrame(Video(backend=MediaVideo),
                     frame_idx=0,
                     instances=[Instance(dummy_skeleton)]))
    assert labels.skeleton == dummy_skeleton
    with pytest.raises(ValueError):
        labels.video

    # More than one skeleton
    dummy_video = Video(backend=MediaVideo)
    labels = Labels()
    labels.append(
        LabeledFrame(dummy_video,
                     frame_idx=0,
                     instances=[Instance(Skeleton())]))
    labels.append(
        LabeledFrame(dummy_video,
                     frame_idx=1,
                     instances=[Instance(Skeleton())]))
    assert labels.video == dummy_video
    with pytest.raises(ValueError):
        labels.skeleton
Exemple #6
0
def test_distinct_skeletons_serializing():
    vid = Video.from_filename("foo.mp4")

    skeleton_a = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")
    skeleton_b = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")
    skeleton_b.add_node("foo")

    lf_a = LabeledFrame(vid, frame_idx=2, instances=[Instance(skeleton_a)])
    lf_b = LabeledFrame(vid, frame_idx=3, instances=[Instance(skeleton_b)])

    new_labels = Labels(labeled_frames=[lf_a, lf_b])

    # Make sure we can serialize this
    new_labels_json = new_labels.to_dict()
Exemple #7
0
def test_name_change(skeleton):
    new_skeleton = Skeleton.rename_skeleton(skeleton, "New Fly")

    import networkx as nx

    def dict_match(dict1, dict2):
        return dict1 == dict2

    # Make sure the graphs are the same, not exact but clo
    assert nx.is_isomorphic(new_skeleton._graph,
                            skeleton._graph,
                            node_match=dict_match)

    # Make sure the skeletons are different (because of name)
    assert new_skeleton != skeleton

    # Make sure they hash different
    assert hash(new_skeleton) != hash(skeleton)

    # Make sure sets work
    assert len({new_skeleton, skeleton}) == 2

    # Make sure changing the name causues problems
    with pytest.raises(NotImplementedError):
        skeleton.name = "Test"
Exemple #8
0
def test_instance_access():
    labels = Labels()

    dummy_skeleton = Skeleton()
    dummy_video = Video(backend=MediaVideo)
    dummy_video2 = Video(backend=MediaVideo)

    for i in range(10):
        labels.append(
            LabeledFrame(
                dummy_video,
                frame_idx=i,
                instances=[Instance(dummy_skeleton),
                           Instance(dummy_skeleton)],
            ))
    for i in range(10):
        labels.append(
            LabeledFrame(
                dummy_video2,
                frame_idx=i,
                instances=[
                    Instance(dummy_skeleton),
                    Instance(dummy_skeleton),
                    Instance(dummy_skeleton),
                ],
            ))

    assert len(labels.all_instances) == 50
    assert len(list(labels.instances(video=dummy_video))) == 20
    assert len(list(labels.instances(video=dummy_video2))) == 30
Exemple #9
0
def test_dont_unify_skeletons():
    vid = Video.from_filename("foo.mp4")

    skeleton_a = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")
    skeleton_b = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")

    lf_a = LabeledFrame(vid, frame_idx=2, instances=[Instance(skeleton_a)])
    lf_b = LabeledFrame(vid, frame_idx=3, instances=[Instance(skeleton_b)])

    labels = Labels(labeled_frames=[lf_a])
    labels.extend_from([lf_b], unify=False)
    ids = skeleton_ids_from_label_instances(labels)

    # Make sure we still have two distinct skeleton objects
    assert len(set(ids)) == 2

    # Make sure we can serialize this
    labels.to_dict()
Exemple #10
0
def test_nms_instances_to_remove():
    skeleton = Skeleton()
    skeleton.add_nodes(("a", "b"))

    instances = []

    inst = PredictedInstance(skeleton=skeleton)
    inst["a"].x = 10
    inst["a"].y = 10
    inst["b"].x = 20
    inst["b"].y = 20
    inst.score = 1
    instances.append(inst)

    inst = PredictedInstance(skeleton=skeleton)
    inst["a"].x = 10
    inst["a"].y = 10
    inst["b"].x = 15
    inst["b"].y = 15
    inst.score = 0.3
    instances.append(inst)

    inst = PredictedInstance(skeleton=skeleton)
    inst["a"].x = 30
    inst["a"].y = 30
    inst["b"].x = 40
    inst["b"].y = 40
    inst.score = 1
    instances.append(inst)

    inst = PredictedInstance(skeleton=skeleton)
    inst["a"].x = 32
    inst["a"].y = 32
    inst["b"].x = 42
    inst["b"].y = 42
    inst.score = 0.5
    instances.append(inst)

    to_keep, to_remove = nms_instances(instances,
                                       iou_threshold=0.5,
                                       target_count=3)

    assert len(to_remove) == 1
    assert to_remove[0].matches(instances[1])
Exemple #11
0
def test_unify_skeletons():
    vid = Video.from_filename("foo.mp4")

    skeleton_a = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")
    skeleton_b = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")

    lf_a = LabeledFrame(vid, frame_idx=2, instances=[Instance(skeleton_a)])
    lf_b = LabeledFrame(vid, frame_idx=3, instances=[Instance(skeleton_b)])

    labels = Labels()
    labels.extend_from([lf_a], unify=True)
    labels.extend_from([lf_b], unify=True)
    ids = skeleton_ids_from_label_instances(labels)

    # Make sure that skeleton_b got replaced with skeleton_a when we
    # added the frame with "unify" set
    assert len(set(ids)) == 1

    # Make sure we can serialize this
    labels.to_dict()
Exemple #12
0
def test_labels_merge():
    dummy_video = Video(backend=MediaVideo)
    dummy_skeleton = Skeleton()
    dummy_skeleton.add_node("node")

    labels = Labels()
    dummy_frames = []

    # Add 10 instances with different points (so they aren't "redundant")
    for i in range(10):
        instance = Instance(skeleton=dummy_skeleton, points=dict(node=Point(i, i)))
        dummy_frame = LabeledFrame(dummy_video, frame_idx=0, instances=[instance])
        dummy_frames.append(dummy_frame)

    labels.labeled_frames.extend(dummy_frames)
    assert len(labels) == 10
    assert len(labels.labeled_frames[0].instances) == 1

    labels.merge_matching_frames()
    assert len(labels) == 1
    assert len(labels.labeled_frames[0].instances) == 10
Exemple #13
0
def test_json(skeleton, tmpdir):
    """
    Test saving and loading a Skeleton object in JSON.
    """
    JSON_TEST_FILENAME = os.path.join(tmpdir, "skeleton.json")

    # Save it to a JSON filename
    skeleton.save_json(JSON_TEST_FILENAME)

    # Load the JSON object back in
    skeleton_copy = Skeleton.load_json(JSON_TEST_FILENAME)

    # Make sure we get back the same skeleton we saved.
    assert skeleton.matches(skeleton_copy)
Exemple #14
0
def test_basic_suggestions(small_robot_mp4_vid):
    dummy_video = small_robot_mp4_vid
    dummy_skeleton = Skeleton()
    dummy_instance = Instance(dummy_skeleton)
    dummy_frame = LabeledFrame(dummy_video, frame_idx=0, instances=[dummy_instance])

    labels = Labels()
    labels.append(dummy_frame)

    suggestions = VideoFrameSuggestions.suggest(
        labels=labels, params=dict(method="sample", per_video=13)
    )
    labels.set_suggestions(suggestions)

    assert len(labels.get_video_suggestions(dummy_video)) == 13
Exemple #15
0
def removal_test_labels():
    skeleton = Skeleton()
    video = Video(backend=MediaVideo)
    lf_user_only = LabeledFrame(
        video=video, frame_idx=0, instances=[Instance(skeleton=skeleton)]
    )
    lf_pred_only = LabeledFrame(
        video=video, frame_idx=1, instances=[PredictedInstance(skeleton=skeleton)]
    )
    lf_both = LabeledFrame(
        video=video,
        frame_idx=2,
        instances=[Instance(skeleton=skeleton), PredictedInstance(skeleton=skeleton)],
    )
    labels = Labels([lf_user_only, lf_pred_only, lf_both])
    return labels
Exemple #16
0
def test_merge_predictions():
    dummy_video_a = Video.from_filename("foo.mp4")
    dummy_video_b = Video.from_filename("foo.mp4")

    dummy_skeleton_a = Skeleton()
    dummy_skeleton_a.add_node("node")

    dummy_skeleton_b = Skeleton()
    dummy_skeleton_b.add_node("node")

    dummy_instances_a = []
    dummy_instances_a.append(
        Instance(skeleton=dummy_skeleton_a, points=dict(node=Point(1, 1)))
    )
    dummy_instances_a.append(
        Instance(skeleton=dummy_skeleton_a, points=dict(node=Point(2, 2)))
    )

    labels_a = Labels()
    labels_a.append(
        LabeledFrame(dummy_video_a, frame_idx=0, instances=dummy_instances_a)
    )

    dummy_instances_b = []
    dummy_instances_b.append(
        Instance(skeleton=dummy_skeleton_b, points=dict(node=Point(1, 1)))
    )
    dummy_instances_b.append(
        PredictedInstance(
            skeleton=dummy_skeleton_b, points=dict(node=Point(3, 3)), score=1
        )
    )

    labels_b = Labels()
    labels_b.append(
        LabeledFrame(dummy_video_b, frame_idx=0, instances=dummy_instances_b)
    )

    # Frames have one redundant instance (perfect match) and all the
    # non-matching instances are different types (one predicted, one not).
    merged, extra_a, extra_b = Labels.complex_merge_between(labels_a, labels_b)
    assert len(merged[dummy_video_a]) == 1
    assert len(merged[dummy_video_a][0]) == 1  # the predicted instance was merged
    assert not extra_a
    assert not extra_b
Exemple #17
0
def test_multivideo_tracks():
    vid_a = Video.from_filename("foo.mp4")
    vid_b = Video.from_filename("bar.mp4")

    skeleton = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")

    track_a = Track(spawned_on=2, name="A")
    track_b = Track(spawned_on=3, name="B")

    inst_a = Instance(track=track_a, skeleton=skeleton)
    inst_b = Instance(track=track_b, skeleton=skeleton)

    lf_a = LabeledFrame(vid_a, frame_idx=2, instances=[inst_a])
    lf_b = LabeledFrame(vid_b, frame_idx=3, instances=[inst_b])

    labels = Labels(labeled_frames=[lf_a, lf_b])

    # Try setting video B instance to track used in video A
    labels.track_swap(vid_b, new_track=track_a, old_track=track_b, frame_range=(3, 4))

    assert inst_b.track == track_a
Exemple #18
0
def test_deserialize_suggestions(small_robot_mp4_vid, tmpdir):
    dummy_video = small_robot_mp4_vid
    dummy_skeleton = Skeleton()
    dummy_instance = Instance(dummy_skeleton)
    dummy_frame = LabeledFrame(dummy_video, frame_idx=0, instances=[dummy_instance])

    labels = Labels()
    labels.append(dummy_frame)

    suggestions = VideoFrameSuggestions.suggest(
        labels=labels, params=dict(method="sample", per_video=13)
    )
    labels.set_suggestions(suggestions)

    filename = os.path.join(tmpdir, "new_suggestions.h5")
    Labels.save_file(filename=filename, labels=labels)

    new_suggestion_labels = Labels.load_file(filename)
    assert len(suggestions) == len(new_suggestion_labels.suggestions)
    assert [frame.frame_idx for frame in suggestions] == [
        frame.frame_idx for frame in new_suggestion_labels.suggestions
    ]
Exemple #19
0
    def __init__(self, labels_path: Optional[str] = None, *args, **kwargs):
        """Initialize the app.

        Args:
            labels_path: Path to saved :class:`Labels` dataset.

        Returns:
            None.
        """
        super(MainWindow, self).__init__(*args, **kwargs)

        self.state = GuiState()
        self.labels = Labels()

        self.commands = CommandContext(state=self.state,
                                       app=self,
                                       update_callback=self.on_data_update)

        self._menu_actions = dict()
        self._buttons = dict()
        self._child_windows = dict()

        self.overlays = dict()

        self.state.connect("filename", self.setWindowTitle)

        self.state["skeleton"] = Skeleton()
        self.state["labeled_frame"] = None
        self.state["filename"] = None
        self.state["show labels"] = True
        self.state["show edges"] = True
        self.state["edge style"] = "Line"
        self.state["fit"] = False
        self.state["color predicted"] = prefs["color predicted"]

        self._initialize_gui()

        if labels_path:
            self.loadProjectFile(labels_path)
Exemple #20
0
def test_skeleton_node_name_change():
    """
    Test that and instance is not broken after a node on the
    skeleton has its name changed.
    """

    s = Skeleton("Test")
    s.add_nodes(["a", "b", "c", "d", "e"])
    s.add_edge("a", "b")

    instance = Instance(s)
    instance["a"] = Point(1, 2)
    instance["b"] = Point(3, 4)

    # Rename the node
    s.relabel_nodes({"a": "A"})

    # Reference to the old node name should raise a KeyError
    with pytest.raises(KeyError):
        instance["a"].x = 2

    # Make sure the A now references the same point on the instance
    assert instance["A"] == Point(1, 2)
    assert instance["b"] == Point(3, 4)
Exemple #21
0
def stickman():

    # Make a skeleton with a space in its name to test things.
    stickman = Skeleton("Stick man")
    stickman.add_nodes(
        ["head", "neck", "body", "right-arm", "left-arm", "right-leg", "left-leg"]
    )
    stickman.add_edge("neck", "head")
    stickman.add_edge("body", "neck")
    stickman.add_edge("body", "right-arm")
    stickman.add_edge("body", "left-arm")
    stickman.add_edge("body", "right-leg")
    stickman.add_edge("body", "left-leg")
    stickman.add_symmetry(node1="left-arm", node2="right-arm")
    stickman.add_symmetry(node1="left-leg", node2="right-leg")

    return stickman
Exemple #22
0
def test_complex_merge():
    dummy_video_a = Video.from_filename("foo.mp4")
    dummy_video_b = Video.from_filename("foo.mp4")

    dummy_skeleton_a = Skeleton()
    dummy_skeleton_a.add_node("node")

    dummy_skeleton_b = Skeleton()
    dummy_skeleton_b.add_node("node")

    dummy_instances_a = []
    dummy_instances_a.append(
        Instance(skeleton=dummy_skeleton_a, points=dict(node=Point(1, 1))))
    dummy_instances_a.append(
        Instance(skeleton=dummy_skeleton_a, points=dict(node=Point(2, 2))))

    labels_a = Labels()
    labels_a.append(
        LabeledFrame(dummy_video_a, frame_idx=0, instances=dummy_instances_a))

    dummy_instances_b = []
    dummy_instances_b.append(
        Instance(skeleton=dummy_skeleton_b, points=dict(node=Point(1, 1))))
    dummy_instances_b.append(
        Instance(skeleton=dummy_skeleton_b, points=dict(node=Point(3, 3))))

    labels_b = Labels()
    labels_b.append(
        LabeledFrame(dummy_video_b, frame_idx=0,
                     instances=dummy_instances_b))  # conflict
    labels_b.append(
        LabeledFrame(dummy_video_b, frame_idx=1,
                     instances=dummy_instances_b))  # clean

    merged, extra_a, extra_b = Labels.complex_merge_between(labels_a, labels_b)

    # Check that we have the cleanly merged frame
    assert dummy_video_a in merged
    assert len(merged[dummy_video_a]) == 1  # one merged frame
    assert len(merged[dummy_video_a][1]) == 2  # with two instances

    # Check that labels_a includes redundant and clean
    assert len(labels_a.labeled_frames) == 2
    assert len(labels_a.labeled_frames[0].instances) == 1
    assert labels_a.labeled_frames[0].instances[0].points[0].x == 1
    assert len(labels_a.labeled_frames[1].instances) == 2
    assert labels_a.labeled_frames[1].instances[0].points[0].x == 1
    assert labels_a.labeled_frames[1].instances[1].points[0].x == 3

    # Check that extra_a/b includes the appropriate conflicting instance
    assert len(extra_a) == 1
    assert len(extra_b) == 1
    assert len(extra_a[0].instances) == 1
    assert len(extra_b[0].instances) == 1
    assert extra_a[0].instances[0].points[0].x == 2
    assert extra_b[0].instances[0].points[0].x == 3

    # Check that objects were unified
    assert extra_a[0].video == extra_b[0].video

    # Check resolving the conflict using new
    Labels.finish_complex_merge(labels_a, extra_b)
    assert len(labels_a.labeled_frames) == 2
    assert len(labels_a.labeled_frames[0].instances) == 2
    assert labels_a.labeled_frames[0].instances[1].points[0].x == 3
Exemple #23
0
def test_symmetry():
    s1 = Skeleton("s1")
    s1.add_nodes(["1", "2", "3", "4", "5", "6"])
    s1.add_edge("1", "2")
    s1.add_edge("3", "4")
    s1.add_edge("5", "6")
    s1.add_symmetry("1", "5")
    s1.add_symmetry("3", "6")

    assert (s1.nodes[0], s1.nodes[4]) in s1.symmetries
    assert (s1.nodes[2], s1.nodes[5]) in s1.symmetries
    assert len(s1.symmetries) == 2

    assert (0, 4) in s1.symmetric_inds
    assert (2, 5) in s1.symmetric_inds
    assert len(s1.symmetric_inds) == 2

    assert s1.get_symmetry("1").name == "5"
    assert s1.get_symmetry("5").name == "1"

    assert s1.get_symmetry("3").name == "6"

    # Cannot add more than one symmetry to a node
    with pytest.raises(ValueError):
        s1.add_symmetry("1", "6")
    with pytest.raises(ValueError):
        s1.add_symmetry("6", "1")

    s1.delete_symmetry("1", "5")
    assert s1.get_symmetry("1") is None

    with pytest.raises(ValueError):
        s1.delete_symmetry("1", "5")
Exemple #24
0
def test_arborescence():
    skeleton = Skeleton()
    skeleton.add_node("a")
    skeleton.add_node("b")
    skeleton.add_node("c")

    # linear: a -> b -> c
    skeleton.add_edge("a", "b")
    skeleton.add_edge("b", "c")

    assert skeleton.is_arborescence

    skeleton = Skeleton()
    skeleton.add_node("a")
    skeleton.add_node("b")
    skeleton.add_node("c")

    # two branches from a: a -> b and a -> c
    skeleton.add_edge("a", "b")
    skeleton.add_edge("a", "c")

    assert skeleton.is_arborescence

    skeleton = Skeleton()
    skeleton.add_node("a")
    skeleton.add_node("b")
    skeleton.add_node("c")

    # no edges so too many roots
    assert not skeleton.is_arborescence
    assert sorted((n.name for n in skeleton.root_nodes)) == ["a", "b", "c"]

    # still too many roots: a and c
    skeleton.add_edge("a", "b")

    assert not skeleton.is_arborescence
    assert sorted((n.name for n in skeleton.root_nodes)) == ["a", "c"]

    skeleton = Skeleton()
    skeleton.add_node("a")
    skeleton.add_node("b")
    skeleton.add_node("c")

    # cycle
    skeleton.add_edge("a", "b")
    skeleton.add_edge("b", "c")
    skeleton.add_edge("c", "a")

    assert not skeleton.is_arborescence
    assert len(skeleton.cycles) == 1
    assert len(skeleton.root_nodes) == 0

    skeleton = Skeleton()
    skeleton.add_node("a")
    skeleton.add_node("b")
    skeleton.add_node("c")
    skeleton.add_node("d")

    # diamond, too many sources leading to d
    skeleton.add_edge("a", "b")
    skeleton.add_edge("a", "c")
    skeleton.add_edge("b", "d")
    skeleton.add_edge("c", "d")

    assert not skeleton.is_arborescence
    assert len(skeleton.cycles) == 0
    assert len(skeleton.root_nodes) == 1
    assert len(skeleton.in_degree_over_one) == 1
Exemple #25
0
    def from_json_data(cls,
                       data: Union[str, dict],
                       match_to: Optional["Labels"] = None) -> "Labels":
        """
        Create instance of class from data in dictionary.

        Method is used by other methods that load from JSON.

        Args:
            data: Dictionary, deserialized from JSON.
            match_to: If given, we'll replace particular objects in the
                data dictionary with *matching* objects in the match_to
                :class:`Labels` object. This ensures that the newly
                instantiated :class:`Labels` can be merged without
                duplicate matching objects (e.g., :class:`Video` objects ).
        Returns:
            A new :class:`Labels` object.
        """

        # Parse the json string if needed.
        if type(data) is str:
            dicts = json_loads(data)
        else:
            dicts = data

        dicts["tracks"] = dicts.get(
            "tracks", [])  # don't break if json doesn't include tracks

        # First, deserialize the skeletons, videos, and nodes lists.
        # The labels reference these so we will need them while deserializing.
        nodes = cattr.structure(dicts["nodes"], List[Node])

        idx_to_node = {i: nodes[i] for i in range(len(nodes))}
        skeletons = Skeleton.make_cattr(idx_to_node).structure(
            dicts["skeletons"], List[Skeleton])
        videos = Video.cattr().structure(dicts["videos"], List[Video])

        try:
            # First try unstructuring tuple (newer format)
            track_cattr = cattr.Converter(
                unstruct_strat=cattr.UnstructureStrategy.AS_TUPLE)
            tracks = track_cattr.structure(dicts["tracks"], List[Track])
        except:
            # Then try unstructuring dict (older format)
            try:
                tracks = cattr.structure(dicts["tracks"], List[Track])
            except:
                raise ValueError("Unable to load tracks as tuple or dict!")

        # if we're given a Labels object to match, use its objects when they match
        if match_to is not None:
            for idx, sk in enumerate(skeletons):
                for old_sk in match_to.skeletons:
                    if sk.matches(old_sk):
                        # use nodes from matched skeleton
                        for (node, match_node) in zip(sk.nodes, old_sk.nodes):
                            node_idx = nodes.index(node)
                            nodes[node_idx] = match_node
                        # use skeleton from match
                        skeletons[idx] = old_sk
                        break
            for idx, vid in enumerate(videos):
                for old_vid in match_to.videos:

                    # Try to match videos using either their current or source filename
                    # if available.
                    old_vid_paths = [old_vid.filename]
                    if getattr(old_vid.backend, "has_embedded_images", False):
                        old_vid_paths.append(
                            old_vid.backend._source_video.filename)

                    new_vid_paths = [vid.filename]
                    if getattr(vid.backend, "has_embedded_images", False):
                        new_vid_paths.append(
                            vid.backend._source_video.filename)

                    is_match = False
                    for old_vid_path in old_vid_paths:
                        for new_vid_path in new_vid_paths:
                            if old_vid_path == new_vid_path or weak_filename_match(
                                    old_vid_path, new_vid_path):
                                is_match = True
                                videos[idx] = old_vid
                                break
                        if is_match:
                            break
                    if is_match:
                        break

        suggestions = []
        if "suggestions" in dicts:
            suggestions_cattr = cattr.Converter()
            suggestions_cattr.register_structure_hook(
                Video, lambda x, type: videos[int(x)])
            try:
                suggestions = suggestions_cattr.structure(
                    dicts["suggestions"], List[SuggestionFrame])
            except Exception as e:
                print("Error while loading suggestions (1)")
                print(e)

                try:
                    # Convert old suggestion format to new format.
                    # Old format: {video: list of frame indices}
                    # New format: [SuggestionFrames]
                    old_suggestions = suggestions_cattr.structure(
                        dicts["suggestions"], Dict[Video, List])
                    for video in old_suggestions.keys():
                        suggestions.extend([
                            SuggestionFrame(video, idx)
                            for idx in old_suggestions[video]
                        ])
                except Exception as e:
                    print("Error while loading suggestions (2)")
                    print(e)
                    pass

        if "negative_anchors" in dicts:
            negative_anchors_cattr = cattr.Converter()
            negative_anchors_cattr.register_structure_hook(
                Video, lambda x, type: videos[int(x)])
            negative_anchors = negative_anchors_cattr.structure(
                dicts["negative_anchors"], Dict[Video, List])
        else:
            negative_anchors = dict()

        if "provenance" in dicts:
            provenance = dicts["provenance"]
        else:
            provenance = dict()

        # If there is actual labels data, get it.
        if "labels" in dicts:
            label_cattr = make_instance_cattr()
            label_cattr.register_structure_hook(
                Skeleton, lambda x, type: skeletons[int(x)])
            label_cattr.register_structure_hook(Video,
                                                lambda x, type: videos[int(x)])
            label_cattr.register_structure_hook(
                Node, lambda x, type: x
                if isinstance(x, Node) else nodes[int(x)])
            label_cattr.register_structure_hook(
                Track, lambda x, type: None if x is None else tracks[int(x)])

            labels = label_cattr.structure(dicts["labels"], List[LabeledFrame])
        else:
            labels = []

        return Labels(
            labeled_frames=labels,
            videos=videos,
            skeletons=skeletons,
            nodes=nodes,
            suggestions=suggestions,
            negative_anchors=negative_anchors,
            tracks=tracks,
            provenance=provenance,
        )
Exemple #26
0
def test_symmetry():
    s1 = Skeleton("s1")
    s1.add_nodes(["1", "2", "3", "4", "5", "6"])
    s1.add_edge("1", "2")
    s1.add_edge("3", "4")
    s1.add_edge("5", "6")
    s1.add_symmetry("1", "5")
    s1.add_symmetry("3", "6")

    assert s1.get_symmetry("1").name == "5"
    assert s1.get_symmetry("5").name == "1"

    assert s1.get_symmetry("3").name == "6"

    # Cannot add more than one symmetry to a node
    with pytest.raises(ValueError):
        s1.add_symmetry("1", "6")
    with pytest.raises(ValueError):
        s1.add_symmetry("6", "1")

    s1.delete_symmetry("1", "5")
    assert s1.get_symmetry("1") is None

    with pytest.raises(ValueError):
        s1.delete_symmetry("1", "5")
Exemple #27
0
def test_eq():
    s1 = Skeleton("s1")
    s1.add_nodes(["1", "2", "3", "4", "5", "6"])
    s1.add_edge("1", "2")
    s1.add_edge("3", "4")
    s1.add_edge("5", "6")
    s1.add_symmetry("3", "6")

    # Make a copy check that they are equal
    s2 = copy.deepcopy(s1)
    assert s1.matches(s2)

    # Add an edge, check that they are not equal
    s2 = copy.deepcopy(s1)
    s2.add_edge("5", "1")
    assert not s1.matches(s2)

    # Add a symmetry edge, not equal
    s2 = copy.deepcopy(s1)
    s2.add_symmetry("5", "1")
    assert not s1.matches(s2)

    # Delete a node
    s2 = copy.deepcopy(s1)
    s2.delete_node("5")
    assert not s1.matches(s2)

    # Delete and edge, not equal
    s2 = copy.deepcopy(s1)
    s2.delete_edge("1", "2")
    assert not s1.matches(s2)
Exemple #28
0
def test_hdf5(skeleton, stickman, tmpdir):
    filename = os.path.join(tmpdir, "skeleton.h5")

    if os.path.isfile(filename):
        os.remove(filename)

    # Save both skeletons to the HDF5 filename
    skeleton.save_hdf5(filename)
    stickman.save_hdf5(filename)

    # Load the all the skeletons as a list
    sk_list = Skeleton.load_all_hdf5(filename)

    # Lets check that they are equal to what we saved, this checks the order too.
    assert skeleton.matches(sk_list[0])
    assert stickman.matches(sk_list[1])

    # Check load to dict as well
    sk_dict = Skeleton.load_all_hdf5(filename, return_dict=True)
    assert skeleton.matches(sk_dict[skeleton.name])
    assert stickman.matches(sk_dict[stickman.name])

    # Check individual load
    assert Skeleton.load_hdf5(filename, skeleton.name).matches(skeleton)
    assert Skeleton.load_hdf5(filename, stickman.name).matches(stickman)

    # Check overwrite save and save list
    Skeleton.save_all_hdf5(filename, [skeleton, stickman])
    assert Skeleton.load_hdf5(filename, skeleton.name).matches(skeleton)
    assert Skeleton.load_hdf5(filename, stickman.name).matches(stickman)

    # Make sure we can't load a non-existent skeleton
    with pytest.raises(KeyError):
        Skeleton.load_hdf5(filename, "BadName")

    # Make sure we can't save skeletons with the same name
    with pytest.raises(ValueError):
        Skeleton.save_all_hdf5(
            filename, [skeleton, Skeleton(name=skeleton.name)])
Exemple #29
0
def test_load_mat_format():
    skeleton = Skeleton.load_mat(
        "tests/data/skeleton/leap_mat_format/skeleton_legs.mat")

    # Check some stuff about the skeleton we loaded
    assert len(skeleton.nodes) == 24
    assert len(skeleton.edges) == 23

    # The node and edge list that should be present in skeleton_legs.mat
    node_names = [
        "head",
        "neck",
        "thorax",
        "abdomen",
        "wingL",
        "wingR",
        "forelegL1",
        "forelegL2",
        "forelegL3",
        "forelegR1",
        "forelegR2",
        "forelegR3",
        "midlegL1",
        "midlegL2",
        "midlegL3",
        "midlegR1",
        "midlegR2",
        "midlegR3",
        "hindlegL1",
        "hindlegL2",
        "hindlegL3",
        "hindlegR1",
        "hindlegR2",
        "hindlegR3",
    ]

    edges = [
        [2, 1],
        [1, 0],
        [2, 3],
        [2, 4],
        [2, 5],
        [2, 6],
        [6, 7],
        [7, 8],
        [2, 9],
        [9, 10],
        [10, 11],
        [2, 12],
        [12, 13],
        [13, 14],
        [2, 15],
        [15, 16],
        [16, 17],
        [2, 18],
        [18, 19],
        [19, 20],
        [2, 21],
        [21, 22],
        [22, 23],
    ]

    assert [n.name for n in skeleton.nodes] == node_names

    # Check the edges and their order
    for i, edge in enumerate(skeleton.edge_names):
        assert tuple(edges[i]) == (
            skeleton.node_to_index(edge[0]),
            skeleton.node_to_index(edge[1]),
        )
Exemple #30
0
def test_edge_order():
    """Test is edge list order is maintained upon insertion"""

    skeleton = Skeleton("Test")