@camstack/lib-pipeline-analysis 0.1.0
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.
- package/dist/index.d.mts +333 -0
- package/dist/index.d.ts +333 -0
- package/dist/index.js +1336 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1279 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/zones/geometry.ts","../src/tracker/hungarian.ts","../src/tracker/sort-tracker.ts","../src/state/state-analyzer.ts","../src/zones/zone-evaluator.ts","../src/events/event-filters.ts","../src/events/event-emitter.ts","../src/analytics/track-store.ts","../src/analytics/live-state-manager.ts","../src/analytics/heatmap-aggregator.ts","../src/analytics/analytics-provider.ts","../src/snapshots/snapshot-manager.ts","../src/pipeline/analysis-pipeline.ts"],"sourcesContent":["// Geometry utilities\nexport * from './zones/geometry.js'\n\n// Tracker\nexport { SortTracker, DEFAULT_TRACKER_CONFIG } from './tracker/sort-tracker.js'\nexport type { ITracker, TrackerConfig } from './tracker/tracker.interface.js'\nexport { greedyAssignment } from './tracker/hungarian.js'\n\n// State analyzer\nexport { StateAnalyzer, DEFAULT_STATE_ANALYZER_CONFIG } from './state/state-analyzer.js'\nexport type { StateAnalyzerConfig } from './state/state-analyzer.js'\n\n// Zone evaluator\nexport { ZoneEvaluator } from './zones/zone-evaluator.js'\n\n// Events\nexport { EventFilter, DEFAULT_EVENT_FILTER_CONFIG } from './events/event-filters.js'\nexport type { EventFilterConfig } from './events/event-filters.js'\nexport { DetectionEventEmitter } from './events/event-emitter.js'\n\n// Analytics\nexport { TrackStore } from './analytics/track-store.js'\nexport { LiveStateManager } from './analytics/live-state-manager.js'\nexport { HeatmapAggregator } from './analytics/heatmap-aggregator.js'\nexport { AnalyticsProvider } from './analytics/analytics-provider.js'\n\n// Snapshots\nexport { SnapshotManager, DEFAULT_SNAPSHOT_CONFIG } from './snapshots/snapshot-manager.js'\nexport type { SnapshotConfig } from './snapshots/snapshot-manager.js'\n\n// Pipeline orchestrator\nexport { AnalysisPipeline } from './pipeline/analysis-pipeline.js'\nexport type { IAnalysisAddon, AnalysisPipelineConfig } from './pipeline/analysis-pipeline.js'\n","export interface Point {\n readonly x: number\n readonly y: number\n}\n\nexport interface LineSegment {\n readonly p1: Point\n readonly p2: Point\n}\n\n/**\n * Point-in-polygon test using the ray casting algorithm.\n * Returns true if the point is inside the polygon.\n */\nexport function pointInPolygon(point: Point, polygon: readonly Point[]): boolean {\n if (polygon.length < 3) return false\n\n let inside = false\n const { x, y } = point\n const n = polygon.length\n\n for (let i = 0, j = n - 1; i < n; j = i++) {\n const xi = polygon[i]!.x\n const yi = polygon[i]!.y\n const xj = polygon[j]!.x\n const yj = polygon[j]!.y\n\n const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi\n\n if (intersect) inside = !inside\n }\n\n return inside\n}\n\n/**\n * Line segment intersection — returns the intersection point or null if they don't intersect.\n * Uses parametric form of line equations.\n */\nexport function lineIntersection(a: LineSegment, b: LineSegment): Point | null {\n const dx1 = a.p2.x - a.p1.x\n const dy1 = a.p2.y - a.p1.y\n const dx2 = b.p2.x - b.p1.x\n const dy2 = b.p2.y - b.p1.y\n\n const denom = dx1 * dy2 - dy1 * dx2\n\n // Lines are parallel or collinear\n if (Math.abs(denom) < 1e-10) return null\n\n const dx3 = b.p1.x - a.p1.x\n const dy3 = b.p1.y - a.p1.y\n\n const t = (dx3 * dy2 - dy3 * dx2) / denom\n const u = (dx3 * dy1 - dy3 * dx1) / denom\n\n // Intersection only within both segments\n if (t < 0 || t > 1 || u < 0 || u > 1) return null\n\n return {\n x: a.p1.x + t * dx1,\n y: a.p1.y + t * dy1,\n }\n}\n\n/**\n * Check if a movement from prev to curr crosses the given tripwire.\n * Returns crossed=true and direction if crossed, null otherwise.\n * Direction is determined by the cross product sign:\n * - 'right' if moving from the left side of the tripwire to the right\n * - 'left' if moving from the right side to the left\n */\nexport function tripwireCrossing(\n prev: Point,\n curr: Point,\n tripwire: LineSegment,\n): { crossed: boolean; direction: 'left' | 'right' } | null {\n const movement: LineSegment = { p1: prev, p2: curr }\n const intersection = lineIntersection(movement, tripwire)\n\n if (intersection === null) return null\n\n // Determine direction using cross product of tripwire direction × movement direction\n const twDx = tripwire.p2.x - tripwire.p1.x\n const twDy = tripwire.p2.y - tripwire.p1.y\n const movDx = curr.x - prev.x\n const movDy = curr.y - prev.y\n\n const cross = twDx * movDy - twDy * movDx\n\n // cross > 0 means movement is to the left of the tripwire direction\n // cross < 0 means movement is to the right\n const direction: 'left' | 'right' = cross > 0 ? 'left' : 'right'\n\n return { crossed: true, direction }\n}\n\n/**\n * Calculate the centroid (center point) of a bounding box.\n */\nexport function bboxCentroid(bbox: { x: number; y: number; w: number; h: number }): Point {\n return {\n x: bbox.x + bbox.w / 2,\n y: bbox.y + bbox.h / 2,\n }\n}\n\n/**\n * Convert normalized coordinates (0–1 range) to pixel coordinates.\n */\nexport function normalizeToPixel(point: Point, imageWidth: number, imageHeight: number): Point {\n return {\n x: point.x * imageWidth,\n y: point.y * imageHeight,\n }\n}\n","/**\n * Greedy assignment algorithm for matching detections to tracks based on IoU.\n *\n * Sorts all (track, detection) pairs by IoU descending, then greedily assigns\n * pairs as long as neither the track nor detection has been assigned yet and\n * the IoU meets the threshold.\n *\n * @param costMatrix [tracks × detections] — values are IoU (higher = better)\n * @param threshold Minimum IoU to accept a match\n * @returns matches, unmatchedTracks, unmatchedDetections indices\n */\nexport function greedyAssignment(\n costMatrix: readonly (readonly number[])[],\n threshold: number,\n): { matches: [number, number][]; unmatchedTracks: number[]; unmatchedDetections: number[] } {\n const numTracks = costMatrix.length\n const numDetections = numTracks > 0 ? (costMatrix[0]?.length ?? 0) : 0\n\n // Collect all (iou, trackIdx, detectionIdx) triplets\n const candidates: Array<{ iou: number; trackIdx: number; detIdx: number }> = []\n\n for (let t = 0; t < numTracks; t++) {\n for (let d = 0; d < numDetections; d++) {\n const iou = costMatrix[t]![d] ?? 0\n if (iou >= threshold) {\n candidates.push({ iou, trackIdx: t, detIdx: d })\n }\n }\n }\n\n // Sort by IoU descending\n candidates.sort((a, b) => b.iou - a.iou)\n\n const assignedTracks = new Set<number>()\n const assignedDets = new Set<number>()\n const matches: [number, number][] = []\n\n for (const { trackIdx, detIdx } of candidates) {\n if (assignedTracks.has(trackIdx) || assignedDets.has(detIdx)) continue\n matches.push([trackIdx, detIdx])\n assignedTracks.add(trackIdx)\n assignedDets.add(detIdx)\n }\n\n const unmatchedTracks: number[] = []\n for (let t = 0; t < numTracks; t++) {\n if (!assignedTracks.has(t)) unmatchedTracks.push(t)\n }\n\n const unmatchedDetections: number[] = []\n for (let d = 0; d < numDetections; d++) {\n if (!assignedDets.has(d)) unmatchedDetections.push(d)\n }\n\n return { matches, unmatchedTracks, unmatchedDetections }\n}\n","import type { BoundingBox, Landmark, SpatialDetection, TrackedDetection } from '@camstack/types'\nimport { type ITracker, type TrackerConfig } from './tracker.interface.js'\nimport { greedyAssignment } from './hungarian.js'\n\nconst MAX_PATH_LENGTH = 300\n\ninterface Track {\n id: string\n bbox: BoundingBox\n class: string\n originalClass: string\n score: number\n landmarks?: readonly Landmark[]\n /** Frames since last successful match */\n age: number\n /** Total successful matches */\n hits: number\n /** Ring buffer of last N bounding box positions */\n path: BoundingBox[]\n firstSeen: number\n lastSeen: number\n velocity: { dx: number; dy: number }\n /** Whether this track has been \"lost\" (exceeded maxAge) */\n lost: boolean\n}\n\n/** Compute IoU between two bounding boxes */\nfunction iou(a: BoundingBox, b: BoundingBox): number {\n const ax1 = a.x\n const ay1 = a.y\n const ax2 = a.x + a.w\n const ay2 = a.y + a.h\n\n const bx1 = b.x\n const by1 = b.y\n const bx2 = b.x + b.w\n const by2 = b.y + b.h\n\n const interX1 = Math.max(ax1, bx1)\n const interY1 = Math.max(ay1, by1)\n const interX2 = Math.min(ax2, bx2)\n const interY2 = Math.min(ay2, by2)\n\n const interW = Math.max(0, interX2 - interX1)\n const interH = Math.max(0, interY2 - interY1)\n const interArea = interW * interH\n\n if (interArea === 0) return 0\n\n const aArea = a.w * a.h\n const bArea = b.w * b.h\n const unionArea = aArea + bArea - interArea\n\n return unionArea <= 0 ? 0 : interArea / unionArea\n}\n\nfunction trackToTrackedDetection(track: Track): TrackedDetection {\n return {\n class: track.class,\n originalClass: track.originalClass,\n score: track.score,\n bbox: track.bbox,\n landmarks: track.landmarks,\n trackId: track.id,\n trackAge: track.hits,\n velocity: track.velocity,\n path: track.path.slice() as readonly BoundingBox[],\n }\n}\n\nfunction pushToRingBuffer(buffer: BoundingBox[], item: BoundingBox, maxLength: number): void {\n if (buffer.length >= maxLength) {\n buffer.shift()\n }\n buffer.push(item)\n}\n\nexport const DEFAULT_TRACKER_CONFIG: TrackerConfig = {\n maxAge: 30,\n minHits: 3,\n iouThreshold: 0.3,\n}\n\nexport class SortTracker implements ITracker {\n private tracks: Track[] = []\n private lostTracks: Track[] = []\n private nextTrackId = 1\n private readonly config: TrackerConfig\n\n constructor(config: Partial<TrackerConfig> = {}) {\n this.config = { ...DEFAULT_TRACKER_CONFIG, ...config }\n }\n\n update(detections: readonly SpatialDetection[], frameTimestamp: number): TrackedDetection[] {\n this.lostTracks = []\n\n if (this.tracks.length === 0) {\n // All detections become new tracks\n for (const det of detections) {\n this.createTrack(det, frameTimestamp)\n }\n return this.getConfirmedTracks()\n }\n\n if (detections.length === 0) {\n // Age all tracks, remove lost ones\n this.ageTracksAndPruneLost(frameTimestamp)\n return this.getConfirmedTracks()\n }\n\n // Build IoU cost matrix [tracks × detections]\n const costMatrix = this.tracks.map(track =>\n detections.map(det => iou(track.bbox, det.bbox)),\n )\n\n const { matches, unmatchedTracks, unmatchedDetections } = greedyAssignment(\n costMatrix,\n this.config.iouThreshold,\n )\n\n // Update matched tracks\n for (const [trackIdx, detIdx] of matches) {\n const track = this.tracks[trackIdx]!\n const det = detections[detIdx]!\n\n const prevCx = track.bbox.x + track.bbox.w / 2\n const prevCy = track.bbox.y + track.bbox.h / 2\n const newCx = det.bbox.x + det.bbox.w / 2\n const newCy = det.bbox.y + det.bbox.h / 2\n\n // Push old bbox to path before updating\n pushToRingBuffer(track.path, track.bbox, MAX_PATH_LENGTH)\n\n track.bbox = det.bbox\n track.class = det.class\n track.originalClass = det.originalClass\n track.score = det.score\n track.landmarks = det.landmarks\n track.age = 0\n track.hits++\n track.lastSeen = frameTimestamp\n track.velocity = { dx: newCx - prevCx, dy: newCy - prevCy }\n }\n\n // Age unmatched tracks\n for (const trackIdx of unmatchedTracks) {\n const track = this.tracks[trackIdx]!\n track.age++\n }\n\n // Remove tracks that exceeded maxAge\n const survived: Track[] = []\n for (const track of this.tracks) {\n if (track.age > this.config.maxAge) {\n track.lost = true\n this.lostTracks.push(track)\n } else {\n survived.push(track)\n }\n }\n this.tracks = survived\n\n // Create new tracks for unmatched detections\n for (const detIdx of unmatchedDetections) {\n const det = detections[detIdx]!\n this.createTrack(det, frameTimestamp)\n }\n\n return this.getConfirmedTracks()\n }\n\n getActiveTracks(): TrackedDetection[] {\n return this.tracks.map(trackToTrackedDetection)\n }\n\n getLostTracks(): TrackedDetection[] {\n return this.lostTracks.map(trackToTrackedDetection)\n }\n\n reset(): void {\n this.tracks = []\n this.lostTracks = []\n this.nextTrackId = 1\n }\n\n private createTrack(det: SpatialDetection, timestamp: number): Track {\n const track: Track = {\n id: String(this.nextTrackId++),\n bbox: det.bbox,\n class: det.class,\n originalClass: det.originalClass,\n score: det.score,\n landmarks: det.landmarks,\n age: 0,\n hits: 1,\n path: [],\n firstSeen: timestamp,\n lastSeen: timestamp,\n velocity: { dx: 0, dy: 0 },\n lost: false,\n }\n this.tracks.push(track)\n return track\n }\n\n private getConfirmedTracks(): TrackedDetection[] {\n return this.tracks\n .filter(t => t.hits >= this.config.minHits)\n .map(trackToTrackedDetection)\n }\n\n private ageTracksAndPruneLost(frameTimestamp: number): void {\n const survived: Track[] = []\n for (const track of this.tracks) {\n track.age++\n if (track.age > this.config.maxAge) {\n track.lost = true\n this.lostTracks.push(track)\n } else {\n survived.push(track)\n }\n }\n this.tracks = survived\n // frameTimestamp used to suppress unused var warning\n void frameTimestamp\n }\n}\n","import type { TrackedDetection, TrackedObjectState } from '@camstack/types'\n\nexport interface StateAnalyzerConfig {\n /** Seconds without movement to transition to 'stationary' (default: 10) */\n readonly stationaryThresholdSec: number\n /** Seconds stationary to transition to 'loitering' (default: 60) */\n readonly loiteringThresholdSec: number\n /** Pixels/frame below which a track is considered not moving (default: 2) */\n readonly velocityThreshold: number\n /** Track age (frames) below which it's considered 'entering' (default: 5) */\n readonly enteringFrames: number\n}\n\nexport const DEFAULT_STATE_ANALYZER_CONFIG: StateAnalyzerConfig = {\n stationaryThresholdSec: 10,\n loiteringThresholdSec: 60,\n velocityThreshold: 2,\n enteringFrames: 5,\n}\n\ninterface InternalState {\n readonly enteredAt: number\n readonly stationarySince: number | undefined\n readonly totalDistancePx: number\n readonly lastPosition: { x: number; y: number }\n}\n\nfunction magnitude(v: { dx: number; dy: number }): number {\n return Math.sqrt(v.dx * v.dx + v.dy * v.dy)\n}\n\nexport class StateAnalyzer {\n private readonly states: Map<string, InternalState> = new Map()\n private readonly config: StateAnalyzerConfig\n\n constructor(config: Partial<StateAnalyzerConfig> = {}) {\n this.config = { ...DEFAULT_STATE_ANALYZER_CONFIG, ...config }\n }\n\n analyze(tracks: readonly TrackedDetection[], timestamp: number): TrackedObjectState[] {\n const results: TrackedObjectState[] = []\n const activeIds = new Set<string>()\n\n for (const track of tracks) {\n activeIds.add(track.trackId)\n const prev = this.states.get(track.trackId)\n\n const centroid = {\n x: track.bbox.x + track.bbox.w / 2,\n y: track.bbox.y + track.bbox.h / 2,\n }\n\n const speed = track.velocity ? magnitude(track.velocity) : 0\n\n let enteredAt: number\n let stationarySince: number | undefined\n let totalDistancePx: number\n\n if (!prev) {\n // New track — start stationary timer immediately if not moving\n enteredAt = timestamp\n stationarySince = speed <= this.config.velocityThreshold ? timestamp : undefined\n totalDistancePx = 0\n } else {\n enteredAt = prev.enteredAt\n\n const dx = centroid.x - prev.lastPosition.x\n const dy = centroid.y - prev.lastPosition.y\n const dist = Math.sqrt(dx * dx + dy * dy)\n totalDistancePx = prev.totalDistancePx + dist\n\n if (speed > this.config.velocityThreshold) {\n // Moving — clear stationary timer\n stationarySince = undefined\n } else {\n // Not moving — start or continue stationary timer\n stationarySince = prev.stationarySince ?? timestamp\n }\n }\n\n const newInternal: InternalState = {\n enteredAt,\n stationarySince,\n totalDistancePx,\n lastPosition: centroid,\n }\n this.states.set(track.trackId, newInternal)\n\n // Determine ObjectState\n const dwellTimeMs = timestamp - enteredAt\n const state = this.computeObjectState(track.trackAge, speed, stationarySince, timestamp)\n\n results.push({\n trackId: track.trackId,\n state,\n stationarySince,\n enteredAt,\n totalDistancePx,\n dwellTimeMs,\n })\n }\n\n // Emit 'leaving' state for tracks that disappeared\n for (const [id, internalState] of this.states) {\n if (!activeIds.has(id)) {\n results.push({\n trackId: id,\n state: 'leaving',\n stationarySince: internalState.stationarySince,\n enteredAt: internalState.enteredAt,\n totalDistancePx: internalState.totalDistancePx,\n dwellTimeMs: timestamp - internalState.enteredAt,\n })\n this.states.delete(id)\n }\n }\n\n return results\n }\n\n private computeObjectState(\n trackAge: number,\n speed: number,\n stationarySince: number | undefined,\n timestamp: number,\n ): TrackedObjectState['state'] {\n if (trackAge <= this.config.enteringFrames) {\n return 'entering'\n }\n\n if (stationarySince !== undefined) {\n const stationaryDurationSec = (timestamp - stationarySince) / 1000\n if (stationaryDurationSec >= this.config.loiteringThresholdSec) {\n return 'loitering'\n }\n if (stationaryDurationSec >= this.config.stationaryThresholdSec) {\n return 'stationary'\n }\n }\n\n if (speed > this.config.velocityThreshold) {\n return 'moving'\n }\n\n // Speed is below threshold but not yet stationary for long enough\n return 'moving'\n }\n}\n","import type { TrackedDetection, ZoneDefinition, ZoneEvent } from '@camstack/types'\nimport { pointInPolygon, bboxCentroid, tripwireCrossing, normalizeToPixel } from './geometry.js'\n\nexport class ZoneEvaluator {\n /** Track which zones each track was in last frame */\n private readonly trackZoneState: Map<string, Set<string>> = new Map()\n\n evaluate(\n tracks: readonly TrackedDetection[],\n zones: readonly ZoneDefinition[],\n imageWidth: number,\n imageHeight: number,\n timestamp: number,\n ): ZoneEvent[] {\n const events: ZoneEvent[] = []\n const activeTrackIds = new Set<string>()\n\n for (const track of tracks) {\n activeTrackIds.add(track.trackId)\n const centroid = bboxCentroid(track.bbox)\n const prevZones = this.trackZoneState.get(track.trackId) ?? new Set<string>()\n const currZones = new Set<string>()\n\n for (const zone of zones) {\n // Check class filter\n if (zone.alertOnClasses && zone.alertOnClasses.length > 0) {\n if (!zone.alertOnClasses.includes(track.class)) continue\n }\n\n if (zone.type === 'polygon') {\n const pixelPoints = zone.points.map(p => normalizeToPixel(p, imageWidth, imageHeight))\n const inside = pointInPolygon(centroid, pixelPoints)\n\n if (inside) {\n currZones.add(zone.id)\n }\n\n // Zone enter event\n if (inside && !prevZones.has(zone.id)) {\n events.push({\n type: 'zone-enter',\n zoneId: zone.id,\n zoneName: zone.name,\n trackId: track.trackId,\n detection: track,\n timestamp,\n })\n }\n\n // Zone exit event\n if (!inside && prevZones.has(zone.id)) {\n events.push({\n type: 'zone-exit',\n zoneId: zone.id,\n zoneName: zone.name,\n trackId: track.trackId,\n detection: track,\n timestamp,\n })\n }\n } else if (zone.type === 'tripwire' && track.path.length >= 1) {\n // Tripwire: check if movement since last known position crossed the line\n const prevBbox = track.path[track.path.length - 1]\n if (!prevBbox) continue\n\n const prevCentroid = bboxCentroid(prevBbox)\n const p0 = zone.points[0]\n const p1 = zone.points[1]\n if (!p0 || !p1) continue\n\n const tripwireLine = {\n p1: normalizeToPixel(p0, imageWidth, imageHeight),\n p2: normalizeToPixel(p1, imageWidth, imageHeight),\n }\n\n const cross = tripwireCrossing(prevCentroid, centroid, tripwireLine)\n if (cross?.crossed) {\n events.push({\n type: 'tripwire-cross',\n zoneId: zone.id,\n zoneName: zone.name,\n trackId: track.trackId,\n detection: track,\n direction: cross.direction,\n timestamp,\n })\n }\n }\n }\n\n this.trackZoneState.set(track.trackId, currZones)\n }\n\n // Cleanup state for disappeared tracks\n for (const trackId of this.trackZoneState.keys()) {\n if (!activeTrackIds.has(trackId)) {\n this.trackZoneState.delete(trackId)\n }\n }\n\n return events\n }\n\n /** Returns a snapshot of the current track → zones mapping */\n getTrackZones(): Map<string, Set<string>> {\n return new Map(this.trackZoneState)\n }\n}\n","import type { DetectionEventType } from '@camstack/types'\n\nexport interface EventFilterConfig {\n /** Don't emit for tracks younger than N frames */\n readonly minTrackAge: number\n /** Seconds between same event type for same track */\n readonly cooldownSec: number\n /** Event types that are enabled */\n readonly enabledTypes: readonly DetectionEventType[]\n}\n\nexport const DEFAULT_EVENT_FILTER_CONFIG: EventFilterConfig = {\n minTrackAge: 3,\n cooldownSec: 5,\n enabledTypes: [\n 'object.entering',\n 'object.leaving',\n 'object.stationary',\n 'object.loitering',\n 'zone.enter',\n 'zone.exit',\n 'tripwire.cross',\n ],\n}\n\nexport class EventFilter {\n /** key: `${trackId}:${eventType}` → last emitted timestamp */\n private readonly lastEmitted: Map<string, number> = new Map()\n\n constructor(private readonly config: EventFilterConfig) {}\n\n shouldEmit(\n trackId: string,\n eventType: DetectionEventType,\n trackAge: number,\n timestamp: number,\n ): boolean {\n if (!this.config.enabledTypes.includes(eventType)) return false\n if (trackAge < this.config.minTrackAge) return false\n\n const key = `${trackId}:${eventType}`\n const last = this.lastEmitted.get(key)\n if (last !== undefined && timestamp - last < this.config.cooldownSec * 1000) return false\n\n this.lastEmitted.set(key, timestamp)\n return true\n }\n\n /** Record an emission without a gate check — for events that bypass normal cooldown logic */\n recordEmission(trackId: string, eventType: DetectionEventType, timestamp: number): void {\n const key = `${trackId}:${eventType}`\n this.lastEmitted.set(key, timestamp)\n }\n\n /** Remove cooldown entries for tracks that are no longer active */\n cleanup(activeTrackIds: ReadonlySet<string>): void {\n for (const key of this.lastEmitted.keys()) {\n const colonIdx = key.indexOf(':')\n if (colonIdx === -1) continue\n const trackId = key.slice(0, colonIdx)\n if (!activeTrackIds.has(trackId)) {\n this.lastEmitted.delete(key)\n }\n }\n }\n\n /** Reset all cooldown state */\n reset(): void {\n this.lastEmitted.clear()\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type {\n TrackedDetection,\n TrackedObjectState,\n ZoneEvent,\n DetectionEvent,\n Classification,\n DetectionEventType,\n ObjectState,\n} from '@camstack/types'\nimport { EventFilter, type EventFilterConfig, DEFAULT_EVENT_FILTER_CONFIG } from './event-filters.js'\n\nexport class DetectionEventEmitter {\n private readonly filter: EventFilter\n /** trackId → last known ObjectState */\n private readonly previousStates: Map<string, ObjectState> = new Map()\n\n constructor(filterConfig: Partial<EventFilterConfig> = {}) {\n this.filter = new EventFilter({ ...DEFAULT_EVENT_FILTER_CONFIG, ...filterConfig })\n }\n\n emit(\n tracks: readonly TrackedDetection[],\n states: readonly TrackedObjectState[],\n zoneEvents: readonly ZoneEvent[],\n classifications: readonly { trackId: string; classifications: Classification[] }[],\n deviceId: string,\n ): DetectionEvent[] {\n const events: DetectionEvent[] = []\n const timestamp = Date.now()\n\n const trackMap = new Map<string, TrackedDetection>()\n for (const t of tracks) trackMap.set(t.trackId, t)\n\n const stateMap = new Map<string, TrackedObjectState>()\n for (const s of states) stateMap.set(s.trackId, s)\n\n const classifMap = new Map<string, Classification[]>()\n for (const c of classifications) classifMap.set(c.trackId, c.classifications)\n\n // State transition events\n for (const state of states) {\n const track = trackMap.get(state.trackId)\n if (!track) continue\n\n const prevState = this.previousStates.get(state.trackId)\n const classifs = classifMap.get(state.trackId) ?? []\n\n // object.entering — first N frames\n if (state.state === 'entering' && prevState === undefined) {\n this.tryEmit(events, 'object.entering', track, state, classifs, [], deviceId, timestamp)\n }\n\n // object.leaving — track disappeared\n if (state.state === 'leaving') {\n this.tryEmit(events, 'object.leaving', track, state, classifs, [], deviceId, timestamp)\n }\n\n // object.stationary — transition from moving → stationary\n if (state.state === 'stationary' && prevState !== undefined && prevState !== 'stationary' && prevState !== 'loitering') {\n this.tryEmit(events, 'object.stationary', track, state, classifs, [], deviceId, timestamp)\n }\n\n // object.loitering — transition from stationary → loitering\n if (state.state === 'loitering' && prevState === 'stationary') {\n this.tryEmit(events, 'object.loitering', track, state, classifs, [], deviceId, timestamp)\n }\n\n if (state.state !== 'leaving') {\n this.previousStates.set(state.trackId, state.state)\n } else {\n this.previousStates.delete(state.trackId)\n }\n }\n\n // Zone events\n for (const ze of zoneEvents) {\n const track = trackMap.get(ze.trackId)\n if (!track) continue\n const state = stateMap.get(ze.trackId)\n if (!state) continue\n\n let eventType: DetectionEventType\n if (ze.type === 'tripwire-cross') {\n eventType = 'tripwire.cross'\n } else if (ze.type === 'zone-enter') {\n eventType = 'zone.enter'\n } else {\n eventType = 'zone.exit'\n }\n\n const classifs = classifMap.get(ze.trackId) ?? []\n this.tryEmit(events, eventType, track, state, classifs, [ze], deviceId, timestamp)\n }\n\n // Cleanup old track entries\n const activeIds = new Set(tracks.map(t => t.trackId))\n this.filter.cleanup(activeIds)\n\n return events\n }\n\n private tryEmit(\n events: DetectionEvent[],\n eventType: DetectionEventType,\n track: TrackedDetection,\n state: TrackedObjectState,\n classifications: Classification[],\n zoneEvents: ZoneEvent[],\n deviceId: string,\n timestamp: number,\n ): void {\n if (!this.filter.shouldEmit(track.trackId, eventType, track.trackAge, timestamp)) return\n\n events.push({\n id: randomUUID(),\n type: eventType,\n timestamp,\n deviceId,\n detection: track,\n classifications,\n objectState: state,\n zoneEvents,\n trackPath: track.path,\n })\n }\n\n reset(): void {\n this.previousStates.clear()\n this.filter.reset()\n }\n}\n","import type {\n TrackedDetection,\n TrackedObjectState,\n TrackDetail,\n Classification,\n ZoneEvent,\n BoundingBox,\n ObjectState,\n EventSnapshot,\n DetectionEvent,\n} from '@camstack/types'\n\ninterface ZoneTransition {\n zoneId: string\n zoneName: string\n entered: number\n exited?: number\n dwellMs: number\n}\n\ninterface PathPoint {\n timestamp: number\n bbox: BoundingBox\n velocity: { dx: number; dy: number }\n}\n\ninterface TrackAccumulator {\n readonly trackId: string\n class: string\n originalClass: string\n state: ObjectState\n firstSeen: number\n lastSeen: number\n path: PathPoint[]\n zoneTransitions: ZoneTransition[]\n events: DetectionEvent[]\n bestSnapshot?: EventSnapshot\n identity?: { name: string; confidence: number; matchedAt: number }\n plateText?: { text: string; confidence: number; readAt: number }\n subClass?: { class: string; confidence: number }\n}\n\nconst MAX_PATH_LENGTH = 300\n\nexport class TrackStore {\n private readonly activeTracks: Map<string, TrackAccumulator> = new Map()\n\n update(\n tracks: readonly TrackedDetection[],\n states: readonly TrackedObjectState[],\n zoneEvents: readonly ZoneEvent[],\n classifications: readonly { trackId: string; classifications: Classification[] }[],\n ): void {\n const stateMap = new Map<string, TrackedObjectState>()\n for (const s of states) stateMap.set(s.trackId, s)\n\n const classifMap = new Map<string, Classification[]>()\n for (const c of classifications) classifMap.set(c.trackId, c.classifications)\n\n const now = Date.now()\n\n for (const track of tracks) {\n let acc = this.activeTracks.get(track.trackId)\n\n if (!acc) {\n acc = {\n trackId: track.trackId,\n class: track.class,\n originalClass: track.originalClass,\n state: 'entering',\n firstSeen: track.path.length === 0 ? now : now,\n lastSeen: now,\n path: [],\n zoneTransitions: [],\n events: [],\n }\n this.activeTracks.set(track.trackId, acc)\n }\n\n // Update mutable fields\n acc.class = track.class\n acc.originalClass = track.originalClass\n acc.lastSeen = now\n\n const state = stateMap.get(track.trackId)\n if (state) acc.state = state.state\n\n // Append path point (ring buffer)\n const pathPoint: PathPoint = {\n timestamp: now,\n bbox: track.bbox,\n velocity: track.velocity ?? { dx: 0, dy: 0 },\n }\n if (acc.path.length >= MAX_PATH_LENGTH) {\n acc.path.shift()\n }\n acc.path.push(pathPoint)\n\n // Update classification-derived identity / plate / subClass\n const classifs = classifMap.get(track.trackId) ?? []\n for (const c of classifs) {\n if (c.metadata?.type === 'face-recognition' && typeof c.text === 'string') {\n acc.identity = { name: c.text, confidence: c.score, matchedAt: now }\n } else if (c.metadata?.type === 'plate-recognition' && typeof c.text === 'string') {\n acc.plateText = { text: c.text, confidence: c.score, readAt: now }\n } else if (c.metadata?.type === 'sub-class') {\n acc.subClass = { class: c.class, confidence: c.score }\n }\n }\n }\n\n // Process zone events for transitions\n for (const ze of zoneEvents) {\n const acc = this.activeTracks.get(ze.trackId)\n if (!acc) continue\n\n if (ze.type === 'zone-enter') {\n acc.zoneTransitions.push({\n zoneId: ze.zoneId,\n zoneName: ze.zoneName,\n entered: ze.timestamp,\n dwellMs: 0,\n })\n } else if (ze.type === 'zone-exit') {\n // Find the last open transition for this zone and close it (ES2022 compatible)\n let openIdx = -1\n for (let i = acc.zoneTransitions.length - 1; i >= 0; i--) {\n const t = acc.zoneTransitions[i]!\n if (t.zoneId === ze.zoneId && t.exited === undefined) {\n openIdx = i\n break\n }\n }\n if (openIdx >= 0) {\n const open = acc.zoneTransitions[openIdx]!\n acc.zoneTransitions[openIdx] = {\n ...open,\n exited: ze.timestamp,\n dwellMs: ze.timestamp - open.entered,\n }\n }\n }\n }\n }\n\n /** Attach a DetectionEvent to its associated track accumulator */\n addEvent(trackId: string, event: DetectionEvent): void {\n const acc = this.activeTracks.get(trackId)\n if (!acc) return\n acc.events.push(event)\n if (event.snapshot && !acc.bestSnapshot) {\n acc.bestSnapshot = event.snapshot\n }\n }\n\n /** Get accumulated detail for an active track */\n getTrackDetail(trackId: string): TrackDetail | null {\n const acc = this.activeTracks.get(trackId)\n if (!acc) return null\n return this.buildTrackDetail(acc)\n }\n\n /** Called when a track ends — returns complete TrackDetail and removes from active set */\n finishTrack(trackId: string): TrackDetail | null {\n const acc = this.activeTracks.get(trackId)\n if (!acc) return null\n const detail = this.buildTrackDetail(acc)\n this.activeTracks.delete(trackId)\n return detail\n }\n\n /** Get all active track IDs */\n getActiveTrackIds(): string[] {\n return Array.from(this.activeTracks.keys())\n }\n\n /** Clear all accumulated state */\n reset(): void {\n this.activeTracks.clear()\n }\n\n private buildTrackDetail(acc: TrackAccumulator): TrackDetail {\n return {\n trackId: acc.trackId,\n class: acc.class,\n originalClass: acc.originalClass,\n state: acc.state,\n firstSeen: acc.firstSeen,\n lastSeen: acc.lastSeen,\n totalDwellMs: acc.lastSeen - acc.firstSeen,\n path: acc.path,\n identity: acc.identity,\n plateText: acc.plateText,\n subClass: acc.subClass,\n zoneTransitions: acc.zoneTransitions,\n bestSnapshot: acc.bestSnapshot,\n events: acc.events,\n }\n }\n}\n","import type {\n TrackedDetection,\n TrackedObjectState,\n ZoneDefinition,\n CameraLiveState,\n ZoneLiveState,\n TrackedObjectSummary,\n PipelineStatus,\n DetectionEvent,\n} from '@camstack/types'\n\nclass FpsCounter {\n private readonly frameTimes: number[] = []\n private readonly windowMs = 5000\n\n tick(timestamp: number): void {\n this.frameTimes.push(timestamp)\n // Prune entries older than the window\n const cutoff = timestamp - this.windowMs\n while (this.frameTimes.length > 0 && this.frameTimes[0]! < cutoff) {\n this.frameTimes.shift()\n }\n }\n\n getFps(): number {\n if (this.frameTimes.length < 2) return 0\n const oldest = this.frameTimes[0]!\n const newest = this.frameTimes[this.frameTimes.length - 1]!\n const durationSec = (newest - oldest) / 1000\n if (durationSec <= 0) return 0\n return (this.frameTimes.length - 1) / durationSec\n }\n}\n\nexport class LiveStateManager {\n private zones: ZoneDefinition[] = []\n private readonly fpsCounter = new FpsCounter()\n private readonly pipelineMsHistory: number[] = []\n private readonly maxPipelineHistory = 30\n\n setZones(zones: ZoneDefinition[]): void {\n this.zones = [...zones]\n }\n\n buildState(\n deviceId: string,\n tracks: readonly TrackedDetection[],\n states: readonly TrackedObjectState[],\n trackZones: Map<string, Set<string>>,\n pipelineStatus: readonly PipelineStatus[],\n pipelineMs: number,\n lastEvent: DetectionEvent | undefined,\n timestamp: number,\n ): CameraLiveState {\n this.fpsCounter.tick(timestamp)\n\n if (this.pipelineMsHistory.length >= this.maxPipelineHistory) {\n this.pipelineMsHistory.shift()\n }\n this.pipelineMsHistory.push(pipelineMs)\n\n const avgPipelineMs =\n this.pipelineMsHistory.length === 0\n ? 0\n : this.pipelineMsHistory.reduce((sum, v) => sum + v, 0) / this.pipelineMsHistory.length\n\n const stateMap = new Map<string, TrackedObjectState>()\n for (const s of states) stateMap.set(s.trackId, s)\n\n // Build track summaries\n const trackSummaries: TrackedObjectSummary[] = tracks.map(track => {\n const state = stateMap.get(track.trackId)\n const inZones = Array.from(trackZones.get(track.trackId) ?? [])\n\n return {\n trackId: track.trackId,\n class: track.class,\n originalClass: track.originalClass,\n state: state?.state ?? 'moving',\n bbox: track.bbox,\n velocity: track.velocity ?? { dx: 0, dy: 0 },\n dwellTimeMs: state?.dwellTimeMs ?? 0,\n inZones,\n }\n })\n\n // Count objects by state\n let movingObjects = 0\n let stationaryObjects = 0\n for (const summary of trackSummaries) {\n if (summary.state === 'moving' || summary.state === 'entering') movingObjects++\n else if (summary.state === 'stationary' || summary.state === 'loitering') stationaryObjects++\n }\n\n // Count objects by class\n const objectCounts: Record<string, number> = {}\n for (const summary of trackSummaries) {\n objectCounts[summary.class] = (objectCounts[summary.class] ?? 0) + 1\n }\n\n // Build zone live states\n const zoneLiveStates: ZoneLiveState[] = this.zones.map(zone => {\n const tracksInZone = trackSummaries.filter(t => t.inZones.includes(zone.id))\n const objectsByClass: Record<string, number> = {}\n const loiteringTracks: string[] = []\n\n for (const t of tracksInZone) {\n objectsByClass[t.class] = (objectsByClass[t.class] ?? 0) + 1\n if (t.state === 'loitering') loiteringTracks.push(t.trackId)\n }\n\n const avgDwellTimeMs =\n tracksInZone.length === 0\n ? 0\n : tracksInZone.reduce((sum, t) => sum + t.dwellTimeMs, 0) / tracksInZone.length\n\n return {\n zoneId: zone.id,\n zoneName: zone.name,\n occupied: tracksInZone.length > 0,\n objectCount: tracksInZone.length,\n objectsByClass,\n trackIds: tracksInZone.map(t => t.trackId),\n avgDwellTimeMs,\n totalEntrancesToday: 0, // requires DB — left for server orchestrator\n totalExitsToday: 0,\n loiteringTracks,\n }\n })\n\n return {\n deviceId,\n lastFrameTimestamp: timestamp,\n activeObjects: trackSummaries.length,\n movingObjects,\n stationaryObjects,\n objectCounts,\n tracks: trackSummaries,\n zones: zoneLiveStates,\n lastEvent,\n pipelineStatus,\n avgPipelineMs,\n currentFps: this.fpsCounter.getFps(),\n }\n }\n\n reset(): void {\n this.pipelineMsHistory.length = 0\n }\n}\n","import type { HeatmapData } from '@camstack/types'\n\n/**\n * Grid-based accumulator for track centroid positions.\n *\n * Positions are normalized (0–1) and mapped into a grid of `gridSize × gridSize` cells.\n * Each update increments the count of the corresponding cell.\n */\nexport class HeatmapAggregator {\n private readonly grid: Float32Array\n private maxCount = 0\n\n constructor(\n private readonly width: number,\n private readonly height: number,\n private readonly gridSize: number,\n ) {\n if (gridSize <= 0) throw new Error('gridSize must be > 0')\n this.grid = new Float32Array(gridSize * gridSize)\n }\n\n /**\n * Add a normalized point (0–1 range) to the heatmap.\n * Points outside [0, 1] are clamped to the grid boundary.\n */\n addPoint(x: number, y: number): void {\n const col = Math.min(Math.floor(x * this.gridSize), this.gridSize - 1)\n const row = Math.min(Math.floor(y * this.gridSize), this.gridSize - 1)\n const idx = row * this.gridSize + col\n this.grid[idx]! += 1\n if (this.grid[idx]! > this.maxCount) {\n this.maxCount = this.grid[idx]!\n }\n }\n\n /** Add a pixel-coordinate point. Normalizes against the configured width/height. */\n addPixelPoint(px: number, py: number): void {\n this.addPoint(px / this.width, py / this.height)\n }\n\n getHeatmap(): HeatmapData {\n return {\n width: this.width,\n height: this.height,\n gridSize: this.gridSize,\n cells: new Float32Array(this.grid),\n maxCount: this.maxCount,\n }\n }\n\n reset(): void {\n this.grid.fill(0)\n this.maxCount = 0\n }\n\n /** Total number of points accumulated */\n get totalPoints(): number {\n let total = 0\n for (let i = 0; i < this.grid.length; i++) {\n total += this.grid[i]!\n }\n return total\n }\n}\n","import type {\n ICameraAnalyticsProvider,\n CameraLiveState,\n TrackedObjectSummary,\n ZoneLiveState,\n TrackDetail,\n TrackFilter,\n ZoneHistoryPoint,\n HeatmapData,\n HeatmapOptions,\n TimeRangeOptions,\n PipelineStatus,\n ObjectState,\n} from '@camstack/types'\nimport type { LiveStateManager } from './live-state-manager.js'\nimport type { TrackStore } from './track-store.js'\n\nexport class AnalyticsProvider implements ICameraAnalyticsProvider {\n constructor(\n private readonly liveStateManager: LiveStateManager,\n private readonly trackStore: TrackStore,\n private readonly getZoneHistoryCb?: (\n deviceId: string,\n zoneId: string,\n options: TimeRangeOptions,\n ) => Promise<ZoneHistoryPoint[]>,\n private readonly getHeatmapCb?: (\n deviceId: string,\n options: HeatmapOptions,\n ) => Promise<HeatmapData>,\n /** Cached live state reference — kept up to date by the pipeline orchestrator */\n private lastLiveState: CameraLiveState | null = null,\n ) {}\n\n /** Called by the orchestrator each frame to update the cached live state */\n updateLiveState(state: CameraLiveState): void {\n this.lastLiveState = state\n }\n\n getLiveState(_deviceId: string): CameraLiveState | null {\n return this.lastLiveState\n }\n\n getTracks(_deviceId: string, filter?: TrackFilter): TrackedObjectSummary[] {\n const tracks = this.lastLiveState?.tracks ?? []\n if (!filter) return [...tracks]\n\n return tracks.filter(t => {\n if (filter.class && !filter.class.includes(t.class)) return false\n if (filter.state && !filter.state.includes(t.state as ObjectState)) return false\n if (filter.inZone && !t.inZones.includes(filter.inZone)) return false\n if (filter.minDwellMs !== undefined && t.dwellTimeMs < filter.minDwellMs) return false\n return true\n })\n }\n\n getZoneState(_deviceId: string, zoneId: string): ZoneLiveState | null {\n return this.lastLiveState?.zones.find(z => z.zoneId === zoneId) ?? null\n }\n\n async getZoneHistory(\n deviceId: string,\n zoneId: string,\n options: TimeRangeOptions,\n ): Promise<ZoneHistoryPoint[]> {\n if (this.getZoneHistoryCb) {\n return this.getZoneHistoryCb(deviceId, zoneId, options)\n }\n return []\n }\n\n async getHeatmap(deviceId: string, options: HeatmapOptions): Promise<HeatmapData> {\n if (this.getHeatmapCb) {\n return this.getHeatmapCb(deviceId, options)\n }\n // Return an empty heatmap matching the requested resolution\n const gridSize = options.resolution\n return {\n width: 1920,\n height: 1080,\n gridSize,\n cells: new Float32Array(gridSize * gridSize),\n maxCount: 0,\n }\n }\n\n getTrackDetail(_deviceId: string, trackId: string): TrackDetail | null {\n return this.trackStore.getTrackDetail(trackId)\n }\n\n getCameraStatus(_deviceId: string): PipelineStatus[] {\n return this.lastLiveState ? [...this.lastLiveState.pipelineStatus] : []\n }\n}\n","import type { FrameInput, TrackedDetection, EventSnapshot, BoundingBox, IAddonFileStorage } from '@camstack/types'\n\nexport interface SnapshotConfig {\n readonly enabled: boolean\n readonly saveThumbnail: boolean\n readonly saveAnnotatedFrame: boolean\n readonly saveDebugThumbnails: boolean\n /** File storage abstraction for snapshot persistence */\n readonly mediaStorage?: IAddonFileStorage\n /** Legacy: output directory for direct file system writes */\n readonly outputDir?: string\n}\n\nexport const DEFAULT_SNAPSHOT_CONFIG: Omit<SnapshotConfig, 'mediaStorage' | 'outputDir'> = {\n enabled: false,\n saveThumbnail: true,\n saveAnnotatedFrame: false,\n saveDebugThumbnails: false,\n}\n\n/**\n * Manages snapshot capture for detection events.\n *\n * Core operation: crop the detection bbox from the full frame and persist as JPEG.\n * Annotated frame (bbox overlay) is optional and requires saveAnnotatedFrame = true.\n *\n * All persistence goes through mediaStorage (IAddonFileStorage).\n *\n * sharp is imported dynamically so the module can load even when sharp is unavailable\n * (e.g., in test environments that mock this class).\n */\nexport class SnapshotManager {\n constructor(private readonly config: SnapshotConfig) {}\n\n async capture(\n frame: FrameInput,\n detection: TrackedDetection,\n allDetections: readonly TrackedDetection[],\n eventId: string,\n ): Promise<EventSnapshot | undefined> {\n if (!this.config.enabled) return undefined\n\n await this.ensureOutputDir()\n\n let thumbnailPath: string | undefined\n let annotatedFramePath: string | undefined\n\n if (this.config.saveThumbnail) {\n thumbnailPath = await this.saveThumbnail(frame, detection.bbox, eventId)\n }\n\n if (this.config.saveAnnotatedFrame) {\n annotatedFramePath = await this.saveAnnotatedFrame(frame, allDetections, eventId)\n }\n\n if (!thumbnailPath && !annotatedFramePath) return undefined\n\n return {\n thumbnailPath: thumbnailPath ?? '',\n annotatedFramePath: annotatedFramePath ?? '',\n } as EventSnapshot\n }\n\n private async saveThumbnail(\n frame: FrameInput,\n bbox: BoundingBox,\n eventId: string,\n ): Promise<string> {\n const sharp = await import('sharp')\n\n // Resolve actual frame dimensions — JPEG frames from decoders may have width=0\n const { frameWidth, frameHeight } = await this.resolveFrameDimensions(frame)\n\n // Clamp bbox to frame dimensions\n const left = Math.max(0, Math.round(bbox.x))\n const top = Math.max(0, Math.round(bbox.y))\n const width = Math.min(Math.round(bbox.w), frameWidth - left)\n const height = Math.min(Math.round(bbox.h), frameHeight - top)\n\n if (width <= 0 || height <= 0) {\n throw new Error(`Invalid crop dimensions for event ${eventId}: ${JSON.stringify({ left, top, width, height, frameWidth, frameHeight })}`)\n }\n\n const relativePath = `${eventId}_thumb.jpg`\n const inputOptions = this.sharpInputOptions(frame)\n\n const buffer = await sharp.default(frame.data, inputOptions)\n .extract({ left, top, width, height })\n .jpeg({ quality: 85 })\n .toBuffer()\n\n await this.writeOutput(relativePath, buffer)\n\n return relativePath\n }\n\n private async saveAnnotatedFrame(\n frame: FrameInput,\n detections: readonly TrackedDetection[],\n eventId: string,\n ): Promise<string> {\n const sharp = await import('sharp')\n\n const { frameWidth, frameHeight } = await this.resolveFrameDimensions(frame)\n\n const relativePath = `${eventId}_annotated.jpg`\n\n // Build SVG overlays for each bounding box\n const svgBoxes = detections.map(det => {\n const x = Math.max(0, Math.round(det.bbox.x))\n const y = Math.max(0, Math.round(det.bbox.y))\n const w = Math.min(Math.round(det.bbox.w), frameWidth - x)\n const h = Math.min(Math.round(det.bbox.h), frameHeight - y)\n const label = `${det.class} ${(det.score * 100).toFixed(0)}%`\n return `<rect x=\"${x}\" y=\"${y}\" width=\"${w}\" height=\"${h}\" fill=\"none\" stroke=\"lime\" stroke-width=\"2\"/>\n <text x=\"${x + 2}\" y=\"${Math.max(y - 2, 10)}\" font-size=\"12\" fill=\"lime\" font-family=\"sans-serif\">${label}</text>`\n }).join('\\n')\n\n const svgOverlay = Buffer.from(\n `<svg width=\"${frameWidth}\" height=\"${frameHeight}\" xmlns=\"http://www.w3.org/2000/svg\">${svgBoxes}</svg>`,\n )\n\n const inputOptions = this.sharpInputOptions(frame)\n\n const buffer = await sharp.default(frame.data, inputOptions)\n .composite([{ input: svgOverlay, top: 0, left: 0 }])\n .jpeg({ quality: 85 })\n .toBuffer()\n\n await this.writeOutput(relativePath, buffer)\n\n return relativePath\n }\n\n /**\n * Write output using mediaStorage if available, otherwise fall back to fs.writeFile.\n */\n private async writeOutput(relativePath: string, data: Buffer): Promise<void> {\n if (this.config.mediaStorage) {\n await this.config.mediaStorage.writeFile(relativePath, data)\n } else if (this.config.outputDir) {\n const { writeFile } = await import('node:fs/promises')\n const { join } = await import('node:path')\n await writeFile(join(this.config.outputDir, relativePath), data)\n }\n }\n\n /**\n * Resolve actual frame dimensions. JPEG frames from decoders may report\n * width=0, height=0 — in that case read the real size from sharp metadata.\n */\n private async resolveFrameDimensions(\n frame: FrameInput,\n ): Promise<{ frameWidth: number; frameHeight: number }> {\n if (frame.width > 0 && frame.height > 0) {\n return { frameWidth: frame.width, frameHeight: frame.height }\n }\n\n if (frame.format === 'jpeg') {\n const sharp = await import('sharp')\n const meta = await sharp.default(frame.data).metadata()\n return {\n frameWidth: meta.width ?? 0,\n frameHeight: meta.height ?? 0,\n }\n }\n\n return { frameWidth: frame.width, frameHeight: frame.height }\n }\n\n private sharpInputOptions(frame: FrameInput): object {\n if (frame.format === 'jpeg') {\n return {}\n }\n // rgb or yuv420 — provide raw channel info\n const channels = frame.format === 'rgb' ? 3 : 3\n return {\n raw: {\n width: frame.width,\n height: frame.height,\n channels,\n },\n }\n }\n\n private async ensureOutputDir(): Promise<void> {\n if (this.config.outputDir) {\n const { mkdir } = await import('node:fs/promises')\n await mkdir(this.config.outputDir, { recursive: true })\n }\n // When using mediaStorage, directories are abstracted away — nothing to do\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type {\n ICamstackAddon,\n ICameraAnalyticsProvider,\n AddonManifest,\n AddonContext,\n FrameInput,\n PipelineConfig,\n PipelineStatus,\n DetectionEvent,\n ZoneDefinition,\n KnownFace,\n KnownPlate,\n CameraLiveState,\n TrackedObjectSummary,\n ZoneLiveState,\n TrackDetail,\n TrackFilter,\n ZoneHistoryPoint,\n HeatmapData,\n HeatmapOptions,\n TimeRangeOptions,\n PipelineResult,\n SpatialDetection,\n Classification,\n DetectorOutput,\n ClassifierOutput,\n} from '@camstack/types'\nimport { SortTracker } from '../tracker/sort-tracker.js'\nimport { StateAnalyzer } from '../state/state-analyzer.js'\nimport { ZoneEvaluator } from '../zones/zone-evaluator.js'\nimport { DetectionEventEmitter } from '../events/event-emitter.js'\nimport { TrackStore } from '../analytics/track-store.js'\nimport { LiveStateManager } from '../analytics/live-state-manager.js'\nimport { HeatmapAggregator } from '../analytics/heatmap-aggregator.js'\nimport { AnalyticsProvider } from '../analytics/analytics-provider.js'\nimport { SnapshotManager, DEFAULT_SNAPSHOT_CONFIG, type SnapshotConfig } from '../snapshots/snapshot-manager.js'\nimport type { TrackerConfig } from '../tracker/tracker.interface.js'\nimport type { StateAnalyzerConfig } from '../state/state-analyzer.js'\nimport type { EventFilterConfig } from '../events/event-filters.js'\n\ninterface CameraAnalysisState {\n readonly tracker: SortTracker\n readonly stateAnalyzer: StateAnalyzer\n readonly zoneEvaluator: ZoneEvaluator\n readonly eventEmitter: DetectionEventEmitter\n readonly trackStore: TrackStore\n readonly liveStateManager: LiveStateManager\n readonly heatmapAggregator: HeatmapAggregator\n readonly analyticsProvider: AnalyticsProvider\n readonly snapshotManager: SnapshotManager\n zones: ZoneDefinition[]\n lastLiveState: CameraLiveState | null\n}\n\nexport interface AnalysisPipelineConfig {\n readonly tracker?: Partial<TrackerConfig>\n readonly stateAnalyzer?: Partial<StateAnalyzerConfig>\n readonly eventFilter?: Partial<EventFilterConfig>\n readonly snapshot?: Partial<SnapshotConfig>\n /** Heatmap grid resolution (default: 32) */\n readonly heatmapGridSize?: number\n /** Default frame dimensions when not available from FrameInput (default: 1920×1080) */\n readonly defaultFrameWidth?: number\n readonly defaultFrameHeight?: number\n}\n\n/**\n * IAnalysisAddon-compatible interface.\n *\n * NOTE: The types package defines `processFrame(deviceId, frame)` on IAnalysisAddon.\n * In practice the server orchestrator already calls the vision pipeline and passes\n * the PipelineResult. We add an overloaded variant that accepts the PipelineResult\n * as a third argument while remaining compatible with the base interface.\n */\nexport interface IAnalysisAddon extends ICamstackAddon, ICameraAnalyticsProvider {\n processFrame(deviceId: string, frame: FrameInput, pipelineResult?: PipelineResult): Promise<DetectionEvent[]>\n setCameraPipeline(deviceId: string, config: PipelineConfig): void\n setCameraZones(deviceId: string, zones: ZoneDefinition[]): void\n setKnownFaces(faces: KnownFace[]): void\n setKnownPlates(plates: KnownPlate[]): void\n onLiveStateChange(deviceId: string, callback: (state: CameraLiveState) => void): () => void\n onTrackFinished?: (deviceId: string, detail: TrackDetail) => void\n}\n\nexport class AnalysisPipeline implements IAnalysisAddon {\n readonly id = 'pipeline-analysis'\n readonly manifest: AddonManifest = {\n id: 'pipeline-analysis',\n name: 'Pipeline Analysis',\n version: '0.1.0',\n description: 'Object tracking, state analysis, zone evaluation, and event emission',\n packageName: '@camstack/lib-pipeline-analysis',\n }\n\n private readonly config: Required<AnalysisPipelineConfig>\n private readonly cameras: Map<string, CameraAnalysisState> = new Map()\n private knownFaces: KnownFace[] = []\n private knownPlates: KnownPlate[] = []\n private readonly listeners: Map<string, Set<(state: CameraLiveState) => void>> = new Map()\n\n /** Optional callback: server orchestrator can hook in to persist finished tracks */\n onTrackFinished?: (deviceId: string, detail: TrackDetail) => void\n\n constructor(config: AnalysisPipelineConfig = {}) {\n this.config = {\n tracker: config.tracker ?? {},\n stateAnalyzer: config.stateAnalyzer ?? {},\n eventFilter: config.eventFilter ?? {},\n snapshot: config.snapshot ?? {},\n heatmapGridSize: config.heatmapGridSize ?? 32,\n defaultFrameWidth: config.defaultFrameWidth ?? 1920,\n defaultFrameHeight: config.defaultFrameHeight ?? 1080,\n }\n }\n\n async initialize(_ctx: AddonContext): Promise<void> {\n // Nothing to initialize globally — per-camera state is created lazily\n }\n\n async shutdown(): Promise<void> {\n this.cameras.clear()\n this.listeners.clear()\n }\n\n async processFrame(\n deviceId: string,\n frame: FrameInput,\n pipelineResult?: PipelineResult,\n ): Promise<DetectionEvent[]> {\n const camera = this.getOrCreateCamera(deviceId)\n\n const frameWidth = frame.width > 0 ? frame.width : this.config.defaultFrameWidth\n const frameHeight = frame.height > 0 ? frame.height : this.config.defaultFrameHeight\n const timestamp = frame.timestamp\n\n // 1. Extract spatial detections from pipeline result\n const detections: SpatialDetection[] = pipelineResult\n ? this.extractDetections(pipelineResult)\n : []\n\n // 2. Track\n const tracked = camera.tracker.update(detections, timestamp)\n\n // 3. Analyze state\n const states = camera.stateAnalyzer.analyze(tracked, timestamp)\n\n // 4. Evaluate zones\n const zoneEvents = camera.zoneEvaluator.evaluate(\n tracked,\n camera.zones,\n frameWidth,\n frameHeight,\n timestamp,\n )\n\n // 5. Match classifications to tracks\n const classificationsByTrack = pipelineResult\n ? this.matchClassifications(pipelineResult, tracked.map(t => t.trackId))\n : []\n\n // 6. Update track store\n camera.trackStore.update(tracked, states, zoneEvents, classificationsByTrack)\n\n // 7. Emit events\n const events = camera.eventEmitter.emit(\n tracked,\n states,\n zoneEvents,\n classificationsByTrack,\n deviceId,\n )\n\n // 8. Capture snapshots for events and attach to track store\n for (const event of events) {\n const snapshot = await camera.snapshotManager.capture(frame, event.detection, tracked, event.id)\n if (snapshot) {\n // Attach snapshot to track accumulator — cast to allow mutation before freeze\n ;(event as { snapshot?: typeof snapshot }).snapshot = snapshot\n }\n camera.trackStore.addEvent(event.detection.trackId, event)\n }\n\n // 9. Update heatmap from current track centroids\n for (const track of tracked) {\n const cx = (track.bbox.x + track.bbox.w / 2) / frameWidth\n const cy = (track.bbox.y + track.bbox.h / 2) / frameHeight\n camera.heatmapAggregator.addPoint(cx, cy)\n }\n\n // 10. Finish lost tracks\n for (const lostTrack of camera.tracker.getLostTracks()) {\n const detail = camera.trackStore.finishTrack(lostTrack.trackId)\n if (detail && this.onTrackFinished) {\n this.onTrackFinished(deviceId, detail)\n }\n }\n\n // 11. Build live state\n const pipelineMs = pipelineResult?.totalMs ?? 0\n const pipelineStatus: PipelineStatus[] = []\n\n const liveState = camera.liveStateManager.buildState(\n deviceId,\n tracked,\n states,\n camera.zoneEvaluator.getTrackZones(),\n pipelineStatus,\n pipelineMs,\n events[events.length - 1],\n timestamp,\n )\n camera.lastLiveState = liveState\n camera.analyticsProvider.updateLiveState(liveState)\n\n // 12. Notify live state subscribers\n const cameraListeners = this.listeners.get(deviceId)\n if (cameraListeners) {\n for (const cb of cameraListeners) {\n cb(liveState)\n }\n }\n\n return events\n }\n\n setCameraPipeline(deviceId: string, _config: PipelineConfig): void {\n // Ensure camera state exists — config stored for future use\n this.getOrCreateCamera(deviceId)\n }\n\n setCameraZones(deviceId: string, zones: ZoneDefinition[]): void {\n const camera = this.getOrCreateCamera(deviceId)\n camera.zones = [...zones]\n camera.liveStateManager.setZones(zones)\n }\n\n setKnownFaces(faces: KnownFace[]): void {\n this.knownFaces = [...faces]\n }\n\n setKnownPlates(plates: KnownPlate[]): void {\n this.knownPlates = [...plates]\n }\n\n onLiveStateChange(\n deviceId: string,\n callback: (state: CameraLiveState) => void,\n ): () => void {\n if (!this.listeners.has(deviceId)) {\n this.listeners.set(deviceId, new Set())\n }\n this.listeners.get(deviceId)!.add(callback)\n return () => {\n this.listeners.get(deviceId)?.delete(callback)\n }\n }\n\n // ICameraAnalyticsProvider delegates to per-camera AnalyticsProvider\n\n getLiveState(deviceId: string): CameraLiveState | null {\n return this.cameras.get(deviceId)?.lastLiveState ?? null\n }\n\n getTracks(deviceId: string, filter?: TrackFilter): TrackedObjectSummary[] {\n const camera = this.cameras.get(deviceId)\n if (!camera) return []\n return camera.analyticsProvider.getTracks(deviceId, filter)\n }\n\n getZoneState(deviceId: string, zoneId: string): ZoneLiveState | null {\n const camera = this.cameras.get(deviceId)\n if (!camera) return null\n return camera.analyticsProvider.getZoneState(deviceId, zoneId)\n }\n\n async getZoneHistory(\n deviceId: string,\n zoneId: string,\n options: TimeRangeOptions,\n ): Promise<ZoneHistoryPoint[]> {\n const camera = this.cameras.get(deviceId)\n if (!camera) return []\n return camera.analyticsProvider.getZoneHistory(deviceId, zoneId, options)\n }\n\n async getHeatmap(deviceId: string, options: HeatmapOptions): Promise<HeatmapData> {\n const camera = this.cameras.get(deviceId)\n if (!camera) {\n const gridSize = options.resolution\n return {\n width: this.config.defaultFrameWidth,\n height: this.config.defaultFrameHeight,\n gridSize,\n cells: new Float32Array(gridSize * gridSize),\n maxCount: 0,\n }\n }\n return camera.heatmapAggregator.getHeatmap()\n }\n\n getTrackDetail(deviceId: string, trackId: string): TrackDetail | null {\n const camera = this.cameras.get(deviceId)\n if (!camera) return null\n return camera.trackStore.getTrackDetail(trackId)\n }\n\n getCameraStatus(deviceId: string): PipelineStatus[] {\n const camera = this.cameras.get(deviceId)\n if (!camera) return []\n return camera.analyticsProvider.getCameraStatus(deviceId)\n }\n\n private getOrCreateCamera(deviceId: string): CameraAnalysisState {\n const existing = this.cameras.get(deviceId)\n if (existing) return existing\n\n const tracker = new SortTracker(this.config.tracker)\n const stateAnalyzer = new StateAnalyzer(this.config.stateAnalyzer)\n const zoneEvaluator = new ZoneEvaluator()\n const eventEmitter = new DetectionEventEmitter(this.config.eventFilter)\n const trackStore = new TrackStore()\n const liveStateManager = new LiveStateManager()\n const heatmapAggregator = new HeatmapAggregator(\n this.config.defaultFrameWidth,\n this.config.defaultFrameHeight,\n this.config.heatmapGridSize,\n )\n const analyticsProvider = new AnalyticsProvider(liveStateManager, trackStore)\n const snapshotManager = new SnapshotManager({\n ...DEFAULT_SNAPSHOT_CONFIG,\n ...this.config.snapshot,\n })\n\n const cameraState: CameraAnalysisState = {\n tracker,\n stateAnalyzer,\n zoneEvaluator,\n eventEmitter,\n trackStore,\n liveStateManager,\n heatmapAggregator,\n analyticsProvider,\n snapshotManager,\n zones: [],\n lastLiveState: null,\n }\n\n this.cameras.set(deviceId, cameraState)\n return cameraState\n }\n\n private extractDetections(pipelineResult: PipelineResult): SpatialDetection[] {\n const detections: SpatialDetection[] = []\n for (const stepResult of pipelineResult.results) {\n if (stepResult.slot === 'detector') {\n const output = stepResult.output as DetectorOutput\n if (output.detections) {\n detections.push(...output.detections)\n }\n }\n }\n return detections\n }\n\n private matchClassifications(\n pipelineResult: PipelineResult,\n trackIds: string[],\n ): { trackId: string; classifications: Classification[] }[] {\n // Classifiers run after cropper; we associate classifications with the nearest track\n // by index (simplistic: classifier i → track i). The server orchestrator may provide\n // a more sophisticated mapping in future.\n const classifierResults: Classification[][] = []\n\n for (const stepResult of pipelineResult.results) {\n if (stepResult.slot === 'classifier') {\n const output = stepResult.output as ClassifierOutput\n if (output.classifications) {\n classifierResults.push([...output.classifications])\n }\n }\n }\n\n return trackIds\n .slice(0, classifierResults.length)\n .map((trackId, i) => ({\n trackId,\n classifications: classifierResults[i] ?? [],\n }))\n }\n}\n"],"mappings":"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","names":["iou","MAX_PATH_LENGTH"]}
|