@camstack/addon-pipeline-analysis 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,208 @@
1
+ import { ICamstackAddon, AddonManifest, AddonContext, CapabilityProviderMap, PipelineConfig, CameraZone, MotionSource, KnownFace, KnownPlate, CameraLiveState, FrameInput, PipelineRunResult, DetectionEvent, TrackFilter, TrackedObjectSummary, ZoneLiveState, TimeRangeOptions, ZoneHistoryPoint, HeatmapOptions, HeatmapData, TrackDetail, PipelineStatus, DetectionZoneMembership, SpatialDetection, TrackedDetection, BoundingBox, TrackedObjectState, ZoneEvent, Classification } from '@camstack/types';
2
+
3
+ declare class AnalysisPipelineAddon implements ICamstackAddon {
4
+ readonly manifest: AddonManifest;
5
+ private pipeline;
6
+ initialize(context: AddonContext): Promise<void>;
7
+ shutdown(): Promise<void>;
8
+ getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
9
+ }
10
+
11
+ /**
12
+ * AnalysisPipeline — the main per-camera orchestrator.
13
+ *
14
+ * Implements IAnalysisAddon (extends ICamstackAddon + ICameraAnalyticsProvider).
15
+ * Per-camera state is keyed by deviceId.
16
+ *
17
+ * processFrame pipeline:
18
+ * PipelineRunResult → convert bboxes → zone filter → track → analyze state
19
+ * → emit events → update analytics → notify callbacks
20
+ */
21
+ declare class AnalysisPipeline implements ICamstackAddon {
22
+ readonly manifest: AddonManifest;
23
+ private readonly cameraStates;
24
+ private readonly analytics;
25
+ private readonly liveStateCallbacks;
26
+ initialize(_context: AddonContext): Promise<void>;
27
+ shutdown(): Promise<void>;
28
+ getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
29
+ setCameraPipeline(deviceId: string, _config: PipelineConfig): void;
30
+ setCameraZones(deviceId: string, zones: readonly CameraZone[]): void;
31
+ setCameraMotionConfig(_deviceId: string, _source: MotionSource): void;
32
+ setKnownFaces(_faces: KnownFace[]): void;
33
+ setKnownPlates(_plates: KnownPlate[]): void;
34
+ onLiveStateChange(deviceId: string, callback: (state: CameraLiveState) => void): () => void;
35
+ processFrame(deviceId: string, frame: FrameInput, pipelineResult?: PipelineRunResult): Promise<DetectionEvent[]>;
36
+ getLiveState(deviceId: string): CameraLiveState | null;
37
+ getTracks(deviceId: string, filter?: TrackFilter): TrackedObjectSummary[];
38
+ getZoneState(deviceId: string, zoneId: string): ZoneLiveState | null;
39
+ getZoneHistory(deviceId: string, zoneId: string, options: TimeRangeOptions): Promise<ZoneHistoryPoint[]>;
40
+ getHeatmap(deviceId: string, options: HeatmapOptions): Promise<HeatmapData>;
41
+ getTrackDetail(deviceId: string, trackId: string): TrackDetail | null;
42
+ getCameraStatus(deviceId: string): PipelineStatus[];
43
+ private ensureCameraState;
44
+ /**
45
+ * Convert PipelineDetection bbox [x1, y1, x2, y2] to BoundingBox {x, y, w, h}.
46
+ * Pipeline bboxes are in pixel coordinates.
47
+ */
48
+ private convertBbox;
49
+ }
50
+
51
+ interface Point {
52
+ readonly x: number;
53
+ readonly y: number;
54
+ }
55
+ interface LineSegment {
56
+ readonly p1: Point;
57
+ readonly p2: Point;
58
+ }
59
+ interface BboxRect {
60
+ readonly x: number;
61
+ readonly y: number;
62
+ readonly w: number;
63
+ readonly h: number;
64
+ }
65
+ interface TripwireResult {
66
+ readonly crossed: boolean;
67
+ readonly direction: 'left' | 'right';
68
+ }
69
+ /** Ray-casting point-in-polygon test */
70
+ declare function pointInPolygon(point: Point, polygon: readonly Point[]): boolean;
71
+ /** Parametric line-segment intersection. Returns intersection point or null. */
72
+ declare function lineIntersection(a: LineSegment, b: LineSegment): Point | null;
73
+ /** Detect tripwire crossing and direction via cross product. */
74
+ declare function tripwireCrossing(prev: Point, curr: Point, wire: LineSegment): TripwireResult | null;
75
+ /** Centroid of a bounding box { x, y, w, h } */
76
+ declare function bboxCentroid(bbox: BboxRect): Point;
77
+ /** Convert normalized (0–1) coordinates to pixel coordinates */
78
+ declare function normalizeToPixel(p: Point, width: number, height: number): Point;
79
+
80
+ interface FilterResult<T> {
81
+ readonly passed: readonly T[];
82
+ readonly excluded: readonly T[];
83
+ readonly annotations: ReadonlyMap<T, readonly DetectionZoneMembership[]>;
84
+ }
85
+ type Stage = 'motion' | 'detection';
86
+ declare class ZoneEngine {
87
+ /**
88
+ * Annotate a single detection with its zone memberships.
89
+ * Returns zones where the detection overlaps above threshold.
90
+ */
91
+ annotateDetection(bbox: BboxRect, zones: readonly CameraZone[], frameWidth: number, frameHeight: number, mask?: Uint8Array, maskWidth?: number, maskHeight?: number, className?: string): DetectionZoneMembership[];
92
+ /**
93
+ * Filter detections based on zone include/exclude/monitor logic for a given stage.
94
+ */
95
+ filterDetections<T extends BboxRect>(detections: readonly T[], zones: readonly CameraZone[], frameWidth: number, frameHeight: number, stage: Stage, getClassName?: (d: T) => string | undefined, getMask?: (d: T) => {
96
+ mask: Uint8Array;
97
+ width: number;
98
+ height: number;
99
+ } | undefined): FilterResult<T>;
100
+ /**
101
+ * Generate an auto-border exclusion zone as a polygon with a hole.
102
+ */
103
+ generateAutoBorderZone(percent: number): CameraZone;
104
+ }
105
+
106
+ interface TrackerConfig {
107
+ readonly iouThreshold: number;
108
+ readonly maxMissedFrames: number;
109
+ readonly minHits: number;
110
+ }
111
+ declare const DEFAULT_TRACKER_CONFIG: TrackerConfig;
112
+ interface InternalTrack {
113
+ id: string;
114
+ bbox: BoundingBox;
115
+ class: string;
116
+ originalClass: string;
117
+ score: number;
118
+ age: number;
119
+ hits: number;
120
+ path: BoundingBox[];
121
+ firstSeen: number;
122
+ lastSeen: number;
123
+ velocity: {
124
+ dx: number;
125
+ dy: number;
126
+ };
127
+ lost: boolean;
128
+ }
129
+ declare class SortTracker {
130
+ private readonly config;
131
+ private tracks;
132
+ private lostTracks;
133
+ constructor(config?: Partial<TrackerConfig>);
134
+ update(detections: readonly SpatialDetection[], timestamp: number): TrackedDetection[];
135
+ getActiveTracks(): readonly InternalTrack[];
136
+ getLostTracks(): readonly InternalTrack[];
137
+ reset(): void;
138
+ }
139
+
140
+ interface StateAnalyzerConfig {
141
+ readonly stationaryThresholdSec: number;
142
+ readonly loiteringThresholdSec: number;
143
+ readonly velocityThreshold: number;
144
+ readonly enteringFrames: number;
145
+ }
146
+ declare const DEFAULT_STATE_ANALYZER_CONFIG: StateAnalyzerConfig;
147
+ declare class StateAnalyzer {
148
+ private readonly config;
149
+ private readonly states;
150
+ constructor(config?: Partial<StateAnalyzerConfig>);
151
+ analyze(tracks: readonly TrackedDetection[], timestamp: number): TrackedObjectState[];
152
+ reset(): void;
153
+ }
154
+
155
+ interface EventEmitterConfig {
156
+ readonly minTrackAge: number;
157
+ readonly cooldownSec: number;
158
+ readonly enabledTypes: readonly string[];
159
+ }
160
+
161
+ declare class DetectionEventEmitter {
162
+ private readonly config;
163
+ private readonly previousStates;
164
+ private readonly lastEmitted;
165
+ constructor(config?: Partial<EventEmitterConfig>);
166
+ emit(tracks: readonly TrackedDetection[], states: readonly TrackedObjectState[], zoneEvents: readonly ZoneEvent[], classifications: readonly Classification[], deviceId: string): DetectionEvent[];
167
+ reset(): void;
168
+ }
169
+
170
+ declare class HeatmapAggregator {
171
+ private readonly gridSize;
172
+ private readonly cells;
173
+ private maxCount;
174
+ private _totalPoints;
175
+ constructor(gridSize?: number);
176
+ get totalPoints(): number;
177
+ addPoint(x: number, y: number): void;
178
+ getHeatmap(): HeatmapData;
179
+ reset(): void;
180
+ }
181
+
182
+ declare class TrackStore {
183
+ private readonly tracks;
184
+ update(tracked: readonly TrackedDetection[], zoneEvents: readonly ZoneEvent[], classifications: readonly Classification[], timestamp: number): void;
185
+ addEvent(trackId: string, event: DetectionEvent): void;
186
+ getTrackDetail(trackId: string): TrackDetail | null;
187
+ finishTrack(trackId: string): TrackDetail | null;
188
+ getActiveTrackIds(): string[];
189
+ reset(): void;
190
+ private toDetail;
191
+ }
192
+
193
+ /**
194
+ * Calculate overlap of a bounding box with a polygon.
195
+ * Uses sampling: divides bbox into grid, counts points inside polygon.
196
+ * Returns fraction 0–1 (intersection area / bbox area).
197
+ */
198
+ declare function bboxPolygonOverlap(bbox: BboxRect, polygon: readonly Point[]): number;
199
+ /**
200
+ * Calculate overlap of a segmentation mask with a polygon.
201
+ * Mask is a binary array (0/1) at maskWidth×maskHeight resolution,
202
+ * positioned at bbox within a frame of frameWidth×frameHeight.
203
+ * Polygon points are in pixel coordinates.
204
+ * Returns fraction 0–1 (mask pixels inside polygon / total mask pixels).
205
+ */
206
+ declare function maskPolygonOverlap(mask: Uint8Array, maskWidth: number, maskHeight: number, bbox: BboxRect, polygon: readonly Point[], _frameWidth: number, _frameHeight: number): number;
207
+
208
+ export { AnalysisPipeline, AnalysisPipelineAddon, type BboxRect, DEFAULT_STATE_ANALYZER_CONFIG, DEFAULT_TRACKER_CONFIG, DetectionEventEmitter, HeatmapAggregator, type LineSegment, type Point, SortTracker, StateAnalyzer, TrackStore, type TripwireResult, ZoneEngine, bboxCentroid, bboxPolygonOverlap, lineIntersection, maskPolygonOverlap, normalizeToPixel, pointInPolygon, tripwireCrossing };
@@ -0,0 +1,208 @@
1
+ import { ICamstackAddon, AddonManifest, AddonContext, CapabilityProviderMap, PipelineConfig, CameraZone, MotionSource, KnownFace, KnownPlate, CameraLiveState, FrameInput, PipelineRunResult, DetectionEvent, TrackFilter, TrackedObjectSummary, ZoneLiveState, TimeRangeOptions, ZoneHistoryPoint, HeatmapOptions, HeatmapData, TrackDetail, PipelineStatus, DetectionZoneMembership, SpatialDetection, TrackedDetection, BoundingBox, TrackedObjectState, ZoneEvent, Classification } from '@camstack/types';
2
+
3
+ declare class AnalysisPipelineAddon implements ICamstackAddon {
4
+ readonly manifest: AddonManifest;
5
+ private pipeline;
6
+ initialize(context: AddonContext): Promise<void>;
7
+ shutdown(): Promise<void>;
8
+ getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
9
+ }
10
+
11
+ /**
12
+ * AnalysisPipeline — the main per-camera orchestrator.
13
+ *
14
+ * Implements IAnalysisAddon (extends ICamstackAddon + ICameraAnalyticsProvider).
15
+ * Per-camera state is keyed by deviceId.
16
+ *
17
+ * processFrame pipeline:
18
+ * PipelineRunResult → convert bboxes → zone filter → track → analyze state
19
+ * → emit events → update analytics → notify callbacks
20
+ */
21
+ declare class AnalysisPipeline implements ICamstackAddon {
22
+ readonly manifest: AddonManifest;
23
+ private readonly cameraStates;
24
+ private readonly analytics;
25
+ private readonly liveStateCallbacks;
26
+ initialize(_context: AddonContext): Promise<void>;
27
+ shutdown(): Promise<void>;
28
+ getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
29
+ setCameraPipeline(deviceId: string, _config: PipelineConfig): void;
30
+ setCameraZones(deviceId: string, zones: readonly CameraZone[]): void;
31
+ setCameraMotionConfig(_deviceId: string, _source: MotionSource): void;
32
+ setKnownFaces(_faces: KnownFace[]): void;
33
+ setKnownPlates(_plates: KnownPlate[]): void;
34
+ onLiveStateChange(deviceId: string, callback: (state: CameraLiveState) => void): () => void;
35
+ processFrame(deviceId: string, frame: FrameInput, pipelineResult?: PipelineRunResult): Promise<DetectionEvent[]>;
36
+ getLiveState(deviceId: string): CameraLiveState | null;
37
+ getTracks(deviceId: string, filter?: TrackFilter): TrackedObjectSummary[];
38
+ getZoneState(deviceId: string, zoneId: string): ZoneLiveState | null;
39
+ getZoneHistory(deviceId: string, zoneId: string, options: TimeRangeOptions): Promise<ZoneHistoryPoint[]>;
40
+ getHeatmap(deviceId: string, options: HeatmapOptions): Promise<HeatmapData>;
41
+ getTrackDetail(deviceId: string, trackId: string): TrackDetail | null;
42
+ getCameraStatus(deviceId: string): PipelineStatus[];
43
+ private ensureCameraState;
44
+ /**
45
+ * Convert PipelineDetection bbox [x1, y1, x2, y2] to BoundingBox {x, y, w, h}.
46
+ * Pipeline bboxes are in pixel coordinates.
47
+ */
48
+ private convertBbox;
49
+ }
50
+
51
+ interface Point {
52
+ readonly x: number;
53
+ readonly y: number;
54
+ }
55
+ interface LineSegment {
56
+ readonly p1: Point;
57
+ readonly p2: Point;
58
+ }
59
+ interface BboxRect {
60
+ readonly x: number;
61
+ readonly y: number;
62
+ readonly w: number;
63
+ readonly h: number;
64
+ }
65
+ interface TripwireResult {
66
+ readonly crossed: boolean;
67
+ readonly direction: 'left' | 'right';
68
+ }
69
+ /** Ray-casting point-in-polygon test */
70
+ declare function pointInPolygon(point: Point, polygon: readonly Point[]): boolean;
71
+ /** Parametric line-segment intersection. Returns intersection point or null. */
72
+ declare function lineIntersection(a: LineSegment, b: LineSegment): Point | null;
73
+ /** Detect tripwire crossing and direction via cross product. */
74
+ declare function tripwireCrossing(prev: Point, curr: Point, wire: LineSegment): TripwireResult | null;
75
+ /** Centroid of a bounding box { x, y, w, h } */
76
+ declare function bboxCentroid(bbox: BboxRect): Point;
77
+ /** Convert normalized (0–1) coordinates to pixel coordinates */
78
+ declare function normalizeToPixel(p: Point, width: number, height: number): Point;
79
+
80
+ interface FilterResult<T> {
81
+ readonly passed: readonly T[];
82
+ readonly excluded: readonly T[];
83
+ readonly annotations: ReadonlyMap<T, readonly DetectionZoneMembership[]>;
84
+ }
85
+ type Stage = 'motion' | 'detection';
86
+ declare class ZoneEngine {
87
+ /**
88
+ * Annotate a single detection with its zone memberships.
89
+ * Returns zones where the detection overlaps above threshold.
90
+ */
91
+ annotateDetection(bbox: BboxRect, zones: readonly CameraZone[], frameWidth: number, frameHeight: number, mask?: Uint8Array, maskWidth?: number, maskHeight?: number, className?: string): DetectionZoneMembership[];
92
+ /**
93
+ * Filter detections based on zone include/exclude/monitor logic for a given stage.
94
+ */
95
+ filterDetections<T extends BboxRect>(detections: readonly T[], zones: readonly CameraZone[], frameWidth: number, frameHeight: number, stage: Stage, getClassName?: (d: T) => string | undefined, getMask?: (d: T) => {
96
+ mask: Uint8Array;
97
+ width: number;
98
+ height: number;
99
+ } | undefined): FilterResult<T>;
100
+ /**
101
+ * Generate an auto-border exclusion zone as a polygon with a hole.
102
+ */
103
+ generateAutoBorderZone(percent: number): CameraZone;
104
+ }
105
+
106
+ interface TrackerConfig {
107
+ readonly iouThreshold: number;
108
+ readonly maxMissedFrames: number;
109
+ readonly minHits: number;
110
+ }
111
+ declare const DEFAULT_TRACKER_CONFIG: TrackerConfig;
112
+ interface InternalTrack {
113
+ id: string;
114
+ bbox: BoundingBox;
115
+ class: string;
116
+ originalClass: string;
117
+ score: number;
118
+ age: number;
119
+ hits: number;
120
+ path: BoundingBox[];
121
+ firstSeen: number;
122
+ lastSeen: number;
123
+ velocity: {
124
+ dx: number;
125
+ dy: number;
126
+ };
127
+ lost: boolean;
128
+ }
129
+ declare class SortTracker {
130
+ private readonly config;
131
+ private tracks;
132
+ private lostTracks;
133
+ constructor(config?: Partial<TrackerConfig>);
134
+ update(detections: readonly SpatialDetection[], timestamp: number): TrackedDetection[];
135
+ getActiveTracks(): readonly InternalTrack[];
136
+ getLostTracks(): readonly InternalTrack[];
137
+ reset(): void;
138
+ }
139
+
140
+ interface StateAnalyzerConfig {
141
+ readonly stationaryThresholdSec: number;
142
+ readonly loiteringThresholdSec: number;
143
+ readonly velocityThreshold: number;
144
+ readonly enteringFrames: number;
145
+ }
146
+ declare const DEFAULT_STATE_ANALYZER_CONFIG: StateAnalyzerConfig;
147
+ declare class StateAnalyzer {
148
+ private readonly config;
149
+ private readonly states;
150
+ constructor(config?: Partial<StateAnalyzerConfig>);
151
+ analyze(tracks: readonly TrackedDetection[], timestamp: number): TrackedObjectState[];
152
+ reset(): void;
153
+ }
154
+
155
+ interface EventEmitterConfig {
156
+ readonly minTrackAge: number;
157
+ readonly cooldownSec: number;
158
+ readonly enabledTypes: readonly string[];
159
+ }
160
+
161
+ declare class DetectionEventEmitter {
162
+ private readonly config;
163
+ private readonly previousStates;
164
+ private readonly lastEmitted;
165
+ constructor(config?: Partial<EventEmitterConfig>);
166
+ emit(tracks: readonly TrackedDetection[], states: readonly TrackedObjectState[], zoneEvents: readonly ZoneEvent[], classifications: readonly Classification[], deviceId: string): DetectionEvent[];
167
+ reset(): void;
168
+ }
169
+
170
+ declare class HeatmapAggregator {
171
+ private readonly gridSize;
172
+ private readonly cells;
173
+ private maxCount;
174
+ private _totalPoints;
175
+ constructor(gridSize?: number);
176
+ get totalPoints(): number;
177
+ addPoint(x: number, y: number): void;
178
+ getHeatmap(): HeatmapData;
179
+ reset(): void;
180
+ }
181
+
182
+ declare class TrackStore {
183
+ private readonly tracks;
184
+ update(tracked: readonly TrackedDetection[], zoneEvents: readonly ZoneEvent[], classifications: readonly Classification[], timestamp: number): void;
185
+ addEvent(trackId: string, event: DetectionEvent): void;
186
+ getTrackDetail(trackId: string): TrackDetail | null;
187
+ finishTrack(trackId: string): TrackDetail | null;
188
+ getActiveTrackIds(): string[];
189
+ reset(): void;
190
+ private toDetail;
191
+ }
192
+
193
+ /**
194
+ * Calculate overlap of a bounding box with a polygon.
195
+ * Uses sampling: divides bbox into grid, counts points inside polygon.
196
+ * Returns fraction 0–1 (intersection area / bbox area).
197
+ */
198
+ declare function bboxPolygonOverlap(bbox: BboxRect, polygon: readonly Point[]): number;
199
+ /**
200
+ * Calculate overlap of a segmentation mask with a polygon.
201
+ * Mask is a binary array (0/1) at maskWidth×maskHeight resolution,
202
+ * positioned at bbox within a frame of frameWidth×frameHeight.
203
+ * Polygon points are in pixel coordinates.
204
+ * Returns fraction 0–1 (mask pixels inside polygon / total mask pixels).
205
+ */
206
+ declare function maskPolygonOverlap(mask: Uint8Array, maskWidth: number, maskHeight: number, bbox: BboxRect, polygon: readonly Point[], _frameWidth: number, _frameHeight: number): number;
207
+
208
+ export { AnalysisPipeline, AnalysisPipelineAddon, type BboxRect, DEFAULT_STATE_ANALYZER_CONFIG, DEFAULT_TRACKER_CONFIG, DetectionEventEmitter, HeatmapAggregator, type LineSegment, type Point, SortTracker, StateAnalyzer, TrackStore, type TripwireResult, ZoneEngine, bboxCentroid, bboxPolygonOverlap, lineIntersection, maskPolygonOverlap, normalizeToPixel, pointInPolygon, tripwireCrossing };