@camstack/addon-vision 0.1.7 → 0.1.10
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/addons/animal-classifier/index.d.mts +30 -0
- package/dist/addons/animal-classifier/index.d.ts +30 -0
- package/dist/addons/animal-classifier/index.js +822 -999
- package/dist/addons/animal-classifier/index.js.map +1 -1
- package/dist/addons/animal-classifier/index.mjs +7 -242
- package/dist/addons/animal-classifier/index.mjs.map +1 -1
- package/dist/addons/audio-classification/index.d.mts +36 -0
- package/dist/addons/audio-classification/index.d.ts +36 -0
- package/dist/addons/audio-classification/index.js +378 -501
- package/dist/addons/audio-classification/index.js.map +1 -1
- package/dist/addons/audio-classification/index.mjs +4 -224
- package/dist/addons/audio-classification/index.mjs.map +1 -1
- package/dist/addons/bird-global-classifier/index.d.mts +31 -0
- package/dist/addons/bird-global-classifier/index.d.ts +31 -0
- package/dist/addons/bird-global-classifier/index.js +825 -1002
- package/dist/addons/bird-global-classifier/index.js.map +1 -1
- package/dist/addons/bird-global-classifier/index.mjs +7 -248
- package/dist/addons/bird-global-classifier/index.mjs.map +1 -1
- package/dist/addons/bird-nabirds-classifier/index.d.mts +33 -0
- package/dist/addons/bird-nabirds-classifier/index.d.ts +33 -0
- package/dist/addons/bird-nabirds-classifier/index.js +825 -1002
- package/dist/addons/bird-nabirds-classifier/index.js.map +1 -1
- package/dist/addons/bird-nabirds-classifier/index.mjs +7 -289
- package/dist/addons/bird-nabirds-classifier/index.mjs.map +1 -1
- package/dist/addons/face-detection/index.d.mts +29 -0
- package/dist/addons/face-detection/index.d.ts +29 -0
- package/dist/addons/face-detection/index.js +934 -1196
- package/dist/addons/face-detection/index.js.map +1 -1
- package/dist/addons/face-detection/index.mjs +7 -227
- package/dist/addons/face-detection/index.mjs.map +1 -1
- package/dist/addons/face-recognition/index.d.mts +29 -0
- package/dist/addons/face-recognition/index.d.ts +29 -0
- package/dist/addons/face-recognition/index.js +807 -1003
- package/dist/addons/face-recognition/index.js.map +1 -1
- package/dist/addons/face-recognition/index.mjs +6 -197
- package/dist/addons/face-recognition/index.mjs.map +1 -1
- package/dist/addons/motion-detection/index.d.mts +28 -0
- package/dist/addons/motion-detection/index.d.ts +28 -0
- package/dist/addons/motion-detection/index.js +111 -214
- package/dist/addons/motion-detection/index.js.map +1 -1
- package/dist/addons/motion-detection/index.mjs +9 -12
- package/dist/addons/motion-detection/index.mjs.map +1 -1
- package/dist/addons/object-detection/index.d.mts +31 -0
- package/dist/addons/object-detection/index.d.ts +31 -0
- package/dist/addons/object-detection/index.js +1082 -1287
- package/dist/addons/object-detection/index.js.map +1 -1
- package/dist/addons/object-detection/index.mjs +7 -373
- package/dist/addons/object-detection/index.mjs.map +1 -1
- package/dist/addons/plate-detection/index.d.mts +30 -0
- package/dist/addons/plate-detection/index.d.ts +30 -0
- package/dist/addons/plate-detection/index.js +868 -1075
- package/dist/addons/plate-detection/index.js.map +1 -1
- package/dist/addons/plate-detection/index.mjs +7 -230
- package/dist/addons/plate-detection/index.mjs.map +1 -1
- package/dist/addons/plate-recognition/index.d.mts +31 -0
- package/dist/addons/plate-recognition/index.d.ts +31 -0
- package/dist/addons/plate-recognition/index.js +505 -684
- package/dist/addons/plate-recognition/index.js.map +1 -1
- package/dist/addons/plate-recognition/index.mjs +5 -244
- package/dist/addons/plate-recognition/index.mjs.map +1 -1
- package/dist/addons/segmentation-refiner/index.d.mts +30 -0
- package/dist/addons/segmentation-refiner/index.d.ts +30 -0
- package/dist/addons/segmentation-refiner/index.js +790 -967
- package/dist/addons/segmentation-refiner/index.js.map +1 -1
- package/dist/addons/segmentation-refiner/index.mjs +17 -21
- package/dist/addons/segmentation-refiner/index.mjs.map +1 -1
- package/dist/addons/vehicle-classifier/index.d.mts +31 -0
- package/dist/addons/vehicle-classifier/index.d.ts +31 -0
- package/dist/addons/vehicle-classifier/index.js +410 -581
- package/dist/addons/vehicle-classifier/index.js.map +1 -1
- package/dist/addons/vehicle-classifier/index.mjs +16 -20
- package/dist/addons/vehicle-classifier/index.mjs.map +1 -1
- package/dist/chunk-22BHCDT5.mjs +101 -0
- package/dist/{chunk-WG66JYYW.mjs.map → chunk-22BHCDT5.mjs.map} +1 -1
- package/dist/chunk-2IOKI4ES.mjs +335 -0
- package/dist/{chunk-PIFS7AIT.mjs.map → chunk-2IOKI4ES.mjs.map} +1 -1
- package/dist/chunk-7DYHXUPZ.mjs +36 -0
- package/dist/{chunk-BS4DKYGN.mjs.map → chunk-7DYHXUPZ.mjs.map} +1 -1
- package/dist/chunk-BJTO5JO5.mjs +11 -0
- package/dist/chunk-BP7H4NFS.mjs +412 -0
- package/dist/{chunk-MGT6RUVX.mjs.map → chunk-BP7H4NFS.mjs.map} +1 -1
- package/dist/chunk-BR2FPGOX.mjs +98 -0
- package/dist/{chunk-YYDM6V2F.mjs.map → chunk-BR2FPGOX.mjs.map} +1 -1
- package/dist/chunk-D6WEHN33.mjs +276 -0
- package/dist/chunk-D6WEHN33.mjs.map +1 -0
- package/dist/chunk-DRYFGARD.mjs +289 -0
- package/dist/chunk-DRYFGARD.mjs.map +1 -0
- package/dist/chunk-DUN6XU3N.mjs +72 -0
- package/dist/{chunk-XD7WGXHZ.mjs.map → chunk-DUN6XU3N.mjs.map} +1 -1
- package/dist/chunk-ESLHNWWE.mjs +387 -0
- package/dist/chunk-ESLHNWWE.mjs.map +1 -0
- package/dist/chunk-JUQEW6ON.mjs +256 -0
- package/dist/chunk-JUQEW6ON.mjs.map +1 -0
- package/dist/chunk-KUO2BVFY.mjs +90 -0
- package/dist/{chunk-DE7I3VHO.mjs.map → chunk-KUO2BVFY.mjs.map} +1 -1
- package/dist/chunk-R5J3WAUI.mjs +645 -0
- package/dist/chunk-R5J3WAUI.mjs.map +1 -0
- package/dist/chunk-XZ6ZMXXU.mjs +39 -0
- package/dist/{chunk-K36R6HWY.mjs.map → chunk-XZ6ZMXXU.mjs.map} +1 -1
- package/dist/chunk-YPU4WTXZ.mjs +269 -0
- package/dist/chunk-YPU4WTXZ.mjs.map +1 -0
- package/dist/chunk-YUCD2TFH.mjs +242 -0
- package/dist/chunk-YUCD2TFH.mjs.map +1 -0
- package/dist/chunk-ZTJENCFC.mjs +379 -0
- package/dist/chunk-ZTJENCFC.mjs.map +1 -0
- package/dist/chunk-ZWYXXCXP.mjs +248 -0
- package/dist/chunk-ZWYXXCXP.mjs.map +1 -0
- package/dist/index.d.mts +183 -0
- package/dist/index.d.ts +183 -0
- package/dist/index.js +3930 -4449
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +250 -2698
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/dist/chunk-2YMA6QOV.mjs +0 -193
- package/dist/chunk-2YMA6QOV.mjs.map +0 -1
- package/dist/chunk-3IIFBJCD.mjs +0 -45
- package/dist/chunk-BS4DKYGN.mjs +0 -48
- package/dist/chunk-DE7I3VHO.mjs +0 -106
- package/dist/chunk-F6D2OZ36.mjs +0 -89
- package/dist/chunk-F6D2OZ36.mjs.map +0 -1
- package/dist/chunk-GAOIFQDX.mjs +0 -59
- package/dist/chunk-GAOIFQDX.mjs.map +0 -1
- package/dist/chunk-HUIX2XVR.mjs +0 -159
- package/dist/chunk-HUIX2XVR.mjs.map +0 -1
- package/dist/chunk-K36R6HWY.mjs +0 -51
- package/dist/chunk-MBTAI3WE.mjs +0 -78
- package/dist/chunk-MBTAI3WE.mjs.map +0 -1
- package/dist/chunk-MGT6RUVX.mjs +0 -423
- package/dist/chunk-PIFS7AIT.mjs +0 -446
- package/dist/chunk-WG66JYYW.mjs +0 -116
- package/dist/chunk-XD7WGXHZ.mjs +0 -82
- package/dist/chunk-YYDM6V2F.mjs +0 -113
- package/dist/chunk-ZK7P3TZN.mjs +0 -286
- package/dist/chunk-ZK7P3TZN.mjs.map +0 -1
- /package/dist/{chunk-3IIFBJCD.mjs.map → chunk-BJTO5JO5.mjs.map} +0 -0
|
@@ -5,9 +5,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
-
};
|
|
11
8
|
var __export = (target, all) => {
|
|
12
9
|
for (var name in all)
|
|
13
10
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -30,226 +27,126 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
27
|
));
|
|
31
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
29
|
|
|
33
|
-
// src/
|
|
34
|
-
var
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
right: targetSize - scaledWidth - padX,
|
|
73
|
-
background: { r: 114, g: 114, b: 114 }
|
|
74
|
-
}).removeAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
75
|
-
const numPixels = targetSize * targetSize;
|
|
76
|
-
const float32 = new Float32Array(3 * numPixels);
|
|
77
|
-
for (let i = 0; i < numPixels; i++) {
|
|
78
|
-
const srcBase = i * 3;
|
|
79
|
-
float32[0 * numPixels + i] = data[srcBase] / 255;
|
|
80
|
-
float32[1 * numPixels + i] = data[srcBase + 1] / 255;
|
|
81
|
-
float32[2 * numPixels + i] = data[srcBase + 2] / 255;
|
|
82
|
-
}
|
|
83
|
-
return { data: float32, scale, padX, padY, originalWidth, originalHeight };
|
|
30
|
+
// src/addons/motion-detection/index.ts
|
|
31
|
+
var motion_detection_exports = {};
|
|
32
|
+
__export(motion_detection_exports, {
|
|
33
|
+
default: () => MotionDetectionAddon
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(motion_detection_exports);
|
|
36
|
+
|
|
37
|
+
// src/shared/image-utils.ts
|
|
38
|
+
var import_sharp = __toESM(require("sharp"));
|
|
39
|
+
async function jpegToRgb(jpeg) {
|
|
40
|
+
const { data, info } = await (0, import_sharp.default)(jpeg).removeAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
41
|
+
return { data, width: info.width, height: info.height };
|
|
42
|
+
}
|
|
43
|
+
function rgbToGrayscale(rgb, width, height) {
|
|
44
|
+
const numPixels = width * height;
|
|
45
|
+
const gray = new Uint8Array(numPixels);
|
|
46
|
+
for (let i = 0; i < numPixels; i++) {
|
|
47
|
+
const r = rgb[i * 3];
|
|
48
|
+
const g = rgb[i * 3 + 1];
|
|
49
|
+
const b = rgb[i * 3 + 2];
|
|
50
|
+
gray[i] = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
|
|
51
|
+
}
|
|
52
|
+
return gray;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/addons/motion-detection/frame-diff.ts
|
|
56
|
+
function detectMotion(current, previous, width, height, threshold, minArea) {
|
|
57
|
+
const numPixels = width * height;
|
|
58
|
+
const mask = new Uint8Array(numPixels);
|
|
59
|
+
for (let i = 0; i < numPixels; i++) {
|
|
60
|
+
mask[i] = Math.abs((current[i] ?? 0) - (previous[i] ?? 0)) > threshold ? 1 : 0;
|
|
61
|
+
}
|
|
62
|
+
const labels = new Int32Array(numPixels).fill(0);
|
|
63
|
+
const parent = new Int32Array(numPixels + 1).fill(0);
|
|
64
|
+
let nextLabel = 1;
|
|
65
|
+
function findRoot(x) {
|
|
66
|
+
while (parent[x] !== x) {
|
|
67
|
+
parent[x] = parent[parent[x]];
|
|
68
|
+
x = parent[x];
|
|
84
69
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
70
|
+
return x;
|
|
71
|
+
}
|
|
72
|
+
function union(a, b) {
|
|
73
|
+
const ra = findRoot(a);
|
|
74
|
+
const rb = findRoot(b);
|
|
75
|
+
if (ra !== rb) parent[rb] = ra;
|
|
76
|
+
return ra;
|
|
77
|
+
}
|
|
78
|
+
for (let i = 0; i <= numPixels; i++) {
|
|
79
|
+
parent[i] = i;
|
|
80
|
+
}
|
|
81
|
+
for (let y = 0; y < height; y++) {
|
|
82
|
+
for (let x = 0; x < width; x++) {
|
|
83
|
+
const idx = y * width + x;
|
|
84
|
+
if (!mask[idx]) continue;
|
|
85
|
+
const above = y > 0 ? labels[(y - 1) * width + x] ?? 0 : 0;
|
|
86
|
+
const left = x > 0 ? labels[y * width + (x - 1)] ?? 0 : 0;
|
|
87
|
+
if (above === 0 && left === 0) {
|
|
88
|
+
labels[idx] = nextLabel;
|
|
89
|
+
parent[nextLabel] = nextLabel;
|
|
90
|
+
nextLabel++;
|
|
91
|
+
} else if (above !== 0 && left === 0) {
|
|
92
|
+
labels[idx] = above;
|
|
93
|
+
} else if (above === 0 && left !== 0) {
|
|
94
|
+
labels[idx] = left;
|
|
107
95
|
} else {
|
|
108
|
-
|
|
109
|
-
const srcBase = i * 3;
|
|
110
|
-
for (let c = 0; c < 3; c++) {
|
|
111
|
-
const raw = data[srcBase + c] / 255;
|
|
112
|
-
let val;
|
|
113
|
-
if (normalization === "zero-one") {
|
|
114
|
-
val = raw;
|
|
115
|
-
} else if (normalization === "imagenet") {
|
|
116
|
-
val = (raw - mean[c]) / std[c];
|
|
117
|
-
} else {
|
|
118
|
-
val = data[srcBase + c];
|
|
119
|
-
}
|
|
120
|
-
float32[i * 3 + c] = val;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
96
|
+
labels[idx] = union(above, left);
|
|
123
97
|
}
|
|
124
|
-
return float32;
|
|
125
98
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const r = rgb[i * 3];
|
|
131
|
-
const g = rgb[i * 3 + 1];
|
|
132
|
-
const b = rgb[i * 3 + 2];
|
|
133
|
-
gray[i] = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
|
|
134
|
-
}
|
|
135
|
-
return gray;
|
|
99
|
+
}
|
|
100
|
+
for (let i = 0; i < numPixels; i++) {
|
|
101
|
+
if (labels[i]) {
|
|
102
|
+
labels[i] = findRoot(labels[i]);
|
|
136
103
|
}
|
|
137
104
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
function union(a, b) {
|
|
163
|
-
const ra = findRoot(a);
|
|
164
|
-
const rb = findRoot(b);
|
|
165
|
-
if (ra !== rb)
|
|
166
|
-
parent[rb] = ra;
|
|
167
|
-
return ra;
|
|
168
|
-
}
|
|
169
|
-
for (let i = 0; i <= numPixels; i++) {
|
|
170
|
-
parent[i] = i;
|
|
171
|
-
}
|
|
172
|
-
for (let y = 0; y < height; y++) {
|
|
173
|
-
for (let x = 0; x < width; x++) {
|
|
174
|
-
const idx = y * width + x;
|
|
175
|
-
if (!mask[idx])
|
|
176
|
-
continue;
|
|
177
|
-
const above = y > 0 ? labels[(y - 1) * width + x] ?? 0 : 0;
|
|
178
|
-
const left = x > 0 ? labels[y * width + (x - 1)] ?? 0 : 0;
|
|
179
|
-
if (above === 0 && left === 0) {
|
|
180
|
-
labels[idx] = nextLabel;
|
|
181
|
-
parent[nextLabel] = nextLabel;
|
|
182
|
-
nextLabel++;
|
|
183
|
-
} else if (above !== 0 && left === 0) {
|
|
184
|
-
labels[idx] = above;
|
|
185
|
-
} else if (above === 0 && left !== 0) {
|
|
186
|
-
labels[idx] = left;
|
|
187
|
-
} else {
|
|
188
|
-
labels[idx] = union(above, left);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
for (let i = 0; i < numPixels; i++) {
|
|
193
|
-
if (labels[i]) {
|
|
194
|
-
labels[i] = findRoot(labels[i]);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
const bboxMap = /* @__PURE__ */ new Map();
|
|
198
|
-
for (let y = 0; y < height; y++) {
|
|
199
|
-
for (let x = 0; x < width; x++) {
|
|
200
|
-
const idx = y * width + x;
|
|
201
|
-
const label = labels[idx];
|
|
202
|
-
if (!label)
|
|
203
|
-
continue;
|
|
204
|
-
const diff = Math.abs((current[idx] ?? 0) - (previous[idx] ?? 0));
|
|
205
|
-
const existing = bboxMap.get(label);
|
|
206
|
-
if (existing) {
|
|
207
|
-
existing.minX = Math.min(existing.minX, x);
|
|
208
|
-
existing.minY = Math.min(existing.minY, y);
|
|
209
|
-
existing.maxX = Math.max(existing.maxX, x);
|
|
210
|
-
existing.maxY = Math.max(existing.maxY, y);
|
|
211
|
-
existing.count++;
|
|
212
|
-
existing.intensitySum += diff;
|
|
213
|
-
} else {
|
|
214
|
-
bboxMap.set(label, {
|
|
215
|
-
minX: x,
|
|
216
|
-
minY: y,
|
|
217
|
-
maxX: x,
|
|
218
|
-
maxY: y,
|
|
219
|
-
count: 1,
|
|
220
|
-
intensitySum: diff
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
const regions = [];
|
|
226
|
-
for (const [, info] of bboxMap) {
|
|
227
|
-
if (info.count < minArea)
|
|
228
|
-
continue;
|
|
229
|
-
regions.push({
|
|
230
|
-
bbox: {
|
|
231
|
-
x: info.minX,
|
|
232
|
-
y: info.minY,
|
|
233
|
-
w: info.maxX - info.minX + 1,
|
|
234
|
-
h: info.maxY - info.minY + 1
|
|
235
|
-
},
|
|
236
|
-
pixelCount: info.count,
|
|
237
|
-
intensity: info.intensitySum / info.count
|
|
105
|
+
const bboxMap = /* @__PURE__ */ new Map();
|
|
106
|
+
for (let y = 0; y < height; y++) {
|
|
107
|
+
for (let x = 0; x < width; x++) {
|
|
108
|
+
const idx = y * width + x;
|
|
109
|
+
const label = labels[idx];
|
|
110
|
+
if (!label) continue;
|
|
111
|
+
const diff = Math.abs((current[idx] ?? 0) - (previous[idx] ?? 0));
|
|
112
|
+
const existing = bboxMap.get(label);
|
|
113
|
+
if (existing) {
|
|
114
|
+
existing.minX = Math.min(existing.minX, x);
|
|
115
|
+
existing.minY = Math.min(existing.minY, y);
|
|
116
|
+
existing.maxX = Math.max(existing.maxX, x);
|
|
117
|
+
existing.maxY = Math.max(existing.maxY, y);
|
|
118
|
+
existing.count++;
|
|
119
|
+
existing.intensitySum += diff;
|
|
120
|
+
} else {
|
|
121
|
+
bboxMap.set(label, {
|
|
122
|
+
minX: x,
|
|
123
|
+
minY: y,
|
|
124
|
+
maxX: x,
|
|
125
|
+
maxY: y,
|
|
126
|
+
count: 1,
|
|
127
|
+
intensitySum: diff
|
|
238
128
|
});
|
|
239
129
|
}
|
|
240
|
-
return regions;
|
|
241
130
|
}
|
|
242
131
|
}
|
|
243
|
-
|
|
132
|
+
const regions = [];
|
|
133
|
+
for (const [, info] of bboxMap) {
|
|
134
|
+
if (info.count < minArea) continue;
|
|
135
|
+
regions.push({
|
|
136
|
+
bbox: {
|
|
137
|
+
x: info.minX,
|
|
138
|
+
y: info.minY,
|
|
139
|
+
w: info.maxX - info.minX + 1,
|
|
140
|
+
h: info.maxY - info.minY + 1
|
|
141
|
+
},
|
|
142
|
+
pixelCount: info.count,
|
|
143
|
+
intensity: info.intensitySum / info.count
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return regions;
|
|
147
|
+
}
|
|
244
148
|
|
|
245
149
|
// src/addons/motion-detection/index.ts
|
|
246
|
-
var motion_detection_exports = {};
|
|
247
|
-
__export(motion_detection_exports, {
|
|
248
|
-
default: () => MotionDetectionAddon
|
|
249
|
-
});
|
|
250
|
-
module.exports = __toCommonJS(motion_detection_exports);
|
|
251
|
-
var import_image_utils = __toESM(require_image_utils());
|
|
252
|
-
var import_frame_diff = __toESM(require_frame_diff());
|
|
253
150
|
var MOTION_LABEL = { id: "motion", name: "Motion" };
|
|
254
151
|
var MOTION_LABELS = [MOTION_LABEL];
|
|
255
152
|
var EMPTY_CLASS_MAP = { mapping: {}, preserveOriginal: true };
|
|
@@ -292,15 +189,15 @@ var MotionDetectionAddon = class {
|
|
|
292
189
|
}
|
|
293
190
|
async detect(frame) {
|
|
294
191
|
const start = Date.now();
|
|
295
|
-
const { data, width, height } = await
|
|
296
|
-
const currentGray =
|
|
192
|
+
const { data, width, height } = await jpegToRgb(frame.data);
|
|
193
|
+
const currentGray = rgbToGrayscale(data, width, height);
|
|
297
194
|
if (!this.previousGray || this.previousWidth !== width || this.previousHeight !== height) {
|
|
298
195
|
this.previousGray = currentGray;
|
|
299
196
|
this.previousWidth = width;
|
|
300
197
|
this.previousHeight = height;
|
|
301
198
|
return { detections: [], inferenceMs: Date.now() - start, modelId: "frame-diff" };
|
|
302
199
|
}
|
|
303
|
-
const regions =
|
|
200
|
+
const regions = detectMotion(
|
|
304
201
|
currentGray,
|
|
305
202
|
this.previousGray,
|
|
306
203
|
width,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/shared/image-utils.ts","../../../src/addons/motion-detection/frame-diff.ts","../../../src/addons/motion-detection/index.ts"],"sourcesContent":["import sharp from 'sharp'\nimport type { BoundingBox } from '@camstack/types'\n\n/** Decode JPEG to raw RGB pixels */\nexport async function jpegToRgb(\n jpeg: Buffer,\n): Promise<{ data: Buffer; width: number; height: number }> {\n const { data, info } = await sharp(jpeg)\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true })\n return { data, width: info.width, height: info.height }\n}\n\n/** Crop a region from a JPEG buffer */\nexport async function cropRegion(jpeg: Buffer, roi: BoundingBox): Promise<Buffer> {\n return sharp(jpeg)\n .extract({\n left: Math.round(roi.x),\n top: Math.round(roi.y),\n width: Math.round(roi.w),\n height: Math.round(roi.h),\n })\n .jpeg()\n .toBuffer()\n}\n\n/** Letterbox resize for YOLO: resize preserving aspect ratio, pad to square */\nexport async function letterbox(\n jpeg: Buffer,\n targetSize: number,\n): Promise<{\n data: Float32Array\n scale: number\n padX: number\n padY: number\n originalWidth: number\n originalHeight: number\n}> {\n const meta = await sharp(jpeg).metadata()\n const originalWidth = meta.width ?? 0\n const originalHeight = meta.height ?? 0\n\n const scale = Math.min(targetSize / originalWidth, targetSize / originalHeight)\n const scaledWidth = Math.round(originalWidth * scale)\n const scaledHeight = Math.round(originalHeight * scale)\n\n const padX = Math.floor((targetSize - scaledWidth) / 2)\n const padY = Math.floor((targetSize - scaledHeight) / 2)\n\n const { data } = await sharp(jpeg)\n .resize(scaledWidth, scaledHeight)\n .extend({\n top: padY,\n bottom: targetSize - scaledHeight - padY,\n left: padX,\n right: targetSize - scaledWidth - padX,\n background: { r: 114, g: 114, b: 114 },\n })\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true })\n\n // Convert HWC uint8 to CHW float [0,1]\n const numPixels = targetSize * targetSize\n const float32 = new Float32Array(3 * numPixels)\n for (let i = 0; i < numPixels; i++) {\n const srcBase = i * 3\n float32[0 * numPixels + i] = (data[srcBase]! / 255)\n float32[1 * numPixels + i] = (data[srcBase + 1]! / 255)\n float32[2 * numPixels + i] = (data[srcBase + 2]! / 255)\n }\n\n return { data: float32, scale, padX, padY, originalWidth, originalHeight }\n}\n\n/** Resize and normalize to Float32Array */\nexport async function resizeAndNormalize(\n jpeg: Buffer,\n targetWidth: number,\n targetHeight: number,\n normalization: 'zero-one' | 'imagenet' | 'none',\n layout: 'nchw' | 'nhwc',\n): Promise<Float32Array> {\n const { data } = await sharp(jpeg)\n .resize(targetWidth, targetHeight, { fit: 'fill' })\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true })\n\n const numPixels = targetWidth * targetHeight\n const float32 = new Float32Array(3 * numPixels)\n\n // ImageNet mean and std per channel\n const mean = [0.485, 0.456, 0.406]\n const std = [0.229, 0.224, 0.225]\n\n if (layout === 'nchw') {\n for (let i = 0; i < numPixels; i++) {\n const srcBase = i * 3\n for (let c = 0; c < 3; c++) {\n const raw = data[srcBase + c]! / 255\n let val: number\n if (normalization === 'zero-one') {\n val = raw\n } else if (normalization === 'imagenet') {\n val = (raw - mean[c]!) / std[c]!\n } else {\n val = data[srcBase + c]!\n }\n float32[c * numPixels + i] = val\n }\n }\n } else {\n // nhwc\n for (let i = 0; i < numPixels; i++) {\n const srcBase = i * 3\n for (let c = 0; c < 3; c++) {\n const raw = data[srcBase + c]! / 255\n let val: number\n if (normalization === 'zero-one') {\n val = raw\n } else if (normalization === 'imagenet') {\n val = (raw - mean[c]!) / std[c]!\n } else {\n val = data[srcBase + c]!\n }\n float32[i * 3 + c] = val\n }\n }\n }\n\n return float32\n}\n\n/** Convert raw RGB to grayscale Uint8Array */\nexport function rgbToGrayscale(rgb: Buffer, width: number, height: number): Uint8Array {\n const numPixels = width * height\n const gray = new Uint8Array(numPixels)\n for (let i = 0; i < numPixels; i++) {\n const r = rgb[i * 3]!\n const g = rgb[i * 3 + 1]!\n const b = rgb[i * 3 + 2]!\n // BT.601 luma\n gray[i] = Math.round(0.299 * r + 0.587 * g + 0.114 * b)\n }\n return gray\n}\n","import type { BoundingBox } from '@camstack/types'\n\nexport interface MotionRegion {\n readonly bbox: BoundingBox\n readonly pixelCount: number\n readonly intensity: number\n}\n\n/**\n * Detect motion by frame differencing.\n *\n * @param current - Grayscale pixel array for the current frame (Uint8Array, length = width * height)\n * @param previous - Grayscale pixel array for the previous frame\n * @param width - Frame width in pixels\n * @param height - Frame height in pixels\n * @param threshold - Pixel diff threshold 0-255; differences below this are ignored\n * @param minArea - Minimum number of changed pixels for a region to be reported\n */\nexport function detectMotion(\n current: Uint8Array,\n previous: Uint8Array,\n width: number,\n height: number,\n threshold: number,\n minArea: number,\n): MotionRegion[] {\n const numPixels = width * height\n\n // Step 1: Compute binary mask — 1 where abs(current - previous) > threshold\n const mask = new Uint8Array(numPixels)\n for (let i = 0; i < numPixels; i++) {\n mask[i] = Math.abs((current[i] ?? 0) - (previous[i] ?? 0)) > threshold ? 1 : 0\n }\n\n // Step 2: Two-pass connected component labeling\n const labels = new Int32Array(numPixels).fill(0)\n const parent = new Int32Array(numPixels + 1).fill(0)\n let nextLabel = 1\n\n // Union-Find helpers\n function findRoot(x: number): number {\n while (parent[x] !== x) {\n parent[x] = parent[parent[x]!]! // path compression\n x = parent[x]!\n }\n return x\n }\n\n function union(a: number, b: number): number {\n const ra = findRoot(a)\n const rb = findRoot(b)\n if (ra !== rb) parent[rb] = ra\n return ra\n }\n\n // Initialize parent array as identity\n for (let i = 0; i <= numPixels; i++) {\n parent[i] = i\n }\n\n // First pass: assign provisional labels\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x\n if (!mask[idx]) continue\n\n const above = y > 0 ? labels[(y - 1) * width + x] ?? 0 : 0\n const left = x > 0 ? labels[y * width + (x - 1)] ?? 0 : 0\n\n if (above === 0 && left === 0) {\n labels[idx] = nextLabel\n parent[nextLabel] = nextLabel\n nextLabel++\n } else if (above !== 0 && left === 0) {\n labels[idx] = above\n } else if (above === 0 && left !== 0) {\n labels[idx] = left\n } else {\n // Both neighbors — merge\n labels[idx] = union(above, left)\n }\n }\n }\n\n // Second pass: resolve all labels to roots\n for (let i = 0; i < numPixels; i++) {\n if (labels[i]) {\n labels[i] = findRoot(labels[i]!)\n }\n }\n\n // Step 3: Collect bounding boxes and pixel counts per root label\n const bboxMap = new Map<\n number,\n { minX: number; minY: number; maxX: number; maxY: number; count: number; intensitySum: number }\n >()\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x\n const label = labels[idx]\n if (!label) continue\n\n const diff = Math.abs((current[idx] ?? 0) - (previous[idx] ?? 0))\n const existing = bboxMap.get(label)\n if (existing) {\n existing.minX = Math.min(existing.minX, x)\n existing.minY = Math.min(existing.minY, y)\n existing.maxX = Math.max(existing.maxX, x)\n existing.maxY = Math.max(existing.maxY, y)\n existing.count++\n existing.intensitySum += diff\n } else {\n bboxMap.set(label, {\n minX: x,\n minY: y,\n maxX: x,\n maxY: y,\n count: 1,\n intensitySum: diff,\n })\n }\n }\n }\n\n // Step 4: Filter by minimum area and build result\n const regions: MotionRegion[] = []\n for (const [, info] of bboxMap) {\n if (info.count < minArea) continue\n regions.push({\n bbox: {\n x: info.minX,\n y: info.minY,\n w: info.maxX - info.minX + 1,\n h: info.maxY - info.minY + 1,\n },\n pixelCount: info.count,\n intensity: info.intensitySum / info.count,\n })\n }\n\n return regions\n}\n","import type {\n IDetectorProvider,\n IDetectionAddon,\n AddonManifest,\n AddonContext,\n FrameInput,\n DetectorOutput,\n ConfigUISchema,\n ClassMapDefinition,\n ProbeResult,\n ModelCatalogEntry,\n DetectionModel,\n LabelDefinition,\n SpatialDetection,\n ModelRequirement,\n} from '@camstack/types'\nimport { jpegToRgb, rgbToGrayscale } from '../../shared/image-utils.js'\nimport { detectMotion } from './frame-diff.js'\n\nconst MOTION_LABEL: LabelDefinition = { id: 'motion', name: 'Motion' }\nconst MOTION_LABELS: readonly LabelDefinition[] = [MOTION_LABEL]\nconst EMPTY_CLASS_MAP: ClassMapDefinition = { mapping: {}, preserveOriginal: true }\n\nexport default class MotionDetectionAddon implements IDetectorProvider, IDetectionAddon {\n readonly id = 'motion-detection'\n readonly slot = 'detector' as const\n readonly inputClasses: readonly string[] | null = null\n readonly outputClasses = ['motion'] as const\n readonly slotPriority = 10 // runs first — feeds other detectors\n\n /** Motion detection has no ML models — returns empty requirements */\n getModelRequirements(): ModelRequirement[] {\n return []\n }\n\n readonly manifest: AddonManifest = {\n id: 'motion-detection',\n name: 'Motion Detection',\n version: '0.1.0',\n\n description: 'Frame-differencing motion detector — no inference engine required',\n\n slot: 'detector',\n inputClasses: undefined,\n outputClasses: ['motion'],\n supportsCustomModels: false,\n mayRequirePython: false,\n passive: true,\n defaultConfig: {\n threshold: 25,\n minArea: 500,\n },\n }\n\n private previousGray: Uint8Array | null = null\n private previousWidth = 0\n private previousHeight = 0\n private threshold = 25\n private minArea = 500\n\n async initialize(ctx: AddonContext): Promise<void> {\n const cfg = ctx.addonConfig\n this.threshold = (cfg['threshold'] as number | undefined) ?? 25\n this.minArea = (cfg['minArea'] as number | undefined) ?? 500\n }\n\n async detect(frame: FrameInput): Promise<DetectorOutput> {\n const start = Date.now()\n\n const { data, width, height } = await jpegToRgb(frame.data)\n const currentGray = rgbToGrayscale(data, width, height)\n\n if (!this.previousGray || this.previousWidth !== width || this.previousHeight !== height) {\n // Store first frame and return empty — no previous to diff against\n this.previousGray = currentGray\n this.previousWidth = width\n this.previousHeight = height\n return { detections: [], inferenceMs: Date.now() - start, modelId: 'frame-diff' }\n }\n\n const regions = detectMotion(\n currentGray,\n this.previousGray,\n width,\n height,\n this.threshold,\n this.minArea,\n )\n\n this.previousGray = currentGray\n\n const detections: SpatialDetection[] = regions.map((r) => ({\n class: 'motion',\n originalClass: 'motion',\n score: Math.min(1, r.intensity / 255),\n bbox: r.bbox,\n }))\n\n return {\n detections,\n inferenceMs: Date.now() - start,\n modelId: 'frame-diff',\n }\n }\n\n async shutdown(): Promise<void> {\n this.previousGray = null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'motion',\n title: 'Motion Detection',\n columns: 2,\n fields: [\n {\n key: 'threshold',\n label: 'Pixel Difference Threshold',\n description: 'Minimum per-pixel intensity change to count as motion (0-255)',\n type: 'slider',\n min: 5,\n max: 100,\n step: 5,\n default: 25,\n },\n {\n key: 'minArea',\n label: 'Minimum Region Area (px)',\n description: 'Minimum number of changed pixels to report a motion region',\n type: 'slider',\n min: 50,\n max: 10000,\n step: 50,\n default: 500,\n showValue: true,\n unit: 'px',\n },\n ],\n },\n ],\n }\n }\n\n getClassMap(): ClassMapDefinition {\n return EMPTY_CLASS_MAP\n }\n\n getModelCatalog(): ModelCatalogEntry[] {\n return []\n }\n\n getAvailableModels(): DetectionModel[] {\n return []\n }\n\n getActiveLabels(): readonly LabelDefinition[] {\n return MOTION_LABELS\n }\n\n async probe(): Promise<ProbeResult> {\n return {\n available: true,\n runtime: 'onnx', // no inference; satisfies the type (any runtime works)\n device: 'cpu',\n capabilities: ['fp32'],\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,IAAAA,SAAA,YAAAC;AAWA,IAAAD,SAAA,aAAA;AAaA,IAAAA,SAAA,YAAA;AAiDA,IAAAA,SAAA,qBAAA;AA2DA,IAAAA,SAAA,iBAAAE;AAxIA,QAAA,UAAA,gBAAA,QAAA,OAAA,CAAA;AAIO,mBAAeD,WACpB,MAAY;AAEZ,YAAM,EAAE,MAAM,KAAI,IAAK,OAAM,GAAA,QAAA,SAAM,IAAI,EACpC,YAAW,EACX,IAAG,EACH,SAAS,EAAE,mBAAmB,KAAI,CAAE;AACvC,aAAO,EAAE,MAAM,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAM;IACvD;AAGO,mBAAe,WAAW,MAAc,KAAgB;AAC7D,cAAO,GAAA,QAAA,SAAM,IAAI,EACd,QAAQ;QACP,MAAM,KAAK,MAAM,IAAI,CAAC;QACtB,KAAK,KAAK,MAAM,IAAI,CAAC;QACrB,OAAO,KAAK,MAAM,IAAI,CAAC;QACvB,QAAQ,KAAK,MAAM,IAAI,CAAC;OACzB,EACA,KAAI,EACJ,SAAQ;IACb;AAGO,mBAAe,UACpB,MACA,YAAkB;AASlB,YAAM,OAAO,OAAM,GAAA,QAAA,SAAM,IAAI,EAAE,SAAQ;AACvC,YAAM,gBAAgB,KAAK,SAAS;AACpC,YAAM,iBAAiB,KAAK,UAAU;AAEtC,YAAM,QAAQ,KAAK,IAAI,aAAa,eAAe,aAAa,cAAc;AAC9E,YAAM,cAAc,KAAK,MAAM,gBAAgB,KAAK;AACpD,YAAM,eAAe,KAAK,MAAM,iBAAiB,KAAK;AAEtD,YAAM,OAAO,KAAK,OAAO,aAAa,eAAe,CAAC;AACtD,YAAM,OAAO,KAAK,OAAO,aAAa,gBAAgB,CAAC;AAEvD,YAAM,EAAE,KAAI,IAAK,OAAM,GAAA,QAAA,SAAM,IAAI,EAC9B,OAAO,aAAa,YAAY,EAChC,OAAO;QACN,KAAK;QACL,QAAQ,aAAa,eAAe;QACpC,MAAM;QACN,OAAO,aAAa,cAAc;QAClC,YAAY,EAAE,GAAG,KAAK,GAAG,KAAK,GAAG,IAAG;OACrC,EACA,YAAW,EACX,IAAG,EACH,SAAS,EAAE,mBAAmB,KAAI,CAAE;AAGvC,YAAM,YAAY,aAAa;AAC/B,YAAM,UAAU,IAAI,aAAa,IAAI,SAAS;AAC9C,eAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,cAAM,UAAU,IAAI;AACpB,gBAAQ,IAAI,YAAY,CAAC,IAAK,KAAK,OAAO,IAAK;AAC/C,gBAAQ,IAAI,YAAY,CAAC,IAAK,KAAK,UAAU,CAAC,IAAK;AACnD,gBAAQ,IAAI,YAAY,CAAC,IAAK,KAAK,UAAU,CAAC,IAAK;MACrD;AAEA,aAAO,EAAE,MAAM,SAAS,OAAO,MAAM,MAAM,eAAe,eAAc;IAC1E;AAGO,mBAAe,mBACpB,MACA,aACA,cACA,eACA,QAAuB;AAEvB,YAAM,EAAE,KAAI,IAAK,OAAM,GAAA,QAAA,SAAM,IAAI,EAC9B,OAAO,aAAa,cAAc,EAAE,KAAK,OAAM,CAAE,EACjD,YAAW,EACX,IAAG,EACH,SAAS,EAAE,mBAAmB,KAAI,CAAE;AAEvC,YAAM,YAAY,cAAc;AAChC,YAAM,UAAU,IAAI,aAAa,IAAI,SAAS;AAG9C,YAAM,OAAO,CAAC,OAAO,OAAO,KAAK;AACjC,YAAM,MAAM,CAAC,OAAO,OAAO,KAAK;AAEhC,UAAI,WAAW,QAAQ;AACrB,iBAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,gBAAM,UAAU,IAAI;AACpB,mBAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,kBAAM,MAAM,KAAK,UAAU,CAAC,IAAK;AACjC,gBAAI;AACJ,gBAAI,kBAAkB,YAAY;AAChC,oBAAM;YACR,WAAW,kBAAkB,YAAY;AACvC,qBAAO,MAAM,KAAK,CAAC,KAAM,IAAI,CAAC;YAChC,OAAO;AACL,oBAAM,KAAK,UAAU,CAAC;YACxB;AACA,oBAAQ,IAAI,YAAY,CAAC,IAAI;UAC/B;QACF;MACF,OAAO;AAEL,iBAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,gBAAM,UAAU,IAAI;AACpB,mBAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,kBAAM,MAAM,KAAK,UAAU,CAAC,IAAK;AACjC,gBAAI;AACJ,gBAAI,kBAAkB,YAAY;AAChC,oBAAM;YACR,WAAW,kBAAkB,YAAY;AACvC,qBAAO,MAAM,KAAK,CAAC,KAAM,IAAI,CAAC;YAChC,OAAO;AACL,oBAAM,KAAK,UAAU,CAAC;YACxB;AACA,oBAAQ,IAAI,IAAI,CAAC,IAAI;UACvB;QACF;MACF;AAEA,aAAO;IACT;AAGA,aAAgBC,gBAAe,KAAa,OAAe,QAAc;AACvE,YAAM,YAAY,QAAQ;AAC1B,YAAM,OAAO,IAAI,WAAW,SAAS;AACrC,eAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,cAAM,IAAI,IAAI,IAAI,CAAC;AACnB,cAAM,IAAI,IAAI,IAAI,IAAI,CAAC;AACvB,cAAM,IAAI,IAAI,IAAI,IAAI,CAAC;AAEvB,aAAK,CAAC,IAAI,KAAK,MAAM,QAAQ,IAAI,QAAQ,IAAI,QAAQ,CAAC;MACxD;AACA,aAAO;IACT;;;;;;;;;ACjIA,IAAAC,SAAA,eAAAC;AAAA,aAAgBA,cACd,SACA,UACA,OACA,QACA,WACA,SAAe;AAEf,YAAM,YAAY,QAAQ;AAG1B,YAAM,OAAO,IAAI,WAAW,SAAS;AACrC,eAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,aAAK,CAAC,IAAI,KAAK,KAAK,QAAQ,CAAC,KAAK,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,YAAY,IAAI;MAC/E;AAGA,YAAM,SAAS,IAAI,WAAW,SAAS,EAAE,KAAK,CAAC;AAC/C,YAAM,SAAS,IAAI,WAAW,YAAY,CAAC,EAAE,KAAK,CAAC;AACnD,UAAI,YAAY;AAGhB,eAAS,SAAS,GAAS;AACzB,eAAO,OAAO,CAAC,MAAM,GAAG;AACtB,iBAAO,CAAC,IAAI,OAAO,OAAO,CAAC,CAAE;AAC7B,cAAI,OAAO,CAAC;QACd;AACA,eAAO;MACT;AAEA,eAAS,MAAM,GAAW,GAAS;AACjC,cAAM,KAAK,SAAS,CAAC;AACrB,cAAM,KAAK,SAAS,CAAC;AACrB,YAAI,OAAO;AAAI,iBAAO,EAAE,IAAI;AAC5B,eAAO;MACT;AAGA,eAAS,IAAI,GAAG,KAAK,WAAW,KAAK;AACnC,eAAO,CAAC,IAAI;MACd;AAGA,eAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,iBAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,gBAAM,MAAM,IAAI,QAAQ;AACxB,cAAI,CAAC,KAAK,GAAG;AAAG;AAEhB,gBAAM,QAAQ,IAAI,IAAI,QAAQ,IAAI,KAAK,QAAQ,CAAC,KAAK,IAAI;AACzD,gBAAM,OAAO,IAAI,IAAI,OAAO,IAAI,SAAS,IAAI,EAAE,KAAK,IAAI;AAExD,cAAI,UAAU,KAAK,SAAS,GAAG;AAC7B,mBAAO,GAAG,IAAI;AACd,mBAAO,SAAS,IAAI;AACpB;UACF,WAAW,UAAU,KAAK,SAAS,GAAG;AACpC,mBAAO,GAAG,IAAI;UAChB,WAAW,UAAU,KAAK,SAAS,GAAG;AACpC,mBAAO,GAAG,IAAI;UAChB,OAAO;AAEL,mBAAO,GAAG,IAAI,MAAM,OAAO,IAAI;UACjC;QACF;MACF;AAGA,eAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,YAAI,OAAO,CAAC,GAAG;AACb,iBAAO,CAAC,IAAI,SAAS,OAAO,CAAC,CAAE;QACjC;MACF;AAGA,YAAM,UAAU,oBAAI,IAAG;AAKvB,eAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,iBAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,gBAAM,MAAM,IAAI,QAAQ;AACxB,gBAAM,QAAQ,OAAO,GAAG;AACxB,cAAI,CAAC;AAAO;AAEZ,gBAAM,OAAO,KAAK,KAAK,QAAQ,GAAG,KAAK,MAAM,SAAS,GAAG,KAAK,EAAE;AAChE,gBAAM,WAAW,QAAQ,IAAI,KAAK;AAClC,cAAI,UAAU;AACZ,qBAAS,OAAO,KAAK,IAAI,SAAS,MAAM,CAAC;AACzC,qBAAS,OAAO,KAAK,IAAI,SAAS,MAAM,CAAC;AACzC,qBAAS,OAAO,KAAK,IAAI,SAAS,MAAM,CAAC;AACzC,qBAAS,OAAO,KAAK,IAAI,SAAS,MAAM,CAAC;AACzC,qBAAS;AACT,qBAAS,gBAAgB;UAC3B,OAAO;AACL,oBAAQ,IAAI,OAAO;cACjB,MAAM;cACN,MAAM;cACN,MAAM;cACN,MAAM;cACN,OAAO;cACP,cAAc;aACf;UACH;QACF;MACF;AAGA,YAAM,UAA0B,CAAA;AAChC,iBAAW,CAAC,EAAE,IAAI,KAAK,SAAS;AAC9B,YAAI,KAAK,QAAQ;AAAS;AAC1B,gBAAQ,KAAK;UACX,MAAM;YACJ,GAAG,KAAK;YACR,GAAG,KAAK;YACR,GAAG,KAAK,OAAO,KAAK,OAAO;YAC3B,GAAG,KAAK,OAAO,KAAK,OAAO;;UAE7B,YAAY,KAAK;UACjB,WAAW,KAAK,eAAe,KAAK;SACrC;MACH;AAEA,aAAO;IACT;;;;;AC9IA;AAAA;AAAA;AAAA;AAAA;AAgBA,yBAA0C;AAC1C,wBAA6B;AAE7B,IAAM,eAAgC,EAAE,IAAI,UAAU,MAAM,SAAS;AACrE,IAAM,gBAA4C,CAAC,YAAY;AAC/D,IAAM,kBAAsC,EAAE,SAAS,CAAC,GAAG,kBAAkB,KAAK;AAElF,IAAqB,uBAArB,MAAwF;AAAA,EAC7E,KAAK;AAAA,EACL,OAAO;AAAA,EACP,eAAyC;AAAA,EACzC,gBAAgB,CAAC,QAAQ;AAAA,EACzB,eAAe;AAAA;AAAA;AAAA,EAGxB,uBAA2C;AACzC,WAAO,CAAC;AAAA,EACV;AAAA,EAES,WAA0B;AAAA,IACjC,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IAET,aAAa;AAAA,IAEb,MAAM;AAAA,IACN,cAAc;AAAA,IACd,eAAe,CAAC,QAAQ;AAAA,IACxB,sBAAsB;AAAA,IACtB,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,eAAe;AAAA,MACb,WAAW;AAAA,MACX,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEQ,eAAkC;AAAA,EAClC,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ,UAAU;AAAA,EAElB,MAAM,WAAW,KAAkC;AACjD,UAAM,MAAM,IAAI;AAChB,SAAK,YAAa,IAAI,WAAW,KAA4B;AAC7D,SAAK,UAAW,IAAI,SAAS,KAA4B;AAAA,EAC3D;AAAA,EAEA,MAAM,OAAO,OAA4C;AACvD,UAAM,QAAQ,KAAK,IAAI;AAEvB,UAAM,EAAE,MAAM,OAAO,OAAO,IAAI,UAAM,8BAAU,MAAM,IAAI;AAC1D,UAAM,kBAAc,mCAAe,MAAM,OAAO,MAAM;AAEtD,QAAI,CAAC,KAAK,gBAAgB,KAAK,kBAAkB,SAAS,KAAK,mBAAmB,QAAQ;AAExF,WAAK,eAAe;AACpB,WAAK,gBAAgB;AACrB,WAAK,iBAAiB;AACtB,aAAO,EAAE,YAAY,CAAC,GAAG,aAAa,KAAK,IAAI,IAAI,OAAO,SAAS,aAAa;AAAA,IAClF;AAEA,UAAM,cAAU;AAAA,MACd;AAAA,MACA,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AAEA,SAAK,eAAe;AAEpB,UAAM,aAAiC,QAAQ,IAAI,CAAC,OAAO;AAAA,MACzD,OAAO;AAAA,MACP,eAAe;AAAA,MACf,OAAO,KAAK,IAAI,GAAG,EAAE,YAAY,GAAG;AAAA,MACpC,MAAM,EAAE;AAAA,IACV,EAAE;AAEF,WAAO;AAAA,MACL;AAAA,MACA,aAAa,KAAK,IAAI,IAAI;AAAA,MAC1B,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,WAA0B;AAC9B,SAAK,eAAe;AAAA,EACtB;AAAA,EAEA,kBAAkC;AAChC,WAAO;AAAA,MACL,UAAU;AAAA,QACR;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,SAAS;AAAA,UACT,QAAQ;AAAA,YACN;AAAA,cACE,KAAK;AAAA,cACL,OAAO;AAAA,cACP,aAAa;AAAA,cACb,MAAM;AAAA,cACN,KAAK;AAAA,cACL,KAAK;AAAA,cACL,MAAM;AAAA,cACN,SAAS;AAAA,YACX;AAAA,YACA;AAAA,cACE,KAAK;AAAA,cACL,OAAO;AAAA,cACP,aAAa;AAAA,cACb,MAAM;AAAA,cACN,KAAK;AAAA,cACL,KAAK;AAAA,cACL,MAAM;AAAA,cACN,SAAS;AAAA,cACT,WAAW;AAAA,cACX,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,cAAkC;AAChC,WAAO;AAAA,EACT;AAAA,EAEA,kBAAuC;AACrC,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,qBAAuC;AACrC,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,kBAA8C;AAC5C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAA8B;AAClC,WAAO;AAAA,MACL,WAAW;AAAA,MACX,SAAS;AAAA;AAAA,MACT,QAAQ;AAAA,MACR,cAAc,CAAC,MAAM;AAAA,IACvB;AAAA,EACF;AACF;","names":["exports","jpegToRgb","rgbToGrayscale","exports","detectMotion"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/addons/motion-detection/index.ts","../../../src/shared/image-utils.ts","../../../src/addons/motion-detection/frame-diff.ts"],"sourcesContent":["import type {\n IDetectorProvider,\n IDetectionAddon,\n AddonManifest,\n AddonContext,\n FrameInput,\n DetectorOutput,\n ConfigUISchema,\n ClassMapDefinition,\n ProbeResult,\n ModelCatalogEntry,\n DetectionModel,\n LabelDefinition,\n SpatialDetection,\n ModelRequirement,\n} from '@camstack/types'\nimport { jpegToRgb, rgbToGrayscale } from '../../shared/image-utils.js'\nimport { detectMotion } from './frame-diff.js'\n\nconst MOTION_LABEL: LabelDefinition = { id: 'motion', name: 'Motion' }\nconst MOTION_LABELS: readonly LabelDefinition[] = [MOTION_LABEL]\nconst EMPTY_CLASS_MAP: ClassMapDefinition = { mapping: {}, preserveOriginal: true }\n\nexport default class MotionDetectionAddon implements IDetectorProvider, IDetectionAddon {\n readonly id = 'motion-detection'\n readonly slot = 'detector' as const\n readonly inputClasses: readonly string[] | null = null\n readonly outputClasses = ['motion'] as const\n readonly slotPriority = 10 // runs first — feeds other detectors\n\n /** Motion detection has no ML models — returns empty requirements */\n getModelRequirements(): ModelRequirement[] {\n return []\n }\n\n readonly manifest: AddonManifest = {\n id: 'motion-detection',\n name: 'Motion Detection',\n version: '0.1.0',\n\n description: 'Frame-differencing motion detector — no inference engine required',\n\n slot: 'detector',\n inputClasses: undefined,\n outputClasses: ['motion'],\n supportsCustomModels: false,\n mayRequirePython: false,\n passive: true,\n defaultConfig: {\n threshold: 25,\n minArea: 500,\n },\n }\n\n private previousGray: Uint8Array | null = null\n private previousWidth = 0\n private previousHeight = 0\n private threshold = 25\n private minArea = 500\n\n async initialize(ctx: AddonContext): Promise<void> {\n const cfg = ctx.addonConfig\n this.threshold = (cfg['threshold'] as number | undefined) ?? 25\n this.minArea = (cfg['minArea'] as number | undefined) ?? 500\n }\n\n async detect(frame: FrameInput): Promise<DetectorOutput> {\n const start = Date.now()\n\n const { data, width, height } = await jpegToRgb(frame.data)\n const currentGray = rgbToGrayscale(data, width, height)\n\n if (!this.previousGray || this.previousWidth !== width || this.previousHeight !== height) {\n // Store first frame and return empty — no previous to diff against\n this.previousGray = currentGray\n this.previousWidth = width\n this.previousHeight = height\n return { detections: [], inferenceMs: Date.now() - start, modelId: 'frame-diff' }\n }\n\n const regions = detectMotion(\n currentGray,\n this.previousGray,\n width,\n height,\n this.threshold,\n this.minArea,\n )\n\n this.previousGray = currentGray\n\n const detections: SpatialDetection[] = regions.map((r) => ({\n class: 'motion',\n originalClass: 'motion',\n score: Math.min(1, r.intensity / 255),\n bbox: r.bbox,\n }))\n\n return {\n detections,\n inferenceMs: Date.now() - start,\n modelId: 'frame-diff',\n }\n }\n\n async shutdown(): Promise<void> {\n this.previousGray = null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'motion',\n title: 'Motion Detection',\n columns: 2,\n fields: [\n {\n key: 'threshold',\n label: 'Pixel Difference Threshold',\n description: 'Minimum per-pixel intensity change to count as motion (0-255)',\n type: 'slider',\n min: 5,\n max: 100,\n step: 5,\n default: 25,\n },\n {\n key: 'minArea',\n label: 'Minimum Region Area (px)',\n description: 'Minimum number of changed pixels to report a motion region',\n type: 'slider',\n min: 50,\n max: 10000,\n step: 50,\n default: 500,\n showValue: true,\n unit: 'px',\n },\n ],\n },\n ],\n }\n }\n\n getClassMap(): ClassMapDefinition {\n return EMPTY_CLASS_MAP\n }\n\n getModelCatalog(): ModelCatalogEntry[] {\n return []\n }\n\n getAvailableModels(): DetectionModel[] {\n return []\n }\n\n getActiveLabels(): readonly LabelDefinition[] {\n return MOTION_LABELS\n }\n\n async probe(): Promise<ProbeResult> {\n return {\n available: true,\n runtime: 'onnx', // no inference; satisfies the type (any runtime works)\n device: 'cpu',\n capabilities: ['fp32'],\n }\n }\n}\n","import sharp from 'sharp'\nimport type { BoundingBox } from '@camstack/types'\n\n/** Decode JPEG to raw RGB pixels */\nexport async function jpegToRgb(\n jpeg: Buffer,\n): Promise<{ data: Buffer; width: number; height: number }> {\n const { data, info } = await sharp(jpeg)\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true })\n return { data, width: info.width, height: info.height }\n}\n\n/** Crop a region from a JPEG buffer */\nexport async function cropRegion(jpeg: Buffer, roi: BoundingBox): Promise<Buffer> {\n return sharp(jpeg)\n .extract({\n left: Math.round(roi.x),\n top: Math.round(roi.y),\n width: Math.round(roi.w),\n height: Math.round(roi.h),\n })\n .jpeg()\n .toBuffer()\n}\n\n/** Letterbox resize for YOLO: resize preserving aspect ratio, pad to square */\nexport async function letterbox(\n jpeg: Buffer,\n targetSize: number,\n): Promise<{\n data: Float32Array\n scale: number\n padX: number\n padY: number\n originalWidth: number\n originalHeight: number\n}> {\n const meta = await sharp(jpeg).metadata()\n const originalWidth = meta.width ?? 0\n const originalHeight = meta.height ?? 0\n\n const scale = Math.min(targetSize / originalWidth, targetSize / originalHeight)\n const scaledWidth = Math.round(originalWidth * scale)\n const scaledHeight = Math.round(originalHeight * scale)\n\n const padX = Math.floor((targetSize - scaledWidth) / 2)\n const padY = Math.floor((targetSize - scaledHeight) / 2)\n\n const { data } = await sharp(jpeg)\n .resize(scaledWidth, scaledHeight)\n .extend({\n top: padY,\n bottom: targetSize - scaledHeight - padY,\n left: padX,\n right: targetSize - scaledWidth - padX,\n background: { r: 114, g: 114, b: 114 },\n })\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true })\n\n // Convert HWC uint8 to CHW float [0,1]\n const numPixels = targetSize * targetSize\n const float32 = new Float32Array(3 * numPixels)\n for (let i = 0; i < numPixels; i++) {\n const srcBase = i * 3\n float32[0 * numPixels + i] = (data[srcBase]! / 255)\n float32[1 * numPixels + i] = (data[srcBase + 1]! / 255)\n float32[2 * numPixels + i] = (data[srcBase + 2]! / 255)\n }\n\n return { data: float32, scale, padX, padY, originalWidth, originalHeight }\n}\n\n/** Resize and normalize to Float32Array */\nexport async function resizeAndNormalize(\n jpeg: Buffer,\n targetWidth: number,\n targetHeight: number,\n normalization: 'zero-one' | 'imagenet' | 'none',\n layout: 'nchw' | 'nhwc',\n): Promise<Float32Array> {\n const { data } = await sharp(jpeg)\n .resize(targetWidth, targetHeight, { fit: 'fill' })\n .removeAlpha()\n .raw()\n .toBuffer({ resolveWithObject: true })\n\n const numPixels = targetWidth * targetHeight\n const float32 = new Float32Array(3 * numPixels)\n\n // ImageNet mean and std per channel\n const mean = [0.485, 0.456, 0.406]\n const std = [0.229, 0.224, 0.225]\n\n if (layout === 'nchw') {\n for (let i = 0; i < numPixels; i++) {\n const srcBase = i * 3\n for (let c = 0; c < 3; c++) {\n const raw = data[srcBase + c]! / 255\n let val: number\n if (normalization === 'zero-one') {\n val = raw\n } else if (normalization === 'imagenet') {\n val = (raw - mean[c]!) / std[c]!\n } else {\n val = data[srcBase + c]!\n }\n float32[c * numPixels + i] = val\n }\n }\n } else {\n // nhwc\n for (let i = 0; i < numPixels; i++) {\n const srcBase = i * 3\n for (let c = 0; c < 3; c++) {\n const raw = data[srcBase + c]! / 255\n let val: number\n if (normalization === 'zero-one') {\n val = raw\n } else if (normalization === 'imagenet') {\n val = (raw - mean[c]!) / std[c]!\n } else {\n val = data[srcBase + c]!\n }\n float32[i * 3 + c] = val\n }\n }\n }\n\n return float32\n}\n\n/** Convert raw RGB to grayscale Uint8Array */\nexport function rgbToGrayscale(rgb: Buffer, width: number, height: number): Uint8Array {\n const numPixels = width * height\n const gray = new Uint8Array(numPixels)\n for (let i = 0; i < numPixels; i++) {\n const r = rgb[i * 3]!\n const g = rgb[i * 3 + 1]!\n const b = rgb[i * 3 + 2]!\n // BT.601 luma\n gray[i] = Math.round(0.299 * r + 0.587 * g + 0.114 * b)\n }\n return gray\n}\n","import type { BoundingBox } from '@camstack/types'\n\nexport interface MotionRegion {\n readonly bbox: BoundingBox\n readonly pixelCount: number\n readonly intensity: number\n}\n\n/**\n * Detect motion by frame differencing.\n *\n * @param current - Grayscale pixel array for the current frame (Uint8Array, length = width * height)\n * @param previous - Grayscale pixel array for the previous frame\n * @param width - Frame width in pixels\n * @param height - Frame height in pixels\n * @param threshold - Pixel diff threshold 0-255; differences below this are ignored\n * @param minArea - Minimum number of changed pixels for a region to be reported\n */\nexport function detectMotion(\n current: Uint8Array,\n previous: Uint8Array,\n width: number,\n height: number,\n threshold: number,\n minArea: number,\n): MotionRegion[] {\n const numPixels = width * height\n\n // Step 1: Compute binary mask — 1 where abs(current - previous) > threshold\n const mask = new Uint8Array(numPixels)\n for (let i = 0; i < numPixels; i++) {\n mask[i] = Math.abs((current[i] ?? 0) - (previous[i] ?? 0)) > threshold ? 1 : 0\n }\n\n // Step 2: Two-pass connected component labeling\n const labels = new Int32Array(numPixels).fill(0)\n const parent = new Int32Array(numPixels + 1).fill(0)\n let nextLabel = 1\n\n // Union-Find helpers\n function findRoot(x: number): number {\n while (parent[x] !== x) {\n parent[x] = parent[parent[x]!]! // path compression\n x = parent[x]!\n }\n return x\n }\n\n function union(a: number, b: number): number {\n const ra = findRoot(a)\n const rb = findRoot(b)\n if (ra !== rb) parent[rb] = ra\n return ra\n }\n\n // Initialize parent array as identity\n for (let i = 0; i <= numPixels; i++) {\n parent[i] = i\n }\n\n // First pass: assign provisional labels\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x\n if (!mask[idx]) continue\n\n const above = y > 0 ? labels[(y - 1) * width + x] ?? 0 : 0\n const left = x > 0 ? labels[y * width + (x - 1)] ?? 0 : 0\n\n if (above === 0 && left === 0) {\n labels[idx] = nextLabel\n parent[nextLabel] = nextLabel\n nextLabel++\n } else if (above !== 0 && left === 0) {\n labels[idx] = above\n } else if (above === 0 && left !== 0) {\n labels[idx] = left\n } else {\n // Both neighbors — merge\n labels[idx] = union(above, left)\n }\n }\n }\n\n // Second pass: resolve all labels to roots\n for (let i = 0; i < numPixels; i++) {\n if (labels[i]) {\n labels[i] = findRoot(labels[i]!)\n }\n }\n\n // Step 3: Collect bounding boxes and pixel counts per root label\n const bboxMap = new Map<\n number,\n { minX: number; minY: number; maxX: number; maxY: number; count: number; intensitySum: number }\n >()\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x\n const label = labels[idx]\n if (!label) continue\n\n const diff = Math.abs((current[idx] ?? 0) - (previous[idx] ?? 0))\n const existing = bboxMap.get(label)\n if (existing) {\n existing.minX = Math.min(existing.minX, x)\n existing.minY = Math.min(existing.minY, y)\n existing.maxX = Math.max(existing.maxX, x)\n existing.maxY = Math.max(existing.maxY, y)\n existing.count++\n existing.intensitySum += diff\n } else {\n bboxMap.set(label, {\n minX: x,\n minY: y,\n maxX: x,\n maxY: y,\n count: 1,\n intensitySum: diff,\n })\n }\n }\n }\n\n // Step 4: Filter by minimum area and build result\n const regions: MotionRegion[] = []\n for (const [, info] of bboxMap) {\n if (info.count < minArea) continue\n regions.push({\n bbox: {\n x: info.minX,\n y: info.minY,\n w: info.maxX - info.minX + 1,\n h: info.maxY - info.minY + 1,\n },\n pixelCount: info.count,\n intensity: info.intensitySum / info.count,\n })\n }\n\n return regions\n}\n"],"mappings":"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","names":["sharp"]}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "../../chunk-
|
|
2
|
+
detectMotion
|
|
3
|
+
} from "../../chunk-BR2FPGOX.mjs";
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "../../chunk-3IIFBJCD.mjs";
|
|
5
|
+
jpegToRgb,
|
|
6
|
+
rgbToGrayscale
|
|
7
|
+
} from "../../chunk-22BHCDT5.mjs";
|
|
8
|
+
import "../../chunk-BJTO5JO5.mjs";
|
|
10
9
|
|
|
11
10
|
// src/addons/motion-detection/index.ts
|
|
12
|
-
var import_image_utils = __toESM(require_image_utils());
|
|
13
|
-
var import_frame_diff = __toESM(require_frame_diff());
|
|
14
11
|
var MOTION_LABEL = { id: "motion", name: "Motion" };
|
|
15
12
|
var MOTION_LABELS = [MOTION_LABEL];
|
|
16
13
|
var EMPTY_CLASS_MAP = { mapping: {}, preserveOriginal: true };
|
|
@@ -53,15 +50,15 @@ var MotionDetectionAddon = class {
|
|
|
53
50
|
}
|
|
54
51
|
async detect(frame) {
|
|
55
52
|
const start = Date.now();
|
|
56
|
-
const { data, width, height } = await
|
|
57
|
-
const currentGray =
|
|
53
|
+
const { data, width, height } = await jpegToRgb(frame.data);
|
|
54
|
+
const currentGray = rgbToGrayscale(data, width, height);
|
|
58
55
|
if (!this.previousGray || this.previousWidth !== width || this.previousHeight !== height) {
|
|
59
56
|
this.previousGray = currentGray;
|
|
60
57
|
this.previousWidth = width;
|
|
61
58
|
this.previousHeight = height;
|
|
62
59
|
return { detections: [], inferenceMs: Date.now() - start, modelId: "frame-diff" };
|
|
63
60
|
}
|
|
64
|
-
const regions =
|
|
61
|
+
const regions = detectMotion(
|
|
65
62
|
currentGray,
|
|
66
63
|
this.previousGray,
|
|
67
64
|
width,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/addons/motion-detection/index.ts"],"sourcesContent":["import type {\n IDetectorProvider,\n IDetectionAddon,\n AddonManifest,\n AddonContext,\n FrameInput,\n DetectorOutput,\n ConfigUISchema,\n ClassMapDefinition,\n ProbeResult,\n ModelCatalogEntry,\n DetectionModel,\n LabelDefinition,\n SpatialDetection,\n ModelRequirement,\n} from '@camstack/types'\nimport { jpegToRgb, rgbToGrayscale } from '../../shared/image-utils.js'\nimport { detectMotion } from './frame-diff.js'\n\nconst MOTION_LABEL: LabelDefinition = { id: 'motion', name: 'Motion' }\nconst MOTION_LABELS: readonly LabelDefinition[] = [MOTION_LABEL]\nconst EMPTY_CLASS_MAP: ClassMapDefinition = { mapping: {}, preserveOriginal: true }\n\nexport default class MotionDetectionAddon implements IDetectorProvider, IDetectionAddon {\n readonly id = 'motion-detection'\n readonly slot = 'detector' as const\n readonly inputClasses: readonly string[] | null = null\n readonly outputClasses = ['motion'] as const\n readonly slotPriority = 10 // runs first — feeds other detectors\n\n /** Motion detection has no ML models — returns empty requirements */\n getModelRequirements(): ModelRequirement[] {\n return []\n }\n\n readonly manifest: AddonManifest = {\n id: 'motion-detection',\n name: 'Motion Detection',\n version: '0.1.0',\n\n description: 'Frame-differencing motion detector — no inference engine required',\n\n slot: 'detector',\n inputClasses: undefined,\n outputClasses: ['motion'],\n supportsCustomModels: false,\n mayRequirePython: false,\n passive: true,\n defaultConfig: {\n threshold: 25,\n minArea: 500,\n },\n }\n\n private previousGray: Uint8Array | null = null\n private previousWidth = 0\n private previousHeight = 0\n private threshold = 25\n private minArea = 500\n\n async initialize(ctx: AddonContext): Promise<void> {\n const cfg = ctx.addonConfig\n this.threshold = (cfg['threshold'] as number | undefined) ?? 25\n this.minArea = (cfg['minArea'] as number | undefined) ?? 500\n }\n\n async detect(frame: FrameInput): Promise<DetectorOutput> {\n const start = Date.now()\n\n const { data, width, height } = await jpegToRgb(frame.data)\n const currentGray = rgbToGrayscale(data, width, height)\n\n if (!this.previousGray || this.previousWidth !== width || this.previousHeight !== height) {\n // Store first frame and return empty — no previous to diff against\n this.previousGray = currentGray\n this.previousWidth = width\n this.previousHeight = height\n return { detections: [], inferenceMs: Date.now() - start, modelId: 'frame-diff' }\n }\n\n const regions = detectMotion(\n currentGray,\n this.previousGray,\n width,\n height,\n this.threshold,\n this.minArea,\n )\n\n this.previousGray = currentGray\n\n const detections: SpatialDetection[] = regions.map((r) => ({\n class: 'motion',\n originalClass: 'motion',\n score: Math.min(1, r.intensity / 255),\n bbox: r.bbox,\n }))\n\n return {\n detections,\n inferenceMs: Date.now() - start,\n modelId: 'frame-diff',\n }\n }\n\n async shutdown(): Promise<void> {\n this.previousGray = null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'motion',\n title: 'Motion Detection',\n columns: 2,\n fields: [\n {\n key: 'threshold',\n label: 'Pixel Difference Threshold',\n description: 'Minimum per-pixel intensity change to count as motion (0-255)',\n type: 'slider',\n min: 5,\n max: 100,\n step: 5,\n default: 25,\n },\n {\n key: 'minArea',\n label: 'Minimum Region Area (px)',\n description: 'Minimum number of changed pixels to report a motion region',\n type: 'slider',\n min: 50,\n max: 10000,\n step: 50,\n default: 500,\n showValue: true,\n unit: 'px',\n },\n ],\n },\n ],\n }\n }\n\n getClassMap(): ClassMapDefinition {\n return EMPTY_CLASS_MAP\n }\n\n getModelCatalog(): ModelCatalogEntry[] {\n return []\n }\n\n getAvailableModels(): DetectionModel[] {\n return []\n }\n\n getActiveLabels(): readonly LabelDefinition[] {\n return MOTION_LABELS\n }\n\n async probe(): Promise<ProbeResult> {\n return {\n available: true,\n runtime: 'onnx', // no inference; satisfies the type (any runtime works)\n device: 'cpu',\n capabilities: ['fp32'],\n }\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/addons/motion-detection/index.ts"],"sourcesContent":["import type {\n IDetectorProvider,\n IDetectionAddon,\n AddonManifest,\n AddonContext,\n FrameInput,\n DetectorOutput,\n ConfigUISchema,\n ClassMapDefinition,\n ProbeResult,\n ModelCatalogEntry,\n DetectionModel,\n LabelDefinition,\n SpatialDetection,\n ModelRequirement,\n} from '@camstack/types'\nimport { jpegToRgb, rgbToGrayscale } from '../../shared/image-utils.js'\nimport { detectMotion } from './frame-diff.js'\n\nconst MOTION_LABEL: LabelDefinition = { id: 'motion', name: 'Motion' }\nconst MOTION_LABELS: readonly LabelDefinition[] = [MOTION_LABEL]\nconst EMPTY_CLASS_MAP: ClassMapDefinition = { mapping: {}, preserveOriginal: true }\n\nexport default class MotionDetectionAddon implements IDetectorProvider, IDetectionAddon {\n readonly id = 'motion-detection'\n readonly slot = 'detector' as const\n readonly inputClasses: readonly string[] | null = null\n readonly outputClasses = ['motion'] as const\n readonly slotPriority = 10 // runs first — feeds other detectors\n\n /** Motion detection has no ML models — returns empty requirements */\n getModelRequirements(): ModelRequirement[] {\n return []\n }\n\n readonly manifest: AddonManifest = {\n id: 'motion-detection',\n name: 'Motion Detection',\n version: '0.1.0',\n\n description: 'Frame-differencing motion detector — no inference engine required',\n\n slot: 'detector',\n inputClasses: undefined,\n outputClasses: ['motion'],\n supportsCustomModels: false,\n mayRequirePython: false,\n passive: true,\n defaultConfig: {\n threshold: 25,\n minArea: 500,\n },\n }\n\n private previousGray: Uint8Array | null = null\n private previousWidth = 0\n private previousHeight = 0\n private threshold = 25\n private minArea = 500\n\n async initialize(ctx: AddonContext): Promise<void> {\n const cfg = ctx.addonConfig\n this.threshold = (cfg['threshold'] as number | undefined) ?? 25\n this.minArea = (cfg['minArea'] as number | undefined) ?? 500\n }\n\n async detect(frame: FrameInput): Promise<DetectorOutput> {\n const start = Date.now()\n\n const { data, width, height } = await jpegToRgb(frame.data)\n const currentGray = rgbToGrayscale(data, width, height)\n\n if (!this.previousGray || this.previousWidth !== width || this.previousHeight !== height) {\n // Store first frame and return empty — no previous to diff against\n this.previousGray = currentGray\n this.previousWidth = width\n this.previousHeight = height\n return { detections: [], inferenceMs: Date.now() - start, modelId: 'frame-diff' }\n }\n\n const regions = detectMotion(\n currentGray,\n this.previousGray,\n width,\n height,\n this.threshold,\n this.minArea,\n )\n\n this.previousGray = currentGray\n\n const detections: SpatialDetection[] = regions.map((r) => ({\n class: 'motion',\n originalClass: 'motion',\n score: Math.min(1, r.intensity / 255),\n bbox: r.bbox,\n }))\n\n return {\n detections,\n inferenceMs: Date.now() - start,\n modelId: 'frame-diff',\n }\n }\n\n async shutdown(): Promise<void> {\n this.previousGray = null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'motion',\n title: 'Motion Detection',\n columns: 2,\n fields: [\n {\n key: 'threshold',\n label: 'Pixel Difference Threshold',\n description: 'Minimum per-pixel intensity change to count as motion (0-255)',\n type: 'slider',\n min: 5,\n max: 100,\n step: 5,\n default: 25,\n },\n {\n key: 'minArea',\n label: 'Minimum Region Area (px)',\n description: 'Minimum number of changed pixels to report a motion region',\n type: 'slider',\n min: 50,\n max: 10000,\n step: 50,\n default: 500,\n showValue: true,\n unit: 'px',\n },\n ],\n },\n ],\n }\n }\n\n getClassMap(): ClassMapDefinition {\n return EMPTY_CLASS_MAP\n }\n\n getModelCatalog(): ModelCatalogEntry[] {\n return []\n }\n\n getAvailableModels(): DetectionModel[] {\n return []\n }\n\n getActiveLabels(): readonly LabelDefinition[] {\n return MOTION_LABELS\n }\n\n async probe(): Promise<ProbeResult> {\n return {\n available: true,\n runtime: 'onnx', // no inference; satisfies the type (any runtime works)\n device: 'cpu',\n capabilities: ['fp32'],\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { IDetectorProvider, IDetectionAddon, AddonManifest, ModelRequirement, ResolvedInferenceConfig, AddonContext, FrameInput, DetectorOutput, ConfigUISchema, ClassMapDefinition, ModelCatalogEntry, DetectionModel, LabelDefinition, ProbeResult } from '@camstack/types';
|
|
2
|
+
|
|
3
|
+
declare class ObjectDetectionAddon implements IDetectorProvider, IDetectionAddon {
|
|
4
|
+
readonly id = "object-detection";
|
|
5
|
+
readonly slot: "detector";
|
|
6
|
+
readonly inputClasses: readonly string[] | null;
|
|
7
|
+
readonly outputClasses: readonly ["person", "vehicle", "animal"];
|
|
8
|
+
readonly slotPriority = 0;
|
|
9
|
+
readonly manifest: AddonManifest;
|
|
10
|
+
private engine;
|
|
11
|
+
private modelEntry;
|
|
12
|
+
private confidence;
|
|
13
|
+
private iouThreshold;
|
|
14
|
+
private classMapMode;
|
|
15
|
+
private resolvedConfig;
|
|
16
|
+
private ctx;
|
|
17
|
+
getModelRequirements(): ModelRequirement[];
|
|
18
|
+
configure(config: ResolvedInferenceConfig): void;
|
|
19
|
+
initialize(ctx: AddonContext): Promise<void>;
|
|
20
|
+
detect(frame: FrameInput): Promise<DetectorOutput>;
|
|
21
|
+
private ensureEngine;
|
|
22
|
+
shutdown(): Promise<void>;
|
|
23
|
+
getConfigSchema(): ConfigUISchema;
|
|
24
|
+
getClassMap(): ClassMapDefinition;
|
|
25
|
+
getModelCatalog(): ModelCatalogEntry[];
|
|
26
|
+
getAvailableModels(): DetectionModel[];
|
|
27
|
+
getActiveLabels(): readonly LabelDefinition[];
|
|
28
|
+
probe(): Promise<ProbeResult>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { ObjectDetectionAddon as default };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { IDetectorProvider, IDetectionAddon, AddonManifest, ModelRequirement, ResolvedInferenceConfig, AddonContext, FrameInput, DetectorOutput, ConfigUISchema, ClassMapDefinition, ModelCatalogEntry, DetectionModel, LabelDefinition, ProbeResult } from '@camstack/types';
|
|
2
|
+
|
|
3
|
+
declare class ObjectDetectionAddon implements IDetectorProvider, IDetectionAddon {
|
|
4
|
+
readonly id = "object-detection";
|
|
5
|
+
readonly slot: "detector";
|
|
6
|
+
readonly inputClasses: readonly string[] | null;
|
|
7
|
+
readonly outputClasses: readonly ["person", "vehicle", "animal"];
|
|
8
|
+
readonly slotPriority = 0;
|
|
9
|
+
readonly manifest: AddonManifest;
|
|
10
|
+
private engine;
|
|
11
|
+
private modelEntry;
|
|
12
|
+
private confidence;
|
|
13
|
+
private iouThreshold;
|
|
14
|
+
private classMapMode;
|
|
15
|
+
private resolvedConfig;
|
|
16
|
+
private ctx;
|
|
17
|
+
getModelRequirements(): ModelRequirement[];
|
|
18
|
+
configure(config: ResolvedInferenceConfig): void;
|
|
19
|
+
initialize(ctx: AddonContext): Promise<void>;
|
|
20
|
+
detect(frame: FrameInput): Promise<DetectorOutput>;
|
|
21
|
+
private ensureEngine;
|
|
22
|
+
shutdown(): Promise<void>;
|
|
23
|
+
getConfigSchema(): ConfigUISchema;
|
|
24
|
+
getClassMap(): ClassMapDefinition;
|
|
25
|
+
getModelCatalog(): ModelCatalogEntry[];
|
|
26
|
+
getAvailableModels(): DetectionModel[];
|
|
27
|
+
getActiveLabels(): readonly LabelDefinition[];
|
|
28
|
+
probe(): Promise<ProbeResult>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { ObjectDetectionAddon as default };
|