|
| 1 | +/* @vitest-environment node */ |
| 2 | +import { describe, it, expect } from "vitest"; |
| 3 | +import { |
| 4 | + Labels, |
| 5 | + Video, |
| 6 | + Skeleton, |
| 7 | + Instance, |
| 8 | + Track, |
| 9 | + ROI, |
| 10 | + SegmentationMask, |
| 11 | + AnnotationType, |
| 12 | +} from "../src/index.js"; |
| 13 | + |
| 14 | +describe("Labels ROI and Mask integration", () => { |
| 15 | + it("stores rois and masks", () => { |
| 16 | + const video = new Video({ filename: "test.mp4" }); |
| 17 | + const roi = ROI.fromBbox(10, 20, 100, 200, { video }); |
| 18 | + const mask = SegmentationMask.fromArray(new Uint8Array(16), 4, 4, { video }); |
| 19 | + const labels = new Labels({ videos: [video], rois: [roi], masks: [mask] }); |
| 20 | + expect(labels.rois).toHaveLength(1); |
| 21 | + expect(labels.masks).toHaveLength(1); |
| 22 | + expect(labels.rois[0]).toBe(roi); |
| 23 | + expect(labels.masks[0]).toBe(mask); |
| 24 | + }); |
| 25 | + |
| 26 | + it("defaults rois and masks to empty arrays", () => { |
| 27 | + const labels = new Labels(); |
| 28 | + expect(labels.rois).toEqual([]); |
| 29 | + expect(labels.masks).toEqual([]); |
| 30 | + }); |
| 31 | + |
| 32 | + it("filters staticRois and temporalRois", () => { |
| 33 | + const video = new Video({ filename: "test.mp4" }); |
| 34 | + const staticRoi = ROI.fromBbox(0, 0, 10, 10, { video }); |
| 35 | + const temporalRoi = ROI.fromBbox(0, 0, 20, 20, { video, frameIdx: 5 }); |
| 36 | + const labels = new Labels({ rois: [staticRoi, temporalRoi] }); |
| 37 | + |
| 38 | + expect(labels.staticRois).toHaveLength(1); |
| 39 | + expect(labels.staticRois[0]).toBe(staticRoi); |
| 40 | + expect(labels.temporalRois).toHaveLength(1); |
| 41 | + expect(labels.temporalRois[0]).toBe(temporalRoi); |
| 42 | + }); |
| 43 | + |
| 44 | + it("getRois filters by video", () => { |
| 45 | + const v1 = new Video({ filename: "a.mp4" }); |
| 46 | + const v2 = new Video({ filename: "b.mp4" }); |
| 47 | + const roi1 = ROI.fromBbox(0, 0, 10, 10, { video: v1 }); |
| 48 | + const roi2 = ROI.fromBbox(0, 0, 10, 10, { video: v2 }); |
| 49 | + const labels = new Labels({ videos: [v1, v2], rois: [roi1, roi2] }); |
| 50 | + |
| 51 | + expect(labels.getRois({ video: v1 })).toEqual([roi1]); |
| 52 | + expect(labels.getRois({ video: v2 })).toEqual([roi2]); |
| 53 | + }); |
| 54 | + |
| 55 | + it("getRois filters by frameIdx", () => { |
| 56 | + const roi1 = ROI.fromBbox(0, 0, 10, 10, { frameIdx: 0 }); |
| 57 | + const roi2 = ROI.fromBbox(0, 0, 10, 10, { frameIdx: 5 }); |
| 58 | + const roi3 = ROI.fromBbox(0, 0, 10, 10); |
| 59 | + const labels = new Labels({ rois: [roi1, roi2, roi3] }); |
| 60 | + |
| 61 | + expect(labels.getRois({ frameIdx: 0 })).toEqual([roi1]); |
| 62 | + expect(labels.getRois({ frameIdx: 5 })).toEqual([roi2]); |
| 63 | + }); |
| 64 | + |
| 65 | + it("getRois filters by category", () => { |
| 66 | + const roi1 = ROI.fromBbox(0, 0, 10, 10, { category: "animal" }); |
| 67 | + const roi2 = ROI.fromBbox(0, 0, 10, 10, { category: "arena" }); |
| 68 | + const labels = new Labels({ rois: [roi1, roi2] }); |
| 69 | + |
| 70 | + expect(labels.getRois({ category: "animal" })).toEqual([roi1]); |
| 71 | + expect(labels.getRois({ category: "arena" })).toEqual([roi2]); |
| 72 | + }); |
| 73 | + |
| 74 | + it("getRois filters by annotationType", () => { |
| 75 | + const roi1 = ROI.fromBbox(0, 0, 10, 10); |
| 76 | + const roi2 = ROI.fromPolygon([[0, 0], [10, 0], [10, 10], [0, 10]]); |
| 77 | + const labels = new Labels({ rois: [roi1, roi2] }); |
| 78 | + |
| 79 | + expect(labels.getRois({ annotationType: AnnotationType.BOUNDING_BOX })).toEqual([roi1]); |
| 80 | + expect(labels.getRois({ annotationType: AnnotationType.SEGMENTATION })).toEqual([roi2]); |
| 81 | + }); |
| 82 | + |
| 83 | + it("getRois filters by track and instance", () => { |
| 84 | + const skeleton = new Skeleton({ nodes: ["A"] }); |
| 85 | + const track = new Track({ name: "track1" }); |
| 86 | + const inst = new Instance({ points: { A: [1, 2] }, skeleton, track }); |
| 87 | + const roi1 = ROI.fromBbox(0, 0, 10, 10, { track, instance: inst }); |
| 88 | + const roi2 = ROI.fromBbox(0, 0, 10, 10); |
| 89 | + const labels = new Labels({ rois: [roi1, roi2] }); |
| 90 | + |
| 91 | + expect(labels.getRois({ track })).toEqual([roi1]); |
| 92 | + expect(labels.getRois({ instance: inst })).toEqual([roi1]); |
| 93 | + }); |
| 94 | + |
| 95 | + it("getRois with combined filters uses AND logic", () => { |
| 96 | + const v1 = new Video({ filename: "a.mp4" }); |
| 97 | + const roi1 = ROI.fromBbox(0, 0, 10, 10, { video: v1, category: "animal", frameIdx: 0 }); |
| 98 | + const roi2 = ROI.fromBbox(0, 0, 10, 10, { video: v1, category: "arena", frameIdx: 0 }); |
| 99 | + const roi3 = ROI.fromBbox(0, 0, 10, 10, { video: v1, category: "animal", frameIdx: 5 }); |
| 100 | + const labels = new Labels({ rois: [roi1, roi2, roi3] }); |
| 101 | + |
| 102 | + const result = labels.getRois({ video: v1, category: "animal", frameIdx: 0 }); |
| 103 | + expect(result).toEqual([roi1]); |
| 104 | + }); |
| 105 | + |
| 106 | + it("getMasks filters by frameIdx", () => { |
| 107 | + const m1 = SegmentationMask.fromArray(new Uint8Array(4), 2, 2, { frameIdx: 0 }); |
| 108 | + const m2 = SegmentationMask.fromArray(new Uint8Array(4), 2, 2, { frameIdx: 3 }); |
| 109 | + const labels = new Labels({ masks: [m1, m2] }); |
| 110 | + |
| 111 | + expect(labels.getMasks({ frameIdx: 0 })).toEqual([m1]); |
| 112 | + expect(labels.getMasks({ frameIdx: 3 })).toEqual([m2]); |
| 113 | + }); |
| 114 | + |
| 115 | + it("getMasks filters by category", () => { |
| 116 | + const m1 = SegmentationMask.fromArray(new Uint8Array(4), 2, 2, { category: "bg" }); |
| 117 | + const m2 = SegmentationMask.fromArray(new Uint8Array(4), 2, 2, { category: "fg" }); |
| 118 | + const labels = new Labels({ masks: [m1, m2] }); |
| 119 | + |
| 120 | + expect(labels.getMasks({ category: "bg" })).toEqual([m1]); |
| 121 | + }); |
| 122 | + |
| 123 | + it("getMasks filters by video", () => { |
| 124 | + const v1 = new Video({ filename: "a.mp4" }); |
| 125 | + const v2 = new Video({ filename: "b.mp4" }); |
| 126 | + const m1 = SegmentationMask.fromArray(new Uint8Array(4), 2, 2, { video: v1 }); |
| 127 | + const m2 = SegmentationMask.fromArray(new Uint8Array(4), 2, 2, { video: v2 }); |
| 128 | + const labels = new Labels({ masks: [m1, m2] }); |
| 129 | + |
| 130 | + expect(labels.getMasks({ video: v1 })).toEqual([m1]); |
| 131 | + expect(labels.getMasks({ video: v2 })).toEqual([m2]); |
| 132 | + }); |
| 133 | + |
| 134 | + it("getMasks filters by track", () => { |
| 135 | + const track = new Track({ name: "t1" }); |
| 136 | + const m1 = SegmentationMask.fromArray(new Uint8Array(4), 2, 2, { track }); |
| 137 | + const m2 = SegmentationMask.fromArray(new Uint8Array(4), 2, 2); |
| 138 | + const labels = new Labels({ masks: [m1, m2] }); |
| 139 | + |
| 140 | + expect(labels.getMasks({ track })).toEqual([m1]); |
| 141 | + }); |
| 142 | + |
| 143 | + it("getMasks filters by annotationType", () => { |
| 144 | + const m1 = SegmentationMask.fromArray(new Uint8Array(4), 2, 2, { |
| 145 | + annotationType: AnnotationType.SEGMENTATION, |
| 146 | + }); |
| 147 | + const m2 = SegmentationMask.fromArray(new Uint8Array(4), 2, 2, { |
| 148 | + annotationType: AnnotationType.ARENA, |
| 149 | + }); |
| 150 | + const labels = new Labels({ masks: [m1, m2] }); |
| 151 | + |
| 152 | + expect(labels.getMasks({ annotationType: AnnotationType.SEGMENTATION })).toEqual([m1]); |
| 153 | + expect(labels.getMasks({ annotationType: AnnotationType.ARENA })).toEqual([m2]); |
| 154 | + }); |
| 155 | +}); |
0 commit comments