@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.
- package/dist/addons/animal-classifier/index.d.mts +25 -0
- package/dist/addons/animal-classifier/index.d.ts +25 -0
- package/dist/addons/animal-classifier/index.js +652 -0
- package/dist/addons/animal-classifier/index.js.map +1 -0
- package/dist/addons/animal-classifier/index.mjs +10 -0
- package/dist/addons/animal-classifier/index.mjs.map +1 -0
- package/dist/addons/audio-classification/index.d.mts +31 -0
- package/dist/addons/audio-classification/index.d.ts +31 -0
- package/dist/addons/audio-classification/index.js +572 -0
- package/dist/addons/audio-classification/index.js.map +1 -0
- package/dist/addons/audio-classification/index.mjs +8 -0
- package/dist/addons/audio-classification/index.mjs.map +1 -0
- package/dist/addons/bird-global-classifier/index.d.mts +26 -0
- package/dist/addons/bird-global-classifier/index.d.ts +26 -0
- package/dist/addons/bird-global-classifier/index.js +658 -0
- package/dist/addons/bird-global-classifier/index.js.map +1 -0
- package/dist/addons/bird-global-classifier/index.mjs +10 -0
- package/dist/addons/bird-global-classifier/index.mjs.map +1 -0
- package/dist/addons/bird-nabirds-classifier/index.d.mts +28 -0
- package/dist/addons/bird-nabirds-classifier/index.d.ts +28 -0
- package/dist/addons/bird-nabirds-classifier/index.js +700 -0
- package/dist/addons/bird-nabirds-classifier/index.js.map +1 -0
- package/dist/addons/bird-nabirds-classifier/index.mjs +10 -0
- package/dist/addons/bird-nabirds-classifier/index.mjs.map +1 -0
- package/dist/addons/camera-native-detection/index.d.mts +32 -0
- package/dist/addons/camera-native-detection/index.d.ts +32 -0
- package/dist/addons/camera-native-detection/index.js +99 -0
- package/dist/addons/camera-native-detection/index.js.map +1 -0
- package/dist/addons/camera-native-detection/index.mjs +7 -0
- package/dist/addons/camera-native-detection/index.mjs.map +1 -0
- package/dist/addons/face-detection/index.d.mts +24 -0
- package/dist/addons/face-detection/index.d.ts +24 -0
- package/dist/addons/face-detection/index.js +720 -0
- package/dist/addons/face-detection/index.js.map +1 -0
- package/dist/addons/face-detection/index.mjs +10 -0
- package/dist/addons/face-detection/index.mjs.map +1 -0
- package/dist/addons/face-recognition/index.d.mts +24 -0
- package/dist/addons/face-recognition/index.d.ts +24 -0
- package/dist/addons/face-recognition/index.js +603 -0
- package/dist/addons/face-recognition/index.js.map +1 -0
- package/dist/addons/face-recognition/index.mjs +9 -0
- package/dist/addons/face-recognition/index.mjs.map +1 -0
- package/dist/addons/motion-detection/index.d.mts +26 -0
- package/dist/addons/motion-detection/index.d.ts +26 -0
- package/dist/addons/motion-detection/index.js +273 -0
- package/dist/addons/motion-detection/index.js.map +1 -0
- package/dist/addons/motion-detection/index.mjs +8 -0
- package/dist/addons/motion-detection/index.mjs.map +1 -0
- package/dist/addons/object-detection/index.d.mts +26 -0
- package/dist/addons/object-detection/index.d.ts +26 -0
- package/dist/addons/object-detection/index.js +1214 -0
- package/dist/addons/object-detection/index.js.map +1 -0
- package/dist/addons/object-detection/index.mjs +10 -0
- package/dist/addons/object-detection/index.mjs.map +1 -0
- package/dist/addons/plate-detection/index.d.mts +25 -0
- package/dist/addons/plate-detection/index.d.ts +25 -0
- package/dist/addons/plate-detection/index.js +646 -0
- package/dist/addons/plate-detection/index.js.map +1 -0
- package/dist/addons/plate-detection/index.mjs +10 -0
- package/dist/addons/plate-detection/index.mjs.map +1 -0
- package/dist/addons/plate-recognition/index.d.mts +25 -0
- package/dist/addons/plate-recognition/index.d.ts +25 -0
- package/dist/addons/plate-recognition/index.js +648 -0
- package/dist/addons/plate-recognition/index.js.map +1 -0
- package/dist/addons/plate-recognition/index.mjs +9 -0
- package/dist/addons/plate-recognition/index.mjs.map +1 -0
- package/dist/chunk-3MQFUDRU.mjs +260 -0
- package/dist/chunk-3MQFUDRU.mjs.map +1 -0
- package/dist/chunk-5AIQSN32.mjs +227 -0
- package/dist/chunk-5AIQSN32.mjs.map +1 -0
- package/dist/chunk-5JJZGKL7.mjs +186 -0
- package/dist/chunk-5JJZGKL7.mjs.map +1 -0
- package/dist/chunk-6OR5TE7A.mjs +101 -0
- package/dist/chunk-6OR5TE7A.mjs.map +1 -0
- package/dist/chunk-AYBFB7ID.mjs +763 -0
- package/dist/chunk-AYBFB7ID.mjs.map +1 -0
- package/dist/chunk-B3R66MPF.mjs +219 -0
- package/dist/chunk-B3R66MPF.mjs.map +1 -0
- package/dist/chunk-DTOAB2CE.mjs +79 -0
- package/dist/chunk-DTOAB2CE.mjs.map +1 -0
- package/dist/chunk-ISOIDU4U.mjs +54 -0
- package/dist/chunk-ISOIDU4U.mjs.map +1 -0
- package/dist/chunk-J4WRYHHY.mjs +212 -0
- package/dist/chunk-J4WRYHHY.mjs.map +1 -0
- package/dist/chunk-KUO2BVFY.mjs +90 -0
- package/dist/chunk-KUO2BVFY.mjs.map +1 -0
- package/dist/chunk-LPI42WL6.mjs +324 -0
- package/dist/chunk-LPI42WL6.mjs.map +1 -0
- package/dist/chunk-MEVASN3P.mjs +305 -0
- package/dist/chunk-MEVASN3P.mjs.map +1 -0
- package/dist/chunk-PDSHDDPV.mjs +255 -0
- package/dist/chunk-PDSHDDPV.mjs.map +1 -0
- package/dist/chunk-Q3SQOYG6.mjs +218 -0
- package/dist/chunk-Q3SQOYG6.mjs.map +1 -0
- package/dist/chunk-QIMDG34B.mjs +229 -0
- package/dist/chunk-QIMDG34B.mjs.map +1 -0
- package/dist/index.d.mts +171 -0
- package/dist/index.d.ts +171 -0
- package/dist/index.js +3463 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +111 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +49 -0
- package/python/__pycache__/coreml_inference.cpython-313.pyc +0 -0
- package/python/__pycache__/openvino_inference.cpython-313.pyc +0 -0
- package/python/__pycache__/pytorch_inference.cpython-313.pyc +0 -0
- package/python/coreml_inference.py +319 -0
- package/python/openvino_inference.py +247 -0
- package/python/pytorch_inference.py +255 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/catalogs/object-detection-models.ts","../src/catalogs/segmentation-models.ts","../src/addons/object-detection/index.ts","../src/shared/postprocess/yolo-seg.ts"],"sourcesContent":["import type { ModelCatalogEntry } from '@camstack/types'\nimport { hfModelUrl, COCO_80_LABELS } from '@camstack/types'\n\nconst HF_REPO = 'camstack/camstack-models'\n\nexport const OBJECT_DETECTION_MODELS: readonly ModelCatalogEntry[] = [\n {\n id: 'yolov8n',\n name: 'YOLOv8 Nano',\n description: 'YOLOv8 Nano — fastest, smallest object detection model',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/onnx/camstack-yolov8n.onnx'),\n sizeMB: 12,\n },\n coreml: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/coreml/camstack-yolov8n.mlpackage'),\n sizeMB: 6,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/openvino/camstack-yolov8n.xml'),\n sizeMB: 7,\n },\n tflite: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/tflite/camstack-yolov8n_float32.tflite'),\n sizeMB: 12,\n },\n },\n },\n {\n id: 'yolov8s',\n name: 'YOLOv8 Small',\n description: 'YOLOv8 Small — balanced speed and accuracy',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/onnx/camstack-yolov8s.onnx'),\n sizeMB: 43,\n },\n coreml: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/coreml/camstack-yolov8s.mlpackage'),\n sizeMB: 21,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/openvino/camstack-yolov8s.xml'),\n sizeMB: 22,\n },\n tflite: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/tflite/camstack-yolov8s_float32.tflite'),\n sizeMB: 43,\n },\n },\n },\n {\n id: 'yolov8m',\n name: 'YOLOv8 Medium',\n description: 'YOLOv8 Medium — higher accuracy, moderate size',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/onnx/camstack-yolov8m.onnx'),\n sizeMB: 99,\n },\n coreml: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/coreml/camstack-yolov8m.mlpackage'),\n sizeMB: 49,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/openvino/camstack-yolov8m.xml'),\n sizeMB: 50,\n },\n tflite: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov8/tflite/camstack-yolov8m_float32.tflite'),\n sizeMB: 99,\n },\n },\n },\n {\n id: 'yolov9t',\n name: 'YOLOv9 Tiny',\n description: 'YOLOv9 Tiny — ultra-lightweight next-gen detector',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/onnx/camstack-yolov9t.onnx'),\n sizeMB: 8,\n },\n coreml: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/coreml/camstack-yolov9t.mlpackage'),\n sizeMB: 4,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/openvino/camstack-yolov9t.xml'),\n sizeMB: 6,\n },\n tflite: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/tflite/camstack-yolov9t_float32.tflite'),\n sizeMB: 8,\n },\n },\n },\n {\n id: 'yolov9s',\n name: 'YOLOv9 Small',\n description: 'YOLOv9 Small — improved efficiency over YOLOv8s',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/onnx/camstack-yolov9s.onnx'),\n sizeMB: 28,\n },\n coreml: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/coreml/camstack-yolov9s.mlpackage'),\n sizeMB: 14,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/openvino/camstack-yolov9s.xml'),\n sizeMB: 16,\n },\n tflite: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/tflite/camstack-yolov9s_float32.tflite'),\n sizeMB: 28,\n },\n },\n },\n {\n id: 'yolov9c',\n name: 'YOLOv9 C',\n description: 'YOLOv9 C — high-accuracy compact model',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/onnx/camstack-yolov9c.onnx'),\n sizeMB: 97,\n },\n coreml: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/coreml/camstack-yolov9c.mlpackage'),\n sizeMB: 48,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/openvino/camstack-yolov9c.xml'),\n sizeMB: 49,\n },\n tflite: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolov9/tflite/camstack-yolov9c_float32.tflite'),\n sizeMB: 97,\n },\n },\n },\n // YOLO11 — no CoreML (coremltools incompatible)\n {\n id: 'yolo11n',\n name: 'YOLO11 Nano',\n description: 'YOLO11 Nano — fastest, smallest YOLO11 detection model',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/onnx/camstack-yolo11n.onnx'),\n sizeMB: 10,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/openvino/camstack-yolo11n.xml'),\n sizeMB: 5.4,\n },\n tflite: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/tflite/camstack-yolo11n_float32.tflite'),\n sizeMB: 10,\n },\n },\n },\n {\n id: 'yolo11s',\n name: 'YOLO11 Small',\n description: 'YOLO11 Small — balanced speed and accuracy',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/onnx/camstack-yolo11s.onnx'),\n sizeMB: 36,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/openvino/camstack-yolo11s.xml'),\n sizeMB: 18,\n },\n tflite: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/tflite/camstack-yolo11s_float32.tflite'),\n sizeMB: 36,\n },\n },\n },\n {\n id: 'yolo11m',\n name: 'YOLO11 Medium',\n description: 'YOLO11 Medium — higher accuracy, moderate size',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/onnx/camstack-yolo11m.onnx'),\n sizeMB: 77,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/openvino/camstack-yolo11m.xml'),\n sizeMB: 39,\n },\n tflite: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/tflite/camstack-yolo11m_float32.tflite'),\n sizeMB: 77,\n },\n },\n },\n {\n id: 'yolo11l',\n name: 'YOLO11 Large',\n description: 'YOLO11 Large — high-accuracy large model',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/onnx/camstack-yolo11l.onnx'),\n sizeMB: 97,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/openvino/camstack-yolo11l.xml'),\n sizeMB: 49,\n },\n tflite: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/tflite/camstack-yolo11l_float32.tflite'),\n sizeMB: 97,\n },\n },\n },\n {\n id: 'yolo11x',\n name: 'YOLO11 Extra-Large',\n description: 'YOLO11 Extra-Large — maximum accuracy',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/onnx/camstack-yolo11x.onnx'),\n sizeMB: 218,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/openvino/camstack-yolo11x.xml'),\n sizeMB: 109,\n },\n tflite: {\n url: hfModelUrl(HF_REPO, 'objectDetection/yolo11/tflite/camstack-yolo11x_float32.tflite'),\n sizeMB: 218,\n },\n },\n },\n] as const\n","import type { ModelCatalogEntry } from '@camstack/types'\nimport { hfModelUrl, COCO_80_LABELS } from '@camstack/types'\n\nconst HF_REPO = 'camstack/camstack-models'\n\nexport const SEGMENTATION_MODELS: readonly ModelCatalogEntry[] = [\n // YOLO11-seg — no CoreML (coremltools incompatible)\n {\n id: 'yolo11n-seg',\n name: 'YOLO11 Nano Segmentation',\n description: 'YOLO11 Nano — fastest, smallest YOLO11 instance segmentation model',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolo11-seg/onnx/camstack-yolo11n-seg.onnx'),\n sizeMB: 11,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolo11-seg/openvino/camstack-yolo11n-seg.xml'),\n sizeMB: 6,\n },\n },\n },\n {\n id: 'yolo11s-seg',\n name: 'YOLO11 Small Segmentation',\n description: 'YOLO11 Small — balanced speed and accuracy for instance segmentation',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolo11-seg/onnx/camstack-yolo11s-seg.onnx'),\n sizeMB: 39,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolo11-seg/openvino/camstack-yolo11s-seg.xml'),\n sizeMB: 20,\n },\n },\n },\n {\n id: 'yolo11m-seg',\n name: 'YOLO11 Medium Segmentation',\n description: 'YOLO11 Medium — higher accuracy instance segmentation',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolo11-seg/onnx/camstack-yolo11m-seg.onnx'),\n sizeMB: 86,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolo11-seg/openvino/camstack-yolo11m-seg.xml'),\n sizeMB: 43,\n },\n },\n },\n // YOLOv8-seg — CoreML available\n {\n id: 'yolov8n-seg',\n name: 'YOLOv8 Nano Segmentation',\n description: 'YOLOv8 Nano — fastest, smallest YOLOv8 instance segmentation model',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolov8-seg/onnx/camstack-yolov8n-seg.onnx'),\n sizeMB: 13,\n },\n coreml: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolov8-seg/coreml/camstack-yolov8n-seg.mlpackage'),\n sizeMB: 7,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolov8-seg/openvino/camstack-yolov8n-seg.xml'),\n sizeMB: 7,\n },\n },\n },\n {\n id: 'yolov8s-seg',\n name: 'YOLOv8 Small Segmentation',\n description: 'YOLOv8 Small — balanced speed and accuracy for instance segmentation',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolov8-seg/onnx/camstack-yolov8s-seg.onnx'),\n sizeMB: 45,\n },\n coreml: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolov8-seg/coreml/camstack-yolov8s-seg.mlpackage'),\n sizeMB: 23,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolov8-seg/openvino/camstack-yolov8s-seg.xml'),\n sizeMB: 23,\n },\n },\n },\n {\n id: 'yolov8m-seg',\n name: 'YOLOv8 Medium Segmentation',\n description: 'YOLOv8 Medium — higher accuracy instance segmentation',\n inputSize: { width: 640, height: 640 },\n labels: COCO_80_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolov8-seg/onnx/camstack-yolov8m-seg.onnx'),\n sizeMB: 104,\n },\n coreml: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolov8-seg/coreml/camstack-yolov8m-seg.mlpackage'),\n sizeMB: 52,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'segmentation/yolov8-seg/openvino/camstack-yolov8m-seg.xml'),\n sizeMB: 53,\n },\n },\n },\n] as const\n","import type {\n IDetectorProvider,\n IDetectionAddon,\n AddonManifest,\n AddonContext,\n FrameInput,\n DetectorOutput,\n SpatialDetection,\n ConfigUISchema,\n ClassMapDefinition,\n ProbeResult,\n ModelCatalogEntry,\n DetectionModel,\n LabelDefinition,\n IInferenceEngine,\n} from '@camstack/types'\nimport { OBJECT_DETECTION_MODELS } from '../../catalogs/object-detection-models.js'\nimport { SEGMENTATION_MODELS } from '../../catalogs/segmentation-models.js'\nimport { COCO_TO_MACRO, MACRO_LABELS, COCO_80_LABELS } from '@camstack/types'\nimport { letterbox } from '../../shared/image-utils.js'\nimport { yoloPostprocess } from '../../shared/postprocess/yolo.js'\nimport { yoloSegPostprocess } from '../../shared/postprocess/yolo-seg.js'\nimport { resolveEngine } from '../../shared/engine-resolver.js'\n\n/** Returns true when the model id identifies a YOLO segmentation model (e.g. yolov8n-seg, yolo11m-seg) */\nfunction isSegModel(modelId: string): boolean {\n return modelId.includes('-seg')\n}\n\n/** Combined catalog: regular detection models + segmentation models */\nconst ALL_DETECTION_MODELS: readonly ModelCatalogEntry[] = [\n ...OBJECT_DETECTION_MODELS,\n ...SEGMENTATION_MODELS,\n]\n\n/**\n * classMapMode controls how raw COCO labels are mapped after inference:\n *\n * - 'macro' (default): apply COCO_TO_MACRO — only person / vehicle / animal\n * survive, all other classes are dropped.\n * - 'all': keep every raw COCO label (80 classes). originalClass === class.\n */\ntype ClassMapMode = 'macro' | 'all'\n\n/** Map COCO-class detections to macro categories (person/vehicle/animal) */\nfunction applyClassMap(\n detections: SpatialDetection[],\n classMap: ClassMapDefinition,\n): SpatialDetection[] {\n return detections\n .filter((d) => classMap.mapping[d.class] !== undefined)\n .map((d) => ({\n ...d,\n originalClass: d.class,\n class: classMap.mapping[d.class]!,\n }))\n}\n\nexport default class ObjectDetectionAddon implements IDetectorProvider, IDetectionAddon {\n readonly id = 'object-detection'\n readonly slot = 'detector' as const\n readonly inputClasses: readonly string[] | null = null\n readonly outputClasses = ['person', 'vehicle', 'animal'] as const\n readonly slotPriority = 0\n readonly manifest: AddonManifest = {\n id: 'object-detection',\n name: 'Object Detection',\n version: '0.1.0',\n description: 'YOLO-based object detection — detects persons, vehicles, and animals',\n packageName: '@camstack/addon-vision',\n slot: 'detector',\n inputClasses: undefined,\n outputClasses: ['person', 'vehicle', 'animal'],\n supportsCustomModels: true,\n mayRequirePython: false,\n defaultConfig: {\n modelId: 'yolov8n',\n runtime: 'auto',\n backend: 'cpu',\n confidence: 0.5,\n iouThreshold: 0.45,\n classMapMode: 'macro',\n },\n }\n\n private engine!: IInferenceEngine\n private modelEntry!: ModelCatalogEntry\n private confidence = 0.5\n private iouThreshold = 0.45\n private classMapMode: ClassMapMode = 'macro'\n\n async initialize(ctx: AddonContext): Promise<void> {\n const cfg = ctx.addonConfig\n const modelId = (cfg['modelId'] as string | undefined) ?? 'yolov8n'\n const runtime = (cfg['runtime'] as string | undefined) ?? 'auto'\n const backend = (cfg['backend'] as string | undefined) ?? 'cpu'\n this.confidence = (cfg['confidence'] as number | undefined) ?? 0.5\n this.iouThreshold = (cfg['iouThreshold'] as number | undefined) ?? 0.45\n this.classMapMode = (cfg['classMapMode'] as ClassMapMode | undefined) ?? 'macro'\n\n const entry = ALL_DETECTION_MODELS.find((m) => m.id === modelId)\n if (!entry) {\n throw new Error(`ObjectDetectionAddon: unknown modelId \"${modelId}\"`)\n }\n this.modelEntry = entry\n\n const resolved = await resolveEngine({\n runtime: runtime as 'auto',\n backend,\n modelEntry: entry,\n modelsDir: ctx.locationPaths.models,\n })\n this.engine = resolved.engine\n }\n\n async detect(frame: FrameInput): Promise<DetectorOutput> {\n const start = Date.now()\n const { width: inputW, height: inputH } = this.modelEntry.inputSize\n const targetSize = Math.max(inputW, inputH)\n\n const lb = await letterbox(frame.data, targetSize)\n\n const numClasses = this.modelEntry.labels.length\n const labels = this.modelEntry.labels.map((l) => l.id)\n const postprocessOpts = {\n confidence: this.confidence,\n iouThreshold: this.iouThreshold,\n labels,\n scale: lb.scale,\n padX: lb.padX,\n padY: lb.padY,\n originalWidth: lb.originalWidth,\n originalHeight: lb.originalHeight,\n }\n\n let rawDetections: SpatialDetection[]\n\n if (isSegModel(this.modelEntry.id)) {\n // YOLO-seg models produce two outputs:\n // output0: [1, 4 + numClasses + 32, numBoxes] (detection + mask coefficients)\n // output1: [1, 32, 160, 160] (prototype masks)\n const outputs = await this.engine.runMultiOutput(lb.data, [1, 3, targetSize, targetSize])\n const outputNames = Object.keys(outputs)\n\n if (outputNames.length < 2) {\n throw new Error(\n `ObjectDetectionAddon: seg model \"${this.modelEntry.id}\" returned ${outputNames.length} output(s); expected 2`,\n )\n }\n\n // ONNX output order is deterministic; first output is the detection tensor, second is protos\n const detectionOutput = outputs[outputNames[0]!]!\n const protoOutput = outputs[outputNames[1]!]!\n\n // Infer dims from tensor sizes\n const numMaskCoeffs = 32\n const numBoxes = detectionOutput.length / (4 + numClasses + numMaskCoeffs)\n const maskHeight = 160\n const maskWidth = 160\n\n rawDetections = yoloSegPostprocess(\n {\n detectionOutput,\n protoOutput,\n numClasses,\n numBoxes,\n numMaskCoeffs,\n maskHeight,\n maskWidth,\n },\n postprocessOpts,\n )\n } else {\n // Standard YOLO output: [1, 4+numClasses, numBoxes]\n const output = await this.engine.run(lb.data, [1, 3, targetSize, targetSize])\n const numBoxes = output.length / (4 + numClasses)\n rawDetections = yoloPostprocess(output, numClasses, numBoxes, postprocessOpts)\n }\n\n const detections = this.classMapMode === 'all'\n ? rawDetections\n : applyClassMap(rawDetections, COCO_TO_MACRO)\n\n return {\n detections,\n inferenceMs: Date.now() - start,\n modelId: this.modelEntry.id,\n }\n }\n\n async shutdown(): Promise<void> {\n await this.engine?.dispose()\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'model',\n title: 'Model',\n columns: 2,\n fields: [\n {\n key: 'modelId',\n label: 'Model',\n type: 'model-selector',\n catalog: [...ALL_DETECTION_MODELS],\n allowCustom: true,\n allowConversion: true,\n acceptFormats: ['onnx', 'coreml', 'openvino', 'tflite'],\n requiredMetadata: ['inputSize', 'labels', 'outputFormat'],\n outputFormatHint: 'yolo',\n },\n ],\n },\n {\n id: 'runtime',\n title: 'Runtime',\n columns: 2,\n fields: [\n {\n key: 'runtime',\n label: 'Runtime',\n type: 'select',\n options: [\n { value: 'auto', label: 'Auto (recommended)' },\n { value: 'onnx', label: 'ONNX Runtime' },\n { value: 'coreml', label: 'CoreML (Apple)' },\n { value: 'openvino', label: 'OpenVINO (Intel)' },\n ],\n },\n {\n key: 'backend',\n label: 'Backend',\n type: 'select',\n dependsOn: { runtime: 'onnx' },\n options: [\n { value: 'cpu', label: 'CPU' },\n { value: 'coreml', label: 'CoreML' },\n { value: 'cuda', label: 'CUDA (NVIDIA)' },\n { value: 'tensorrt', label: 'TensorRT (NVIDIA)' },\n ],\n },\n ],\n },\n {\n id: 'thresholds',\n title: 'Detection Thresholds',\n columns: 2,\n fields: [\n {\n key: 'confidence',\n label: 'Confidence Threshold',\n type: 'slider',\n min: 0.1,\n max: 1.0,\n step: 0.05,\n default: 0.5,\n },\n {\n key: 'iouThreshold',\n label: 'IoU Threshold (NMS)',\n type: 'slider',\n min: 0.1,\n max: 1.0,\n step: 0.05,\n default: 0.45,\n },\n ],\n },\n {\n id: 'classmap',\n title: 'Class Mapping',\n columns: 1,\n fields: [\n {\n key: 'classMapMode',\n label: 'Output classes',\n type: 'select',\n options: [\n { value: 'macro', label: 'Macro (person / vehicle / animal)' },\n { value: 'all', label: 'All COCO classes (80)' },\n ],\n },\n ],\n },\n ],\n }\n }\n\n getClassMap(): ClassMapDefinition {\n return COCO_TO_MACRO\n }\n\n getModelCatalog(): ModelCatalogEntry[] {\n return [...ALL_DETECTION_MODELS]\n }\n\n getAvailableModels(): DetectionModel[] {\n // TODO: check downloaded models in modelsDir\n return []\n }\n\n getActiveLabels(): readonly LabelDefinition[] {\n return this.classMapMode === 'all' ? COCO_80_LABELS : MACRO_LABELS\n }\n\n async probe(): Promise<ProbeResult> {\n return {\n available: true,\n runtime: this.engine?.runtime ?? 'onnx',\n device: this.engine?.device ?? 'cpu',\n capabilities: ['fp32'],\n }\n }\n}\n","import type { SpatialDetection, BoundingBox } from '@camstack/types'\nimport { nms, iou as _iou } from './yolo.js'\nimport type { YoloPostprocessOptions } from './yolo.js'\n\nexport interface YoloSegOutput {\n /** Detection output: [1, 4 + numClasses + numMaskCoeffs, numBoxes] (row-major, batch dim stripped) */\n readonly detectionOutput: Float32Array\n /** Prototype masks: [1, numMaskCoeffs, maskH, maskW] (batch dim stripped) */\n readonly protoOutput: Float32Array\n readonly numClasses: number\n readonly numBoxes: number\n /** Number of mask prototype coefficients per detection (typically 32) */\n readonly numMaskCoeffs: number\n /** Height of prototype mask grid (typically 160) */\n readonly maskHeight: number\n /** Width of prototype mask grid (typically 160) */\n readonly maskWidth: number\n}\n\nexport interface YoloSegPostprocessOptions extends YoloPostprocessOptions {\n /** Binary mask threshold — pixels above this value become 255, others 0 (default: 0.5) */\n readonly maskThreshold?: number\n}\n\n/** Sigmoid activation: σ(x) = 1 / (1 + e^-x) */\nexport function sigmoid(x: number): number {\n return 1 / (1 + Math.exp(-x))\n}\n\n/**\n * Compute instance segmentation mask for a single detection.\n *\n * @param coeffs [numMaskCoeffs] mask coefficients for this detection\n * @param protos [numMaskCoeffs × maskH × maskW] prototype masks (flat, row-major)\n * @param numMaskCoeffs number of prototype channels (e.g. 32)\n * @param maskH prototype grid height (e.g. 160)\n * @param maskW prototype grid width (e.g. 160)\n * @returns [maskH × maskW] sigmoid-activated raw mask values in [0, 1]\n */\nexport function computeRawMask(\n coeffs: Float32Array,\n protos: Float32Array,\n numMaskCoeffs: number,\n maskH: number,\n maskW: number,\n): Float32Array {\n const maskSize = maskH * maskW\n const rawMask = new Float32Array(maskSize)\n\n // mask_raw[y * maskW + x] = sum_k( coeffs[k] * protos[k * maskSize + y * maskW + x] )\n // Then apply sigmoid element-wise.\n for (let px = 0; px < maskSize; px++) {\n let val = 0\n for (let k = 0; k < numMaskCoeffs; k++) {\n val += (coeffs[k] ?? 0) * (protos[k * maskSize + px] ?? 0)\n }\n rawMask[px] = sigmoid(val)\n }\n\n return rawMask\n}\n\n/**\n * Crop a flat [maskH × maskW] mask to a bounding box region (in mask coordinate space),\n * threshold to binary, and return the cropped Uint8Array along with its dimensions.\n *\n * @param rawMask [maskH × maskW] sigmoid-activated values in [0, 1]\n * @param maskH full mask grid height\n * @param maskW full mask grid width\n * @param bbox detection bounding box in the inference input space (e.g. 640×640 letterboxed)\n * @param maskThreshold threshold above which a pixel is considered foreground (default 0.5)\n * @param maskScale ratio of mask resolution to inference resolution (e.g. 160/640 = 0.25)\n * @returns { data: Uint8Array, width, height } of the cropped binary mask\n */\nexport function cropAndThresholdMask(\n rawMask: Float32Array,\n maskH: number,\n maskW: number,\n bbox: BoundingBox,\n maskThreshold: number,\n maskScale: number,\n): { readonly data: Uint8Array; readonly width: number; readonly height: number } {\n const cropX1 = Math.max(0, Math.floor(bbox.x * maskScale))\n const cropY1 = Math.max(0, Math.floor(bbox.y * maskScale))\n const cropX2 = Math.min(maskW, Math.ceil((bbox.x + bbox.w) * maskScale))\n const cropY2 = Math.min(maskH, Math.ceil((bbox.y + bbox.h) * maskScale))\n\n const cropW = Math.max(1, cropX2 - cropX1)\n const cropH = Math.max(1, cropY2 - cropY1)\n\n const data = new Uint8Array(cropW * cropH)\n\n for (let row = 0; row < cropH; row++) {\n const srcRow = cropY1 + row\n for (let col = 0; col < cropW; col++) {\n const srcCol = cropX1 + col\n const srcIdx = srcRow * maskW + srcCol\n data[row * cropW + col] = (rawMask[srcIdx] ?? 0) > maskThreshold ? 255 : 0\n }\n }\n\n return { data, width: cropW, height: cropH }\n}\n\n/**\n * YOLO-seg postprocessing: run detection filtering + NMS, then decode instance masks.\n *\n * The seg detection tensor has layout [1, 4 + numClasses + numMaskCoeffs, numBoxes]:\n * rows 0–3 : cx, cy, w, h\n * rows 4 to 4+C-1 : class scores\n * rows 4+C to end : mask coefficients (32)\n *\n * Steps:\n * 1. Filter boxes by confidence threshold, collecting mask coefficients per candidate.\n * 2. Run NMS across all candidates.\n * 3. For each surviving detection, compute the instance mask and attach it.\n */\nexport function yoloSegPostprocess(\n segOutput: YoloSegOutput,\n options: YoloSegPostprocessOptions,\n): SpatialDetection[] {\n const {\n detectionOutput,\n protoOutput,\n numClasses,\n numBoxes,\n numMaskCoeffs,\n maskHeight,\n maskWidth,\n } = segOutput\n\n const {\n confidence,\n iouThreshold,\n labels,\n scale,\n padX,\n padY,\n originalWidth,\n originalHeight,\n maskThreshold = 0.5,\n } = options\n\n // The mask resolution to inference resolution scale factor (e.g. 160/640 = 0.25)\n // We derive the inference size from scale/pad context: the letterboxed input is typically 640×640\n // but we receive coordinates in that space already, so we use maskHeight / inferH.\n // Since all YOLO-seg models use 640×640 input and 160×160 proto, the ratio is always 160/640.\n // We compute it generically from the known prototype dims + fixed YOLO input of 640.\n const yoloInputSize = 640\n const maskScale = maskHeight / yoloInputSize\n\n interface Candidate {\n readonly bbox: BoundingBox\n readonly score: number\n readonly classIdx: number\n readonly coeffs: Float32Array\n }\n\n const candidates: Candidate[] = []\n\n for (let i = 0; i < numBoxes; i++) {\n const cx = detectionOutput[0 * numBoxes + i] ?? 0\n const cy = detectionOutput[1 * numBoxes + i] ?? 0\n const w = detectionOutput[2 * numBoxes + i] ?? 0\n const h = detectionOutput[3 * numBoxes + i] ?? 0\n\n let bestScore = -Infinity\n let bestClass = 0\n\n for (let j = 0; j < numClasses; j++) {\n const score = detectionOutput[(4 + j) * numBoxes + i] ?? 0\n if (score > bestScore) {\n bestScore = score\n bestClass = j\n }\n }\n\n if (bestScore < confidence) continue\n\n const bbox: BoundingBox = {\n x: cx - w / 2,\n y: cy - h / 2,\n w,\n h,\n }\n\n // Extract mask coefficients for this box\n const coeffs = new Float32Array(numMaskCoeffs)\n for (let k = 0; k < numMaskCoeffs; k++) {\n coeffs[k] = detectionOutput[(4 + numClasses + k) * numBoxes + i] ?? 0\n }\n\n candidates.push({ bbox, score: bestScore, classIdx: bestClass, coeffs })\n }\n\n if (candidates.length === 0) return []\n\n const keptIndices = nms(candidates, iouThreshold)\n\n return keptIndices.map((idx) => {\n const { bbox, score, classIdx, coeffs } = candidates[idx]!\n const label = labels[classIdx] ?? String(classIdx)\n\n // Scale bbox back from letterbox space to original image coords\n const x = Math.max(0, Math.min(originalWidth, (bbox.x - padX) / scale))\n const y = Math.max(0, Math.min(originalHeight, (bbox.y - padY) / scale))\n const x2 = Math.max(0, Math.min(originalWidth, (bbox.x + bbox.w - padX) / scale))\n const y2 = Math.max(0, Math.min(originalHeight, (bbox.y + bbox.h - padY) / scale))\n const finalBbox: BoundingBox = { x, y, w: x2 - x, h: y2 - y }\n\n // Decode instance mask using the letterbox-space bbox (before coord scaling)\n const rawMask = computeRawMask(coeffs, protoOutput, numMaskCoeffs, maskHeight, maskWidth)\n const { data: maskData, width: mW, height: mH } = cropAndThresholdMask(\n rawMask,\n maskHeight,\n maskWidth,\n bbox,\n maskThreshold,\n maskScale,\n )\n\n return {\n class: label,\n originalClass: label,\n score,\n bbox: finalBbox,\n mask: maskData,\n maskWidth: mW,\n maskHeight: mH,\n } satisfies SpatialDetection\n })\n}\n"],"mappings":"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","names":["hfModelUrl","COCO_80_LABELS","HF_REPO","COCO_80_LABELS","COCO_80_LABELS"]}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cropRegion,
|
|
3
|
+
resizeAndNormalize
|
|
4
|
+
} from "./chunk-6OR5TE7A.mjs";
|
|
5
|
+
import {
|
|
6
|
+
resolveEngine
|
|
7
|
+
} from "./chunk-LPI42WL6.mjs";
|
|
8
|
+
|
|
9
|
+
// src/catalogs/face-recognition-models.ts
|
|
10
|
+
import { hfModelUrl } from "@camstack/types";
|
|
11
|
+
var HF_REPO = "camstack/camstack-models";
|
|
12
|
+
var FACE_EMBEDDING_LABELS = [
|
|
13
|
+
{ id: "embedding", name: "Face Embedding" }
|
|
14
|
+
];
|
|
15
|
+
var FACE_RECOGNITION_MODELS = [
|
|
16
|
+
{
|
|
17
|
+
id: "arcface-r100",
|
|
18
|
+
name: "ArcFace R100",
|
|
19
|
+
description: "ArcFace ResNet-100 \u2014 high-accuracy face recognition embeddings",
|
|
20
|
+
inputSize: { width: 112, height: 112 },
|
|
21
|
+
inputLayout: "nhwc",
|
|
22
|
+
labels: FACE_EMBEDDING_LABELS,
|
|
23
|
+
formats: {
|
|
24
|
+
onnx: {
|
|
25
|
+
url: hfModelUrl(HF_REPO, "faceRecognition/arcface/onnx/camstack-arcface-arcface.onnx"),
|
|
26
|
+
sizeMB: 130
|
|
27
|
+
},
|
|
28
|
+
coreml: {
|
|
29
|
+
url: hfModelUrl(HF_REPO, "faceRecognition/arcface/coreml/camstack-arcface-r100.mlpackage"),
|
|
30
|
+
sizeMB: 65
|
|
31
|
+
},
|
|
32
|
+
openvino: {
|
|
33
|
+
url: hfModelUrl(HF_REPO, "faceRecognition/arcface/openvino/camstack-arcface-r100.xml"),
|
|
34
|
+
sizeMB: 65
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
// src/shared/postprocess/arcface.ts
|
|
41
|
+
function l2Normalize(vec) {
|
|
42
|
+
let sumSq = 0;
|
|
43
|
+
for (let i = 0; i < vec.length; i++) {
|
|
44
|
+
sumSq += vec[i] * vec[i];
|
|
45
|
+
}
|
|
46
|
+
const norm = Math.sqrt(sumSq);
|
|
47
|
+
if (norm === 0) return new Float32Array(vec.length);
|
|
48
|
+
const out = new Float32Array(vec.length);
|
|
49
|
+
for (let i = 0; i < vec.length; i++) {
|
|
50
|
+
out[i] = vec[i] / norm;
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
function cosineSimilarity(a, b) {
|
|
55
|
+
if (a.length !== b.length) throw new Error("Embedding length mismatch");
|
|
56
|
+
let dot = 0;
|
|
57
|
+
for (let i = 0; i < a.length; i++) {
|
|
58
|
+
dot += a[i] * b[i];
|
|
59
|
+
}
|
|
60
|
+
return dot;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/addons/face-recognition/index.ts
|
|
64
|
+
var IDENTITY_LABEL = { id: "identity", name: "Identity" };
|
|
65
|
+
var IDENTITY_LABELS = [IDENTITY_LABEL];
|
|
66
|
+
var FACE_REC_CLASS_MAP = { mapping: {}, preserveOriginal: true };
|
|
67
|
+
var REQUIRED_STEPS = [
|
|
68
|
+
{ slot: "cropper", outputClasses: ["face"], description: "Requires a face detector" }
|
|
69
|
+
];
|
|
70
|
+
var FaceRecognitionAddon = class {
|
|
71
|
+
id = "face-recognition";
|
|
72
|
+
slot = "classifier";
|
|
73
|
+
inputClasses = ["face"];
|
|
74
|
+
outputClasses = ["identity:*"];
|
|
75
|
+
slotPriority = 0;
|
|
76
|
+
requiredSteps = REQUIRED_STEPS;
|
|
77
|
+
manifest = {
|
|
78
|
+
id: "face-recognition",
|
|
79
|
+
name: "Face Recognition",
|
|
80
|
+
version: "0.1.0",
|
|
81
|
+
description: "ArcFace-based face recognition \u2014 produces 512-d identity embeddings",
|
|
82
|
+
packageName: "@camstack/addon-vision",
|
|
83
|
+
slot: "classifier",
|
|
84
|
+
inputClasses: ["face"],
|
|
85
|
+
outputClasses: ["identity:*"],
|
|
86
|
+
requiredSteps: REQUIRED_STEPS,
|
|
87
|
+
supportsCustomModels: false,
|
|
88
|
+
mayRequirePython: false,
|
|
89
|
+
defaultConfig: {
|
|
90
|
+
modelId: "arcface-r100",
|
|
91
|
+
runtime: "auto",
|
|
92
|
+
backend: "cpu"
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
engine;
|
|
96
|
+
modelEntry;
|
|
97
|
+
async initialize(ctx) {
|
|
98
|
+
const cfg = ctx.addonConfig;
|
|
99
|
+
const modelId = cfg["modelId"] ?? "arcface-r100";
|
|
100
|
+
const runtime = cfg["runtime"] ?? "auto";
|
|
101
|
+
const backend = cfg["backend"] ?? "cpu";
|
|
102
|
+
const entry = FACE_RECOGNITION_MODELS.find((m) => m.id === modelId);
|
|
103
|
+
if (!entry) {
|
|
104
|
+
throw new Error(`FaceRecognitionAddon: unknown modelId "${modelId}"`);
|
|
105
|
+
}
|
|
106
|
+
this.modelEntry = entry;
|
|
107
|
+
const resolved = await resolveEngine({
|
|
108
|
+
runtime,
|
|
109
|
+
backend,
|
|
110
|
+
modelEntry: entry,
|
|
111
|
+
modelsDir: ctx.locationPaths.models
|
|
112
|
+
});
|
|
113
|
+
this.engine = resolved.engine;
|
|
114
|
+
}
|
|
115
|
+
async classify(input) {
|
|
116
|
+
const start = Date.now();
|
|
117
|
+
const { width: inputW, height: inputH } = this.modelEntry.inputSize;
|
|
118
|
+
const faceCrop = await cropRegion(input.frame.data, input.roi);
|
|
119
|
+
const layout = this.modelEntry.inputLayout ?? "nhwc";
|
|
120
|
+
const normalization = this.modelEntry.inputNormalization ?? "zero-one";
|
|
121
|
+
const normalized = await resizeAndNormalize(faceCrop, inputW, inputH, normalization, layout);
|
|
122
|
+
const rawEmbedding = await this.engine.run(normalized, [1, inputH, inputW, 3]);
|
|
123
|
+
const embedding = l2Normalize(rawEmbedding);
|
|
124
|
+
return {
|
|
125
|
+
classifications: [
|
|
126
|
+
{
|
|
127
|
+
class: "identity",
|
|
128
|
+
score: 1,
|
|
129
|
+
embedding
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
inferenceMs: Date.now() - start,
|
|
133
|
+
modelId: this.modelEntry.id
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async shutdown() {
|
|
137
|
+
await this.engine?.dispose();
|
|
138
|
+
}
|
|
139
|
+
getConfigSchema() {
|
|
140
|
+
return {
|
|
141
|
+
sections: [
|
|
142
|
+
{
|
|
143
|
+
id: "model",
|
|
144
|
+
title: "Model",
|
|
145
|
+
columns: 1,
|
|
146
|
+
fields: [
|
|
147
|
+
{
|
|
148
|
+
key: "modelId",
|
|
149
|
+
label: "Model",
|
|
150
|
+
type: "model-selector",
|
|
151
|
+
catalog: [...FACE_RECOGNITION_MODELS],
|
|
152
|
+
allowCustom: false,
|
|
153
|
+
allowConversion: false,
|
|
154
|
+
acceptFormats: ["onnx", "coreml", "openvino"],
|
|
155
|
+
requiredMetadata: ["inputSize", "labels", "outputFormat"],
|
|
156
|
+
outputFormatHint: "embedding"
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: "runtime",
|
|
162
|
+
title: "Runtime",
|
|
163
|
+
columns: 2,
|
|
164
|
+
fields: [
|
|
165
|
+
{
|
|
166
|
+
key: "runtime",
|
|
167
|
+
label: "Runtime",
|
|
168
|
+
type: "select",
|
|
169
|
+
options: [
|
|
170
|
+
{ value: "auto", label: "Auto (recommended)" },
|
|
171
|
+
{ value: "onnx", label: "ONNX Runtime" },
|
|
172
|
+
{ value: "coreml", label: "CoreML (Apple)" }
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
key: "backend",
|
|
177
|
+
label: "Backend",
|
|
178
|
+
type: "select",
|
|
179
|
+
dependsOn: { runtime: "onnx" },
|
|
180
|
+
options: [
|
|
181
|
+
{ value: "cpu", label: "CPU" },
|
|
182
|
+
{ value: "coreml", label: "CoreML" },
|
|
183
|
+
{ value: "cuda", label: "CUDA (NVIDIA)" }
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
getClassMap() {
|
|
192
|
+
return FACE_REC_CLASS_MAP;
|
|
193
|
+
}
|
|
194
|
+
getModelCatalog() {
|
|
195
|
+
return [...FACE_RECOGNITION_MODELS];
|
|
196
|
+
}
|
|
197
|
+
getAvailableModels() {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
getActiveLabels() {
|
|
201
|
+
return IDENTITY_LABELS;
|
|
202
|
+
}
|
|
203
|
+
async probe() {
|
|
204
|
+
return {
|
|
205
|
+
available: true,
|
|
206
|
+
runtime: this.engine?.runtime ?? "onnx",
|
|
207
|
+
device: this.engine?.device ?? "cpu",
|
|
208
|
+
capabilities: ["fp32"]
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export {
|
|
214
|
+
l2Normalize,
|
|
215
|
+
cosineSimilarity,
|
|
216
|
+
FACE_RECOGNITION_MODELS,
|
|
217
|
+
FaceRecognitionAddon
|
|
218
|
+
};
|
|
219
|
+
//# sourceMappingURL=chunk-B3R66MPF.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/catalogs/face-recognition-models.ts","../src/shared/postprocess/arcface.ts","../src/addons/face-recognition/index.ts"],"sourcesContent":["import type { ModelCatalogEntry, LabelDefinition } from '@camstack/types'\nimport { hfModelUrl } from '@camstack/types'\n\nconst HF_REPO = 'camstack/camstack-models'\n\nconst FACE_EMBEDDING_LABELS: readonly LabelDefinition[] = [\n { id: 'embedding', name: 'Face Embedding' },\n] as const\n\nexport const FACE_RECOGNITION_MODELS: readonly ModelCatalogEntry[] = [\n {\n id: 'arcface-r100',\n name: 'ArcFace R100',\n description: 'ArcFace ResNet-100 — high-accuracy face recognition embeddings',\n inputSize: { width: 112, height: 112 },\n inputLayout: 'nhwc',\n labels: FACE_EMBEDDING_LABELS,\n formats: {\n onnx: {\n url: hfModelUrl(HF_REPO, 'faceRecognition/arcface/onnx/camstack-arcface-arcface.onnx'),\n sizeMB: 130,\n },\n coreml: {\n url: hfModelUrl(HF_REPO, 'faceRecognition/arcface/coreml/camstack-arcface-r100.mlpackage'),\n sizeMB: 65,\n },\n openvino: {\n url: hfModelUrl(HF_REPO, 'faceRecognition/arcface/openvino/camstack-arcface-r100.xml'),\n sizeMB: 65,\n },\n },\n },\n] as const\n","/** L2 normalize a vector in-place, returning a new Float32Array */\nexport function l2Normalize(vec: Float32Array): Float32Array {\n let sumSq = 0\n for (let i = 0; i < vec.length; i++) {\n sumSq += vec[i]! * vec[i]!\n }\n const norm = Math.sqrt(sumSq)\n if (norm === 0) return new Float32Array(vec.length)\n\n const out = new Float32Array(vec.length)\n for (let i = 0; i < vec.length; i++) {\n out[i] = vec[i]! / norm\n }\n return out\n}\n\n/** Cosine similarity between two embeddings (assumes they are already L2-normalized) */\nexport function cosineSimilarity(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) throw new Error('Embedding length mismatch')\n let dot = 0\n for (let i = 0; i < a.length; i++) {\n dot += a[i]! * b[i]!\n }\n return dot\n}\n","import type {\n IClassifierProvider,\n IDetectionAddon,\n AddonManifest,\n AddonContext,\n CropInput,\n ClassifierOutput,\n ConfigUISchema,\n ClassMapDefinition,\n ProbeResult,\n ModelCatalogEntry,\n DetectionModel,\n LabelDefinition,\n IInferenceEngine,\n RequiredStep,\n} from '@camstack/types'\nimport { FACE_RECOGNITION_MODELS } from '../../catalogs/face-recognition-models.js'\nimport { cropRegion, resizeAndNormalize } from '../../shared/image-utils.js'\nimport { l2Normalize } from '../../shared/postprocess/arcface.js'\nimport { resolveEngine } from '../../shared/engine-resolver.js'\n\nconst IDENTITY_LABEL: LabelDefinition = { id: 'identity', name: 'Identity' }\nconst IDENTITY_LABELS: readonly LabelDefinition[] = [IDENTITY_LABEL]\nconst FACE_REC_CLASS_MAP: ClassMapDefinition = { mapping: {}, preserveOriginal: true }\n\nconst REQUIRED_STEPS: readonly RequiredStep[] = [\n { slot: 'cropper', outputClasses: ['face'], description: 'Requires a face detector' },\n]\n\nexport default class FaceRecognitionAddon implements IClassifierProvider, IDetectionAddon {\n readonly id = 'face-recognition'\n readonly slot = 'classifier' as const\n readonly inputClasses = ['face'] as const\n readonly outputClasses = ['identity:*'] as const\n readonly slotPriority = 0\n readonly requiredSteps = REQUIRED_STEPS\n readonly manifest: AddonManifest = {\n id: 'face-recognition',\n name: 'Face Recognition',\n version: '0.1.0',\n description: 'ArcFace-based face recognition — produces 512-d identity embeddings',\n packageName: '@camstack/addon-vision',\n slot: 'classifier',\n inputClasses: ['face'],\n outputClasses: ['identity:*'],\n requiredSteps: REQUIRED_STEPS,\n supportsCustomModels: false,\n mayRequirePython: false,\n defaultConfig: {\n modelId: 'arcface-r100',\n runtime: 'auto',\n backend: 'cpu',\n },\n }\n\n private engine!: IInferenceEngine\n private modelEntry!: ModelCatalogEntry\n\n async initialize(ctx: AddonContext): Promise<void> {\n const cfg = ctx.addonConfig\n const modelId = (cfg['modelId'] as string | undefined) ?? 'arcface-r100'\n const runtime = (cfg['runtime'] as string | undefined) ?? 'auto'\n const backend = (cfg['backend'] as string | undefined) ?? 'cpu'\n\n const entry = FACE_RECOGNITION_MODELS.find((m) => m.id === modelId)\n if (!entry) {\n throw new Error(`FaceRecognitionAddon: unknown modelId \"${modelId}\"`)\n }\n this.modelEntry = entry\n\n const resolved = await resolveEngine({\n runtime: runtime as 'auto',\n backend,\n modelEntry: entry,\n modelsDir: ctx.locationPaths.models,\n })\n this.engine = resolved.engine\n }\n\n async classify(input: CropInput): Promise<ClassifierOutput> {\n const start = Date.now()\n const { width: inputW, height: inputH } = this.modelEntry.inputSize\n\n // Crop the face region\n const faceCrop = await cropRegion(input.frame.data, input.roi)\n\n // Resize to 112x112, NHWC layout (ArcFace expects NHWC)\n const layout = this.modelEntry.inputLayout ?? 'nhwc'\n const normalization = this.modelEntry.inputNormalization ?? 'zero-one'\n const normalized = await resizeAndNormalize(faceCrop, inputW, inputH, normalization, layout)\n\n // Run inference — output is 512-d embedding\n const rawEmbedding = await this.engine.run(normalized, [1, inputH, inputW, 3])\n\n // L2 normalize the embedding\n const embedding = l2Normalize(rawEmbedding)\n\n return {\n classifications: [\n {\n class: 'identity',\n score: 1.0,\n embedding,\n },\n ],\n inferenceMs: Date.now() - start,\n modelId: this.modelEntry.id,\n }\n }\n\n async shutdown(): Promise<void> {\n await this.engine?.dispose()\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'model',\n title: 'Model',\n columns: 1,\n fields: [\n {\n key: 'modelId',\n label: 'Model',\n type: 'model-selector',\n catalog: [...FACE_RECOGNITION_MODELS],\n allowCustom: false,\n allowConversion: false,\n acceptFormats: ['onnx', 'coreml', 'openvino'],\n requiredMetadata: ['inputSize', 'labels', 'outputFormat'],\n outputFormatHint: 'embedding',\n },\n ],\n },\n {\n id: 'runtime',\n title: 'Runtime',\n columns: 2,\n fields: [\n {\n key: 'runtime',\n label: 'Runtime',\n type: 'select',\n options: [\n { value: 'auto', label: 'Auto (recommended)' },\n { value: 'onnx', label: 'ONNX Runtime' },\n { value: 'coreml', label: 'CoreML (Apple)' },\n ],\n },\n {\n key: 'backend',\n label: 'Backend',\n type: 'select',\n dependsOn: { runtime: 'onnx' },\n options: [\n { value: 'cpu', label: 'CPU' },\n { value: 'coreml', label: 'CoreML' },\n { value: 'cuda', label: 'CUDA (NVIDIA)' },\n ],\n },\n ],\n },\n ],\n }\n }\n\n getClassMap(): ClassMapDefinition {\n return FACE_REC_CLASS_MAP\n }\n\n getModelCatalog(): ModelCatalogEntry[] {\n return [...FACE_RECOGNITION_MODELS]\n }\n\n getAvailableModels(): DetectionModel[] {\n return []\n }\n\n getActiveLabels(): readonly LabelDefinition[] {\n return IDENTITY_LABELS\n }\n\n async probe(): Promise<ProbeResult> {\n return {\n available: true,\n runtime: this.engine?.runtime ?? 'onnx',\n device: this.engine?.device ?? 'cpu',\n capabilities: ['fp32'],\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// src/addons/camera-native-detection/index.ts
|
|
2
|
+
var NATIVE_LABELS = [
|
|
3
|
+
{ id: "person", name: "Person" },
|
|
4
|
+
{ id: "vehicle", name: "Vehicle" },
|
|
5
|
+
{ id: "motion", name: "Motion" },
|
|
6
|
+
{ id: "face", name: "Face" }
|
|
7
|
+
];
|
|
8
|
+
var NATIVE_CLASS_MAP = { mapping: {}, preserveOriginal: true };
|
|
9
|
+
var CameraNativeDetectionAddon = class {
|
|
10
|
+
id = "camera-native-detection";
|
|
11
|
+
slot = "detector";
|
|
12
|
+
inputClasses = null;
|
|
13
|
+
outputClasses = ["person", "vehicle", "motion", "face"];
|
|
14
|
+
slotPriority = 5;
|
|
15
|
+
manifest = {
|
|
16
|
+
id: "camera-native-detection",
|
|
17
|
+
name: "Camera Native Detection",
|
|
18
|
+
version: "0.1.0",
|
|
19
|
+
description: "Passthrough adapter for camera-native events (Frigate, Scrypted, ONVIF) \u2014 no inference engine",
|
|
20
|
+
packageName: "@camstack/addon-vision",
|
|
21
|
+
slot: "detector",
|
|
22
|
+
inputClasses: void 0,
|
|
23
|
+
outputClasses: ["person", "vehicle", "motion", "face"],
|
|
24
|
+
supportsCustomModels: false,
|
|
25
|
+
mayRequirePython: false,
|
|
26
|
+
defaultConfig: {}
|
|
27
|
+
};
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
29
|
+
async initialize(_ctx) {
|
|
30
|
+
}
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
32
|
+
async detect(_frame) {
|
|
33
|
+
return {
|
|
34
|
+
detections: [],
|
|
35
|
+
inferenceMs: 0,
|
|
36
|
+
modelId: "camera-native"
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async shutdown() {
|
|
40
|
+
}
|
|
41
|
+
getConfigSchema() {
|
|
42
|
+
return {
|
|
43
|
+
sections: [
|
|
44
|
+
{
|
|
45
|
+
id: "info",
|
|
46
|
+
title: "Camera Native Detection",
|
|
47
|
+
description: "This addon forwards detections from native camera events (Frigate webhooks, Scrypted push notifications, ONVIF events). No configuration required.",
|
|
48
|
+
fields: []
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
getClassMap() {
|
|
54
|
+
return NATIVE_CLASS_MAP;
|
|
55
|
+
}
|
|
56
|
+
getModelCatalog() {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
getAvailableModels() {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
getActiveLabels() {
|
|
63
|
+
return NATIVE_LABELS;
|
|
64
|
+
}
|
|
65
|
+
async probe() {
|
|
66
|
+
return {
|
|
67
|
+
available: true,
|
|
68
|
+
runtime: "onnx",
|
|
69
|
+
// no runtime used; satisfies the type
|
|
70
|
+
device: "cpu",
|
|
71
|
+
capabilities: ["fp32"]
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export {
|
|
77
|
+
CameraNativeDetectionAddon
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=chunk-DTOAB2CE.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/addons/camera-native-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} from '@camstack/types'\n\n// Labels reported by cameras natively (a superset across manufacturers)\nconst NATIVE_LABELS: readonly LabelDefinition[] = [\n { id: 'person', name: 'Person' },\n { id: 'vehicle', name: 'Vehicle' },\n { id: 'motion', name: 'Motion' },\n { id: 'face', name: 'Face' },\n] as const\n\nconst NATIVE_CLASS_MAP: ClassMapDefinition = { mapping: {}, preserveOriginal: true }\n\n/**\n * CameraNativeDetectionAddon\n *\n * A stub detector that wraps native camera event subscriptions (e.g. Frigate / Scrypted\n * webhooks). The detect() method always returns empty — real detections are delivered\n * asynchronously via external event subscriptions which should populate the pipeline\n * from outside this addon's detect() call.\n *\n * This addon exists so the pipeline can declare a 'detector' slot backed by camera events\n * without requiring any inference model.\n */\nexport default class CameraNativeDetectionAddon implements IDetectorProvider, IDetectionAddon {\n readonly id = 'camera-native-detection'\n readonly slot = 'detector' as const\n readonly inputClasses: readonly string[] | null = null\n readonly outputClasses = ['person', 'vehicle', 'motion', 'face'] as const\n readonly slotPriority = 5\n readonly manifest: AddonManifest = {\n id: 'camera-native-detection',\n name: 'Camera Native Detection',\n version: '0.1.0',\n description:\n 'Passthrough adapter for camera-native events (Frigate, Scrypted, ONVIF) — no inference engine',\n packageName: '@camstack/addon-vision',\n slot: 'detector',\n inputClasses: undefined,\n outputClasses: ['person', 'vehicle', 'motion', 'face'],\n supportsCustomModels: false,\n mayRequirePython: false,\n defaultConfig: {},\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async initialize(_ctx: AddonContext): Promise<void> {\n // No engine to initialize — events come from external subscriptions\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n async detect(_frame: FrameInput): Promise<DetectorOutput> {\n // Real detections are delivered via event subscriptions, not through detect().\n // This method intentionally returns empty.\n return {\n detections: [],\n inferenceMs: 0,\n modelId: 'camera-native',\n }\n }\n\n async shutdown(): Promise<void> {\n // Nothing to tear down\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'info',\n title: 'Camera Native Detection',\n description:\n 'This addon forwards detections from native camera events (Frigate webhooks, ' +\n 'Scrypted push notifications, ONVIF events). No configuration required.',\n fields: [],\n },\n ],\n }\n }\n\n getClassMap(): ClassMapDefinition {\n return NATIVE_CLASS_MAP\n }\n\n getModelCatalog(): ModelCatalogEntry[] {\n return []\n }\n\n getAvailableModels(): DetectionModel[] {\n return []\n }\n\n getActiveLabels(): readonly LabelDefinition[] {\n return NATIVE_LABELS\n }\n\n async probe(): Promise<ProbeResult> {\n return {\n available: true,\n runtime: 'onnx', // no runtime used; satisfies the type\n device: 'cpu',\n capabilities: ['fp32'],\n }\n }\n}\n"],"mappings":";AAgBA,IAAM,gBAA4C;AAAA,EAChD,EAAE,IAAI,UAAU,MAAM,SAAS;AAAA,EAC/B,EAAE,IAAI,WAAW,MAAM,UAAU;AAAA,EACjC,EAAE,IAAI,UAAU,MAAM,SAAS;AAAA,EAC/B,EAAE,IAAI,QAAQ,MAAM,OAAO;AAC7B;AAEA,IAAM,mBAAuC,EAAE,SAAS,CAAC,GAAG,kBAAkB,KAAK;AAanF,IAAqB,6BAArB,MAA8F;AAAA,EACnF,KAAK;AAAA,EACL,OAAO;AAAA,EACP,eAAyC;AAAA,EACzC,gBAAgB,CAAC,UAAU,WAAW,UAAU,MAAM;AAAA,EACtD,eAAe;AAAA,EACf,WAA0B;AAAA,IACjC,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,MAAM;AAAA,IACN,cAAc;AAAA,IACd,eAAe,CAAC,UAAU,WAAW,UAAU,MAAM;AAAA,IACrD,sBAAsB;AAAA,IACtB,kBAAkB;AAAA,IAClB,eAAe,CAAC;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,WAAW,MAAmC;AAAA,EAEpD;AAAA;AAAA,EAGA,MAAM,OAAO,QAA6C;AAGxD,WAAO;AAAA,MACL,YAAY,CAAC;AAAA,MACb,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,WAA0B;AAAA,EAEhC;AAAA,EAEA,kBAAkC;AAChC,WAAO;AAAA,MACL,UAAU;AAAA,QACR;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,aACE;AAAA,UAEF,QAAQ,CAAC;AAAA,QACX;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":[]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// src/catalogs/animal-classification-models.ts
|
|
2
|
+
import { hfModelUrl } from "@camstack/types";
|
|
3
|
+
var HF_REPO = "camstack/camstack-models";
|
|
4
|
+
var hf = (path) => hfModelUrl(HF_REPO, path);
|
|
5
|
+
var BIRD_LABEL = { id: "species", name: "Bird Species" };
|
|
6
|
+
var ANIMAL_TYPE_LABEL = { id: "animal-type", name: "Animal Type" };
|
|
7
|
+
var BIRD_SPECIES_MODELS = [
|
|
8
|
+
{
|
|
9
|
+
id: "bird-species-525",
|
|
10
|
+
name: "Bird Species (525)",
|
|
11
|
+
description: "EfficientNet bird species classifier \u2014 525 species, MIT license",
|
|
12
|
+
inputSize: { width: 224, height: 224 },
|
|
13
|
+
inputNormalization: "imagenet",
|
|
14
|
+
labels: [BIRD_LABEL],
|
|
15
|
+
formats: {
|
|
16
|
+
onnx: { url: hf("animalClassification/bird-species/onnx/camstack-bird-species-525.onnx"), sizeMB: 32 }
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
];
|
|
20
|
+
var BIRD_NABIRDS_MODELS = [
|
|
21
|
+
{
|
|
22
|
+
id: "bird-nabirds-404",
|
|
23
|
+
name: "NABirds (404 species)",
|
|
24
|
+
description: "ResNet50 trained on NABirds \u2014 404 North American species with ONNX, CoreML, OpenVINO",
|
|
25
|
+
inputSize: { width: 224, height: 224 },
|
|
26
|
+
inputNormalization: "imagenet",
|
|
27
|
+
labels: [{ id: "species", name: "Bird Species" }],
|
|
28
|
+
formats: {
|
|
29
|
+
onnx: { url: hf("animalClassification/bird-nabirds/onnx/camstack-bird-nabirds-404.onnx"), sizeMB: 93 },
|
|
30
|
+
coreml: { url: hf("animalClassification/bird-nabirds/coreml/camstack-bird-nabirds-404.mlpackage"), sizeMB: 47 },
|
|
31
|
+
openvino: { url: hf("animalClassification/bird-nabirds/openvino/camstack-bird-nabirds-404.xml"), sizeMB: 47 }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
];
|
|
35
|
+
var ANIMAL_TYPE_MODELS = [
|
|
36
|
+
{
|
|
37
|
+
id: "animals-10",
|
|
38
|
+
name: "Animal Classifier (10)",
|
|
39
|
+
description: "ViT-based animal type classifier \u2014 cat, cow, dog, dolphin, eagle, panda, horse, monkey, sheep, spider",
|
|
40
|
+
inputSize: { width: 224, height: 224 },
|
|
41
|
+
inputNormalization: "imagenet",
|
|
42
|
+
labels: [ANIMAL_TYPE_LABEL],
|
|
43
|
+
formats: {
|
|
44
|
+
onnx: { url: hf("animalClassification/animals-10/onnx/camstack-animals-10.onnx"), sizeMB: 328 }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
BIRD_SPECIES_MODELS,
|
|
51
|
+
BIRD_NABIRDS_MODELS,
|
|
52
|
+
ANIMAL_TYPE_MODELS
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=chunk-ISOIDU4U.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/catalogs/animal-classification-models.ts"],"sourcesContent":["import type { ModelCatalogEntry, LabelDefinition } from '@camstack/types'\nimport { hfModelUrl } from '@camstack/types'\n\nconst HF_REPO = 'camstack/camstack-models'\n\nconst hf = (path: string) => hfModelUrl(HF_REPO, path)\n\nconst BIRD_LABEL: LabelDefinition = { id: 'species', name: 'Bird Species' }\nconst ANIMAL_TYPE_LABEL: LabelDefinition = { id: 'animal-type', name: 'Animal Type' }\n\nexport const BIRD_SPECIES_MODELS: readonly ModelCatalogEntry[] = [\n {\n id: 'bird-species-525',\n name: 'Bird Species (525)',\n description: 'EfficientNet bird species classifier — 525 species, MIT license',\n inputSize: { width: 224, height: 224 },\n inputNormalization: 'imagenet',\n labels: [BIRD_LABEL],\n formats: {\n onnx: { url: hf('animalClassification/bird-species/onnx/camstack-bird-species-525.onnx'), sizeMB: 32 },\n },\n },\n] as const\n\nexport const BIRD_NABIRDS_MODELS: readonly ModelCatalogEntry[] = [\n {\n id: 'bird-nabirds-404',\n name: 'NABirds (404 species)',\n description: 'ResNet50 trained on NABirds — 404 North American species with ONNX, CoreML, OpenVINO',\n inputSize: { width: 224, height: 224 },\n inputNormalization: 'imagenet',\n labels: [{ id: 'species', name: 'Bird Species' }],\n formats: {\n onnx: { url: hf('animalClassification/bird-nabirds/onnx/camstack-bird-nabirds-404.onnx'), sizeMB: 93 },\n coreml: { url: hf('animalClassification/bird-nabirds/coreml/camstack-bird-nabirds-404.mlpackage'), sizeMB: 47 },\n openvino: { url: hf('animalClassification/bird-nabirds/openvino/camstack-bird-nabirds-404.xml'), sizeMB: 47 },\n },\n },\n] as const\n\nexport const ANIMAL_TYPE_MODELS: readonly ModelCatalogEntry[] = [\n {\n id: 'animals-10',\n name: 'Animal Classifier (10)',\n description: 'ViT-based animal type classifier — cat, cow, dog, dolphin, eagle, panda, horse, monkey, sheep, spider',\n inputSize: { width: 224, height: 224 },\n inputNormalization: 'imagenet',\n labels: [ANIMAL_TYPE_LABEL],\n formats: {\n onnx: { url: hf('animalClassification/animals-10/onnx/camstack-animals-10.onnx'), sizeMB: 328 },\n },\n },\n] as const\n"],"mappings":";AACA,SAAS,kBAAkB;AAE3B,IAAM,UAAU;AAEhB,IAAM,KAAK,CAAC,SAAiB,WAAW,SAAS,IAAI;AAErD,IAAM,aAA8B,EAAE,IAAI,WAAW,MAAM,eAAe;AAC1E,IAAM,oBAAqC,EAAE,IAAI,eAAe,MAAM,cAAc;AAE7E,IAAM,sBAAoD;AAAA,EAC/D;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,IACrC,oBAAoB;AAAA,IACpB,QAAQ,CAAC,UAAU;AAAA,IACnB,SAAS;AAAA,MACP,MAAM,EAAE,KAAK,GAAG,uEAAuE,GAAG,QAAQ,GAAG;AAAA,IACvG;AAAA,EACF;AACF;AAEO,IAAM,sBAAoD;AAAA,EAC/D;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,IACrC,oBAAoB;AAAA,IACpB,QAAQ,CAAC,EAAE,IAAI,WAAW,MAAM,eAAe,CAAC;AAAA,IAChD,SAAS;AAAA,MACP,MAAM,EAAE,KAAK,GAAG,uEAAuE,GAAG,QAAQ,GAAG;AAAA,MACrG,QAAQ,EAAE,KAAK,GAAG,8EAA8E,GAAG,QAAQ,GAAG;AAAA,MAC9G,UAAU,EAAE,KAAK,GAAG,0EAA0E,GAAG,QAAQ,GAAG;AAAA,IAC9G;AAAA,EACF;AACF;AAEO,IAAM,qBAAmD;AAAA,EAC9D;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,IACrC,oBAAoB;AAAA,IACpB,QAAQ,CAAC,iBAAiB;AAAA,IAC1B,SAAS;AAAA,MACP,MAAM,EAAE,KAAK,GAAG,+DAA+D,GAAG,QAAQ,IAAI;AAAA,IAChG;AAAA,EACF;AACF;","names":[]}
|