@camstack/addon-vision 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.
Files changed (109) hide show
  1. package/dist/addons/animal-classifier/index.d.mts +25 -0
  2. package/dist/addons/animal-classifier/index.d.ts +25 -0
  3. package/dist/addons/animal-classifier/index.js +652 -0
  4. package/dist/addons/animal-classifier/index.js.map +1 -0
  5. package/dist/addons/animal-classifier/index.mjs +10 -0
  6. package/dist/addons/animal-classifier/index.mjs.map +1 -0
  7. package/dist/addons/audio-classification/index.d.mts +31 -0
  8. package/dist/addons/audio-classification/index.d.ts +31 -0
  9. package/dist/addons/audio-classification/index.js +572 -0
  10. package/dist/addons/audio-classification/index.js.map +1 -0
  11. package/dist/addons/audio-classification/index.mjs +8 -0
  12. package/dist/addons/audio-classification/index.mjs.map +1 -0
  13. package/dist/addons/bird-global-classifier/index.d.mts +26 -0
  14. package/dist/addons/bird-global-classifier/index.d.ts +26 -0
  15. package/dist/addons/bird-global-classifier/index.js +658 -0
  16. package/dist/addons/bird-global-classifier/index.js.map +1 -0
  17. package/dist/addons/bird-global-classifier/index.mjs +10 -0
  18. package/dist/addons/bird-global-classifier/index.mjs.map +1 -0
  19. package/dist/addons/bird-nabirds-classifier/index.d.mts +28 -0
  20. package/dist/addons/bird-nabirds-classifier/index.d.ts +28 -0
  21. package/dist/addons/bird-nabirds-classifier/index.js +700 -0
  22. package/dist/addons/bird-nabirds-classifier/index.js.map +1 -0
  23. package/dist/addons/bird-nabirds-classifier/index.mjs +10 -0
  24. package/dist/addons/bird-nabirds-classifier/index.mjs.map +1 -0
  25. package/dist/addons/camera-native-detection/index.d.mts +32 -0
  26. package/dist/addons/camera-native-detection/index.d.ts +32 -0
  27. package/dist/addons/camera-native-detection/index.js +99 -0
  28. package/dist/addons/camera-native-detection/index.js.map +1 -0
  29. package/dist/addons/camera-native-detection/index.mjs +7 -0
  30. package/dist/addons/camera-native-detection/index.mjs.map +1 -0
  31. package/dist/addons/face-detection/index.d.mts +24 -0
  32. package/dist/addons/face-detection/index.d.ts +24 -0
  33. package/dist/addons/face-detection/index.js +720 -0
  34. package/dist/addons/face-detection/index.js.map +1 -0
  35. package/dist/addons/face-detection/index.mjs +10 -0
  36. package/dist/addons/face-detection/index.mjs.map +1 -0
  37. package/dist/addons/face-recognition/index.d.mts +24 -0
  38. package/dist/addons/face-recognition/index.d.ts +24 -0
  39. package/dist/addons/face-recognition/index.js +603 -0
  40. package/dist/addons/face-recognition/index.js.map +1 -0
  41. package/dist/addons/face-recognition/index.mjs +9 -0
  42. package/dist/addons/face-recognition/index.mjs.map +1 -0
  43. package/dist/addons/motion-detection/index.d.mts +26 -0
  44. package/dist/addons/motion-detection/index.d.ts +26 -0
  45. package/dist/addons/motion-detection/index.js +273 -0
  46. package/dist/addons/motion-detection/index.js.map +1 -0
  47. package/dist/addons/motion-detection/index.mjs +8 -0
  48. package/dist/addons/motion-detection/index.mjs.map +1 -0
  49. package/dist/addons/object-detection/index.d.mts +26 -0
  50. package/dist/addons/object-detection/index.d.ts +26 -0
  51. package/dist/addons/object-detection/index.js +1214 -0
  52. package/dist/addons/object-detection/index.js.map +1 -0
  53. package/dist/addons/object-detection/index.mjs +10 -0
  54. package/dist/addons/object-detection/index.mjs.map +1 -0
  55. package/dist/addons/plate-detection/index.d.mts +25 -0
  56. package/dist/addons/plate-detection/index.d.ts +25 -0
  57. package/dist/addons/plate-detection/index.js +646 -0
  58. package/dist/addons/plate-detection/index.js.map +1 -0
  59. package/dist/addons/plate-detection/index.mjs +10 -0
  60. package/dist/addons/plate-detection/index.mjs.map +1 -0
  61. package/dist/addons/plate-recognition/index.d.mts +25 -0
  62. package/dist/addons/plate-recognition/index.d.ts +25 -0
  63. package/dist/addons/plate-recognition/index.js +648 -0
  64. package/dist/addons/plate-recognition/index.js.map +1 -0
  65. package/dist/addons/plate-recognition/index.mjs +9 -0
  66. package/dist/addons/plate-recognition/index.mjs.map +1 -0
  67. package/dist/chunk-3MQFUDRU.mjs +260 -0
  68. package/dist/chunk-3MQFUDRU.mjs.map +1 -0
  69. package/dist/chunk-5AIQSN32.mjs +227 -0
  70. package/dist/chunk-5AIQSN32.mjs.map +1 -0
  71. package/dist/chunk-5JJZGKL7.mjs +186 -0
  72. package/dist/chunk-5JJZGKL7.mjs.map +1 -0
  73. package/dist/chunk-6OR5TE7A.mjs +101 -0
  74. package/dist/chunk-6OR5TE7A.mjs.map +1 -0
  75. package/dist/chunk-AYBFB7ID.mjs +763 -0
  76. package/dist/chunk-AYBFB7ID.mjs.map +1 -0
  77. package/dist/chunk-B3R66MPF.mjs +219 -0
  78. package/dist/chunk-B3R66MPF.mjs.map +1 -0
  79. package/dist/chunk-DTOAB2CE.mjs +79 -0
  80. package/dist/chunk-DTOAB2CE.mjs.map +1 -0
  81. package/dist/chunk-ISOIDU4U.mjs +54 -0
  82. package/dist/chunk-ISOIDU4U.mjs.map +1 -0
  83. package/dist/chunk-J4WRYHHY.mjs +212 -0
  84. package/dist/chunk-J4WRYHHY.mjs.map +1 -0
  85. package/dist/chunk-KUO2BVFY.mjs +90 -0
  86. package/dist/chunk-KUO2BVFY.mjs.map +1 -0
  87. package/dist/chunk-LPI42WL6.mjs +324 -0
  88. package/dist/chunk-LPI42WL6.mjs.map +1 -0
  89. package/dist/chunk-MEVASN3P.mjs +305 -0
  90. package/dist/chunk-MEVASN3P.mjs.map +1 -0
  91. package/dist/chunk-PDSHDDPV.mjs +255 -0
  92. package/dist/chunk-PDSHDDPV.mjs.map +1 -0
  93. package/dist/chunk-Q3SQOYG6.mjs +218 -0
  94. package/dist/chunk-Q3SQOYG6.mjs.map +1 -0
  95. package/dist/chunk-QIMDG34B.mjs +229 -0
  96. package/dist/chunk-QIMDG34B.mjs.map +1 -0
  97. package/dist/index.d.mts +171 -0
  98. package/dist/index.d.ts +171 -0
  99. package/dist/index.js +3463 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/index.mjs +111 -0
  102. package/dist/index.mjs.map +1 -0
  103. package/package.json +49 -0
  104. package/python/__pycache__/coreml_inference.cpython-313.pyc +0 -0
  105. package/python/__pycache__/openvino_inference.cpython-313.pyc +0 -0
  106. package/python/__pycache__/pytorch_inference.cpython-313.pyc +0 -0
  107. package/python/coreml_inference.py +319 -0
  108. package/python/openvino_inference.py +247 -0
  109. package/python/pytorch_inference.py +255 -0
@@ -0,0 +1,1214 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/addons/object-detection/index.ts
31
+ var object_detection_exports = {};
32
+ __export(object_detection_exports, {
33
+ default: () => ObjectDetectionAddon
34
+ });
35
+ module.exports = __toCommonJS(object_detection_exports);
36
+
37
+ // src/catalogs/object-detection-models.ts
38
+ var import_types = require("@camstack/types");
39
+ var HF_REPO = "camstack/camstack-models";
40
+ var OBJECT_DETECTION_MODELS = [
41
+ {
42
+ id: "yolov8n",
43
+ name: "YOLOv8 Nano",
44
+ description: "YOLOv8 Nano \u2014 fastest, smallest object detection model",
45
+ inputSize: { width: 640, height: 640 },
46
+ labels: import_types.COCO_80_LABELS,
47
+ formats: {
48
+ onnx: {
49
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8n.onnx"),
50
+ sizeMB: 12
51
+ },
52
+ coreml: {
53
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8n.mlpackage"),
54
+ sizeMB: 6
55
+ },
56
+ openvino: {
57
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8n.xml"),
58
+ sizeMB: 7
59
+ },
60
+ tflite: {
61
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/tflite/camstack-yolov8n_float32.tflite"),
62
+ sizeMB: 12
63
+ }
64
+ }
65
+ },
66
+ {
67
+ id: "yolov8s",
68
+ name: "YOLOv8 Small",
69
+ description: "YOLOv8 Small \u2014 balanced speed and accuracy",
70
+ inputSize: { width: 640, height: 640 },
71
+ labels: import_types.COCO_80_LABELS,
72
+ formats: {
73
+ onnx: {
74
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8s.onnx"),
75
+ sizeMB: 43
76
+ },
77
+ coreml: {
78
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8s.mlpackage"),
79
+ sizeMB: 21
80
+ },
81
+ openvino: {
82
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8s.xml"),
83
+ sizeMB: 22
84
+ },
85
+ tflite: {
86
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/tflite/camstack-yolov8s_float32.tflite"),
87
+ sizeMB: 43
88
+ }
89
+ }
90
+ },
91
+ {
92
+ id: "yolov8m",
93
+ name: "YOLOv8 Medium",
94
+ description: "YOLOv8 Medium \u2014 higher accuracy, moderate size",
95
+ inputSize: { width: 640, height: 640 },
96
+ labels: import_types.COCO_80_LABELS,
97
+ formats: {
98
+ onnx: {
99
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8m.onnx"),
100
+ sizeMB: 99
101
+ },
102
+ coreml: {
103
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8m.mlpackage"),
104
+ sizeMB: 49
105
+ },
106
+ openvino: {
107
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8m.xml"),
108
+ sizeMB: 50
109
+ },
110
+ tflite: {
111
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/tflite/camstack-yolov8m_float32.tflite"),
112
+ sizeMB: 99
113
+ }
114
+ }
115
+ },
116
+ {
117
+ id: "yolov9t",
118
+ name: "YOLOv9 Tiny",
119
+ description: "YOLOv9 Tiny \u2014 ultra-lightweight next-gen detector",
120
+ inputSize: { width: 640, height: 640 },
121
+ labels: import_types.COCO_80_LABELS,
122
+ formats: {
123
+ onnx: {
124
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/onnx/camstack-yolov9t.onnx"),
125
+ sizeMB: 8
126
+ },
127
+ coreml: {
128
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/coreml/camstack-yolov9t.mlpackage"),
129
+ sizeMB: 4
130
+ },
131
+ openvino: {
132
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/openvino/camstack-yolov9t.xml"),
133
+ sizeMB: 6
134
+ },
135
+ tflite: {
136
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/tflite/camstack-yolov9t_float32.tflite"),
137
+ sizeMB: 8
138
+ }
139
+ }
140
+ },
141
+ {
142
+ id: "yolov9s",
143
+ name: "YOLOv9 Small",
144
+ description: "YOLOv9 Small \u2014 improved efficiency over YOLOv8s",
145
+ inputSize: { width: 640, height: 640 },
146
+ labels: import_types.COCO_80_LABELS,
147
+ formats: {
148
+ onnx: {
149
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/onnx/camstack-yolov9s.onnx"),
150
+ sizeMB: 28
151
+ },
152
+ coreml: {
153
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/coreml/camstack-yolov9s.mlpackage"),
154
+ sizeMB: 14
155
+ },
156
+ openvino: {
157
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/openvino/camstack-yolov9s.xml"),
158
+ sizeMB: 16
159
+ },
160
+ tflite: {
161
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/tflite/camstack-yolov9s_float32.tflite"),
162
+ sizeMB: 28
163
+ }
164
+ }
165
+ },
166
+ {
167
+ id: "yolov9c",
168
+ name: "YOLOv9 C",
169
+ description: "YOLOv9 C \u2014 high-accuracy compact model",
170
+ inputSize: { width: 640, height: 640 },
171
+ labels: import_types.COCO_80_LABELS,
172
+ formats: {
173
+ onnx: {
174
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/onnx/camstack-yolov9c.onnx"),
175
+ sizeMB: 97
176
+ },
177
+ coreml: {
178
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/coreml/camstack-yolov9c.mlpackage"),
179
+ sizeMB: 48
180
+ },
181
+ openvino: {
182
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/openvino/camstack-yolov9c.xml"),
183
+ sizeMB: 49
184
+ },
185
+ tflite: {
186
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/tflite/camstack-yolov9c_float32.tflite"),
187
+ sizeMB: 97
188
+ }
189
+ }
190
+ },
191
+ // YOLO11 — no CoreML (coremltools incompatible)
192
+ {
193
+ id: "yolo11n",
194
+ name: "YOLO11 Nano",
195
+ description: "YOLO11 Nano \u2014 fastest, smallest YOLO11 detection model",
196
+ inputSize: { width: 640, height: 640 },
197
+ labels: import_types.COCO_80_LABELS,
198
+ formats: {
199
+ onnx: {
200
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11n.onnx"),
201
+ sizeMB: 10
202
+ },
203
+ openvino: {
204
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11n.xml"),
205
+ sizeMB: 5.4
206
+ },
207
+ tflite: {
208
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11n_float32.tflite"),
209
+ sizeMB: 10
210
+ }
211
+ }
212
+ },
213
+ {
214
+ id: "yolo11s",
215
+ name: "YOLO11 Small",
216
+ description: "YOLO11 Small \u2014 balanced speed and accuracy",
217
+ inputSize: { width: 640, height: 640 },
218
+ labels: import_types.COCO_80_LABELS,
219
+ formats: {
220
+ onnx: {
221
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11s.onnx"),
222
+ sizeMB: 36
223
+ },
224
+ openvino: {
225
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11s.xml"),
226
+ sizeMB: 18
227
+ },
228
+ tflite: {
229
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11s_float32.tflite"),
230
+ sizeMB: 36
231
+ }
232
+ }
233
+ },
234
+ {
235
+ id: "yolo11m",
236
+ name: "YOLO11 Medium",
237
+ description: "YOLO11 Medium \u2014 higher accuracy, moderate size",
238
+ inputSize: { width: 640, height: 640 },
239
+ labels: import_types.COCO_80_LABELS,
240
+ formats: {
241
+ onnx: {
242
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11m.onnx"),
243
+ sizeMB: 77
244
+ },
245
+ openvino: {
246
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11m.xml"),
247
+ sizeMB: 39
248
+ },
249
+ tflite: {
250
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11m_float32.tflite"),
251
+ sizeMB: 77
252
+ }
253
+ }
254
+ },
255
+ {
256
+ id: "yolo11l",
257
+ name: "YOLO11 Large",
258
+ description: "YOLO11 Large \u2014 high-accuracy large model",
259
+ inputSize: { width: 640, height: 640 },
260
+ labels: import_types.COCO_80_LABELS,
261
+ formats: {
262
+ onnx: {
263
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11l.onnx"),
264
+ sizeMB: 97
265
+ },
266
+ openvino: {
267
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11l.xml"),
268
+ sizeMB: 49
269
+ },
270
+ tflite: {
271
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11l_float32.tflite"),
272
+ sizeMB: 97
273
+ }
274
+ }
275
+ },
276
+ {
277
+ id: "yolo11x",
278
+ name: "YOLO11 Extra-Large",
279
+ description: "YOLO11 Extra-Large \u2014 maximum accuracy",
280
+ inputSize: { width: 640, height: 640 },
281
+ labels: import_types.COCO_80_LABELS,
282
+ formats: {
283
+ onnx: {
284
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11x.onnx"),
285
+ sizeMB: 218
286
+ },
287
+ openvino: {
288
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11x.xml"),
289
+ sizeMB: 109
290
+ },
291
+ tflite: {
292
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11x_float32.tflite"),
293
+ sizeMB: 218
294
+ }
295
+ }
296
+ }
297
+ ];
298
+
299
+ // src/catalogs/segmentation-models.ts
300
+ var import_types2 = require("@camstack/types");
301
+ var HF_REPO2 = "camstack/camstack-models";
302
+ var SEGMENTATION_MODELS = [
303
+ // YOLO11-seg — no CoreML (coremltools incompatible)
304
+ {
305
+ id: "yolo11n-seg",
306
+ name: "YOLO11 Nano Segmentation",
307
+ description: "YOLO11 Nano \u2014 fastest, smallest YOLO11 instance segmentation model",
308
+ inputSize: { width: 640, height: 640 },
309
+ labels: import_types2.COCO_80_LABELS,
310
+ formats: {
311
+ onnx: {
312
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolo11-seg/onnx/camstack-yolo11n-seg.onnx"),
313
+ sizeMB: 11
314
+ },
315
+ openvino: {
316
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolo11-seg/openvino/camstack-yolo11n-seg.xml"),
317
+ sizeMB: 6
318
+ }
319
+ }
320
+ },
321
+ {
322
+ id: "yolo11s-seg",
323
+ name: "YOLO11 Small Segmentation",
324
+ description: "YOLO11 Small \u2014 balanced speed and accuracy for instance segmentation",
325
+ inputSize: { width: 640, height: 640 },
326
+ labels: import_types2.COCO_80_LABELS,
327
+ formats: {
328
+ onnx: {
329
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolo11-seg/onnx/camstack-yolo11s-seg.onnx"),
330
+ sizeMB: 39
331
+ },
332
+ openvino: {
333
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolo11-seg/openvino/camstack-yolo11s-seg.xml"),
334
+ sizeMB: 20
335
+ }
336
+ }
337
+ },
338
+ {
339
+ id: "yolo11m-seg",
340
+ name: "YOLO11 Medium Segmentation",
341
+ description: "YOLO11 Medium \u2014 higher accuracy instance segmentation",
342
+ inputSize: { width: 640, height: 640 },
343
+ labels: import_types2.COCO_80_LABELS,
344
+ formats: {
345
+ onnx: {
346
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolo11-seg/onnx/camstack-yolo11m-seg.onnx"),
347
+ sizeMB: 86
348
+ },
349
+ openvino: {
350
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolo11-seg/openvino/camstack-yolo11m-seg.xml"),
351
+ sizeMB: 43
352
+ }
353
+ }
354
+ },
355
+ // YOLOv8-seg — CoreML available
356
+ {
357
+ id: "yolov8n-seg",
358
+ name: "YOLOv8 Nano Segmentation",
359
+ description: "YOLOv8 Nano \u2014 fastest, smallest YOLOv8 instance segmentation model",
360
+ inputSize: { width: 640, height: 640 },
361
+ labels: import_types2.COCO_80_LABELS,
362
+ formats: {
363
+ onnx: {
364
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolov8-seg/onnx/camstack-yolov8n-seg.onnx"),
365
+ sizeMB: 13
366
+ },
367
+ coreml: {
368
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolov8-seg/coreml/camstack-yolov8n-seg.mlpackage"),
369
+ sizeMB: 7
370
+ },
371
+ openvino: {
372
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolov8-seg/openvino/camstack-yolov8n-seg.xml"),
373
+ sizeMB: 7
374
+ }
375
+ }
376
+ },
377
+ {
378
+ id: "yolov8s-seg",
379
+ name: "YOLOv8 Small Segmentation",
380
+ description: "YOLOv8 Small \u2014 balanced speed and accuracy for instance segmentation",
381
+ inputSize: { width: 640, height: 640 },
382
+ labels: import_types2.COCO_80_LABELS,
383
+ formats: {
384
+ onnx: {
385
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolov8-seg/onnx/camstack-yolov8s-seg.onnx"),
386
+ sizeMB: 45
387
+ },
388
+ coreml: {
389
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolov8-seg/coreml/camstack-yolov8s-seg.mlpackage"),
390
+ sizeMB: 23
391
+ },
392
+ openvino: {
393
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolov8-seg/openvino/camstack-yolov8s-seg.xml"),
394
+ sizeMB: 23
395
+ }
396
+ }
397
+ },
398
+ {
399
+ id: "yolov8m-seg",
400
+ name: "YOLOv8 Medium Segmentation",
401
+ description: "YOLOv8 Medium \u2014 higher accuracy instance segmentation",
402
+ inputSize: { width: 640, height: 640 },
403
+ labels: import_types2.COCO_80_LABELS,
404
+ formats: {
405
+ onnx: {
406
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolov8-seg/onnx/camstack-yolov8m-seg.onnx"),
407
+ sizeMB: 104
408
+ },
409
+ coreml: {
410
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolov8-seg/coreml/camstack-yolov8m-seg.mlpackage"),
411
+ sizeMB: 52
412
+ },
413
+ openvino: {
414
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "segmentation/yolov8-seg/openvino/camstack-yolov8m-seg.xml"),
415
+ sizeMB: 53
416
+ }
417
+ }
418
+ }
419
+ ];
420
+
421
+ // src/addons/object-detection/index.ts
422
+ var import_types3 = require("@camstack/types");
423
+
424
+ // src/shared/image-utils.ts
425
+ var import_sharp = __toESM(require("sharp"));
426
+ async function letterbox(jpeg, targetSize) {
427
+ const meta = await (0, import_sharp.default)(jpeg).metadata();
428
+ const originalWidth = meta.width ?? 0;
429
+ const originalHeight = meta.height ?? 0;
430
+ const scale = Math.min(targetSize / originalWidth, targetSize / originalHeight);
431
+ const scaledWidth = Math.round(originalWidth * scale);
432
+ const scaledHeight = Math.round(originalHeight * scale);
433
+ const padX = Math.floor((targetSize - scaledWidth) / 2);
434
+ const padY = Math.floor((targetSize - scaledHeight) / 2);
435
+ const { data } = await (0, import_sharp.default)(jpeg).resize(scaledWidth, scaledHeight).extend({
436
+ top: padY,
437
+ bottom: targetSize - scaledHeight - padY,
438
+ left: padX,
439
+ right: targetSize - scaledWidth - padX,
440
+ background: { r: 114, g: 114, b: 114 }
441
+ }).removeAlpha().raw().toBuffer({ resolveWithObject: true });
442
+ const numPixels = targetSize * targetSize;
443
+ const float32 = new Float32Array(3 * numPixels);
444
+ for (let i = 0; i < numPixels; i++) {
445
+ const srcBase = i * 3;
446
+ float32[0 * numPixels + i] = data[srcBase] / 255;
447
+ float32[1 * numPixels + i] = data[srcBase + 1] / 255;
448
+ float32[2 * numPixels + i] = data[srcBase + 2] / 255;
449
+ }
450
+ return { data: float32, scale, padX, padY, originalWidth, originalHeight };
451
+ }
452
+
453
+ // src/shared/postprocess/yolo.ts
454
+ function iou(a, b) {
455
+ const ax1 = a.x;
456
+ const ay1 = a.y;
457
+ const ax2 = a.x + a.w;
458
+ const ay2 = a.y + a.h;
459
+ const bx1 = b.x;
460
+ const by1 = b.y;
461
+ const bx2 = b.x + b.w;
462
+ const by2 = b.y + b.h;
463
+ const interX1 = Math.max(ax1, bx1);
464
+ const interY1 = Math.max(ay1, by1);
465
+ const interX2 = Math.min(ax2, bx2);
466
+ const interY2 = Math.min(ay2, by2);
467
+ const interW = Math.max(0, interX2 - interX1);
468
+ const interH = Math.max(0, interY2 - interY1);
469
+ const interArea = interW * interH;
470
+ if (interArea === 0) return 0;
471
+ const areaA = a.w * a.h;
472
+ const areaB = b.w * b.h;
473
+ const unionArea = areaA + areaB - interArea;
474
+ return unionArea === 0 ? 0 : interArea / unionArea;
475
+ }
476
+ function nms(boxes, iouThreshold) {
477
+ const indices = boxes.map((_, i) => i).sort((a, b) => boxes[b].score - boxes[a].score);
478
+ const kept = [];
479
+ const suppressed = /* @__PURE__ */ new Set();
480
+ for (const idx of indices) {
481
+ if (suppressed.has(idx)) continue;
482
+ kept.push(idx);
483
+ for (const other of indices) {
484
+ if (other === idx || suppressed.has(other)) continue;
485
+ if (iou(boxes[idx].bbox, boxes[other].bbox) > iouThreshold) {
486
+ suppressed.add(other);
487
+ }
488
+ }
489
+ }
490
+ return kept;
491
+ }
492
+ function yoloPostprocess(output, numClasses, numBoxes, options) {
493
+ const { confidence, iouThreshold, labels, scale, padX, padY, originalWidth, originalHeight } = options;
494
+ const candidates = [];
495
+ for (let i = 0; i < numBoxes; i++) {
496
+ const cx = output[0 * numBoxes + i];
497
+ const cy = output[1 * numBoxes + i];
498
+ const w = output[2 * numBoxes + i];
499
+ const h = output[3 * numBoxes + i];
500
+ let bestScore = -Infinity;
501
+ let bestClass = 0;
502
+ for (let j = 0; j < numClasses; j++) {
503
+ const score = output[(4 + j) * numBoxes + i];
504
+ if (score > bestScore) {
505
+ bestScore = score;
506
+ bestClass = j;
507
+ }
508
+ }
509
+ if (bestScore < confidence) continue;
510
+ const bbox = {
511
+ x: cx - w / 2,
512
+ y: cy - h / 2,
513
+ w,
514
+ h
515
+ };
516
+ candidates.push({ bbox, score: bestScore, classIdx: bestClass });
517
+ }
518
+ if (candidates.length === 0) return [];
519
+ const keptIndices = nms(candidates, iouThreshold);
520
+ return keptIndices.map((idx) => {
521
+ const { bbox, score, classIdx } = candidates[idx];
522
+ const label = labels[classIdx] ?? String(classIdx);
523
+ const x = Math.max(0, Math.min(originalWidth, (bbox.x - padX) / scale));
524
+ const y = Math.max(0, Math.min(originalHeight, (bbox.y - padY) / scale));
525
+ const x2 = Math.max(0, Math.min(originalWidth, (bbox.x + bbox.w - padX) / scale));
526
+ const y2 = Math.max(0, Math.min(originalHeight, (bbox.y + bbox.h - padY) / scale));
527
+ const finalBbox = { x, y, w: x2 - x, h: y2 - y };
528
+ return {
529
+ class: label,
530
+ originalClass: label,
531
+ score,
532
+ bbox: finalBbox
533
+ };
534
+ });
535
+ }
536
+
537
+ // src/shared/postprocess/yolo-seg.ts
538
+ function sigmoid(x) {
539
+ return 1 / (1 + Math.exp(-x));
540
+ }
541
+ function computeRawMask(coeffs, protos, numMaskCoeffs, maskH, maskW) {
542
+ const maskSize = maskH * maskW;
543
+ const rawMask = new Float32Array(maskSize);
544
+ for (let px = 0; px < maskSize; px++) {
545
+ let val = 0;
546
+ for (let k = 0; k < numMaskCoeffs; k++) {
547
+ val += (coeffs[k] ?? 0) * (protos[k * maskSize + px] ?? 0);
548
+ }
549
+ rawMask[px] = sigmoid(val);
550
+ }
551
+ return rawMask;
552
+ }
553
+ function cropAndThresholdMask(rawMask, maskH, maskW, bbox, maskThreshold, maskScale) {
554
+ const cropX1 = Math.max(0, Math.floor(bbox.x * maskScale));
555
+ const cropY1 = Math.max(0, Math.floor(bbox.y * maskScale));
556
+ const cropX2 = Math.min(maskW, Math.ceil((bbox.x + bbox.w) * maskScale));
557
+ const cropY2 = Math.min(maskH, Math.ceil((bbox.y + bbox.h) * maskScale));
558
+ const cropW = Math.max(1, cropX2 - cropX1);
559
+ const cropH = Math.max(1, cropY2 - cropY1);
560
+ const data = new Uint8Array(cropW * cropH);
561
+ for (let row = 0; row < cropH; row++) {
562
+ const srcRow = cropY1 + row;
563
+ for (let col = 0; col < cropW; col++) {
564
+ const srcCol = cropX1 + col;
565
+ const srcIdx = srcRow * maskW + srcCol;
566
+ data[row * cropW + col] = (rawMask[srcIdx] ?? 0) > maskThreshold ? 255 : 0;
567
+ }
568
+ }
569
+ return { data, width: cropW, height: cropH };
570
+ }
571
+ function yoloSegPostprocess(segOutput, options) {
572
+ const {
573
+ detectionOutput,
574
+ protoOutput,
575
+ numClasses,
576
+ numBoxes,
577
+ numMaskCoeffs,
578
+ maskHeight,
579
+ maskWidth
580
+ } = segOutput;
581
+ const {
582
+ confidence,
583
+ iouThreshold,
584
+ labels,
585
+ scale,
586
+ padX,
587
+ padY,
588
+ originalWidth,
589
+ originalHeight,
590
+ maskThreshold = 0.5
591
+ } = options;
592
+ const yoloInputSize = 640;
593
+ const maskScale = maskHeight / yoloInputSize;
594
+ const candidates = [];
595
+ for (let i = 0; i < numBoxes; i++) {
596
+ const cx = detectionOutput[0 * numBoxes + i] ?? 0;
597
+ const cy = detectionOutput[1 * numBoxes + i] ?? 0;
598
+ const w = detectionOutput[2 * numBoxes + i] ?? 0;
599
+ const h = detectionOutput[3 * numBoxes + i] ?? 0;
600
+ let bestScore = -Infinity;
601
+ let bestClass = 0;
602
+ for (let j = 0; j < numClasses; j++) {
603
+ const score = detectionOutput[(4 + j) * numBoxes + i] ?? 0;
604
+ if (score > bestScore) {
605
+ bestScore = score;
606
+ bestClass = j;
607
+ }
608
+ }
609
+ if (bestScore < confidence) continue;
610
+ const bbox = {
611
+ x: cx - w / 2,
612
+ y: cy - h / 2,
613
+ w,
614
+ h
615
+ };
616
+ const coeffs = new Float32Array(numMaskCoeffs);
617
+ for (let k = 0; k < numMaskCoeffs; k++) {
618
+ coeffs[k] = detectionOutput[(4 + numClasses + k) * numBoxes + i] ?? 0;
619
+ }
620
+ candidates.push({ bbox, score: bestScore, classIdx: bestClass, coeffs });
621
+ }
622
+ if (candidates.length === 0) return [];
623
+ const keptIndices = nms(candidates, iouThreshold);
624
+ return keptIndices.map((idx) => {
625
+ const { bbox, score, classIdx, coeffs } = candidates[idx];
626
+ const label = labels[classIdx] ?? String(classIdx);
627
+ const x = Math.max(0, Math.min(originalWidth, (bbox.x - padX) / scale));
628
+ const y = Math.max(0, Math.min(originalHeight, (bbox.y - padY) / scale));
629
+ const x2 = Math.max(0, Math.min(originalWidth, (bbox.x + bbox.w - padX) / scale));
630
+ const y2 = Math.max(0, Math.min(originalHeight, (bbox.y + bbox.h - padY) / scale));
631
+ const finalBbox = { x, y, w: x2 - x, h: y2 - y };
632
+ const rawMask = computeRawMask(coeffs, protoOutput, numMaskCoeffs, maskHeight, maskWidth);
633
+ const { data: maskData, width: mW, height: mH } = cropAndThresholdMask(
634
+ rawMask,
635
+ maskHeight,
636
+ maskWidth,
637
+ bbox,
638
+ maskThreshold,
639
+ maskScale
640
+ );
641
+ return {
642
+ class: label,
643
+ originalClass: label,
644
+ score,
645
+ bbox: finalBbox,
646
+ mask: maskData,
647
+ maskWidth: mW,
648
+ maskHeight: mH
649
+ };
650
+ });
651
+ }
652
+
653
+ // src/shared/engine-resolver.ts
654
+ var fs = __toESM(require("fs"));
655
+ var path2 = __toESM(require("path"));
656
+
657
+ // src/shared/node-engine.ts
658
+ var path = __toESM(require("path"));
659
+ var BACKEND_TO_PROVIDER = {
660
+ cpu: "cpu",
661
+ coreml: "coreml",
662
+ cuda: "cuda",
663
+ tensorrt: "tensorrt",
664
+ dml: "dml"
665
+ };
666
+ var BACKEND_TO_DEVICE = {
667
+ cpu: "cpu",
668
+ coreml: "gpu-mps",
669
+ cuda: "gpu-cuda",
670
+ tensorrt: "tensorrt"
671
+ };
672
+ var NodeInferenceEngine = class {
673
+ constructor(modelPath, backend) {
674
+ this.modelPath = modelPath;
675
+ this.backend = backend;
676
+ this.device = BACKEND_TO_DEVICE[backend] ?? "cpu";
677
+ }
678
+ runtime = "onnx";
679
+ device;
680
+ session = null;
681
+ async initialize() {
682
+ const ort = await import("onnxruntime-node");
683
+ const provider = BACKEND_TO_PROVIDER[this.backend] ?? "cpu";
684
+ const absModelPath = path.isAbsolute(this.modelPath) ? this.modelPath : path.resolve(process.cwd(), this.modelPath);
685
+ const sessionOptions = {
686
+ executionProviders: [provider]
687
+ };
688
+ this.session = await ort.InferenceSession.create(absModelPath, sessionOptions);
689
+ }
690
+ async run(input, inputShape) {
691
+ if (!this.session) {
692
+ throw new Error("NodeInferenceEngine: not initialized \u2014 call initialize() first");
693
+ }
694
+ const ort = await import("onnxruntime-node");
695
+ const sess = this.session;
696
+ const inputName = sess.inputNames[0];
697
+ const tensor = new ort.Tensor("float32", input, [...inputShape]);
698
+ const feeds = { [inputName]: tensor };
699
+ const results = await sess.run(feeds);
700
+ const outputName = sess.outputNames[0];
701
+ const outputTensor = results[outputName];
702
+ return outputTensor.data;
703
+ }
704
+ async runMultiOutput(input, inputShape) {
705
+ if (!this.session) {
706
+ throw new Error("NodeInferenceEngine: not initialized \u2014 call initialize() first");
707
+ }
708
+ const ort = await import("onnxruntime-node");
709
+ const sess = this.session;
710
+ const inputName = sess.inputNames[0];
711
+ const tensor = new ort.Tensor("float32", input, [...inputShape]);
712
+ const feeds = { [inputName]: tensor };
713
+ const results = await sess.run(feeds);
714
+ const out = {};
715
+ for (const name of sess.outputNames) {
716
+ out[name] = results[name].data;
717
+ }
718
+ return out;
719
+ }
720
+ async dispose() {
721
+ this.session = null;
722
+ }
723
+ };
724
+
725
+ // src/shared/python-engine.ts
726
+ var import_node_child_process = require("child_process");
727
+ var PythonInferenceEngine = class {
728
+ constructor(pythonPath, scriptPath, runtime, modelPath, extraArgs = []) {
729
+ this.pythonPath = pythonPath;
730
+ this.scriptPath = scriptPath;
731
+ this.modelPath = modelPath;
732
+ this.extraArgs = extraArgs;
733
+ this.runtime = runtime;
734
+ const runtimeDeviceMap = {
735
+ onnx: "cpu",
736
+ coreml: "gpu-mps",
737
+ pytorch: "cpu",
738
+ openvino: "cpu",
739
+ tflite: "cpu"
740
+ };
741
+ this.device = runtimeDeviceMap[runtime];
742
+ }
743
+ runtime;
744
+ device;
745
+ process = null;
746
+ receiveBuffer = Buffer.alloc(0);
747
+ pendingResolve = null;
748
+ pendingReject = null;
749
+ async initialize() {
750
+ const args = [this.scriptPath, this.modelPath, ...this.extraArgs];
751
+ this.process = (0, import_node_child_process.spawn)(this.pythonPath, args, {
752
+ stdio: ["pipe", "pipe", "pipe"]
753
+ });
754
+ if (!this.process.stdout || !this.process.stdin) {
755
+ throw new Error("PythonInferenceEngine: failed to create process pipes");
756
+ }
757
+ this.process.stderr?.on("data", (chunk) => {
758
+ process.stderr.write(`[python-engine] ${chunk.toString()}`);
759
+ });
760
+ this.process.on("error", (err) => {
761
+ this.pendingReject?.(err);
762
+ this.pendingReject = null;
763
+ this.pendingResolve = null;
764
+ });
765
+ this.process.on("exit", (code) => {
766
+ if (code !== 0) {
767
+ const err = new Error(`PythonInferenceEngine: process exited with code ${code}`);
768
+ this.pendingReject?.(err);
769
+ this.pendingReject = null;
770
+ this.pendingResolve = null;
771
+ }
772
+ });
773
+ this.process.stdout.on("data", (chunk) => {
774
+ this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk]);
775
+ this._tryReceive();
776
+ });
777
+ await new Promise((resolve2, reject) => {
778
+ const timeout = setTimeout(() => resolve2(), 2e3);
779
+ this.process?.on("error", (err) => {
780
+ clearTimeout(timeout);
781
+ reject(err);
782
+ });
783
+ this.process?.on("exit", (code) => {
784
+ clearTimeout(timeout);
785
+ if (code !== 0) {
786
+ reject(new Error(`PythonInferenceEngine: process exited early with code ${code}`));
787
+ }
788
+ });
789
+ });
790
+ }
791
+ _tryReceive() {
792
+ if (this.receiveBuffer.length < 4) return;
793
+ const length = this.receiveBuffer.readUInt32LE(0);
794
+ if (this.receiveBuffer.length < 4 + length) return;
795
+ const jsonBytes = this.receiveBuffer.subarray(4, 4 + length);
796
+ this.receiveBuffer = this.receiveBuffer.subarray(4 + length);
797
+ const resolve2 = this.pendingResolve;
798
+ const reject = this.pendingReject;
799
+ this.pendingResolve = null;
800
+ this.pendingReject = null;
801
+ if (!resolve2) return;
802
+ try {
803
+ const parsed = JSON.parse(jsonBytes.toString("utf8"));
804
+ resolve2(parsed);
805
+ } catch (err) {
806
+ reject?.(err instanceof Error ? err : new Error(String(err)));
807
+ }
808
+ }
809
+ /** Send JPEG buffer, receive JSON detection results */
810
+ async runJpeg(jpeg) {
811
+ if (!this.process?.stdin) {
812
+ throw new Error("PythonInferenceEngine: process not initialized");
813
+ }
814
+ return new Promise((resolve2, reject) => {
815
+ this.pendingResolve = resolve2;
816
+ this.pendingReject = reject;
817
+ const lengthBuf = Buffer.allocUnsafe(4);
818
+ lengthBuf.writeUInt32LE(jpeg.length, 0);
819
+ this.process.stdin.write(Buffer.concat([lengthBuf, jpeg]));
820
+ });
821
+ }
822
+ /** IInferenceEngine.run — wraps runJpeg for compatibility */
823
+ async run(_input, _inputShape) {
824
+ throw new Error(
825
+ "PythonInferenceEngine: use runJpeg() directly \u2014 this engine operates on JPEG input"
826
+ );
827
+ }
828
+ /** IInferenceEngine.runMultiOutput — not supported by Python engine (operates on JPEG input) */
829
+ async runMultiOutput(_input, _inputShape) {
830
+ throw new Error(
831
+ "PythonInferenceEngine: runMultiOutput() is not supported \u2014 this engine operates on JPEG input"
832
+ );
833
+ }
834
+ async dispose() {
835
+ if (this.process) {
836
+ this.process.stdin?.end();
837
+ this.process.kill("SIGTERM");
838
+ this.process = null;
839
+ }
840
+ }
841
+ };
842
+
843
+ // src/shared/engine-resolver.ts
844
+ var AUTO_BACKEND_PRIORITY = ["coreml", "cuda", "tensorrt", "cpu"];
845
+ var BACKEND_TO_FORMAT = {
846
+ cpu: "onnx",
847
+ coreml: "coreml",
848
+ cuda: "onnx",
849
+ tensorrt: "onnx"
850
+ };
851
+ var RUNTIME_TO_FORMAT = {
852
+ onnx: "onnx",
853
+ coreml: "coreml",
854
+ openvino: "openvino",
855
+ tflite: "tflite",
856
+ pytorch: "pt"
857
+ };
858
+ function modelFilePath(modelsDir, modelEntry, format) {
859
+ const formatEntry = modelEntry.formats[format];
860
+ if (!formatEntry) {
861
+ throw new Error(`Model ${modelEntry.id} has no ${format} format`);
862
+ }
863
+ const urlParts = formatEntry.url.split("/");
864
+ const filename = urlParts[urlParts.length - 1] ?? `${modelEntry.id}.${format}`;
865
+ return path2.join(modelsDir, filename);
866
+ }
867
+ function modelExists(filePath) {
868
+ try {
869
+ return fs.existsSync(filePath);
870
+ } catch {
871
+ return false;
872
+ }
873
+ }
874
+ async function resolveEngine(options) {
875
+ const { runtime, backend, modelEntry, modelsDir, downloadModel } = options;
876
+ let selectedFormat;
877
+ let selectedBackend;
878
+ if (runtime === "auto") {
879
+ const available = await probeOnnxBackends();
880
+ let chosen = null;
881
+ for (const b of AUTO_BACKEND_PRIORITY) {
882
+ if (!available.includes(b)) continue;
883
+ const fmt = BACKEND_TO_FORMAT[b];
884
+ if (!fmt) continue;
885
+ if (!modelEntry.formats[fmt]) continue;
886
+ chosen = { backend: b, format: fmt };
887
+ break;
888
+ }
889
+ if (!chosen) {
890
+ throw new Error(
891
+ `resolveEngine: no compatible backend found for model ${modelEntry.id}. Available backends: ${available.join(", ")}`
892
+ );
893
+ }
894
+ selectedFormat = chosen.format;
895
+ selectedBackend = chosen.backend;
896
+ } else {
897
+ const fmt = RUNTIME_TO_FORMAT[runtime];
898
+ if (!fmt) {
899
+ throw new Error(`resolveEngine: unsupported runtime "${runtime}"`);
900
+ }
901
+ if (!modelEntry.formats[fmt]) {
902
+ throw new Error(
903
+ `resolveEngine: model ${modelEntry.id} has no ${fmt} format for runtime ${runtime}`
904
+ );
905
+ }
906
+ selectedFormat = fmt;
907
+ selectedBackend = runtime === "onnx" ? backend || "cpu" : runtime;
908
+ }
909
+ let modelPath = modelFilePath(modelsDir, modelEntry, selectedFormat);
910
+ if (!modelExists(modelPath)) {
911
+ if (downloadModel) {
912
+ const formatEntry = modelEntry.formats[selectedFormat];
913
+ modelPath = await downloadModel(formatEntry.url, modelsDir);
914
+ } else {
915
+ throw new Error(
916
+ `resolveEngine: model file not found at ${modelPath} and no downloadModel function provided`
917
+ );
918
+ }
919
+ }
920
+ if (selectedFormat === "onnx" || selectedFormat === "coreml") {
921
+ const engine = new NodeInferenceEngine(modelPath, selectedBackend);
922
+ await engine.initialize();
923
+ return { engine, format: selectedFormat, modelPath };
924
+ }
925
+ const { pythonPath } = options;
926
+ const PYTHON_SCRIPT_MAP = {
927
+ coreml: "coreml_inference.py",
928
+ pytorch: "pytorch_inference.py",
929
+ openvino: "openvino_inference.py"
930
+ };
931
+ const effectiveRuntime = runtime === "auto" ? selectedBackend : runtime;
932
+ const scriptName = PYTHON_SCRIPT_MAP[effectiveRuntime];
933
+ if (scriptName && pythonPath) {
934
+ const scriptPath = path2.join(__dirname, "../../python", scriptName);
935
+ const inputSize = Math.max(modelEntry.inputSize.width, modelEntry.inputSize.height);
936
+ const engine = new PythonInferenceEngine(pythonPath, scriptPath, effectiveRuntime, modelPath, [
937
+ `--input-size=${inputSize}`,
938
+ `--confidence=0.25`
939
+ ]);
940
+ await engine.initialize();
941
+ return { engine, format: selectedFormat, modelPath };
942
+ }
943
+ const fallbackPath = modelFilePath(modelsDir, modelEntry, "onnx");
944
+ if (modelEntry.formats["onnx"] && modelExists(fallbackPath)) {
945
+ const engine = new NodeInferenceEngine(fallbackPath, "cpu");
946
+ await engine.initialize();
947
+ return { engine, format: "onnx", modelPath: fallbackPath };
948
+ }
949
+ throw new Error(
950
+ `resolveEngine: format ${selectedFormat} is not yet supported by NodeInferenceEngine, no Python runtime is available, and no ONNX fallback exists`
951
+ );
952
+ }
953
+ async function probeOnnxBackends() {
954
+ const available = ["cpu"];
955
+ try {
956
+ const ort = await import("onnxruntime-node");
957
+ const providers = ort.env?.webgl?.disabled !== void 0 ? ort.InferenceSession?.getAvailableProviders?.() ?? [] : [];
958
+ for (const p of providers) {
959
+ const normalized = p.toLowerCase().replace("executionprovider", "");
960
+ if (normalized === "coreml") available.push("coreml");
961
+ else if (normalized === "cuda") available.push("cuda");
962
+ else if (normalized === "tensorrt") available.push("tensorrt");
963
+ }
964
+ } catch {
965
+ }
966
+ if (process.platform === "darwin" && !available.includes("coreml")) {
967
+ available.push("coreml");
968
+ }
969
+ return [...new Set(available)];
970
+ }
971
+
972
+ // src/addons/object-detection/index.ts
973
+ function isSegModel(modelId) {
974
+ return modelId.includes("-seg");
975
+ }
976
+ var ALL_DETECTION_MODELS = [
977
+ ...OBJECT_DETECTION_MODELS,
978
+ ...SEGMENTATION_MODELS
979
+ ];
980
+ function applyClassMap(detections, classMap) {
981
+ return detections.filter((d) => classMap.mapping[d.class] !== void 0).map((d) => ({
982
+ ...d,
983
+ originalClass: d.class,
984
+ class: classMap.mapping[d.class]
985
+ }));
986
+ }
987
+ var ObjectDetectionAddon = class {
988
+ id = "object-detection";
989
+ slot = "detector";
990
+ inputClasses = null;
991
+ outputClasses = ["person", "vehicle", "animal"];
992
+ slotPriority = 0;
993
+ manifest = {
994
+ id: "object-detection",
995
+ name: "Object Detection",
996
+ version: "0.1.0",
997
+ description: "YOLO-based object detection \u2014 detects persons, vehicles, and animals",
998
+ packageName: "@camstack/addon-vision",
999
+ slot: "detector",
1000
+ inputClasses: void 0,
1001
+ outputClasses: ["person", "vehicle", "animal"],
1002
+ supportsCustomModels: true,
1003
+ mayRequirePython: false,
1004
+ defaultConfig: {
1005
+ modelId: "yolov8n",
1006
+ runtime: "auto",
1007
+ backend: "cpu",
1008
+ confidence: 0.5,
1009
+ iouThreshold: 0.45,
1010
+ classMapMode: "macro"
1011
+ }
1012
+ };
1013
+ engine;
1014
+ modelEntry;
1015
+ confidence = 0.5;
1016
+ iouThreshold = 0.45;
1017
+ classMapMode = "macro";
1018
+ async initialize(ctx) {
1019
+ const cfg = ctx.addonConfig;
1020
+ const modelId = cfg["modelId"] ?? "yolov8n";
1021
+ const runtime = cfg["runtime"] ?? "auto";
1022
+ const backend = cfg["backend"] ?? "cpu";
1023
+ this.confidence = cfg["confidence"] ?? 0.5;
1024
+ this.iouThreshold = cfg["iouThreshold"] ?? 0.45;
1025
+ this.classMapMode = cfg["classMapMode"] ?? "macro";
1026
+ const entry = ALL_DETECTION_MODELS.find((m) => m.id === modelId);
1027
+ if (!entry) {
1028
+ throw new Error(`ObjectDetectionAddon: unknown modelId "${modelId}"`);
1029
+ }
1030
+ this.modelEntry = entry;
1031
+ const resolved = await resolveEngine({
1032
+ runtime,
1033
+ backend,
1034
+ modelEntry: entry,
1035
+ modelsDir: ctx.locationPaths.models
1036
+ });
1037
+ this.engine = resolved.engine;
1038
+ }
1039
+ async detect(frame) {
1040
+ const start = Date.now();
1041
+ const { width: inputW, height: inputH } = this.modelEntry.inputSize;
1042
+ const targetSize = Math.max(inputW, inputH);
1043
+ const lb = await letterbox(frame.data, targetSize);
1044
+ const numClasses = this.modelEntry.labels.length;
1045
+ const labels = this.modelEntry.labels.map((l) => l.id);
1046
+ const postprocessOpts = {
1047
+ confidence: this.confidence,
1048
+ iouThreshold: this.iouThreshold,
1049
+ labels,
1050
+ scale: lb.scale,
1051
+ padX: lb.padX,
1052
+ padY: lb.padY,
1053
+ originalWidth: lb.originalWidth,
1054
+ originalHeight: lb.originalHeight
1055
+ };
1056
+ let rawDetections;
1057
+ if (isSegModel(this.modelEntry.id)) {
1058
+ const outputs = await this.engine.runMultiOutput(lb.data, [1, 3, targetSize, targetSize]);
1059
+ const outputNames = Object.keys(outputs);
1060
+ if (outputNames.length < 2) {
1061
+ throw new Error(
1062
+ `ObjectDetectionAddon: seg model "${this.modelEntry.id}" returned ${outputNames.length} output(s); expected 2`
1063
+ );
1064
+ }
1065
+ const detectionOutput = outputs[outputNames[0]];
1066
+ const protoOutput = outputs[outputNames[1]];
1067
+ const numMaskCoeffs = 32;
1068
+ const numBoxes = detectionOutput.length / (4 + numClasses + numMaskCoeffs);
1069
+ const maskHeight = 160;
1070
+ const maskWidth = 160;
1071
+ rawDetections = yoloSegPostprocess(
1072
+ {
1073
+ detectionOutput,
1074
+ protoOutput,
1075
+ numClasses,
1076
+ numBoxes,
1077
+ numMaskCoeffs,
1078
+ maskHeight,
1079
+ maskWidth
1080
+ },
1081
+ postprocessOpts
1082
+ );
1083
+ } else {
1084
+ const output = await this.engine.run(lb.data, [1, 3, targetSize, targetSize]);
1085
+ const numBoxes = output.length / (4 + numClasses);
1086
+ rawDetections = yoloPostprocess(output, numClasses, numBoxes, postprocessOpts);
1087
+ }
1088
+ const detections = this.classMapMode === "all" ? rawDetections : applyClassMap(rawDetections, import_types3.COCO_TO_MACRO);
1089
+ return {
1090
+ detections,
1091
+ inferenceMs: Date.now() - start,
1092
+ modelId: this.modelEntry.id
1093
+ };
1094
+ }
1095
+ async shutdown() {
1096
+ await this.engine?.dispose();
1097
+ }
1098
+ getConfigSchema() {
1099
+ return {
1100
+ sections: [
1101
+ {
1102
+ id: "model",
1103
+ title: "Model",
1104
+ columns: 2,
1105
+ fields: [
1106
+ {
1107
+ key: "modelId",
1108
+ label: "Model",
1109
+ type: "model-selector",
1110
+ catalog: [...ALL_DETECTION_MODELS],
1111
+ allowCustom: true,
1112
+ allowConversion: true,
1113
+ acceptFormats: ["onnx", "coreml", "openvino", "tflite"],
1114
+ requiredMetadata: ["inputSize", "labels", "outputFormat"],
1115
+ outputFormatHint: "yolo"
1116
+ }
1117
+ ]
1118
+ },
1119
+ {
1120
+ id: "runtime",
1121
+ title: "Runtime",
1122
+ columns: 2,
1123
+ fields: [
1124
+ {
1125
+ key: "runtime",
1126
+ label: "Runtime",
1127
+ type: "select",
1128
+ options: [
1129
+ { value: "auto", label: "Auto (recommended)" },
1130
+ { value: "onnx", label: "ONNX Runtime" },
1131
+ { value: "coreml", label: "CoreML (Apple)" },
1132
+ { value: "openvino", label: "OpenVINO (Intel)" }
1133
+ ]
1134
+ },
1135
+ {
1136
+ key: "backend",
1137
+ label: "Backend",
1138
+ type: "select",
1139
+ dependsOn: { runtime: "onnx" },
1140
+ options: [
1141
+ { value: "cpu", label: "CPU" },
1142
+ { value: "coreml", label: "CoreML" },
1143
+ { value: "cuda", label: "CUDA (NVIDIA)" },
1144
+ { value: "tensorrt", label: "TensorRT (NVIDIA)" }
1145
+ ]
1146
+ }
1147
+ ]
1148
+ },
1149
+ {
1150
+ id: "thresholds",
1151
+ title: "Detection Thresholds",
1152
+ columns: 2,
1153
+ fields: [
1154
+ {
1155
+ key: "confidence",
1156
+ label: "Confidence Threshold",
1157
+ type: "slider",
1158
+ min: 0.1,
1159
+ max: 1,
1160
+ step: 0.05,
1161
+ default: 0.5
1162
+ },
1163
+ {
1164
+ key: "iouThreshold",
1165
+ label: "IoU Threshold (NMS)",
1166
+ type: "slider",
1167
+ min: 0.1,
1168
+ max: 1,
1169
+ step: 0.05,
1170
+ default: 0.45
1171
+ }
1172
+ ]
1173
+ },
1174
+ {
1175
+ id: "classmap",
1176
+ title: "Class Mapping",
1177
+ columns: 1,
1178
+ fields: [
1179
+ {
1180
+ key: "classMapMode",
1181
+ label: "Output classes",
1182
+ type: "select",
1183
+ options: [
1184
+ { value: "macro", label: "Macro (person / vehicle / animal)" },
1185
+ { value: "all", label: "All COCO classes (80)" }
1186
+ ]
1187
+ }
1188
+ ]
1189
+ }
1190
+ ]
1191
+ };
1192
+ }
1193
+ getClassMap() {
1194
+ return import_types3.COCO_TO_MACRO;
1195
+ }
1196
+ getModelCatalog() {
1197
+ return [...ALL_DETECTION_MODELS];
1198
+ }
1199
+ getAvailableModels() {
1200
+ return [];
1201
+ }
1202
+ getActiveLabels() {
1203
+ return this.classMapMode === "all" ? import_types3.COCO_80_LABELS : import_types3.MACRO_LABELS;
1204
+ }
1205
+ async probe() {
1206
+ return {
1207
+ available: true,
1208
+ runtime: this.engine?.runtime ?? "onnx",
1209
+ device: this.engine?.device ?? "cpu",
1210
+ capabilities: ["fp32"]
1211
+ };
1212
+ }
1213
+ };
1214
+ //# sourceMappingURL=index.js.map