tempest-react-sdk 0.57.0 → 0.59.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/README.md +14 -2
- package/bin/lib/css/findings.mjs +1 -0
- package/bin/lib/css/semantic.mjs +70 -6
- package/bin/lib/css/semantic.test.mjs +52 -1
- package/bin/lib/icons/generate.test.mjs +4 -4
- package/dist/br/geocode.cjs +1 -1
- package/dist/br/geocode.cjs.map +1 -1
- package/dist/br/geocode.js +1 -1
- package/dist/br/geocode.js.map +1 -1
- package/dist/capture/use-barcode-scanner.cjs +1 -1
- package/dist/capture/use-barcode-scanner.cjs.map +1 -1
- package/dist/capture/use-barcode-scanner.js +1 -1
- package/dist/capture/use-barcode-scanner.js.map +1 -1
- package/dist/components/AIChat/AIChat.cjs +1 -1
- package/dist/components/AIChat/AIChat.cjs.map +1 -1
- package/dist/components/AIChat/AIChat.js +1 -1
- package/dist/components/AIChat/AIChat.js.map +1 -1
- package/dist/components/AIChat/AIChatTurn.cjs +1 -1
- package/dist/components/AIChat/AIChatTurn.cjs.map +1 -1
- package/dist/components/AIChat/AIChatTurn.js +1 -1
- package/dist/components/AIChat/AIChatTurn.js.map +1 -1
- package/dist/components/Alert/Alert.module.cjs.map +1 -1
- package/dist/components/Alert/Alert.module.js.map +1 -1
- package/dist/components/AppBar/use-sticky-body-warning.cjs +1 -1
- package/dist/components/AppBar/use-sticky-body-warning.cjs.map +1 -1
- package/dist/components/AppBar/use-sticky-body-warning.js +1 -1
- package/dist/components/AppBar/use-sticky-body-warning.js.map +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.cjs +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.cjs.map +1 -1
- package/dist/components/AudioPlayer/AudioPlayer.js +2 -2
- package/dist/components/AudioPlayer/AudioPlayer.js.map +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.cjs +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.cjs.map +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.js +1 -1
- package/dist/components/AudioRecorder/AudioRecorder.js.map +1 -1
- package/dist/components/Badge/Badge.module.cjs.map +1 -1
- package/dist/components/Badge/Badge.module.js.map +1 -1
- package/dist/components/BarList/BarList.module.cjs.map +1 -1
- package/dist/components/BarList/BarList.module.js.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.module.cjs.map +1 -1
- package/dist/components/BottomSheet/BottomSheet.module.js.map +1 -1
- package/dist/components/Chat/Chat.cjs +1 -1
- package/dist/components/Chat/Chat.cjs.map +1 -1
- package/dist/components/Chat/Chat.js +1 -1
- package/dist/components/Chat/Chat.js.map +1 -1
- package/dist/components/DataTable/DataTable.module.cjs.map +1 -1
- package/dist/components/DataTable/DataTable.module.js.map +1 -1
- package/dist/components/Dropzone/Dropzone.module.cjs.map +1 -1
- package/dist/components/Dropzone/Dropzone.module.js.map +1 -1
- package/dist/components/ErrorText/ErrorText.module.cjs.map +1 -1
- package/dist/components/ErrorText/ErrorText.module.js.map +1 -1
- package/dist/components/FilterBar/FilterBar.cjs +1 -1
- package/dist/components/FilterBar/FilterBar.cjs.map +1 -1
- package/dist/components/FilterBar/FilterBar.js +1 -1
- package/dist/components/FilterBar/FilterBar.js.map +1 -1
- package/dist/components/FilterBar/filter-apply.cjs +1 -1
- package/dist/components/FilterBar/filter-apply.cjs.map +1 -1
- package/dist/components/FilterBar/filter-apply.js +1 -1
- package/dist/components/FilterBar/filter-apply.js.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.cjs +1 -1
- package/dist/components/ImageCropper/ImageCropper.cjs.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.js +1 -1
- package/dist/components/ImageCropper/ImageCropper.js.map +1 -1
- package/dist/components/Markdown/Markdown.module.cjs.map +1 -1
- package/dist/components/Markdown/Markdown.module.js.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.module.cjs.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.module.js.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.module.cjs.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.module.js.map +1 -1
- package/dist/components/Sidebar/Sidebar.module.cjs.map +1 -1
- package/dist/components/Sidebar/Sidebar.module.js.map +1 -1
- package/dist/components/StepperInput/StepperInput.module.cjs.map +1 -1
- package/dist/components/StepperInput/StepperInput.module.js.map +1 -1
- package/dist/components/Tag/Tag.module.cjs.map +1 -1
- package/dist/components/Tag/Tag.module.js.map +1 -1
- package/dist/components/Timeline/Timeline.module.cjs.map +1 -1
- package/dist/components/Timeline/Timeline.module.js.map +1 -1
- package/dist/components/Toggle/Toggle.module.cjs.map +1 -1
- package/dist/components/Toggle/Toggle.module.js.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.module.cjs.map +1 -1
- package/dist/components/ToggleGroup/ToggleGroup.module.js.map +1 -1
- package/dist/components/VideoPlayer/VideoPlayer.cjs +1 -1
- package/dist/components/VideoPlayer/VideoPlayer.cjs.map +1 -1
- package/dist/components/VideoPlayer/VideoPlayer.js +2 -2
- package/dist/components/VideoPlayer/VideoPlayer.js.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.cjs +1 -1
- package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -1
- package/dist/components/VirtualTable/VirtualTable.js +1 -1
- package/dist/components/VirtualTable/VirtualTable.js.map +1 -1
- package/dist/feature-flags/growthbook-adapter.cjs +1 -1
- package/dist/feature-flags/growthbook-adapter.cjs.map +1 -1
- package/dist/feature-flags/growthbook-adapter.js +1 -1
- package/dist/feature-flags/growthbook-adapter.js.map +1 -1
- package/dist/hooks/use-focus-trap.cjs +1 -1
- package/dist/hooks/use-focus-trap.cjs.map +1 -1
- package/dist/hooks/use-focus-trap.js +1 -1
- package/dist/hooks/use-focus-trap.js.map +1 -1
- package/dist/hooks/use-push-to-talk.cjs +1 -1
- package/dist/hooks/use-push-to-talk.cjs.map +1 -1
- package/dist/hooks/use-push-to-talk.js +1 -1
- package/dist/hooks/use-push-to-talk.js.map +1 -1
- package/dist/http/describe-api-error.cjs +1 -1
- package/dist/http/describe-api-error.cjs.map +1 -1
- package/dist/http/describe-api-error.js +12 -8
- package/dist/http/describe-api-error.js.map +1 -1
- package/dist/http/errors.cjs +1 -1
- package/dist/http/errors.cjs.map +1 -1
- package/dist/http/errors.js +21 -16
- package/dist/http/errors.js.map +1 -1
- package/dist/http/resumable-upload.cjs +1 -1
- package/dist/http/resumable-upload.cjs.map +1 -1
- package/dist/http/resumable-upload.js +1 -1
- package/dist/http/resumable-upload.js.map +1 -1
- package/dist/icons/generated/aliases.cjs +1 -1
- package/dist/icons/generated/aliases.cjs.map +1 -1
- package/dist/icons/generated/aliases.js +1 -0
- package/dist/icons/generated/aliases.js.map +1 -1
- package/dist/icons/generated/icon-names.cjs +1 -1
- package/dist/icons/generated/icon-names.cjs.map +1 -1
- package/dist/icons/generated/icon-names.js +1 -1
- package/dist/icons/generated/icon-names.js.map +1 -1
- package/dist/icons/generated/loaders.cjs +1 -1
- package/dist/icons/generated/loaders.cjs.map +1 -1
- package/dist/icons/generated/loaders.js +48 -42
- package/dist/icons/generated/loaders.js.map +1 -1
- package/dist/icons/generated/shard-02.cjs +1 -1
- package/dist/icons/generated/shard-02.cjs.map +1 -1
- package/dist/icons/generated/shard-02.js +20 -20
- package/dist/icons/generated/shard-02.js.map +1 -1
- package/dist/icons/generated/shard-03.cjs +1 -1
- package/dist/icons/generated/shard-03.cjs.map +1 -1
- package/dist/icons/generated/shard-03.js +41 -41
- package/dist/icons/generated/shard-03.js.map +1 -1
- package/dist/icons/generated/shard-04.cjs +1 -1
- package/dist/icons/generated/shard-04.cjs.map +1 -1
- package/dist/icons/generated/shard-04.js +41 -41
- package/dist/icons/generated/shard-04.js.map +1 -1
- package/dist/icons/generated/shard-05.cjs +1 -1
- package/dist/icons/generated/shard-05.cjs.map +1 -1
- package/dist/icons/generated/shard-05.js +41 -41
- package/dist/icons/generated/shard-05.js.map +1 -1
- package/dist/icons/generated/shard-06.cjs +1 -1
- package/dist/icons/generated/shard-06.cjs.map +1 -1
- package/dist/icons/generated/shard-06.js +41 -41
- package/dist/icons/generated/shard-06.js.map +1 -1
- package/dist/icons/generated/shard-07.cjs +1 -1
- package/dist/icons/generated/shard-07.cjs.map +1 -1
- package/dist/icons/generated/shard-07.js +41 -41
- package/dist/icons/generated/shard-07.js.map +1 -1
- package/dist/icons/generated/shard-08.cjs +1 -1
- package/dist/icons/generated/shard-08.cjs.map +1 -1
- package/dist/icons/generated/shard-08.js +41 -41
- package/dist/icons/generated/shard-08.js.map +1 -1
- package/dist/icons/generated/shard-09.cjs +1 -1
- package/dist/icons/generated/shard-09.cjs.map +1 -1
- package/dist/icons/generated/shard-09.js +41 -41
- package/dist/icons/generated/shard-09.js.map +1 -1
- package/dist/icons/generated/shard-10.cjs +1 -1
- package/dist/icons/generated/shard-10.cjs.map +1 -1
- package/dist/icons/generated/shard-10.js +41 -41
- package/dist/icons/generated/shard-10.js.map +1 -1
- package/dist/icons/generated/shard-11.cjs +1 -1
- package/dist/icons/generated/shard-11.cjs.map +1 -1
- package/dist/icons/generated/shard-11.js +41 -41
- package/dist/icons/generated/shard-11.js.map +1 -1
- package/dist/icons/generated/shard-12.cjs +1 -1
- package/dist/icons/generated/shard-12.cjs.map +1 -1
- package/dist/icons/generated/shard-12.js +41 -41
- package/dist/icons/generated/shard-12.js.map +1 -1
- package/dist/icons/generated/shard-13.cjs +1 -1
- package/dist/icons/generated/shard-13.cjs.map +1 -1
- package/dist/icons/generated/shard-13.js +41 -41
- package/dist/icons/generated/shard-13.js.map +1 -1
- package/dist/icons/generated/shard-14.cjs +1 -1
- package/dist/icons/generated/shard-14.cjs.map +1 -1
- package/dist/icons/generated/shard-14.js +41 -41
- package/dist/icons/generated/shard-14.js.map +1 -1
- package/dist/icons/generated/shard-15.cjs +1 -1
- package/dist/icons/generated/shard-15.cjs.map +1 -1
- package/dist/icons/generated/shard-15.js +41 -41
- package/dist/icons/generated/shard-15.js.map +1 -1
- package/dist/icons/generated/shard-16.cjs +1 -1
- package/dist/icons/generated/shard-16.cjs.map +1 -1
- package/dist/icons/generated/shard-16.js +41 -41
- package/dist/icons/generated/shard-16.js.map +1 -1
- package/dist/icons/generated/shard-17.cjs +1 -1
- package/dist/icons/generated/shard-17.cjs.map +1 -1
- package/dist/icons/generated/shard-17.js +41 -41
- package/dist/icons/generated/shard-17.js.map +1 -1
- package/dist/icons/generated/shard-18.cjs +1 -1
- package/dist/icons/generated/shard-18.cjs.map +1 -1
- package/dist/icons/generated/shard-18.js +41 -41
- package/dist/icons/generated/shard-18.js.map +1 -1
- package/dist/icons/generated/shard-19.cjs +1 -1
- package/dist/icons/generated/shard-19.cjs.map +1 -1
- package/dist/icons/generated/shard-19.js +41 -41
- package/dist/icons/generated/shard-19.js.map +1 -1
- package/dist/icons/generated/shard-20.cjs +1 -1
- package/dist/icons/generated/shard-20.cjs.map +1 -1
- package/dist/icons/generated/shard-20.js +41 -41
- package/dist/icons/generated/shard-20.js.map +1 -1
- package/dist/icons/generated/shard-21.cjs +1 -1
- package/dist/icons/generated/shard-21.cjs.map +1 -1
- package/dist/icons/generated/shard-21.js +41 -41
- package/dist/icons/generated/shard-21.js.map +1 -1
- package/dist/icons/generated/shard-22.cjs +1 -1
- package/dist/icons/generated/shard-22.cjs.map +1 -1
- package/dist/icons/generated/shard-22.js +41 -41
- package/dist/icons/generated/shard-22.js.map +1 -1
- package/dist/icons/generated/shard-23.cjs +1 -1
- package/dist/icons/generated/shard-23.cjs.map +1 -1
- package/dist/icons/generated/shard-23.js +41 -41
- package/dist/icons/generated/shard-23.js.map +1 -1
- package/dist/icons/generated/shard-24.cjs +1 -1
- package/dist/icons/generated/shard-24.cjs.map +1 -1
- package/dist/icons/generated/shard-24.js +41 -41
- package/dist/icons/generated/shard-24.js.map +1 -1
- package/dist/icons/generated/shard-25.cjs +1 -1
- package/dist/icons/generated/shard-25.cjs.map +1 -1
- package/dist/icons/generated/shard-25.js +41 -41
- package/dist/icons/generated/shard-25.js.map +1 -1
- package/dist/icons/generated/shard-26.cjs +1 -1
- package/dist/icons/generated/shard-26.cjs.map +1 -1
- package/dist/icons/generated/shard-26.js +41 -41
- package/dist/icons/generated/shard-26.js.map +1 -1
- package/dist/icons/generated/shard-27.cjs +1 -1
- package/dist/icons/generated/shard-27.cjs.map +1 -1
- package/dist/icons/generated/shard-27.js +41 -41
- package/dist/icons/generated/shard-27.js.map +1 -1
- package/dist/icons/generated/shard-28.cjs +1 -1
- package/dist/icons/generated/shard-28.cjs.map +1 -1
- package/dist/icons/generated/shard-28.js +41 -41
- package/dist/icons/generated/shard-28.js.map +1 -1
- package/dist/icons/generated/shard-29.cjs +1 -1
- package/dist/icons/generated/shard-29.cjs.map +1 -1
- package/dist/icons/generated/shard-29.js +41 -41
- package/dist/icons/generated/shard-29.js.map +1 -1
- package/dist/icons/generated/shard-30.cjs +1 -1
- package/dist/icons/generated/shard-30.cjs.map +1 -1
- package/dist/icons/generated/shard-30.js +41 -41
- package/dist/icons/generated/shard-30.js.map +1 -1
- package/dist/icons/generated/shard-31.cjs +1 -1
- package/dist/icons/generated/shard-31.cjs.map +1 -1
- package/dist/icons/generated/shard-31.js +41 -41
- package/dist/icons/generated/shard-31.js.map +1 -1
- package/dist/icons/generated/shard-32.cjs +1 -1
- package/dist/icons/generated/shard-32.cjs.map +1 -1
- package/dist/icons/generated/shard-32.js +41 -41
- package/dist/icons/generated/shard-32.js.map +1 -1
- package/dist/icons/generated/shard-33.cjs +1 -1
- package/dist/icons/generated/shard-33.cjs.map +1 -1
- package/dist/icons/generated/shard-33.js +41 -41
- package/dist/icons/generated/shard-33.js.map +1 -1
- package/dist/icons/generated/shard-34.cjs +1 -1
- package/dist/icons/generated/shard-34.cjs.map +1 -1
- package/dist/icons/generated/shard-34.js +41 -41
- package/dist/icons/generated/shard-34.js.map +1 -1
- package/dist/icons/generated/shard-35.cjs +1 -1
- package/dist/icons/generated/shard-35.cjs.map +1 -1
- package/dist/icons/generated/shard-35.js +41 -41
- package/dist/icons/generated/shard-35.js.map +1 -1
- package/dist/icons/generated/shard-36.cjs +1 -1
- package/dist/icons/generated/shard-36.cjs.map +1 -1
- package/dist/icons/generated/shard-36.js +41 -41
- package/dist/icons/generated/shard-36.js.map +1 -1
- package/dist/icons/generated/shard-37.cjs +1 -1
- package/dist/icons/generated/shard-37.cjs.map +1 -1
- package/dist/icons/generated/shard-37.js +41 -41
- package/dist/icons/generated/shard-37.js.map +1 -1
- package/dist/icons/generated/shard-38.cjs +1 -1
- package/dist/icons/generated/shard-38.cjs.map +1 -1
- package/dist/icons/generated/shard-38.js +41 -41
- package/dist/icons/generated/shard-38.js.map +1 -1
- package/dist/icons/generated/shard-39.cjs +1 -1
- package/dist/icons/generated/shard-39.cjs.map +1 -1
- package/dist/icons/generated/shard-39.js +41 -41
- package/dist/icons/generated/shard-39.js.map +1 -1
- package/dist/icons/generated/shard-40.cjs +1 -1
- package/dist/icons/generated/shard-40.cjs.map +1 -1
- package/dist/icons/generated/shard-40.js +41 -41
- package/dist/icons/generated/shard-40.js.map +1 -1
- package/dist/icons/generated/shard-41.cjs +1 -1
- package/dist/icons/generated/shard-41.cjs.map +1 -1
- package/dist/icons/generated/shard-41.js +41 -41
- package/dist/icons/generated/shard-41.js.map +1 -1
- package/dist/icons/generated/shard-42.cjs +1 -1
- package/dist/icons/generated/shard-42.cjs.map +1 -1
- package/dist/icons/generated/shard-42.js +41 -41
- package/dist/icons/generated/shard-42.js.map +1 -1
- package/dist/icons/generated/shard-43.cjs +1 -1
- package/dist/icons/generated/shard-43.cjs.map +1 -1
- package/dist/icons/generated/shard-43.js +41 -41
- package/dist/icons/generated/shard-43.js.map +1 -1
- package/dist/icons/generated/shard-44.cjs +1 -1
- package/dist/icons/generated/shard-44.cjs.map +1 -1
- package/dist/icons/generated/shard-44.js +43 -10
- package/dist/icons/generated/shard-44.js.map +1 -1
- package/dist/icons/generated/shard-45.cjs +2 -0
- package/dist/icons/generated/shard-45.cjs.map +1 -0
- package/dist/icons/generated/shard-45.js +15 -0
- package/dist/icons/generated/shard-45.js.map +1 -0
- package/dist/icons/material-symbols.cjs +1 -1
- package/dist/icons/material-symbols.cjs.map +1 -1
- package/dist/icons/material-symbols.js +3 -3
- package/dist/icons/material-symbols.js.map +1 -1
- package/dist/icons.d.ts +4 -4
- package/dist/query/foreign-client-warning.cjs +1 -1
- package/dist/query/foreign-client-warning.cjs.map +1 -1
- package/dist/query/foreign-client-warning.js +1 -1
- package/dist/query/foreign-client-warning.js.map +1 -1
- package/dist/styles/Alert.css +1 -1
- package/dist/styles/Badge.css +1 -1
- package/dist/styles/BarList.css +3 -3
- package/dist/styles/BottomSheet.css +1 -1
- package/dist/styles/DataTable.css +1 -1
- package/dist/styles/Dropzone.css +1 -1
- package/dist/styles/ErrorText.css +1 -1
- package/dist/styles/Markdown.css +1 -1
- package/dist/styles/PasswordInput.css +1 -1
- package/dist/styles/SegmentedControl.css +1 -1
- package/dist/styles/Sidebar.css +2 -2
- package/dist/styles/StepperInput.css +1 -1
- package/dist/styles/Tag.css +1 -1
- package/dist/styles/Timeline.css +1 -1
- package/dist/styles/Toggle.css +1 -1
- package/dist/styles/ToggleGroup.css +1 -1
- package/dist/styles/advanced.css +2 -2
- package/dist/styles/core.css +4 -2
- package/dist/styles/data.css +6 -6
- package/dist/styles/feedback.css +3 -3
- package/dist/styles/forms.css +3 -3
- package/dist/styles/navigation.css +3 -3
- package/dist/styles/overlay.css +1 -1
- package/dist/styles/utility.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/tempest-react-sdk.cjs +1 -1
- package/dist/tempest-react-sdk.d.ts +81 -7
- package/dist/tempest-react-sdk.js +347 -346
- package/dist/theme/create-theme.cjs +3 -3
- package/dist/theme/create-theme.cjs.map +1 -1
- package/dist/theme/create-theme.js +15 -14
- package/dist/theme/create-theme.js.map +1 -1
- package/dist/utils/dev-mode.cjs +1 -1
- package/dist/utils/dev-mode.cjs.map +1 -1
- package/dist/utils/dev-mode.js +7 -2
- package/dist/utils/dev-mode.js.map +1 -1
- package/dist/utils/json-frame.cjs +1 -1
- package/dist/utils/json-frame.cjs.map +1 -1
- package/dist/utils/json-frame.js +1 -1
- package/dist/utils/json-frame.js.map +1 -1
- package/dist/vision/core/providers.cjs +1 -1
- package/dist/vision/core/providers.cjs.map +1 -1
- package/dist/vision/core/providers.js +22 -3
- package/dist/vision/core/providers.js.map +1 -1
- package/dist/vision/core/session.cjs +1 -1
- package/dist/vision/core/session.cjs.map +1 -1
- package/dist/vision/core/session.js +22 -15
- package/dist/vision/core/session.js.map +1 -1
- package/dist/vision/fusion.cjs.map +1 -1
- package/dist/vision/fusion.js.map +1 -1
- package/dist/vision/index.cjs +1 -1
- package/dist/vision/index.cjs.map +1 -1
- package/dist/vision/index.js +17 -16
- package/dist/vision/index.js.map +1 -1
- package/dist/vision/normalization.cjs +2 -0
- package/dist/vision/normalization.cjs.map +1 -0
- package/dist/vision/normalization.js +49 -0
- package/dist/vision/normalization.js.map +1 -0
- package/dist/vision/results.cjs +1 -1
- package/dist/vision/results.cjs.map +1 -1
- package/dist/vision/results.js +8 -2
- package/dist/vision/results.js.map +1 -1
- package/dist/vision/tasks/classifier.cjs +1 -1
- package/dist/vision/tasks/classifier.cjs.map +1 -1
- package/dist/vision/tasks/classifier.js +36 -32
- package/dist/vision/tasks/classifier.js.map +1 -1
- package/dist/vision.cjs +1 -1
- package/dist/vision.d.ts +218 -13
- package/dist/vision.js +19 -18
- package/dist/vite/tempest-pwa-manifest.cjs +1 -1
- package/dist/vite/tempest-pwa-manifest.cjs.map +1 -1
- package/dist/vite/tempest-pwa-manifest.js +1 -1
- package/dist/vite/tempest-pwa-manifest.js.map +1 -1
- package/dist/webrtc/peer-link.cjs +1 -1
- package/dist/webrtc/peer-link.cjs.map +1 -1
- package/dist/webrtc/peer-link.js +1 -1
- package/dist/webrtc/peer-link.js.map +1 -1
- package/dist/webrtc/peer-mesh.cjs +1 -1
- package/dist/webrtc/peer-mesh.cjs.map +1 -1
- package/dist/webrtc/peer-mesh.js +1 -1
- package/dist/webrtc/peer-mesh.js.map +1 -1
- package/dist/ws/create-web-socket.cjs +1 -1
- package/dist/ws/create-web-socket.cjs.map +1 -1
- package/dist/ws/create-web-socket.js +1 -1
- package/dist/ws/create-web-socket.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"results.cjs","names":[],"sources":["../../src/vision/results.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Per-image result envelopes — Ultralytics-style `Results` for the SDK.\n *\n * Each `predict()` call returns a 1-element array of these envelopes,\n * mirroring `YOLO(\"img.jpg\")`. Each envelope holds:\n *\n * - A bulk-array view of the predictions (`Boxes`, `Probs`, `Masks`) with\n * the exact attribute names Ultralytics uses (`xyxy`, `xywh`, `xyxyn`,\n * `xywhn`, `cls`, `conf`, `data`, `top1`, `top5`).\n * - Per-instance dataclasses (`DetectionResult`, `SegmentationResult`,\n * `ClassProbability`) for callers who prefer the OO interface.\n * - `names`: `Record<number, string>` matching Ultralytics' `model.names`.\n * - `origImg` / `origShape` / `path`: provenance for the original input.\n * - `speed`: per-stage timings of the `predict()` call that produced it.\n */\n\nimport { type Speed } from \"./core/timing\";\nimport {\n type ClassificationResult,\n type DetectionResult,\n type RGBImage,\n type SegmentationResult,\n} from \"./types\";\n\n/**\n * Zero timings for an envelope built outside a `predict()` call.\n *\n * Hand-constructed envelopes (tests, adapters) have nothing to measure, and\n * zeros keep `speed.inference` a plain `number` at every call site instead of\n * forcing an optional check that only ever fires for synthetic data.\n */\nconst NO_SPEED: Speed = { load: 0, preprocess: 0, inference: 0, postprocess: 0 };\n\n/**\n * Bulk numpy-style view of detected boxes for a single image.\n *\n * Mirrors Ultralytics' `Boxes` interface. Coordinates in {@link xyxy} and\n * {@link xywh} are absolute pixels in the original image; the `*n` variants\n * are normalized to `[0, 1]` using `origShape`.\n */\nexport class Boxes {\n /**\n * @param xyxy Flat array of length `4 * N` in `[x1, y1, x2, y2, ...]` order.\n * @param cls One class index per box, length `N`.\n * @param conf One confidence per box, length `N`.\n * @param origShape `[height, width]` of the original image.\n */\n constructor(\n public readonly xyxy: Float32Array,\n public readonly cls: Int32Array,\n public readonly conf: Float32Array,\n public readonly origShape: readonly [number, number],\n ) {}\n\n /** Number of detected boxes. */\n get length(): number {\n return this.cls.length;\n }\n\n /** `[N, 4]` shape of the `xyxy` view. */\n get shape(): readonly [number, number] {\n return [this.length, 4];\n }\n\n /** Boxes as `[N, 4]` `[cx, cy, w, h]` flat array in absolute pixels. */\n get xywh(): Float32Array {\n const out = new Float32Array(this.xyxy.length);\n for (let i = 0; i < this.length; i++) {\n const x1 = this.xyxy[i * 4] as number;\n const y1 = this.xyxy[i * 4 + 1] as number;\n const x2 = this.xyxy[i * 4 + 2] as number;\n const y2 = this.xyxy[i * 4 + 3] as number;\n out[i * 4] = (x1 + x2) / 2;\n out[i * 4 + 1] = (y1 + y2) / 2;\n out[i * 4 + 2] = x2 - x1;\n out[i * 4 + 3] = y2 - y1;\n }\n return out;\n }\n\n /** Boxes as `[N, 4]` `[x1, y1, x2, y2]` normalized to `[0, 1]`. */\n get xyxyn(): Float32Array {\n const [h, w] = this.origShape;\n const out = new Float32Array(this.xyxy.length);\n if (this.length === 0 || w <= 0 || h <= 0) return out;\n for (let i = 0; i < this.length; i++) {\n out[i * 4] = (this.xyxy[i * 4] as number) / w;\n out[i * 4 + 1] = (this.xyxy[i * 4 + 1] as number) / h;\n out[i * 4 + 2] = (this.xyxy[i * 4 + 2] as number) / w;\n out[i * 4 + 3] = (this.xyxy[i * 4 + 3] as number) / h;\n }\n return out;\n }\n\n /** Boxes as `[N, 4]` `[cx, cy, w, h]` normalized to `[0, 1]`. */\n get xywhn(): Float32Array {\n const xywh = this.xywh;\n const [h, w] = this.origShape;\n if (this.length === 0 || w <= 0 || h <= 0) return xywh;\n for (let i = 0; i < this.length; i++) {\n xywh[i * 4] = (xywh[i * 4] as number) / w;\n xywh[i * 4 + 1] = (xywh[i * 4 + 1] as number) / h;\n xywh[i * 4 + 2] = (xywh[i * 4 + 2] as number) / w;\n xywh[i * 4 + 3] = (xywh[i * 4 + 3] as number) / h;\n }\n return xywh;\n }\n\n /**\n * Concatenated `[N, 6]` array of `[x1, y1, x2, y2, conf, cls]`.\n *\n * Matches Ultralytics' `boxes.data`.\n */\n get data(): Float32Array {\n const out = new Float32Array(this.length * 6);\n for (let i = 0; i < this.length; i++) {\n out[i * 6] = this.xyxy[i * 4] as number;\n out[i * 6 + 1] = this.xyxy[i * 4 + 1] as number;\n out[i * 6 + 2] = this.xyxy[i * 4 + 2] as number;\n out[i * 6 + 3] = this.xyxy[i * 4 + 3] as number;\n out[i * 6 + 4] = this.conf[i] as number;\n out[i * 6 + 5] = this.cls[i] as number;\n }\n return out;\n }\n}\n\n/** One selection of the highest-probability classes, descending. */\ninterface TopK {\n indices: Int32Array;\n values: Float32Array;\n}\n\n/**\n * Top-k classification probabilities for a single image.\n *\n * Mirrors Ultralytics' `Probs` interface.\n */\nexport class Probs {\n /** @param data `[numClasses]` per-class probabilities, indexed by class id. */\n constructor(public readonly data: Float32Array) {}\n\n /** Number of classes. */\n get length(): number {\n return this.data.length;\n }\n\n /** `[numClasses]` shape of the underlying vector. */\n get shape(): readonly [number] {\n return [this.length];\n }\n\n /** Index of the most probable class. */\n get top1(): number {\n return this._top(1).indices[0] ?? 0;\n }\n\n /** Probability of the top-1 class. */\n get top1conf(): number {\n return this._top(1).values[0] ?? 0;\n }\n\n /** Indices of the top-5 most probable classes, descending. */\n get top5(): Int32Array {\n return this._top(5).indices;\n }\n\n /** Probabilities of the top-5 classes, descending. */\n get top5conf(): Float32Array {\n return this._top(5).values;\n }\n\n private _cache = new Map<number, TopK>();\n\n /**\n * Memoised {@link Probs._topK}.\n *\n * `top5` and `top5conf` are separate getters over the same selection, so a\n * caller reading both would otherwise pay for it twice — once per frame, in\n * a camera loop. The probabilities a `Probs` was built from do not change,\n * so the result is computed once per `k` and kept.\n *\n * @param k - How many classes to select.\n * @returns The cached selection for that `k`.\n */\n private _top(k: number): TopK {\n const hit = this._cache.get(k);\n if (hit) return hit;\n const computed = this._topK(k);\n this._cache.set(k, computed);\n return computed;\n }\n\n /**\n * Select the `k` highest probabilities without ordering the rest.\n *\n * A full sort to read five entries out of a thousand-class vector costs\n * O(n log n) plus an index array the size of the vector; keeping `k` slots\n * ordered by insertion and scanning once costs O(n·k) with no allocation\n * beyond the result. Measured on 1000 classes, that is 123.7 µs against\n * 1.9 µs for the same output.\n *\n * Ties keep the lower class index first, matching the stable sort this\n * replaced: a candidate only displaces an entry it is strictly greater\n * than.\n *\n * @param k - How many classes to select.\n * @returns Indices and probabilities, descending by probability.\n */\n private _topK(k: number): TopK {\n const size = Math.min(k, this.data.length);\n const indices = new Int32Array(size);\n const values = new Float32Array(size);\n if (size === 0) return { indices, values };\n\n values.fill(Number.NEGATIVE_INFINITY);\n for (let i = 0; i < this.data.length; i++) {\n const value = this.data[i] as number;\n if (value <= (values[size - 1] as number)) continue;\n let slot = size - 1;\n while (slot > 0 && (values[slot - 1] as number) < value) {\n values[slot] = values[slot - 1] as number;\n indices[slot] = indices[slot - 1] as number;\n slot -= 1;\n }\n values[slot] = value;\n indices[slot] = i;\n }\n return { indices, values };\n }\n}\n\n/**\n * Per-instance binary masks for a single image.\n *\n * Each mask is cropped to its instance's bounding box. To paint masks onto\n * a full-image canvas, use `xyxy[i]` as the top-left target.\n */\nexport class Masks {\n /**\n * @param data Per-instance binary masks (`Mask` objects from `types.ts`).\n * @param xyxy Flat `[N, 4]` of bounding-box coordinates in original pixels.\n * @param origShape `[height, width]` of the original image.\n */\n constructor(\n public readonly data: ReadonlyArray<{\n readonly data: Uint8Array;\n readonly width: number;\n readonly height: number;\n }>,\n public readonly xyxy: Float32Array,\n public readonly origShape: readonly [number, number],\n ) {}\n\n /** Number of instance masks. */\n get length(): number {\n return this.data.length;\n }\n\n /** `[N]` shape of the masks collection. */\n get shape(): readonly [number] {\n return [this.length];\n }\n\n [Symbol.iterator](): Iterator<{\n readonly data: Uint8Array;\n readonly width: number;\n readonly height: number;\n }> {\n return this.data[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image detection envelope (Ultralytics-style `Results`).\n *\n * Iterating yields per-instance {@link DetectionResult} entries, so legacy\n * code that did `for (const d of detector.predict(img))` only needs an\n * extra `[0]` to bridge:\n *\n * ```typescript\n * for (const d of (await detector.predict(img))[0]) {\n * console.log(d.cls, d.conf, d.box.xyxy);\n * }\n * ```\n *\n * For numpy-style bulk access, use the `boxes` collection.\n */\nexport class DetectionResults implements Iterable<DetectionResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly detections: readonly DetectionResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving detections. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance detections. */\n get(index: number): DetectionResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<DetectionResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image envelope for a fused detect→classify pipeline.\n *\n * Structurally a {@link DetectionResults} with a second class map: every\n * detection it yields carries a populated `classification`, and the two stages\n * have their own, unrelated label spaces — a detector that finds `sheep`\n * feeding a classifier that answers `famacha_3` shares no class ids with it.\n * Merging them into one `names` record would make `cls` and\n * `classification.cls` look comparable when they are not.\n *\n * ```typescript\n * const result = (await pipeline.predict(\"flock.jpg\"))[0];\n * for (const detection of result) {\n * console.log(detection.name, detection.conf, detection.classification?.name);\n * }\n * ```\n */\nexport class DetectClassifyResults implements Iterable<DetectionResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly detections: readonly DetectionResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly classifierNames: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving detections. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance detections. */\n get(index: number): DetectionResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<DetectionResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image classification envelope (Ultralytics-style `Results`).\n */\nexport class ClassificationResults {\n constructor(\n public readonly probs: Probs,\n public readonly result: ClassificationResult,\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Top-1 class index (Ultralytics-style alias). */\n get cls(): number {\n return this.probs.top1;\n }\n\n /** Top-1 confidence (Ultralytics-style alias). */\n get conf(): number {\n return this.probs.top1conf;\n }\n\n /** Top-1 class name. */\n get name(): string {\n return this.names[this.cls] ?? `class_${this.cls}`;\n }\n\n /** Per-class probability list, sorted descending (legacy field). */\n get probabilities(): readonly ClassificationResult[\"probabilities\"][number][] {\n return this.result.probabilities;\n }\n}\n\n/**\n * Per-image instance-segmentation envelope (Ultralytics-style `Results`).\n *\n * Iterating yields per-instance {@link SegmentationResult} entries. `boxes`\n * and `masks` mirror Ultralytics' bulk-array views.\n */\nexport class SegmentationResults implements Iterable<SegmentationResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly masks: Masks,\n public readonly detections: readonly SegmentationResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving instances. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance results. */\n get(index: number): SegmentationResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<SegmentationResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"results.cjs","names":[],"sources":["../../src/vision/results.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Per-image result envelopes — Ultralytics-style `Results` for the SDK.\n *\n * Each `predict()` call returns a 1-element array of these envelopes,\n * mirroring `YOLO(\"img.jpg\")`. Each envelope holds:\n *\n * - A bulk-array view of the predictions (`Boxes`, `Probs`, `Masks`) with\n * the exact attribute names Ultralytics uses (`xyxy`, `xywh`, `xyxyn`,\n * `xywhn`, `cls`, `conf`, `data`, `top1`, `top5`).\n * - Per-instance dataclasses (`DetectionResult`, `SegmentationResult`,\n * `ClassProbability`) for callers who prefer the OO interface.\n * - `names`: `Record<number, string>` matching Ultralytics' `model.names`.\n * - `origImg` / `origShape` / `path`: provenance for the original input.\n * - `speed`: per-stage timings of the `predict()` call that produced it.\n */\n\nimport { type Speed } from \"./core/timing\";\nimport {\n type ClassificationResult,\n type DetectionResult,\n type RGBImage,\n type SegmentationResult,\n} from \"./types\";\n\n/**\n * Zero timings for an envelope built outside a `predict()` call.\n *\n * Hand-constructed envelopes (tests, adapters) have nothing to measure, and\n * zeros keep `speed.inference` a plain `number` at every call site instead of\n * forcing an optional check that only ever fires for synthetic data.\n */\nconst NO_SPEED: Speed = { load: 0, preprocess: 0, inference: 0, postprocess: 0 };\n\n/**\n * Bulk numpy-style view of detected boxes for a single image.\n *\n * Mirrors Ultralytics' `Boxes` interface. Coordinates in {@link xyxy} and\n * {@link xywh} are absolute pixels in the original image; the `*n` variants\n * are normalized to `[0, 1]` using `origShape`.\n */\nexport class Boxes {\n /**\n * @param xyxy Flat array of length `4 * N` in `[x1, y1, x2, y2, ...]` order.\n * @param cls One class index per box, length `N`.\n * @param conf One confidence per box, length `N`.\n * @param origShape `[height, width]` of the original image.\n */\n constructor(\n public readonly xyxy: Float32Array,\n public readonly cls: Int32Array,\n public readonly conf: Float32Array,\n public readonly origShape: readonly [number, number],\n ) {}\n\n /** Number of detected boxes. */\n get length(): number {\n return this.cls.length;\n }\n\n /** `[N, 4]` shape of the `xyxy` view. */\n get shape(): readonly [number, number] {\n return [this.length, 4];\n }\n\n /** Boxes as `[N, 4]` `[cx, cy, w, h]` flat array in absolute pixels. */\n get xywh(): Float32Array {\n const out = new Float32Array(this.xyxy.length);\n for (let i = 0; i < this.length; i++) {\n const x1 = this.xyxy[i * 4] as number;\n const y1 = this.xyxy[i * 4 + 1] as number;\n const x2 = this.xyxy[i * 4 + 2] as number;\n const y2 = this.xyxy[i * 4 + 3] as number;\n out[i * 4] = (x1 + x2) / 2;\n out[i * 4 + 1] = (y1 + y2) / 2;\n out[i * 4 + 2] = x2 - x1;\n out[i * 4 + 3] = y2 - y1;\n }\n return out;\n }\n\n /** Boxes as `[N, 4]` `[x1, y1, x2, y2]` normalized to `[0, 1]`. */\n get xyxyn(): Float32Array {\n const [h, w] = this.origShape;\n const out = new Float32Array(this.xyxy.length);\n if (this.length === 0 || w <= 0 || h <= 0) return out;\n for (let i = 0; i < this.length; i++) {\n out[i * 4] = (this.xyxy[i * 4] as number) / w;\n out[i * 4 + 1] = (this.xyxy[i * 4 + 1] as number) / h;\n out[i * 4 + 2] = (this.xyxy[i * 4 + 2] as number) / w;\n out[i * 4 + 3] = (this.xyxy[i * 4 + 3] as number) / h;\n }\n return out;\n }\n\n /** Boxes as `[N, 4]` `[cx, cy, w, h]` normalized to `[0, 1]`. */\n get xywhn(): Float32Array {\n const xywh = this.xywh;\n const [h, w] = this.origShape;\n if (this.length === 0 || w <= 0 || h <= 0) return xywh;\n for (let i = 0; i < this.length; i++) {\n xywh[i * 4] = (xywh[i * 4] as number) / w;\n xywh[i * 4 + 1] = (xywh[i * 4 + 1] as number) / h;\n xywh[i * 4 + 2] = (xywh[i * 4 + 2] as number) / w;\n xywh[i * 4 + 3] = (xywh[i * 4 + 3] as number) / h;\n }\n return xywh;\n }\n\n /**\n * Concatenated `[N, 6]` array of `[x1, y1, x2, y2, conf, cls]`.\n *\n * Matches Ultralytics' `boxes.data`.\n */\n get data(): Float32Array {\n const out = new Float32Array(this.length * 6);\n for (let i = 0; i < this.length; i++) {\n out[i * 6] = this.xyxy[i * 4] as number;\n out[i * 6 + 1] = this.xyxy[i * 4 + 1] as number;\n out[i * 6 + 2] = this.xyxy[i * 4 + 2] as number;\n out[i * 6 + 3] = this.xyxy[i * 4 + 3] as number;\n out[i * 6 + 4] = this.conf[i] as number;\n out[i * 6 + 5] = this.cls[i] as number;\n }\n return out;\n }\n}\n\n/** One selection of the highest-probability classes, descending. */\ninterface TopK {\n indices: Int32Array;\n values: Float32Array;\n}\n\n/**\n * Top-k classification probabilities for a single image.\n *\n * Mirrors Ultralytics' `Probs` interface.\n */\nexport class Probs {\n /** @param data `[numClasses]` per-class probabilities, indexed by class id. */\n constructor(public readonly data: Float32Array) {}\n\n /** Number of classes. */\n get length(): number {\n return this.data.length;\n }\n\n /** `[numClasses]` shape of the underlying vector. */\n get shape(): readonly [number] {\n return [this.length];\n }\n\n /** Index of the most probable class. */\n get top1(): number {\n if (this.data.length === 0) return 0;\n let best = 0;\n let bestVal = this.data[0] as number;\n for (let i = 1; i < this.data.length; i++) {\n const v = this.data[i] as number;\n if (v > bestVal) {\n best = i;\n bestVal = v;\n }\n }\n return best;\n }\n\n /** Probability of the top-1 class. */\n get top1conf(): number {\n if (this.data.length === 0) return 0;\n return this.data[this.top1] as number;\n }\n\n /**\n * Indices of the top-5 most probable classes, descending.\n *\n * The array is the memoised selection itself, not a copy — reading it twice\n * hands back the same object. Treat it as read-only: writing into it edits\n * what every later read of this `Probs` returns.\n */\n get top5(): Int32Array {\n return this._top(5).indices;\n }\n\n /**\n * Probabilities of the top-5 classes, descending.\n *\n * Shares the memoised selection with {@link Probs.top5}, under the same\n * read-only caveat.\n */\n get top5conf(): Float32Array {\n return this._top(5).values;\n }\n\n private _cache = new Map<number, TopK>();\n\n /**\n * Memoised {@link Probs._topK}.\n *\n * `top5` and `top5conf` are separate getters over the same selection, so a\n * caller reading both would otherwise pay for it twice — once per frame, in\n * a camera loop. The probabilities a `Probs` was built from do not change,\n * so the result is computed once per `k` and kept.\n *\n * @param k - How many classes to select.\n * @returns The cached selection for that `k`.\n */\n private _top(k: number): TopK {\n const hit = this._cache.get(k);\n if (hit) return hit;\n const computed = this._topK(k);\n this._cache.set(k, computed);\n return computed;\n }\n\n /**\n * Select the `k` highest probabilities without ordering the rest.\n *\n * A full sort to read five entries out of a thousand-class vector costs\n * O(n log n) plus an index array the size of the vector; keeping `k` slots\n * ordered by insertion and scanning once costs O(n·k) with no allocation\n * beyond the result. Measured on 1000 classes over 2000 iterations, 134.5 µs\n * against 1.5 µs for the same output.\n *\n * Ties keep the lower class index first, matching the stable sort this\n * replaced: a candidate only displaces an entry it is strictly greater\n * than. That is also what keeps this selection in step with the Python\n * SDK's `np.argsort(-data, kind=\"stable\")`, where the sort is C and the\n * cost this avoids does not arise.\n *\n * @param k - How many classes to select.\n * @returns Indices and probabilities, descending by probability.\n */\n private _topK(k: number): TopK {\n const size = Math.min(k, this.data.length);\n const indices = new Int32Array(size);\n const values = new Float32Array(size);\n if (size === 0) return { indices, values };\n\n values.fill(Number.NEGATIVE_INFINITY);\n for (let i = 0; i < this.data.length; i++) {\n const value = this.data[i] as number;\n if (value <= (values[size - 1] as number)) continue;\n let slot = size - 1;\n while (slot > 0 && (values[slot - 1] as number) < value) {\n values[slot] = values[slot - 1] as number;\n indices[slot] = indices[slot - 1] as number;\n slot -= 1;\n }\n values[slot] = value;\n indices[slot] = i;\n }\n return { indices, values };\n }\n}\n\n/**\n * Per-instance binary masks for a single image.\n *\n * Each mask is cropped to its instance's bounding box. To paint masks onto\n * a full-image canvas, use `xyxy[i]` as the top-left target.\n */\nexport class Masks {\n /**\n * @param data Per-instance binary masks (`Mask` objects from `types.ts`).\n * @param xyxy Flat `[N, 4]` of bounding-box coordinates in original pixels.\n * @param origShape `[height, width]` of the original image.\n */\n constructor(\n public readonly data: ReadonlyArray<{\n readonly data: Uint8Array;\n readonly width: number;\n readonly height: number;\n }>,\n public readonly xyxy: Float32Array,\n public readonly origShape: readonly [number, number],\n ) {}\n\n /** Number of instance masks. */\n get length(): number {\n return this.data.length;\n }\n\n /** `[N]` shape of the masks collection. */\n get shape(): readonly [number] {\n return [this.length];\n }\n\n [Symbol.iterator](): Iterator<{\n readonly data: Uint8Array;\n readonly width: number;\n readonly height: number;\n }> {\n return this.data[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image detection envelope (Ultralytics-style `Results`).\n *\n * Iterating yields per-instance {@link DetectionResult} entries, so legacy\n * code that did `for (const d of detector.predict(img))` only needs an\n * extra `[0]` to bridge:\n *\n * ```typescript\n * for (const d of (await detector.predict(img))[0]) {\n * console.log(d.cls, d.conf, d.box.xyxy);\n * }\n * ```\n *\n * For numpy-style bulk access, use the `boxes` collection.\n */\nexport class DetectionResults implements Iterable<DetectionResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly detections: readonly DetectionResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving detections. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance detections. */\n get(index: number): DetectionResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<DetectionResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image envelope for a fused detect→classify pipeline.\n *\n * Structurally a {@link DetectionResults} with a second class map: every\n * detection it yields carries a populated `classification`, and the two stages\n * have their own, unrelated label spaces — a detector that finds `sheep`\n * feeding a classifier that answers `famacha_3` shares no class ids with it.\n * Merging them into one `names` record would make `cls` and\n * `classification.cls` look comparable when they are not.\n *\n * ```typescript\n * const result = (await pipeline.predict(\"flock.jpg\"))[0];\n * for (const detection of result) {\n * console.log(detection.name, detection.conf, detection.classification?.name);\n * }\n * ```\n */\nexport class DetectClassifyResults implements Iterable<DetectionResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly detections: readonly DetectionResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly classifierNames: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving detections. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance detections. */\n get(index: number): DetectionResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<DetectionResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image classification envelope (Ultralytics-style `Results`).\n */\nexport class ClassificationResults {\n constructor(\n public readonly probs: Probs,\n public readonly result: ClassificationResult,\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Top-1 class index (Ultralytics-style alias). */\n get cls(): number {\n return this.probs.top1;\n }\n\n /** Top-1 confidence (Ultralytics-style alias). */\n get conf(): number {\n return this.probs.top1conf;\n }\n\n /** Top-1 class name. */\n get name(): string {\n return this.names[this.cls] ?? `class_${this.cls}`;\n }\n\n /** Per-class probability list, sorted descending (legacy field). */\n get probabilities(): readonly ClassificationResult[\"probabilities\"][number][] {\n return this.result.probabilities;\n }\n}\n\n/**\n * Per-image instance-segmentation envelope (Ultralytics-style `Results`).\n *\n * Iterating yields per-instance {@link SegmentationResult} entries. `boxes`\n * and `masks` mirror Ultralytics' bulk-array views.\n */\nexport class SegmentationResults implements Iterable<SegmentationResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly masks: Masks,\n public readonly detections: readonly SegmentationResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving instances. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance results. */\n get(index: number): SegmentationResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<SegmentationResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n"],"mappings":"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"}
|
package/dist/vision/results.js
CHANGED
|
@@ -55,10 +55,16 @@ var e = {
|
|
|
55
55
|
return [this.length];
|
|
56
56
|
}
|
|
57
57
|
get top1() {
|
|
58
|
-
|
|
58
|
+
if (this.data.length === 0) return 0;
|
|
59
|
+
let e = 0, t = this.data[0];
|
|
60
|
+
for (let n = 1; n < this.data.length; n++) {
|
|
61
|
+
let r = this.data[n];
|
|
62
|
+
r > t && (e = n, t = r);
|
|
63
|
+
}
|
|
64
|
+
return e;
|
|
59
65
|
}
|
|
60
66
|
get top1conf() {
|
|
61
|
-
return this.
|
|
67
|
+
return this.data.length === 0 ? 0 : this.data[this.top1];
|
|
62
68
|
}
|
|
63
69
|
get top5() {
|
|
64
70
|
return this._top(5).indices;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"results.js","names":[],"sources":["../../src/vision/results.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Per-image result envelopes — Ultralytics-style `Results` for the SDK.\n *\n * Each `predict()` call returns a 1-element array of these envelopes,\n * mirroring `YOLO(\"img.jpg\")`. Each envelope holds:\n *\n * - A bulk-array view of the predictions (`Boxes`, `Probs`, `Masks`) with\n * the exact attribute names Ultralytics uses (`xyxy`, `xywh`, `xyxyn`,\n * `xywhn`, `cls`, `conf`, `data`, `top1`, `top5`).\n * - Per-instance dataclasses (`DetectionResult`, `SegmentationResult`,\n * `ClassProbability`) for callers who prefer the OO interface.\n * - `names`: `Record<number, string>` matching Ultralytics' `model.names`.\n * - `origImg` / `origShape` / `path`: provenance for the original input.\n * - `speed`: per-stage timings of the `predict()` call that produced it.\n */\n\nimport { type Speed } from \"./core/timing\";\nimport {\n type ClassificationResult,\n type DetectionResult,\n type RGBImage,\n type SegmentationResult,\n} from \"./types\";\n\n/**\n * Zero timings for an envelope built outside a `predict()` call.\n *\n * Hand-constructed envelopes (tests, adapters) have nothing to measure, and\n * zeros keep `speed.inference` a plain `number` at every call site instead of\n * forcing an optional check that only ever fires for synthetic data.\n */\nconst NO_SPEED: Speed = { load: 0, preprocess: 0, inference: 0, postprocess: 0 };\n\n/**\n * Bulk numpy-style view of detected boxes for a single image.\n *\n * Mirrors Ultralytics' `Boxes` interface. Coordinates in {@link xyxy} and\n * {@link xywh} are absolute pixels in the original image; the `*n` variants\n * are normalized to `[0, 1]` using `origShape`.\n */\nexport class Boxes {\n /**\n * @param xyxy Flat array of length `4 * N` in `[x1, y1, x2, y2, ...]` order.\n * @param cls One class index per box, length `N`.\n * @param conf One confidence per box, length `N`.\n * @param origShape `[height, width]` of the original image.\n */\n constructor(\n public readonly xyxy: Float32Array,\n public readonly cls: Int32Array,\n public readonly conf: Float32Array,\n public readonly origShape: readonly [number, number],\n ) {}\n\n /** Number of detected boxes. */\n get length(): number {\n return this.cls.length;\n }\n\n /** `[N, 4]` shape of the `xyxy` view. */\n get shape(): readonly [number, number] {\n return [this.length, 4];\n }\n\n /** Boxes as `[N, 4]` `[cx, cy, w, h]` flat array in absolute pixels. */\n get xywh(): Float32Array {\n const out = new Float32Array(this.xyxy.length);\n for (let i = 0; i < this.length; i++) {\n const x1 = this.xyxy[i * 4] as number;\n const y1 = this.xyxy[i * 4 + 1] as number;\n const x2 = this.xyxy[i * 4 + 2] as number;\n const y2 = this.xyxy[i * 4 + 3] as number;\n out[i * 4] = (x1 + x2) / 2;\n out[i * 4 + 1] = (y1 + y2) / 2;\n out[i * 4 + 2] = x2 - x1;\n out[i * 4 + 3] = y2 - y1;\n }\n return out;\n }\n\n /** Boxes as `[N, 4]` `[x1, y1, x2, y2]` normalized to `[0, 1]`. */\n get xyxyn(): Float32Array {\n const [h, w] = this.origShape;\n const out = new Float32Array(this.xyxy.length);\n if (this.length === 0 || w <= 0 || h <= 0) return out;\n for (let i = 0; i < this.length; i++) {\n out[i * 4] = (this.xyxy[i * 4] as number) / w;\n out[i * 4 + 1] = (this.xyxy[i * 4 + 1] as number) / h;\n out[i * 4 + 2] = (this.xyxy[i * 4 + 2] as number) / w;\n out[i * 4 + 3] = (this.xyxy[i * 4 + 3] as number) / h;\n }\n return out;\n }\n\n /** Boxes as `[N, 4]` `[cx, cy, w, h]` normalized to `[0, 1]`. */\n get xywhn(): Float32Array {\n const xywh = this.xywh;\n const [h, w] = this.origShape;\n if (this.length === 0 || w <= 0 || h <= 0) return xywh;\n for (let i = 0; i < this.length; i++) {\n xywh[i * 4] = (xywh[i * 4] as number) / w;\n xywh[i * 4 + 1] = (xywh[i * 4 + 1] as number) / h;\n xywh[i * 4 + 2] = (xywh[i * 4 + 2] as number) / w;\n xywh[i * 4 + 3] = (xywh[i * 4 + 3] as number) / h;\n }\n return xywh;\n }\n\n /**\n * Concatenated `[N, 6]` array of `[x1, y1, x2, y2, conf, cls]`.\n *\n * Matches Ultralytics' `boxes.data`.\n */\n get data(): Float32Array {\n const out = new Float32Array(this.length * 6);\n for (let i = 0; i < this.length; i++) {\n out[i * 6] = this.xyxy[i * 4] as number;\n out[i * 6 + 1] = this.xyxy[i * 4 + 1] as number;\n out[i * 6 + 2] = this.xyxy[i * 4 + 2] as number;\n out[i * 6 + 3] = this.xyxy[i * 4 + 3] as number;\n out[i * 6 + 4] = this.conf[i] as number;\n out[i * 6 + 5] = this.cls[i] as number;\n }\n return out;\n }\n}\n\n/** One selection of the highest-probability classes, descending. */\ninterface TopK {\n indices: Int32Array;\n values: Float32Array;\n}\n\n/**\n * Top-k classification probabilities for a single image.\n *\n * Mirrors Ultralytics' `Probs` interface.\n */\nexport class Probs {\n /** @param data `[numClasses]` per-class probabilities, indexed by class id. */\n constructor(public readonly data: Float32Array) {}\n\n /** Number of classes. */\n get length(): number {\n return this.data.length;\n }\n\n /** `[numClasses]` shape of the underlying vector. */\n get shape(): readonly [number] {\n return [this.length];\n }\n\n /** Index of the most probable class. */\n get top1(): number {\n return this._top(1).indices[0] ?? 0;\n }\n\n /** Probability of the top-1 class. */\n get top1conf(): number {\n return this._top(1).values[0] ?? 0;\n }\n\n /** Indices of the top-5 most probable classes, descending. */\n get top5(): Int32Array {\n return this._top(5).indices;\n }\n\n /** Probabilities of the top-5 classes, descending. */\n get top5conf(): Float32Array {\n return this._top(5).values;\n }\n\n private _cache = new Map<number, TopK>();\n\n /**\n * Memoised {@link Probs._topK}.\n *\n * `top5` and `top5conf` are separate getters over the same selection, so a\n * caller reading both would otherwise pay for it twice — once per frame, in\n * a camera loop. The probabilities a `Probs` was built from do not change,\n * so the result is computed once per `k` and kept.\n *\n * @param k - How many classes to select.\n * @returns The cached selection for that `k`.\n */\n private _top(k: number): TopK {\n const hit = this._cache.get(k);\n if (hit) return hit;\n const computed = this._topK(k);\n this._cache.set(k, computed);\n return computed;\n }\n\n /**\n * Select the `k` highest probabilities without ordering the rest.\n *\n * A full sort to read five entries out of a thousand-class vector costs\n * O(n log n) plus an index array the size of the vector; keeping `k` slots\n * ordered by insertion and scanning once costs O(n·k) with no allocation\n * beyond the result. Measured on 1000 classes, that is 123.7 µs against\n * 1.9 µs for the same output.\n *\n * Ties keep the lower class index first, matching the stable sort this\n * replaced: a candidate only displaces an entry it is strictly greater\n * than.\n *\n * @param k - How many classes to select.\n * @returns Indices and probabilities, descending by probability.\n */\n private _topK(k: number): TopK {\n const size = Math.min(k, this.data.length);\n const indices = new Int32Array(size);\n const values = new Float32Array(size);\n if (size === 0) return { indices, values };\n\n values.fill(Number.NEGATIVE_INFINITY);\n for (let i = 0; i < this.data.length; i++) {\n const value = this.data[i] as number;\n if (value <= (values[size - 1] as number)) continue;\n let slot = size - 1;\n while (slot > 0 && (values[slot - 1] as number) < value) {\n values[slot] = values[slot - 1] as number;\n indices[slot] = indices[slot - 1] as number;\n slot -= 1;\n }\n values[slot] = value;\n indices[slot] = i;\n }\n return { indices, values };\n }\n}\n\n/**\n * Per-instance binary masks for a single image.\n *\n * Each mask is cropped to its instance's bounding box. To paint masks onto\n * a full-image canvas, use `xyxy[i]` as the top-left target.\n */\nexport class Masks {\n /**\n * @param data Per-instance binary masks (`Mask` objects from `types.ts`).\n * @param xyxy Flat `[N, 4]` of bounding-box coordinates in original pixels.\n * @param origShape `[height, width]` of the original image.\n */\n constructor(\n public readonly data: ReadonlyArray<{\n readonly data: Uint8Array;\n readonly width: number;\n readonly height: number;\n }>,\n public readonly xyxy: Float32Array,\n public readonly origShape: readonly [number, number],\n ) {}\n\n /** Number of instance masks. */\n get length(): number {\n return this.data.length;\n }\n\n /** `[N]` shape of the masks collection. */\n get shape(): readonly [number] {\n return [this.length];\n }\n\n [Symbol.iterator](): Iterator<{\n readonly data: Uint8Array;\n readonly width: number;\n readonly height: number;\n }> {\n return this.data[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image detection envelope (Ultralytics-style `Results`).\n *\n * Iterating yields per-instance {@link DetectionResult} entries, so legacy\n * code that did `for (const d of detector.predict(img))` only needs an\n * extra `[0]` to bridge:\n *\n * ```typescript\n * for (const d of (await detector.predict(img))[0]) {\n * console.log(d.cls, d.conf, d.box.xyxy);\n * }\n * ```\n *\n * For numpy-style bulk access, use the `boxes` collection.\n */\nexport class DetectionResults implements Iterable<DetectionResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly detections: readonly DetectionResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving detections. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance detections. */\n get(index: number): DetectionResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<DetectionResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image envelope for a fused detect→classify pipeline.\n *\n * Structurally a {@link DetectionResults} with a second class map: every\n * detection it yields carries a populated `classification`, and the two stages\n * have their own, unrelated label spaces — a detector that finds `sheep`\n * feeding a classifier that answers `famacha_3` shares no class ids with it.\n * Merging them into one `names` record would make `cls` and\n * `classification.cls` look comparable when they are not.\n *\n * ```typescript\n * const result = (await pipeline.predict(\"flock.jpg\"))[0];\n * for (const detection of result) {\n * console.log(detection.name, detection.conf, detection.classification?.name);\n * }\n * ```\n */\nexport class DetectClassifyResults implements Iterable<DetectionResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly detections: readonly DetectionResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly classifierNames: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving detections. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance detections. */\n get(index: number): DetectionResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<DetectionResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image classification envelope (Ultralytics-style `Results`).\n */\nexport class ClassificationResults {\n constructor(\n public readonly probs: Probs,\n public readonly result: ClassificationResult,\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Top-1 class index (Ultralytics-style alias). */\n get cls(): number {\n return this.probs.top1;\n }\n\n /** Top-1 confidence (Ultralytics-style alias). */\n get conf(): number {\n return this.probs.top1conf;\n }\n\n /** Top-1 class name. */\n get name(): string {\n return this.names[this.cls] ?? `class_${this.cls}`;\n }\n\n /** Per-class probability list, sorted descending (legacy field). */\n get probabilities(): readonly ClassificationResult[\"probabilities\"][number][] {\n return this.result.probabilities;\n }\n}\n\n/**\n * Per-image instance-segmentation envelope (Ultralytics-style `Results`).\n *\n * Iterating yields per-instance {@link SegmentationResult} entries. `boxes`\n * and `masks` mirror Ultralytics' bulk-array views.\n */\nexport class SegmentationResults implements Iterable<SegmentationResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly masks: Masks,\n public readonly detections: readonly SegmentationResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving instances. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance results. */\n get(index: number): SegmentationResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<SegmentationResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"results.js","names":[],"sources":["../../src/vision/results.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Per-image result envelopes — Ultralytics-style `Results` for the SDK.\n *\n * Each `predict()` call returns a 1-element array of these envelopes,\n * mirroring `YOLO(\"img.jpg\")`. Each envelope holds:\n *\n * - A bulk-array view of the predictions (`Boxes`, `Probs`, `Masks`) with\n * the exact attribute names Ultralytics uses (`xyxy`, `xywh`, `xyxyn`,\n * `xywhn`, `cls`, `conf`, `data`, `top1`, `top5`).\n * - Per-instance dataclasses (`DetectionResult`, `SegmentationResult`,\n * `ClassProbability`) for callers who prefer the OO interface.\n * - `names`: `Record<number, string>` matching Ultralytics' `model.names`.\n * - `origImg` / `origShape` / `path`: provenance for the original input.\n * - `speed`: per-stage timings of the `predict()` call that produced it.\n */\n\nimport { type Speed } from \"./core/timing\";\nimport {\n type ClassificationResult,\n type DetectionResult,\n type RGBImage,\n type SegmentationResult,\n} from \"./types\";\n\n/**\n * Zero timings for an envelope built outside a `predict()` call.\n *\n * Hand-constructed envelopes (tests, adapters) have nothing to measure, and\n * zeros keep `speed.inference` a plain `number` at every call site instead of\n * forcing an optional check that only ever fires for synthetic data.\n */\nconst NO_SPEED: Speed = { load: 0, preprocess: 0, inference: 0, postprocess: 0 };\n\n/**\n * Bulk numpy-style view of detected boxes for a single image.\n *\n * Mirrors Ultralytics' `Boxes` interface. Coordinates in {@link xyxy} and\n * {@link xywh} are absolute pixels in the original image; the `*n` variants\n * are normalized to `[0, 1]` using `origShape`.\n */\nexport class Boxes {\n /**\n * @param xyxy Flat array of length `4 * N` in `[x1, y1, x2, y2, ...]` order.\n * @param cls One class index per box, length `N`.\n * @param conf One confidence per box, length `N`.\n * @param origShape `[height, width]` of the original image.\n */\n constructor(\n public readonly xyxy: Float32Array,\n public readonly cls: Int32Array,\n public readonly conf: Float32Array,\n public readonly origShape: readonly [number, number],\n ) {}\n\n /** Number of detected boxes. */\n get length(): number {\n return this.cls.length;\n }\n\n /** `[N, 4]` shape of the `xyxy` view. */\n get shape(): readonly [number, number] {\n return [this.length, 4];\n }\n\n /** Boxes as `[N, 4]` `[cx, cy, w, h]` flat array in absolute pixels. */\n get xywh(): Float32Array {\n const out = new Float32Array(this.xyxy.length);\n for (let i = 0; i < this.length; i++) {\n const x1 = this.xyxy[i * 4] as number;\n const y1 = this.xyxy[i * 4 + 1] as number;\n const x2 = this.xyxy[i * 4 + 2] as number;\n const y2 = this.xyxy[i * 4 + 3] as number;\n out[i * 4] = (x1 + x2) / 2;\n out[i * 4 + 1] = (y1 + y2) / 2;\n out[i * 4 + 2] = x2 - x1;\n out[i * 4 + 3] = y2 - y1;\n }\n return out;\n }\n\n /** Boxes as `[N, 4]` `[x1, y1, x2, y2]` normalized to `[0, 1]`. */\n get xyxyn(): Float32Array {\n const [h, w] = this.origShape;\n const out = new Float32Array(this.xyxy.length);\n if (this.length === 0 || w <= 0 || h <= 0) return out;\n for (let i = 0; i < this.length; i++) {\n out[i * 4] = (this.xyxy[i * 4] as number) / w;\n out[i * 4 + 1] = (this.xyxy[i * 4 + 1] as number) / h;\n out[i * 4 + 2] = (this.xyxy[i * 4 + 2] as number) / w;\n out[i * 4 + 3] = (this.xyxy[i * 4 + 3] as number) / h;\n }\n return out;\n }\n\n /** Boxes as `[N, 4]` `[cx, cy, w, h]` normalized to `[0, 1]`. */\n get xywhn(): Float32Array {\n const xywh = this.xywh;\n const [h, w] = this.origShape;\n if (this.length === 0 || w <= 0 || h <= 0) return xywh;\n for (let i = 0; i < this.length; i++) {\n xywh[i * 4] = (xywh[i * 4] as number) / w;\n xywh[i * 4 + 1] = (xywh[i * 4 + 1] as number) / h;\n xywh[i * 4 + 2] = (xywh[i * 4 + 2] as number) / w;\n xywh[i * 4 + 3] = (xywh[i * 4 + 3] as number) / h;\n }\n return xywh;\n }\n\n /**\n * Concatenated `[N, 6]` array of `[x1, y1, x2, y2, conf, cls]`.\n *\n * Matches Ultralytics' `boxes.data`.\n */\n get data(): Float32Array {\n const out = new Float32Array(this.length * 6);\n for (let i = 0; i < this.length; i++) {\n out[i * 6] = this.xyxy[i * 4] as number;\n out[i * 6 + 1] = this.xyxy[i * 4 + 1] as number;\n out[i * 6 + 2] = this.xyxy[i * 4 + 2] as number;\n out[i * 6 + 3] = this.xyxy[i * 4 + 3] as number;\n out[i * 6 + 4] = this.conf[i] as number;\n out[i * 6 + 5] = this.cls[i] as number;\n }\n return out;\n }\n}\n\n/** One selection of the highest-probability classes, descending. */\ninterface TopK {\n indices: Int32Array;\n values: Float32Array;\n}\n\n/**\n * Top-k classification probabilities for a single image.\n *\n * Mirrors Ultralytics' `Probs` interface.\n */\nexport class Probs {\n /** @param data `[numClasses]` per-class probabilities, indexed by class id. */\n constructor(public readonly data: Float32Array) {}\n\n /** Number of classes. */\n get length(): number {\n return this.data.length;\n }\n\n /** `[numClasses]` shape of the underlying vector. */\n get shape(): readonly [number] {\n return [this.length];\n }\n\n /** Index of the most probable class. */\n get top1(): number {\n if (this.data.length === 0) return 0;\n let best = 0;\n let bestVal = this.data[0] as number;\n for (let i = 1; i < this.data.length; i++) {\n const v = this.data[i] as number;\n if (v > bestVal) {\n best = i;\n bestVal = v;\n }\n }\n return best;\n }\n\n /** Probability of the top-1 class. */\n get top1conf(): number {\n if (this.data.length === 0) return 0;\n return this.data[this.top1] as number;\n }\n\n /**\n * Indices of the top-5 most probable classes, descending.\n *\n * The array is the memoised selection itself, not a copy — reading it twice\n * hands back the same object. Treat it as read-only: writing into it edits\n * what every later read of this `Probs` returns.\n */\n get top5(): Int32Array {\n return this._top(5).indices;\n }\n\n /**\n * Probabilities of the top-5 classes, descending.\n *\n * Shares the memoised selection with {@link Probs.top5}, under the same\n * read-only caveat.\n */\n get top5conf(): Float32Array {\n return this._top(5).values;\n }\n\n private _cache = new Map<number, TopK>();\n\n /**\n * Memoised {@link Probs._topK}.\n *\n * `top5` and `top5conf` are separate getters over the same selection, so a\n * caller reading both would otherwise pay for it twice — once per frame, in\n * a camera loop. The probabilities a `Probs` was built from do not change,\n * so the result is computed once per `k` and kept.\n *\n * @param k - How many classes to select.\n * @returns The cached selection for that `k`.\n */\n private _top(k: number): TopK {\n const hit = this._cache.get(k);\n if (hit) return hit;\n const computed = this._topK(k);\n this._cache.set(k, computed);\n return computed;\n }\n\n /**\n * Select the `k` highest probabilities without ordering the rest.\n *\n * A full sort to read five entries out of a thousand-class vector costs\n * O(n log n) plus an index array the size of the vector; keeping `k` slots\n * ordered by insertion and scanning once costs O(n·k) with no allocation\n * beyond the result. Measured on 1000 classes over 2000 iterations, 134.5 µs\n * against 1.5 µs for the same output.\n *\n * Ties keep the lower class index first, matching the stable sort this\n * replaced: a candidate only displaces an entry it is strictly greater\n * than. That is also what keeps this selection in step with the Python\n * SDK's `np.argsort(-data, kind=\"stable\")`, where the sort is C and the\n * cost this avoids does not arise.\n *\n * @param k - How many classes to select.\n * @returns Indices and probabilities, descending by probability.\n */\n private _topK(k: number): TopK {\n const size = Math.min(k, this.data.length);\n const indices = new Int32Array(size);\n const values = new Float32Array(size);\n if (size === 0) return { indices, values };\n\n values.fill(Number.NEGATIVE_INFINITY);\n for (let i = 0; i < this.data.length; i++) {\n const value = this.data[i] as number;\n if (value <= (values[size - 1] as number)) continue;\n let slot = size - 1;\n while (slot > 0 && (values[slot - 1] as number) < value) {\n values[slot] = values[slot - 1] as number;\n indices[slot] = indices[slot - 1] as number;\n slot -= 1;\n }\n values[slot] = value;\n indices[slot] = i;\n }\n return { indices, values };\n }\n}\n\n/**\n * Per-instance binary masks for a single image.\n *\n * Each mask is cropped to its instance's bounding box. To paint masks onto\n * a full-image canvas, use `xyxy[i]` as the top-left target.\n */\nexport class Masks {\n /**\n * @param data Per-instance binary masks (`Mask` objects from `types.ts`).\n * @param xyxy Flat `[N, 4]` of bounding-box coordinates in original pixels.\n * @param origShape `[height, width]` of the original image.\n */\n constructor(\n public readonly data: ReadonlyArray<{\n readonly data: Uint8Array;\n readonly width: number;\n readonly height: number;\n }>,\n public readonly xyxy: Float32Array,\n public readonly origShape: readonly [number, number],\n ) {}\n\n /** Number of instance masks. */\n get length(): number {\n return this.data.length;\n }\n\n /** `[N]` shape of the masks collection. */\n get shape(): readonly [number] {\n return [this.length];\n }\n\n [Symbol.iterator](): Iterator<{\n readonly data: Uint8Array;\n readonly width: number;\n readonly height: number;\n }> {\n return this.data[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image detection envelope (Ultralytics-style `Results`).\n *\n * Iterating yields per-instance {@link DetectionResult} entries, so legacy\n * code that did `for (const d of detector.predict(img))` only needs an\n * extra `[0]` to bridge:\n *\n * ```typescript\n * for (const d of (await detector.predict(img))[0]) {\n * console.log(d.cls, d.conf, d.box.xyxy);\n * }\n * ```\n *\n * For numpy-style bulk access, use the `boxes` collection.\n */\nexport class DetectionResults implements Iterable<DetectionResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly detections: readonly DetectionResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving detections. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance detections. */\n get(index: number): DetectionResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<DetectionResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image envelope for a fused detect→classify pipeline.\n *\n * Structurally a {@link DetectionResults} with a second class map: every\n * detection it yields carries a populated `classification`, and the two stages\n * have their own, unrelated label spaces — a detector that finds `sheep`\n * feeding a classifier that answers `famacha_3` shares no class ids with it.\n * Merging them into one `names` record would make `cls` and\n * `classification.cls` look comparable when they are not.\n *\n * ```typescript\n * const result = (await pipeline.predict(\"flock.jpg\"))[0];\n * for (const detection of result) {\n * console.log(detection.name, detection.conf, detection.classification?.name);\n * }\n * ```\n */\nexport class DetectClassifyResults implements Iterable<DetectionResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly detections: readonly DetectionResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly classifierNames: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving detections. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance detections. */\n get(index: number): DetectionResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<DetectionResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n\n/**\n * Per-image classification envelope (Ultralytics-style `Results`).\n */\nexport class ClassificationResults {\n constructor(\n public readonly probs: Probs,\n public readonly result: ClassificationResult,\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Top-1 class index (Ultralytics-style alias). */\n get cls(): number {\n return this.probs.top1;\n }\n\n /** Top-1 confidence (Ultralytics-style alias). */\n get conf(): number {\n return this.probs.top1conf;\n }\n\n /** Top-1 class name. */\n get name(): string {\n return this.names[this.cls] ?? `class_${this.cls}`;\n }\n\n /** Per-class probability list, sorted descending (legacy field). */\n get probabilities(): readonly ClassificationResult[\"probabilities\"][number][] {\n return this.result.probabilities;\n }\n}\n\n/**\n * Per-image instance-segmentation envelope (Ultralytics-style `Results`).\n *\n * Iterating yields per-instance {@link SegmentationResult} entries. `boxes`\n * and `masks` mirror Ultralytics' bulk-array views.\n */\nexport class SegmentationResults implements Iterable<SegmentationResult> {\n constructor(\n public readonly boxes: Boxes,\n public readonly masks: Masks,\n public readonly detections: readonly SegmentationResult[],\n public readonly names: Readonly<Record<number, string>>,\n public readonly origImg: RGBImage,\n public readonly origShape: readonly [number, number],\n public readonly path: string | null = null,\n public readonly speed: Readonly<Speed> = NO_SPEED,\n ) {}\n\n /** Number of surviving instances. */\n get length(): number {\n return this.detections.length;\n }\n\n /** Index into the per-instance results. */\n get(index: number): SegmentationResult | undefined {\n return this.detections[index];\n }\n\n [Symbol.iterator](): Iterator<SegmentationResult> {\n return this.detections[Symbol.iterator]();\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../core/timing.cjs"),t=require("../results.cjs"),n=require("../labels.cjs"),r=require("../core/graph.cjs"),i=require("../core/metadata.cjs"),a=require("../core/session.cjs"),o=require("../io/image.cjs"),
|
|
1
|
+
const e=require("../core/timing.cjs"),t=require("../results.cjs"),n=require("../labels.cjs"),r=require("../core/graph.cjs"),i=require("../core/metadata.cjs"),a=require("../core/session.cjs"),o=require("../normalization.cjs"),s=require("../io/image.cjs"),c=require("../preprocess/image.cjs"),l=require("../preprocess/pipeline.cjs"),u=require("../postprocess/classification.cjs"),d=require("./base.cjs");var f=class f extends d.VisionTask{_labels;_names;_inputSize;_mean;_std;_applySoftmax;_normalization;constructor(e,t,n,r,i,a,o,s){super(e),this._labels=t,this._names=n,this._inputSize=r,this._mean=i,this._std=a,this._applySoftmax=o,this._normalization=s}get appliesSoftmax(){return this._applySoftmax}get normalization(){return this._normalization}_pipelineCache=null;async warmup(e=1){let[t,n]=this._inputSize;for(let r=0;r<e;r++){let e=c.toFloat32Tensor(l.zeroTensorData(t,n),[1,3,n,t]);await this._session.run({[this._session.inputName]:e})}}get _pipeline(){if(this._pipelineCache===null){let[e,t]=this._inputSize;this._pipelineCache=new l.ResizePipeline(e,t,this._mean,this._std)}return this._pipelineCache}static async create(e,t={}){let s=await a.OrtSession.create(e,t),c=o.resolveNormalization(s.metadata,{normalization:t.normalization,mean:t.mean,std:t.std}),l=t.numClasses??r.classificationNumClasses(s.outputShape)??void 0,u=n.resolveLabels(t.labels??i.modelNames(s.metadata),{numClasses:l}),d={};for(let e=0;e<u.length;e++)d[e]=u[e];return new f(s,u,d,r.resolveInputSize({graphShape:s.inputShape,requested:t.inputSize,fallback:[224,224]}),c.mean,c.std,t.applySoftmax??!o.isUltralyticsClassifier(s.metadata),c.name)}get labels(){return this._labels}get names(){return this._names}get inputSize(){return this._inputSize}get numClasses(){return this._labels.length}async call(e,t={}){return this.predict(e,t)}async predict(n,r={}){let i=new e.SpeedTimer,a=typeof n==`string`?n:null,o=await s.loadImage(n);i.stage(`load`);let c=this._preprocess(o);i.stage(`preprocess`);let l=await this._session.run({[this._session.inputName]:c});this._pipeline.release(),i.stage(`inference`);let d=this._session.outputNames[0];if(d===void 0)throw Error(`Classifier model has no outputs.`);let f=l[d];if(f===void 0)throw Error(`Classifier model output ${d} missing from run() result.`);let p=this._postprocess(f.data),{indices:m,values:h}=u.topK(p,r.topK??null),g=[];for(let e=0;e<m.length;e++){let t=m[e],n=this._labels[t]??`class_${t}`;g.push({classId:t,className:n,probability:h[e],cls:t,name:n,conf:h[e]})}if(g.length===0)throw Error(`Classifier produced no probabilities (empty output).`);let _=g[0],v={classId:_.classId,className:_.className,confidence:_.probability,cls:_.classId,name:_.className,conf:_.probability,image:o,probabilities:g},y=[o.height,o.width],b=new t.Probs(p);return i.stage(`postprocess`),[new t.ClassificationResults(b,v,this._names,o,y,a,i.speed())]}_preprocess(e){let[t,n]=this._inputSize,{data:r}=this._pipeline.run(e);return c.toFloat32Tensor(r,[1,3,n,t])}_postprocess(e){return this._applySoftmax?u.softmax(e):new Float32Array(e)}};exports.Classifier=f;
|
|
2
2
|
//# sourceMappingURL=classifier.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classifier.cjs","names":[],"sources":["../../../src/vision/tasks/classifier.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Image classification task using ONNX Runtime Web.\n */\n\nimport type * as ort from \"onnxruntime-web\";\n\nimport { type ModelSource, type OrtSessionOptions, OrtSession } from \"../core/session\";\nimport { SpeedTimer } from \"../core/timing\";\nimport { type ImageInput, loadImage } from \"../io/image\";\nimport { classificationNumClasses, resolveInputSize } from \"../core/graph\";\nimport { modelNames } from \"../core/metadata\";\nimport { type LabelSpec, resolveLabels } from \"../labels\";\nimport { softmax, topK } from \"../postprocess/classification\";\nimport { toFloat32Tensor } from \"../preprocess/image\";\nimport { ResizePipeline, zeroTensorData } from \"../preprocess/pipeline\";\nimport { ClassificationResults, Probs } from \"../results\";\nimport { VisionTask } from \"./base\";\nimport { type ClassProbability, type ClassificationResult, type RGBImage } from \"../types\";\n\nconst IMAGENET_MEAN: readonly [number, number, number] = [0.485, 0.456, 0.406];\nconst IMAGENET_STD: readonly [number, number, number] = [0.229, 0.224, 0.225];\n\nexport interface ClassifierOptions extends OrtSessionOptions {\n /**\n * Class label spec — see {@link resolveLabels}.\n *\n * Optional: when omitted, the names the export baked into the model are used\n * (Ultralytics writes them as `names` in the metadata map). Only when the\n * model carries none does this fall back to generated `class_<id>` labels.\n * Passing a spec always wins, for a model whose names are wrong or absent.\n */\n readonly labels?: LabelSpec;\n /**\n * Number of classes the model can predict.\n *\n * Optional: inferred from the classification head's declared output shape\n * `(B, nc)`. Pass it to validate that the supplied labels match the model.\n */\n readonly numClasses?: number;\n /**\n * Model input `[width, height]` in pixels.\n *\n * Only used when the model's graph leaves its spatial axes dynamic: a graph\n * that declares a static size always wins, since that is the only shape ONNX\n * Runtime will accept. Defaults to `[224, 224]`.\n */\n readonly inputSize?: readonly [number, number];\n /** Per-channel RGB mean used for normalization. Defaults to ImageNet. */\n readonly mean?: readonly [number, number, number];\n /** Per-channel RGB standard deviation. Defaults to ImageNet. */\n readonly std?: readonly [number, number, number];\n /**\n * If `true` (default), apply softmax to the raw model output. Set to\n * `false` for models whose final layer already produces a probability\n * distribution.\n */\n readonly applySoftmax?: boolean;\n}\n\nexport interface ClassifierPredictOptions {\n /**\n * If set, the per-class probability list in `results[0].result.probabilities`\n * is truncated to the top-K entries. The bulk `probs` view always exposes\n * the full vector.\n */\n readonly topK?: number;\n}\n\n/**\n * Image classifier wrapping an ONNX model with ImageNet-style preprocessing.\n *\n * `predict()` returns `Promise<ClassificationResults[]>` (length 1 for a\n * single image), mirroring Ultralytics' API. The envelope exposes a `probs`\n * collection (`top1`, `top1conf`, `top5`, `top5conf`, `data`) plus the\n * legacy per-class probability list with names already resolved.\n *\n * Defaults: 224×224 RGB input, `float32` normalized with ImageNet mean/std,\n * NCHW layout, batch size 1, softmax applied to the raw output.\n *\n * @example\n * ```typescript\n * const clf = await Classifier.create(\"/models/resnet50.onnx\", {\n * labels: [\"tench\", \"goldfish\", ...] // 1000 ImageNet labels\n * });\n * const r = (await clf.predict(\"/images/dog.jpg\"))[0];\n * console.log(r.cls, r.conf, r.name);\n * console.log(r.probs.top5, r.probs.top5conf);\n * ```\n */\nexport class Classifier extends VisionTask {\n private constructor(\n session: OrtSession,\n private readonly _labels: readonly string[],\n private readonly _names: Readonly<Record<number, string>>,\n private readonly _inputSize: readonly [number, number],\n private readonly _mean: readonly [number, number, number],\n private readonly _std: readonly [number, number, number],\n private readonly _applySoftmax: boolean,\n ) {\n super(session);\n }\n\n private _pipelineCache: ResizePipeline | null = null;\n\n /**\n * Run the model once on a zero tensor, paying one-time costs up front.\n *\n * The first inference of a session is not representative: WebGPU compiles its\n * shaders on it and the WASM backend faults in its arenas. Calling this while\n * a loading spinner is still up moves that cost somewhere the user is already\n * waiting — which matters most for a classifier running as the last step of\n * an on-device analysis, where the delay lands right before the answer shows.\n *\n * @param runs How many warm-up inferences to run. One is enough for WASM;\n * WebGPU sometimes settles on the second.\n */\n async warmup(runs: number = 1): Promise<void> {\n const [tw, th] = this._inputSize;\n for (let i = 0; i < runs; i++) {\n const tensor = toFloat32Tensor(zeroTensorData(tw, th), [1, 3, th, tw]);\n await this._session.run({ [this._session.inputName]: tensor });\n }\n }\n\n /**\n * The fused preprocessing pipeline, built on first use.\n *\n * Lazily, because constructing it reserves the output buffer: a task built in\n * an environment without a canvas implementation stays constructible, and only\n * fails if it is actually asked to preprocess something.\n */\n private get _pipeline(): ResizePipeline {\n if (this._pipelineCache === null) {\n const [tw, th] = this._inputSize;\n this._pipelineCache = new ResizePipeline(tw, th, this._mean, this._std);\n }\n return this._pipelineCache;\n }\n\n /** Load the model and resolve labels. */\n static async create(model: ModelSource, options: ClassifierOptions = {}): Promise<Classifier> {\n const session = await OrtSession.create(model, options);\n const numClasses =\n options.numClasses ?? classificationNumClasses(session.outputShape) ?? undefined;\n const labels = resolveLabels(options.labels ?? modelNames(session.metadata), {\n numClasses,\n });\n const names: Record<number, string> = {};\n for (let i = 0; i < labels.length; i++) {\n names[i] = labels[i] as string;\n }\n return new Classifier(\n session,\n labels,\n names,\n resolveInputSize({\n graphShape: session.inputShape,\n requested: options.inputSize,\n fallback: [224, 224],\n }),\n options.mean ?? IMAGENET_MEAN,\n options.std ?? IMAGENET_STD,\n options.applySoftmax ?? true,\n );\n }\n\n /** Class labels indexed by class id. */\n get labels(): readonly string[] {\n return this._labels;\n }\n\n /** Class id → class name dict (matches Ultralytics' `model.names`). */\n get names(): Readonly<Record<number, string>> {\n return this._names;\n }\n\n /**\n * The `[width, height]` this task preprocesses to.\n *\n * Resolved at creation time from the model's graph when it declares a static\n * input, so reading it back tells you the resolution inference really runs at\n * — not merely what was requested.\n */\n get inputSize(): readonly [number, number] {\n return this._inputSize;\n }\n\n /** Number of classes the model can predict. */\n get numClasses(): number {\n return this._labels.length;\n }\n\n /** Alias for {@link predict} (parity with PyTorch `nn.Module.__call__`). */\n async call(\n image: ImageInput,\n options: ClassifierPredictOptions = {},\n ): Promise<ClassificationResults[]> {\n return this.predict(image, options);\n }\n\n /** Run classification on a single image. */\n async predict(\n image: ImageInput,\n options: ClassifierPredictOptions = {},\n ): Promise<ClassificationResults[]> {\n const timer = new SpeedTimer();\n const path = typeof image === \"string\" ? image : null;\n const original = await loadImage(image);\n timer.stage(\"load\");\n const tensor = this._preprocess(original);\n timer.stage(\"preprocess\");\n const outputs = await this._session.run({ [this._session.inputName]: tensor });\n this._pipeline.release();\n timer.stage(\"inference\");\n const firstOutputName = this._session.outputNames[0];\n if (firstOutputName === undefined) {\n throw new Error(\"Classifier model has no outputs.\");\n }\n const raw = outputs[firstOutputName];\n if (raw === undefined) {\n throw new Error(\n `Classifier model output ${firstOutputName} missing from run() result.`,\n );\n }\n const fullProbs = this._postprocess(raw.data as Float32Array);\n\n const { indices, values } = topK(fullProbs, options.topK ?? null);\n const probabilities: ClassProbability[] = [];\n for (let i = 0; i < indices.length; i++) {\n const id = indices[i] as number;\n const className = this._labels[id] ?? `class_${id}`;\n probabilities.push({\n classId: id,\n className,\n probability: values[i] as number,\n cls: id,\n name: className,\n conf: values[i] as number,\n });\n }\n if (probabilities.length === 0) {\n throw new Error(\"Classifier produced no probabilities (empty output).\");\n }\n\n const top = probabilities[0] as ClassProbability;\n const result: ClassificationResult = {\n classId: top.classId,\n className: top.className,\n confidence: top.probability,\n cls: top.classId,\n name: top.className,\n conf: top.probability,\n image: original,\n probabilities,\n };\n\n const orig: readonly [number, number] = [original.height, original.width];\n const probs = new Probs(fullProbs);\n timer.stage(\"postprocess\");\n return [\n new ClassificationResults(\n probs,\n result,\n this._names,\n original,\n orig,\n path,\n timer.speed(),\n ),\n ];\n }\n\n private _preprocess(image: RGBImage): ort.Tensor {\n const [tw, th] = this._inputSize;\n const { data } = this._pipeline.run(image);\n return toFloat32Tensor(data, [1, 3, th, tw]);\n }\n\n private _postprocess(raw: Float32Array): Float32Array {\n return this._applySoftmax ? softmax(raw) : new Float32Array(raw);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"classifier.cjs","names":[],"sources":["../../../src/vision/tasks/classifier.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Image classification task using ONNX Runtime Web.\n */\n\nimport type * as ort from \"onnxruntime-web\";\n\nimport { type ModelSource, type OrtSessionOptions, OrtSession } from \"../core/session\";\nimport { SpeedTimer } from \"../core/timing\";\nimport { type ImageInput, loadImage } from \"../io/image\";\nimport { classificationNumClasses, resolveInputSize } from \"../core/graph\";\nimport { modelNames } from \"../core/metadata\";\nimport { type LabelSpec, resolveLabels } from \"../labels\";\nimport {\n type Normalization,\n isUltralyticsClassifier,\n resolveNormalization,\n} from \"../normalization\";\nimport { softmax, topK } from \"../postprocess/classification\";\nimport { toFloat32Tensor } from \"../preprocess/image\";\nimport { ResizePipeline, zeroTensorData } from \"../preprocess/pipeline\";\nimport { ClassificationResults, Probs } from \"../results\";\nimport { VisionTask } from \"./base\";\nimport { type ClassProbability, type ClassificationResult, type RGBImage } from \"../types\";\n\nexport interface ClassifierOptions extends OrtSessionOptions {\n /**\n * Class label spec — see {@link resolveLabels}.\n *\n * Optional: when omitted, the names the export baked into the model are used\n * (Ultralytics writes them as `names` in the metadata map). Only when the\n * model carries none does this fall back to generated `class_<id>` labels.\n * Passing a spec always wins, for a model whose names are wrong or absent.\n */\n readonly labels?: LabelSpec;\n /**\n * Number of classes the model can predict.\n *\n * Optional: inferred from the classification head's declared output shape\n * `(B, nc)`. Pass it to validate that the supplied labels match the model.\n */\n readonly numClasses?: number;\n /**\n * Model input `[width, height]` in pixels.\n *\n * Only used when the model's graph leaves its spatial axes dynamic: a graph\n * that declares a static size always wins, since that is the only shape ONNX\n * Runtime will accept. Defaults to `[224, 224]`.\n */\n readonly inputSize?: readonly [number, number];\n /**\n * Which preprocessing this model expects — see {@link Normalization}.\n *\n * Defaults to `\"auto\"`, which reads the model's own export metadata and picks\n * `\"ultralytics\"` (raw `[0, 1]`) for an Ultralytics classification head and\n * `\"imagenet\"` for everything else.\n */\n readonly normalization?: Normalization;\n /** Per-channel RGB mean, overriding the preset. Defaults to the preset's. */\n readonly mean?: readonly [number, number, number];\n /** Per-channel RGB standard deviation, overriding the preset. */\n readonly std?: readonly [number, number, number];\n /**\n * Whether the model's output still needs a softmax.\n *\n * Left undefined (the default), this reads the model's metadata and answers\n * `false` for an Ultralytics classification export, whose graph already ends\n * in one — applying a second softmax to a probability vector keeps the\n * ranking but flattens the confidences, so the top-1 stays right while every\n * number attached to it is wrong. Detection covers that family; for any other\n * model that already emits probabilities, pass `false` explicitly.\n */\n readonly applySoftmax?: boolean;\n}\n\nexport interface ClassifierPredictOptions {\n /**\n * If set, the per-class probability list in `results[0].result.probabilities`\n * is truncated to the top-K entries. The bulk `probs` view always exposes\n * the full vector.\n */\n readonly topK?: number;\n}\n\n/**\n * Image classifier wrapping an ONNX model with ImageNet-style preprocessing.\n *\n * `predict()` returns `Promise<ClassificationResults[]>` (length 1 for a\n * single image), mirroring Ultralytics' API. The envelope exposes a `probs`\n * collection (`top1`, `top1conf`, `top5`, `top5conf`, `data`) plus the\n * legacy per-class probability list with names already resolved.\n *\n * Defaults: 224×224 RGB input, `float32` normalized with ImageNet mean/std,\n * NCHW layout, batch size 1, softmax applied to the raw output.\n *\n * @example\n * ```typescript\n * const clf = await Classifier.create(\"/models/resnet50.onnx\", {\n * labels: [\"tench\", \"goldfish\", ...] // 1000 ImageNet labels\n * });\n * const r = (await clf.predict(\"/images/dog.jpg\"))[0];\n * console.log(r.cls, r.conf, r.name);\n * console.log(r.probs.top5, r.probs.top5conf);\n * ```\n */\nexport class Classifier extends VisionTask {\n private constructor(\n session: OrtSession,\n private readonly _labels: readonly string[],\n private readonly _names: Readonly<Record<number, string>>,\n private readonly _inputSize: readonly [number, number],\n private readonly _mean: readonly [number, number, number],\n private readonly _std: readonly [number, number, number],\n private readonly _applySoftmax: boolean,\n private readonly _normalization: string,\n ) {\n super(session);\n }\n\n /**\n * Whether a softmax is applied to the model's output before ranking.\n *\n * Resolved once at construction. Worth reading when confidences look\n * compressed: a second softmax over an already-normalized vector leaves the\n * ordering intact and the numbers meaningless, which is invisible to any check\n * that only looks at the predicted class.\n */\n get appliesSoftmax(): boolean {\n return this._applySoftmax;\n }\n\n /**\n * Which preprocessing this classifier applies to every image.\n *\n * One of the {@link Normalization} preset names, or `\"custom\"` when the caller\n * supplied `mean`/`std` directly. Worth reading when a model underperforms:\n * feeding a classifier a differently prepared tensor than it was trained on\n * degrades it without throwing anything, so \"what does this assume\" is the\n * first question.\n */\n get normalization(): string {\n return this._normalization;\n }\n\n private _pipelineCache: ResizePipeline | null = null;\n\n /**\n * Run the model once on a zero tensor, paying one-time costs up front.\n *\n * The first inference of a session is not representative: WebGPU compiles its\n * shaders on it and the WASM backend faults in its arenas. Calling this while\n * a loading spinner is still up moves that cost somewhere the user is already\n * waiting — which matters most for a classifier running as the last step of\n * an on-device analysis, where the delay lands right before the answer shows.\n *\n * @param runs How many warm-up inferences to run. One is enough for WASM;\n * WebGPU sometimes settles on the second.\n */\n async warmup(runs: number = 1): Promise<void> {\n const [tw, th] = this._inputSize;\n for (let i = 0; i < runs; i++) {\n const tensor = toFloat32Tensor(zeroTensorData(tw, th), [1, 3, th, tw]);\n await this._session.run({ [this._session.inputName]: tensor });\n }\n }\n\n /**\n * The fused preprocessing pipeline, built on first use.\n *\n * Lazily, because constructing it reserves the output buffer: a task built in\n * an environment without a canvas implementation stays constructible, and only\n * fails if it is actually asked to preprocess something.\n */\n private get _pipeline(): ResizePipeline {\n if (this._pipelineCache === null) {\n const [tw, th] = this._inputSize;\n this._pipelineCache = new ResizePipeline(tw, th, this._mean, this._std);\n }\n return this._pipelineCache;\n }\n\n /**\n * Load the model, resolve labels, and settle the preprocessing.\n *\n * @param model The model source — a URL, or the bytes.\n * @param options Labels, input size, normalization, and session options.\n * @throws {RangeError} If `normalization` names an unknown preset, or names\n * one while `mean`/`std` are also given.\n */\n static async create(model: ModelSource, options: ClassifierOptions = {}): Promise<Classifier> {\n const session = await OrtSession.create(model, options);\n const normalization = resolveNormalization(session.metadata, {\n normalization: options.normalization,\n mean: options.mean,\n std: options.std,\n });\n const numClasses =\n options.numClasses ?? classificationNumClasses(session.outputShape) ?? undefined;\n const labels = resolveLabels(options.labels ?? modelNames(session.metadata), {\n numClasses,\n });\n const names: Record<number, string> = {};\n for (let i = 0; i < labels.length; i++) {\n names[i] = labels[i] as string;\n }\n return new Classifier(\n session,\n labels,\n names,\n resolveInputSize({\n graphShape: session.inputShape,\n requested: options.inputSize,\n fallback: [224, 224],\n }),\n normalization.mean,\n normalization.std,\n options.applySoftmax ?? !isUltralyticsClassifier(session.metadata),\n normalization.name,\n );\n }\n\n /** Class labels indexed by class id. */\n get labels(): readonly string[] {\n return this._labels;\n }\n\n /** Class id → class name dict (matches Ultralytics' `model.names`). */\n get names(): Readonly<Record<number, string>> {\n return this._names;\n }\n\n /**\n * The `[width, height]` this task preprocesses to.\n *\n * Resolved at creation time from the model's graph when it declares a static\n * input, so reading it back tells you the resolution inference really runs at\n * — not merely what was requested.\n */\n get inputSize(): readonly [number, number] {\n return this._inputSize;\n }\n\n /** Number of classes the model can predict. */\n get numClasses(): number {\n return this._labels.length;\n }\n\n /** Alias for {@link predict} (parity with PyTorch `nn.Module.__call__`). */\n async call(\n image: ImageInput,\n options: ClassifierPredictOptions = {},\n ): Promise<ClassificationResults[]> {\n return this.predict(image, options);\n }\n\n /** Run classification on a single image. */\n async predict(\n image: ImageInput,\n options: ClassifierPredictOptions = {},\n ): Promise<ClassificationResults[]> {\n const timer = new SpeedTimer();\n const path = typeof image === \"string\" ? image : null;\n const original = await loadImage(image);\n timer.stage(\"load\");\n const tensor = this._preprocess(original);\n timer.stage(\"preprocess\");\n const outputs = await this._session.run({ [this._session.inputName]: tensor });\n this._pipeline.release();\n timer.stage(\"inference\");\n const firstOutputName = this._session.outputNames[0];\n if (firstOutputName === undefined) {\n throw new Error(\"Classifier model has no outputs.\");\n }\n const raw = outputs[firstOutputName];\n if (raw === undefined) {\n throw new Error(\n `Classifier model output ${firstOutputName} missing from run() result.`,\n );\n }\n const fullProbs = this._postprocess(raw.data as Float32Array);\n\n const { indices, values } = topK(fullProbs, options.topK ?? null);\n const probabilities: ClassProbability[] = [];\n for (let i = 0; i < indices.length; i++) {\n const id = indices[i] as number;\n const className = this._labels[id] ?? `class_${id}`;\n probabilities.push({\n classId: id,\n className,\n probability: values[i] as number,\n cls: id,\n name: className,\n conf: values[i] as number,\n });\n }\n if (probabilities.length === 0) {\n throw new Error(\"Classifier produced no probabilities (empty output).\");\n }\n\n const top = probabilities[0] as ClassProbability;\n const result: ClassificationResult = {\n classId: top.classId,\n className: top.className,\n confidence: top.probability,\n cls: top.classId,\n name: top.className,\n conf: top.probability,\n image: original,\n probabilities,\n };\n\n const orig: readonly [number, number] = [original.height, original.width];\n const probs = new Probs(fullProbs);\n timer.stage(\"postprocess\");\n return [\n new ClassificationResults(\n probs,\n result,\n this._names,\n original,\n orig,\n path,\n timer.speed(),\n ),\n ];\n }\n\n private _preprocess(image: RGBImage): ort.Tensor {\n const [tw, th] = this._inputSize;\n const { data } = this._pipeline.run(image);\n return toFloat32Tensor(data, [1, 3, th, tw]);\n }\n\n private _postprocess(raw: Float32Array): Float32Array {\n return this._applySoftmax ? softmax(raw) : new Float32Array(raw);\n }\n}\n"],"mappings":"kZAyGA,IAAa,EAAb,MAAa,UAAmB,EAAA,UAAW,CAGlB,QACA,OACA,WACA,MACA,KACA,cACA,eARrB,YACI,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACF,CACE,MAAM,CAAO,EARI,KAAA,QAAA,EACA,KAAA,OAAA,EACA,KAAA,WAAA,EACA,KAAA,MAAA,EACA,KAAA,KAAA,EACA,KAAA,cAAA,EACA,KAAA,eAAA,CAGrB,CAUA,IAAI,gBAA0B,CAC1B,OAAO,KAAK,aAChB,CAWA,IAAI,eAAwB,CACxB,OAAO,KAAK,cAChB,CAEA,eAAgD,KAchD,MAAM,OAAO,EAAe,EAAkB,CAC1C,GAAM,CAAC,EAAI,GAAM,KAAK,WACtB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,IAAK,CAC3B,IAAM,EAAS,EAAA,gBAAgB,EAAA,eAAe,EAAI,CAAE,EAAG,CAAC,EAAG,EAAG,EAAI,CAAE,CAAC,EACrE,MAAM,KAAK,SAAS,IAAI,EAAG,KAAK,SAAS,WAAY,CAAO,CAAC,CACjE,CACJ,CASA,IAAY,WAA4B,CACpC,GAAI,KAAK,iBAAmB,KAAM,CAC9B,GAAM,CAAC,EAAI,GAAM,KAAK,WACtB,KAAK,eAAiB,IAAI,EAAA,eAAe,EAAI,EAAI,KAAK,MAAO,KAAK,IAAI,CAC1E,CACA,OAAO,KAAK,cAChB,CAUA,aAAa,OAAO,EAAoB,EAA6B,CAAC,EAAwB,CAC1F,IAAM,EAAU,MAAM,EAAA,WAAW,OAAO,EAAO,CAAO,EAChD,EAAgB,EAAA,qBAAqB,EAAQ,SAAU,CACzD,cAAe,EAAQ,cACvB,KAAM,EAAQ,KACd,IAAK,EAAQ,GACjB,CAAC,EACK,EACF,EAAQ,YAAc,EAAA,yBAAyB,EAAQ,WAAW,GAAK,IAAA,GACrE,EAAS,EAAA,cAAc,EAAQ,QAAU,EAAA,WAAW,EAAQ,QAAQ,EAAG,CACzE,YACJ,CAAC,EACK,EAAgC,CAAC,EACvC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAQ,IAC/B,EAAM,GAAK,EAAO,GAEtB,OAAO,IAAI,EACP,EACA,EACA,EACA,EAAA,iBAAiB,CACb,WAAY,EAAQ,WACpB,UAAW,EAAQ,UACnB,SAAU,CAAC,IAAK,GAAG,CACvB,CAAC,EACD,EAAc,KACd,EAAc,IACd,EAAQ,cAAgB,CAAC,EAAA,wBAAwB,EAAQ,QAAQ,EACjE,EAAc,IAClB,CACJ,CAGA,IAAI,QAA4B,CAC5B,OAAO,KAAK,OAChB,CAGA,IAAI,OAA0C,CAC1C,OAAO,KAAK,MAChB,CASA,IAAI,WAAuC,CACvC,OAAO,KAAK,UAChB,CAGA,IAAI,YAAqB,CACrB,OAAO,KAAK,QAAQ,MACxB,CAGA,MAAM,KACF,EACA,EAAoC,CAAC,EACL,CAChC,OAAO,KAAK,QAAQ,EAAO,CAAO,CACtC,CAGA,MAAM,QACF,EACA,EAAoC,CAAC,EACL,CAChC,IAAM,EAAQ,IAAI,EAAA,WACZ,EAAO,OAAO,GAAU,SAAW,EAAQ,KAC3C,EAAW,MAAM,EAAA,UAAU,CAAK,EACtC,EAAM,MAAM,MAAM,EAClB,IAAM,EAAS,KAAK,YAAY,CAAQ,EACxC,EAAM,MAAM,YAAY,EACxB,IAAM,EAAU,MAAM,KAAK,SAAS,IAAI,EAAG,KAAK,SAAS,WAAY,CAAO,CAAC,EAC7E,KAAK,UAAU,QAAQ,EACvB,EAAM,MAAM,WAAW,EACvB,IAAM,EAAkB,KAAK,SAAS,YAAY,GAClD,GAAI,IAAoB,IAAA,GACpB,MAAU,MAAM,kCAAkC,EAEtD,IAAM,EAAM,EAAQ,GACpB,GAAI,IAAQ,IAAA,GACR,MAAU,MACN,2BAA2B,EAAgB,4BAC/C,EAEJ,IAAM,EAAY,KAAK,aAAa,EAAI,IAAoB,EAEtD,CAAE,UAAS,UAAW,EAAA,KAAK,EAAW,EAAQ,MAAQ,IAAI,EAC1D,EAAoC,CAAC,EAC3C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,OAAQ,IAAK,CACrC,IAAM,EAAK,EAAQ,GACb,EAAY,KAAK,QAAQ,IAAO,SAAS,IAC/C,EAAc,KAAK,CACf,QAAS,EACT,YACA,YAAa,EAAO,GACpB,IAAK,EACL,KAAM,EACN,KAAM,EAAO,EACjB,CAAC,CACL,CACA,GAAI,EAAc,SAAW,EACzB,MAAU,MAAM,sDAAsD,EAG1E,IAAM,EAAM,EAAc,GACpB,EAA+B,CACjC,QAAS,EAAI,QACb,UAAW,EAAI,UACf,WAAY,EAAI,YAChB,IAAK,EAAI,QACT,KAAM,EAAI,UACV,KAAM,EAAI,YACV,MAAO,EACP,eACJ,EAEM,EAAkC,CAAC,EAAS,OAAQ,EAAS,KAAK,EAClE,EAAQ,IAAI,EAAA,MAAM,CAAS,EAEjC,OADA,EAAM,MAAM,aAAa,EAClB,CACH,IAAI,EAAA,sBACA,EACA,EACA,KAAK,OACL,EACA,EACA,EACA,EAAM,MAAM,CAChB,CACJ,CACJ,CAEA,YAAoB,EAA6B,CAC7C,GAAM,CAAC,EAAI,GAAM,KAAK,WAChB,CAAE,QAAS,KAAK,UAAU,IAAI,CAAK,EACzC,OAAO,EAAA,gBAAgB,EAAM,CAAC,EAAG,EAAG,EAAI,CAAE,CAAC,CAC/C,CAEA,aAAqB,EAAiC,CAClD,OAAO,KAAK,cAAgB,EAAA,QAAQ,CAAG,EAAI,IAAI,aAAa,CAAG,CACnE,CACJ"}
|
|
@@ -4,35 +4,35 @@ import { resolveLabels as r } from "../labels.js";
|
|
|
4
4
|
import { classificationNumClasses as i, resolveInputSize as a } from "../core/graph.js";
|
|
5
5
|
import { modelNames as o } from "../core/metadata.js";
|
|
6
6
|
import { OrtSession as s } from "../core/session.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
7
|
+
import { isUltralyticsClassifier as c, resolveNormalization as l } from "../normalization.js";
|
|
8
|
+
import { loadImage as u } from "../io/image.js";
|
|
9
|
+
import { toFloat32Tensor as d } from "../preprocess/image.js";
|
|
10
|
+
import { ResizePipeline as f, zeroTensorData as p } from "../preprocess/pipeline.js";
|
|
11
|
+
import { softmax as m, topK as h } from "../postprocess/classification.js";
|
|
12
|
+
import { VisionTask as g } from "./base.js";
|
|
12
13
|
//#region src/vision/tasks/classifier.ts
|
|
13
|
-
var
|
|
14
|
-
.485,
|
|
15
|
-
.456,
|
|
16
|
-
.406
|
|
17
|
-
], g = [
|
|
18
|
-
.229,
|
|
19
|
-
.224,
|
|
20
|
-
.225
|
|
21
|
-
], _ = class _ extends m {
|
|
14
|
+
var _ = class _ extends g {
|
|
22
15
|
_labels;
|
|
23
16
|
_names;
|
|
24
17
|
_inputSize;
|
|
25
18
|
_mean;
|
|
26
19
|
_std;
|
|
27
20
|
_applySoftmax;
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
_normalization;
|
|
22
|
+
constructor(e, t, n, r, i, a, o, s) {
|
|
23
|
+
super(e), this._labels = t, this._names = n, this._inputSize = r, this._mean = i, this._std = a, this._applySoftmax = o, this._normalization = s;
|
|
24
|
+
}
|
|
25
|
+
get appliesSoftmax() {
|
|
26
|
+
return this._applySoftmax;
|
|
27
|
+
}
|
|
28
|
+
get normalization() {
|
|
29
|
+
return this._normalization;
|
|
30
30
|
}
|
|
31
31
|
_pipelineCache = null;
|
|
32
32
|
async warmup(e = 1) {
|
|
33
33
|
let [t, n] = this._inputSize;
|
|
34
34
|
for (let r = 0; r < e; r++) {
|
|
35
|
-
let e =
|
|
35
|
+
let e = d(p(t, n), [
|
|
36
36
|
1,
|
|
37
37
|
3,
|
|
38
38
|
n,
|
|
@@ -44,18 +44,22 @@ var h = [
|
|
|
44
44
|
get _pipeline() {
|
|
45
45
|
if (this._pipelineCache === null) {
|
|
46
46
|
let [e, t] = this._inputSize;
|
|
47
|
-
this._pipelineCache = new
|
|
47
|
+
this._pipelineCache = new f(e, t, this._mean, this._std);
|
|
48
48
|
}
|
|
49
49
|
return this._pipelineCache;
|
|
50
50
|
}
|
|
51
51
|
static async create(e, t = {}) {
|
|
52
|
-
let n = await s.create(e, t),
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
let n = await s.create(e, t), u = l(n.metadata, {
|
|
53
|
+
normalization: t.normalization,
|
|
54
|
+
mean: t.mean,
|
|
55
|
+
std: t.std
|
|
56
|
+
}), d = t.numClasses ?? i(n.outputShape) ?? void 0, f = r(t.labels ?? o(n.metadata), { numClasses: d }), p = {};
|
|
57
|
+
for (let e = 0; e < f.length; e++) p[e] = f[e];
|
|
58
|
+
return new _(n, f, p, a({
|
|
55
59
|
graphShape: n.inputShape,
|
|
56
60
|
requested: t.inputSize,
|
|
57
61
|
fallback: [224, 224]
|
|
58
|
-
}),
|
|
62
|
+
}), u.mean, u.std, t.applySoftmax ?? !c(n.metadata), u.name);
|
|
59
63
|
}
|
|
60
64
|
get labels() {
|
|
61
65
|
return this._labels;
|
|
@@ -73,19 +77,19 @@ var h = [
|
|
|
73
77
|
return this.predict(e, t);
|
|
74
78
|
}
|
|
75
79
|
async predict(r, i = {}) {
|
|
76
|
-
let a = new e(), o = typeof r == "string" ? r : null, s = await
|
|
80
|
+
let a = new e(), o = typeof r == "string" ? r : null, s = await u(r);
|
|
77
81
|
a.stage("load");
|
|
78
|
-
let
|
|
82
|
+
let c = this._preprocess(s);
|
|
79
83
|
a.stage("preprocess");
|
|
80
|
-
let
|
|
84
|
+
let l = await this._session.run({ [this._session.inputName]: c });
|
|
81
85
|
this._pipeline.release(), a.stage("inference");
|
|
82
86
|
let d = this._session.outputNames[0];
|
|
83
87
|
if (d === void 0) throw Error("Classifier model has no outputs.");
|
|
84
|
-
let f =
|
|
88
|
+
let f = l[d];
|
|
85
89
|
if (f === void 0) throw Error(`Classifier model output ${d} missing from run() result.`);
|
|
86
|
-
let
|
|
87
|
-
for (let e = 0; e <
|
|
88
|
-
let t =
|
|
90
|
+
let p = this._postprocess(f.data), { indices: m, values: g } = h(p, i.topK ?? null), _ = [];
|
|
91
|
+
for (let e = 0; e < m.length; e++) {
|
|
92
|
+
let t = m[e], n = this._labels[t] ?? `class_${t}`;
|
|
89
93
|
_.push({
|
|
90
94
|
classId: t,
|
|
91
95
|
className: n,
|
|
@@ -105,12 +109,12 @@ var h = [
|
|
|
105
109
|
conf: v.probability,
|
|
106
110
|
image: s,
|
|
107
111
|
probabilities: _
|
|
108
|
-
}, b = [s.height, s.width], x = new n(
|
|
112
|
+
}, b = [s.height, s.width], x = new n(p);
|
|
109
113
|
return a.stage("postprocess"), [new t(x, y, this._names, s, b, o, a.speed())];
|
|
110
114
|
}
|
|
111
115
|
_preprocess(e) {
|
|
112
116
|
let [t, n] = this._inputSize, { data: r } = this._pipeline.run(e);
|
|
113
|
-
return
|
|
117
|
+
return d(r, [
|
|
114
118
|
1,
|
|
115
119
|
3,
|
|
116
120
|
n,
|
|
@@ -118,7 +122,7 @@ var h = [
|
|
|
118
122
|
]);
|
|
119
123
|
}
|
|
120
124
|
_postprocess(e) {
|
|
121
|
-
return this._applySoftmax ?
|
|
125
|
+
return this._applySoftmax ? m(e) : new Float32Array(e);
|
|
122
126
|
}
|
|
123
127
|
};
|
|
124
128
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classifier.js","names":[],"sources":["../../../src/vision/tasks/classifier.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Image classification task using ONNX Runtime Web.\n */\n\nimport type * as ort from \"onnxruntime-web\";\n\nimport { type ModelSource, type OrtSessionOptions, OrtSession } from \"../core/session\";\nimport { SpeedTimer } from \"../core/timing\";\nimport { type ImageInput, loadImage } from \"../io/image\";\nimport { classificationNumClasses, resolveInputSize } from \"../core/graph\";\nimport { modelNames } from \"../core/metadata\";\nimport { type LabelSpec, resolveLabels } from \"../labels\";\nimport { softmax, topK } from \"../postprocess/classification\";\nimport { toFloat32Tensor } from \"../preprocess/image\";\nimport { ResizePipeline, zeroTensorData } from \"../preprocess/pipeline\";\nimport { ClassificationResults, Probs } from \"../results\";\nimport { VisionTask } from \"./base\";\nimport { type ClassProbability, type ClassificationResult, type RGBImage } from \"../types\";\n\nconst IMAGENET_MEAN: readonly [number, number, number] = [0.485, 0.456, 0.406];\nconst IMAGENET_STD: readonly [number, number, number] = [0.229, 0.224, 0.225];\n\nexport interface ClassifierOptions extends OrtSessionOptions {\n /**\n * Class label spec — see {@link resolveLabels}.\n *\n * Optional: when omitted, the names the export baked into the model are used\n * (Ultralytics writes them as `names` in the metadata map). Only when the\n * model carries none does this fall back to generated `class_<id>` labels.\n * Passing a spec always wins, for a model whose names are wrong or absent.\n */\n readonly labels?: LabelSpec;\n /**\n * Number of classes the model can predict.\n *\n * Optional: inferred from the classification head's declared output shape\n * `(B, nc)`. Pass it to validate that the supplied labels match the model.\n */\n readonly numClasses?: number;\n /**\n * Model input `[width, height]` in pixels.\n *\n * Only used when the model's graph leaves its spatial axes dynamic: a graph\n * that declares a static size always wins, since that is the only shape ONNX\n * Runtime will accept. Defaults to `[224, 224]`.\n */\n readonly inputSize?: readonly [number, number];\n /** Per-channel RGB mean used for normalization. Defaults to ImageNet. */\n readonly mean?: readonly [number, number, number];\n /** Per-channel RGB standard deviation. Defaults to ImageNet. */\n readonly std?: readonly [number, number, number];\n /**\n * If `true` (default), apply softmax to the raw model output. Set to\n * `false` for models whose final layer already produces a probability\n * distribution.\n */\n readonly applySoftmax?: boolean;\n}\n\nexport interface ClassifierPredictOptions {\n /**\n * If set, the per-class probability list in `results[0].result.probabilities`\n * is truncated to the top-K entries. The bulk `probs` view always exposes\n * the full vector.\n */\n readonly topK?: number;\n}\n\n/**\n * Image classifier wrapping an ONNX model with ImageNet-style preprocessing.\n *\n * `predict()` returns `Promise<ClassificationResults[]>` (length 1 for a\n * single image), mirroring Ultralytics' API. The envelope exposes a `probs`\n * collection (`top1`, `top1conf`, `top5`, `top5conf`, `data`) plus the\n * legacy per-class probability list with names already resolved.\n *\n * Defaults: 224×224 RGB input, `float32` normalized with ImageNet mean/std,\n * NCHW layout, batch size 1, softmax applied to the raw output.\n *\n * @example\n * ```typescript\n * const clf = await Classifier.create(\"/models/resnet50.onnx\", {\n * labels: [\"tench\", \"goldfish\", ...] // 1000 ImageNet labels\n * });\n * const r = (await clf.predict(\"/images/dog.jpg\"))[0];\n * console.log(r.cls, r.conf, r.name);\n * console.log(r.probs.top5, r.probs.top5conf);\n * ```\n */\nexport class Classifier extends VisionTask {\n private constructor(\n session: OrtSession,\n private readonly _labels: readonly string[],\n private readonly _names: Readonly<Record<number, string>>,\n private readonly _inputSize: readonly [number, number],\n private readonly _mean: readonly [number, number, number],\n private readonly _std: readonly [number, number, number],\n private readonly _applySoftmax: boolean,\n ) {\n super(session);\n }\n\n private _pipelineCache: ResizePipeline | null = null;\n\n /**\n * Run the model once on a zero tensor, paying one-time costs up front.\n *\n * The first inference of a session is not representative: WebGPU compiles its\n * shaders on it and the WASM backend faults in its arenas. Calling this while\n * a loading spinner is still up moves that cost somewhere the user is already\n * waiting — which matters most for a classifier running as the last step of\n * an on-device analysis, where the delay lands right before the answer shows.\n *\n * @param runs How many warm-up inferences to run. One is enough for WASM;\n * WebGPU sometimes settles on the second.\n */\n async warmup(runs: number = 1): Promise<void> {\n const [tw, th] = this._inputSize;\n for (let i = 0; i < runs; i++) {\n const tensor = toFloat32Tensor(zeroTensorData(tw, th), [1, 3, th, tw]);\n await this._session.run({ [this._session.inputName]: tensor });\n }\n }\n\n /**\n * The fused preprocessing pipeline, built on first use.\n *\n * Lazily, because constructing it reserves the output buffer: a task built in\n * an environment without a canvas implementation stays constructible, and only\n * fails if it is actually asked to preprocess something.\n */\n private get _pipeline(): ResizePipeline {\n if (this._pipelineCache === null) {\n const [tw, th] = this._inputSize;\n this._pipelineCache = new ResizePipeline(tw, th, this._mean, this._std);\n }\n return this._pipelineCache;\n }\n\n /** Load the model and resolve labels. */\n static async create(model: ModelSource, options: ClassifierOptions = {}): Promise<Classifier> {\n const session = await OrtSession.create(model, options);\n const numClasses =\n options.numClasses ?? classificationNumClasses(session.outputShape) ?? undefined;\n const labels = resolveLabels(options.labels ?? modelNames(session.metadata), {\n numClasses,\n });\n const names: Record<number, string> = {};\n for (let i = 0; i < labels.length; i++) {\n names[i] = labels[i] as string;\n }\n return new Classifier(\n session,\n labels,\n names,\n resolveInputSize({\n graphShape: session.inputShape,\n requested: options.inputSize,\n fallback: [224, 224],\n }),\n options.mean ?? IMAGENET_MEAN,\n options.std ?? IMAGENET_STD,\n options.applySoftmax ?? true,\n );\n }\n\n /** Class labels indexed by class id. */\n get labels(): readonly string[] {\n return this._labels;\n }\n\n /** Class id → class name dict (matches Ultralytics' `model.names`). */\n get names(): Readonly<Record<number, string>> {\n return this._names;\n }\n\n /**\n * The `[width, height]` this task preprocesses to.\n *\n * Resolved at creation time from the model's graph when it declares a static\n * input, so reading it back tells you the resolution inference really runs at\n * — not merely what was requested.\n */\n get inputSize(): readonly [number, number] {\n return this._inputSize;\n }\n\n /** Number of classes the model can predict. */\n get numClasses(): number {\n return this._labels.length;\n }\n\n /** Alias for {@link predict} (parity with PyTorch `nn.Module.__call__`). */\n async call(\n image: ImageInput,\n options: ClassifierPredictOptions = {},\n ): Promise<ClassificationResults[]> {\n return this.predict(image, options);\n }\n\n /** Run classification on a single image. */\n async predict(\n image: ImageInput,\n options: ClassifierPredictOptions = {},\n ): Promise<ClassificationResults[]> {\n const timer = new SpeedTimer();\n const path = typeof image === \"string\" ? image : null;\n const original = await loadImage(image);\n timer.stage(\"load\");\n const tensor = this._preprocess(original);\n timer.stage(\"preprocess\");\n const outputs = await this._session.run({ [this._session.inputName]: tensor });\n this._pipeline.release();\n timer.stage(\"inference\");\n const firstOutputName = this._session.outputNames[0];\n if (firstOutputName === undefined) {\n throw new Error(\"Classifier model has no outputs.\");\n }\n const raw = outputs[firstOutputName];\n if (raw === undefined) {\n throw new Error(\n `Classifier model output ${firstOutputName} missing from run() result.`,\n );\n }\n const fullProbs = this._postprocess(raw.data as Float32Array);\n\n const { indices, values } = topK(fullProbs, options.topK ?? null);\n const probabilities: ClassProbability[] = [];\n for (let i = 0; i < indices.length; i++) {\n const id = indices[i] as number;\n const className = this._labels[id] ?? `class_${id}`;\n probabilities.push({\n classId: id,\n className,\n probability: values[i] as number,\n cls: id,\n name: className,\n conf: values[i] as number,\n });\n }\n if (probabilities.length === 0) {\n throw new Error(\"Classifier produced no probabilities (empty output).\");\n }\n\n const top = probabilities[0] as ClassProbability;\n const result: ClassificationResult = {\n classId: top.classId,\n className: top.className,\n confidence: top.probability,\n cls: top.classId,\n name: top.className,\n conf: top.probability,\n image: original,\n probabilities,\n };\n\n const orig: readonly [number, number] = [original.height, original.width];\n const probs = new Probs(fullProbs);\n timer.stage(\"postprocess\");\n return [\n new ClassificationResults(\n probs,\n result,\n this._names,\n original,\n orig,\n path,\n timer.speed(),\n ),\n ];\n }\n\n private _preprocess(image: RGBImage): ort.Tensor {\n const [tw, th] = this._inputSize;\n const { data } = this._pipeline.run(image);\n return toFloat32Tensor(data, [1, 3, th, tw]);\n }\n\n private _postprocess(raw: Float32Array): Float32Array {\n return this._applySoftmax ? softmax(raw) : new Float32Array(raw);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"classifier.js","names":[],"sources":["../../../src/vision/tasks/classifier.ts"],"sourcesContent":["/** @generated Vendored from @mauriciobenjamin700/ort-vision-sdk-web. Do not hand-edit — regenerate with `npm run vendor:vision`. */\n/**\n * Image classification task using ONNX Runtime Web.\n */\n\nimport type * as ort from \"onnxruntime-web\";\n\nimport { type ModelSource, type OrtSessionOptions, OrtSession } from \"../core/session\";\nimport { SpeedTimer } from \"../core/timing\";\nimport { type ImageInput, loadImage } from \"../io/image\";\nimport { classificationNumClasses, resolveInputSize } from \"../core/graph\";\nimport { modelNames } from \"../core/metadata\";\nimport { type LabelSpec, resolveLabels } from \"../labels\";\nimport {\n type Normalization,\n isUltralyticsClassifier,\n resolveNormalization,\n} from \"../normalization\";\nimport { softmax, topK } from \"../postprocess/classification\";\nimport { toFloat32Tensor } from \"../preprocess/image\";\nimport { ResizePipeline, zeroTensorData } from \"../preprocess/pipeline\";\nimport { ClassificationResults, Probs } from \"../results\";\nimport { VisionTask } from \"./base\";\nimport { type ClassProbability, type ClassificationResult, type RGBImage } from \"../types\";\n\nexport interface ClassifierOptions extends OrtSessionOptions {\n /**\n * Class label spec — see {@link resolveLabels}.\n *\n * Optional: when omitted, the names the export baked into the model are used\n * (Ultralytics writes them as `names` in the metadata map). Only when the\n * model carries none does this fall back to generated `class_<id>` labels.\n * Passing a spec always wins, for a model whose names are wrong or absent.\n */\n readonly labels?: LabelSpec;\n /**\n * Number of classes the model can predict.\n *\n * Optional: inferred from the classification head's declared output shape\n * `(B, nc)`. Pass it to validate that the supplied labels match the model.\n */\n readonly numClasses?: number;\n /**\n * Model input `[width, height]` in pixels.\n *\n * Only used when the model's graph leaves its spatial axes dynamic: a graph\n * that declares a static size always wins, since that is the only shape ONNX\n * Runtime will accept. Defaults to `[224, 224]`.\n */\n readonly inputSize?: readonly [number, number];\n /**\n * Which preprocessing this model expects — see {@link Normalization}.\n *\n * Defaults to `\"auto\"`, which reads the model's own export metadata and picks\n * `\"ultralytics\"` (raw `[0, 1]`) for an Ultralytics classification head and\n * `\"imagenet\"` for everything else.\n */\n readonly normalization?: Normalization;\n /** Per-channel RGB mean, overriding the preset. Defaults to the preset's. */\n readonly mean?: readonly [number, number, number];\n /** Per-channel RGB standard deviation, overriding the preset. */\n readonly std?: readonly [number, number, number];\n /**\n * Whether the model's output still needs a softmax.\n *\n * Left undefined (the default), this reads the model's metadata and answers\n * `false` for an Ultralytics classification export, whose graph already ends\n * in one — applying a second softmax to a probability vector keeps the\n * ranking but flattens the confidences, so the top-1 stays right while every\n * number attached to it is wrong. Detection covers that family; for any other\n * model that already emits probabilities, pass `false` explicitly.\n */\n readonly applySoftmax?: boolean;\n}\n\nexport interface ClassifierPredictOptions {\n /**\n * If set, the per-class probability list in `results[0].result.probabilities`\n * is truncated to the top-K entries. The bulk `probs` view always exposes\n * the full vector.\n */\n readonly topK?: number;\n}\n\n/**\n * Image classifier wrapping an ONNX model with ImageNet-style preprocessing.\n *\n * `predict()` returns `Promise<ClassificationResults[]>` (length 1 for a\n * single image), mirroring Ultralytics' API. The envelope exposes a `probs`\n * collection (`top1`, `top1conf`, `top5`, `top5conf`, `data`) plus the\n * legacy per-class probability list with names already resolved.\n *\n * Defaults: 224×224 RGB input, `float32` normalized with ImageNet mean/std,\n * NCHW layout, batch size 1, softmax applied to the raw output.\n *\n * @example\n * ```typescript\n * const clf = await Classifier.create(\"/models/resnet50.onnx\", {\n * labels: [\"tench\", \"goldfish\", ...] // 1000 ImageNet labels\n * });\n * const r = (await clf.predict(\"/images/dog.jpg\"))[0];\n * console.log(r.cls, r.conf, r.name);\n * console.log(r.probs.top5, r.probs.top5conf);\n * ```\n */\nexport class Classifier extends VisionTask {\n private constructor(\n session: OrtSession,\n private readonly _labels: readonly string[],\n private readonly _names: Readonly<Record<number, string>>,\n private readonly _inputSize: readonly [number, number],\n private readonly _mean: readonly [number, number, number],\n private readonly _std: readonly [number, number, number],\n private readonly _applySoftmax: boolean,\n private readonly _normalization: string,\n ) {\n super(session);\n }\n\n /**\n * Whether a softmax is applied to the model's output before ranking.\n *\n * Resolved once at construction. Worth reading when confidences look\n * compressed: a second softmax over an already-normalized vector leaves the\n * ordering intact and the numbers meaningless, which is invisible to any check\n * that only looks at the predicted class.\n */\n get appliesSoftmax(): boolean {\n return this._applySoftmax;\n }\n\n /**\n * Which preprocessing this classifier applies to every image.\n *\n * One of the {@link Normalization} preset names, or `\"custom\"` when the caller\n * supplied `mean`/`std` directly. Worth reading when a model underperforms:\n * feeding a classifier a differently prepared tensor than it was trained on\n * degrades it without throwing anything, so \"what does this assume\" is the\n * first question.\n */\n get normalization(): string {\n return this._normalization;\n }\n\n private _pipelineCache: ResizePipeline | null = null;\n\n /**\n * Run the model once on a zero tensor, paying one-time costs up front.\n *\n * The first inference of a session is not representative: WebGPU compiles its\n * shaders on it and the WASM backend faults in its arenas. Calling this while\n * a loading spinner is still up moves that cost somewhere the user is already\n * waiting — which matters most for a classifier running as the last step of\n * an on-device analysis, where the delay lands right before the answer shows.\n *\n * @param runs How many warm-up inferences to run. One is enough for WASM;\n * WebGPU sometimes settles on the second.\n */\n async warmup(runs: number = 1): Promise<void> {\n const [tw, th] = this._inputSize;\n for (let i = 0; i < runs; i++) {\n const tensor = toFloat32Tensor(zeroTensorData(tw, th), [1, 3, th, tw]);\n await this._session.run({ [this._session.inputName]: tensor });\n }\n }\n\n /**\n * The fused preprocessing pipeline, built on first use.\n *\n * Lazily, because constructing it reserves the output buffer: a task built in\n * an environment without a canvas implementation stays constructible, and only\n * fails if it is actually asked to preprocess something.\n */\n private get _pipeline(): ResizePipeline {\n if (this._pipelineCache === null) {\n const [tw, th] = this._inputSize;\n this._pipelineCache = new ResizePipeline(tw, th, this._mean, this._std);\n }\n return this._pipelineCache;\n }\n\n /**\n * Load the model, resolve labels, and settle the preprocessing.\n *\n * @param model The model source — a URL, or the bytes.\n * @param options Labels, input size, normalization, and session options.\n * @throws {RangeError} If `normalization` names an unknown preset, or names\n * one while `mean`/`std` are also given.\n */\n static async create(model: ModelSource, options: ClassifierOptions = {}): Promise<Classifier> {\n const session = await OrtSession.create(model, options);\n const normalization = resolveNormalization(session.metadata, {\n normalization: options.normalization,\n mean: options.mean,\n std: options.std,\n });\n const numClasses =\n options.numClasses ?? classificationNumClasses(session.outputShape) ?? undefined;\n const labels = resolveLabels(options.labels ?? modelNames(session.metadata), {\n numClasses,\n });\n const names: Record<number, string> = {};\n for (let i = 0; i < labels.length; i++) {\n names[i] = labels[i] as string;\n }\n return new Classifier(\n session,\n labels,\n names,\n resolveInputSize({\n graphShape: session.inputShape,\n requested: options.inputSize,\n fallback: [224, 224],\n }),\n normalization.mean,\n normalization.std,\n options.applySoftmax ?? !isUltralyticsClassifier(session.metadata),\n normalization.name,\n );\n }\n\n /** Class labels indexed by class id. */\n get labels(): readonly string[] {\n return this._labels;\n }\n\n /** Class id → class name dict (matches Ultralytics' `model.names`). */\n get names(): Readonly<Record<number, string>> {\n return this._names;\n }\n\n /**\n * The `[width, height]` this task preprocesses to.\n *\n * Resolved at creation time from the model's graph when it declares a static\n * input, so reading it back tells you the resolution inference really runs at\n * — not merely what was requested.\n */\n get inputSize(): readonly [number, number] {\n return this._inputSize;\n }\n\n /** Number of classes the model can predict. */\n get numClasses(): number {\n return this._labels.length;\n }\n\n /** Alias for {@link predict} (parity with PyTorch `nn.Module.__call__`). */\n async call(\n image: ImageInput,\n options: ClassifierPredictOptions = {},\n ): Promise<ClassificationResults[]> {\n return this.predict(image, options);\n }\n\n /** Run classification on a single image. */\n async predict(\n image: ImageInput,\n options: ClassifierPredictOptions = {},\n ): Promise<ClassificationResults[]> {\n const timer = new SpeedTimer();\n const path = typeof image === \"string\" ? image : null;\n const original = await loadImage(image);\n timer.stage(\"load\");\n const tensor = this._preprocess(original);\n timer.stage(\"preprocess\");\n const outputs = await this._session.run({ [this._session.inputName]: tensor });\n this._pipeline.release();\n timer.stage(\"inference\");\n const firstOutputName = this._session.outputNames[0];\n if (firstOutputName === undefined) {\n throw new Error(\"Classifier model has no outputs.\");\n }\n const raw = outputs[firstOutputName];\n if (raw === undefined) {\n throw new Error(\n `Classifier model output ${firstOutputName} missing from run() result.`,\n );\n }\n const fullProbs = this._postprocess(raw.data as Float32Array);\n\n const { indices, values } = topK(fullProbs, options.topK ?? null);\n const probabilities: ClassProbability[] = [];\n for (let i = 0; i < indices.length; i++) {\n const id = indices[i] as number;\n const className = this._labels[id] ?? `class_${id}`;\n probabilities.push({\n classId: id,\n className,\n probability: values[i] as number,\n cls: id,\n name: className,\n conf: values[i] as number,\n });\n }\n if (probabilities.length === 0) {\n throw new Error(\"Classifier produced no probabilities (empty output).\");\n }\n\n const top = probabilities[0] as ClassProbability;\n const result: ClassificationResult = {\n classId: top.classId,\n className: top.className,\n confidence: top.probability,\n cls: top.classId,\n name: top.className,\n conf: top.probability,\n image: original,\n probabilities,\n };\n\n const orig: readonly [number, number] = [original.height, original.width];\n const probs = new Probs(fullProbs);\n timer.stage(\"postprocess\");\n return [\n new ClassificationResults(\n probs,\n result,\n this._names,\n original,\n orig,\n path,\n timer.speed(),\n ),\n ];\n }\n\n private _preprocess(image: RGBImage): ort.Tensor {\n const [tw, th] = this._inputSize;\n const { data } = this._pipeline.run(image);\n return toFloat32Tensor(data, [1, 3, th, tw]);\n }\n\n private _postprocess(raw: Float32Array): Float32Array {\n return this._applySoftmax ? softmax(raw) : new Float32Array(raw);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAyGA,IAAa,IAAb,MAAa,UAAmB,EAAW;CAGlB;CACA;CACA;CACA;CACA;CACA;CACA;CARrB,YACI,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACF;EADmB,AAEjB,MAAM,CAAO,GARI,KAAA,UAAA,GACA,KAAA,SAAA,GACA,KAAA,aAAA,GACA,KAAA,QAAA,GACA,KAAA,OAAA,GACA,KAAA,gBAAA,GACA,KAAA,iBAAA;CAGrB;CAUA,IAAI,iBAA0B;EAC1B,OAAO,KAAK;CAChB;CAWA,IAAI,gBAAwB;EACxB,OAAO,KAAK;CAChB;CAEA,iBAAgD;CAchD,MAAM,OAAO,IAAe,GAAkB;EAC1C,IAAM,CAAC,GAAI,KAAM,KAAK;EACtB,KAAK,IAAI,IAAI,GAAG,IAAI,GAAM,KAAK;GAC3B,IAAM,IAAS,EAAgB,EAAe,GAAI,CAAE,GAAG;IAAC;IAAG;IAAG;IAAI;GAAE,CAAC;GACrE,MAAM,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,YAAY,EAAO,CAAC;EACjE;CACJ;CASA,IAAY,YAA4B;EACpC,IAAI,KAAK,mBAAmB,MAAM;GAC9B,IAAM,CAAC,GAAI,KAAM,KAAK;GACtB,KAAK,iBAAiB,IAAI,EAAe,GAAI,GAAI,KAAK,OAAO,KAAK,IAAI;EAC1E;EACA,OAAO,KAAK;CAChB;CAUA,aAAa,OAAO,GAAoB,IAA6B,CAAC,GAAwB;EAC1F,IAAM,IAAU,MAAM,EAAW,OAAO,GAAO,CAAO,GAChD,IAAgB,EAAqB,EAAQ,UAAU;GACzD,eAAe,EAAQ;GACvB,MAAM,EAAQ;GACd,KAAK,EAAQ;EACjB,CAAC,GACK,IACF,EAAQ,cAAc,EAAyB,EAAQ,WAAW,KAAK,KAAA,GACrE,IAAS,EAAc,EAAQ,UAAU,EAAW,EAAQ,QAAQ,GAAG,EACzE,cACJ,CAAC,GACK,IAAgC,CAAC;EACvC,KAAK,IAAI,IAAI,GAAG,IAAI,EAAO,QAAQ,KAC/B,EAAM,KAAK,EAAO;EAEtB,OAAO,IAAI,EACP,GACA,GACA,GACA,EAAiB;GACb,YAAY,EAAQ;GACpB,WAAW,EAAQ;GACnB,UAAU,CAAC,KAAK,GAAG;EACvB,CAAC,GACD,EAAc,MACd,EAAc,KACd,EAAQ,gBAAgB,CAAC,EAAwB,EAAQ,QAAQ,GACjE,EAAc,IAClB;CACJ;CAGA,IAAI,SAA4B;EAC5B,OAAO,KAAK;CAChB;CAGA,IAAI,QAA0C;EAC1C,OAAO,KAAK;CAChB;CASA,IAAI,YAAuC;EACvC,OAAO,KAAK;CAChB;CAGA,IAAI,aAAqB;EACrB,OAAO,KAAK,QAAQ;CACxB;CAGA,MAAM,KACF,GACA,IAAoC,CAAC,GACL;EAChC,OAAO,KAAK,QAAQ,GAAO,CAAO;CACtC;CAGA,MAAM,QACF,GACA,IAAoC,CAAC,GACL;EAChC,IAAM,IAAQ,IAAI,EAAW,GACvB,IAAO,OAAO,KAAU,WAAW,IAAQ,MAC3C,IAAW,MAAM,EAAU,CAAK;EACtC,EAAM,MAAM,MAAM;EAClB,IAAM,IAAS,KAAK,YAAY,CAAQ;EACxC,EAAM,MAAM,YAAY;EACxB,IAAM,IAAU,MAAM,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,YAAY,EAAO,CAAC;EAE7E,AADA,KAAK,UAAU,QAAQ,GACvB,EAAM,MAAM,WAAW;EACvB,IAAM,IAAkB,KAAK,SAAS,YAAY;EAClD,IAAI,MAAoB,KAAA,GACpB,MAAU,MAAM,kCAAkC;EAEtD,IAAM,IAAM,EAAQ;EACpB,IAAI,MAAQ,KAAA,GACR,MAAU,MACN,2BAA2B,EAAgB,4BAC/C;EAEJ,IAAM,IAAY,KAAK,aAAa,EAAI,IAAoB,GAEtD,EAAE,YAAS,cAAW,EAAK,GAAW,EAAQ,QAAQ,IAAI,GAC1D,IAAoC,CAAC;EAC3C,KAAK,IAAI,IAAI,GAAG,IAAI,EAAQ,QAAQ,KAAK;GACrC,IAAM,IAAK,EAAQ,IACb,IAAY,KAAK,QAAQ,MAAO,SAAS;GAC/C,EAAc,KAAK;IACf,SAAS;IACT;IACA,aAAa,EAAO;IACpB,KAAK;IACL,MAAM;IACN,MAAM,EAAO;GACjB,CAAC;EACL;EACA,IAAI,EAAc,WAAW,GACzB,MAAU,MAAM,sDAAsD;EAG1E,IAAM,IAAM,EAAc,IACpB,IAA+B;GACjC,SAAS,EAAI;GACb,WAAW,EAAI;GACf,YAAY,EAAI;GAChB,KAAK,EAAI;GACT,MAAM,EAAI;GACV,MAAM,EAAI;GACV,OAAO;GACP;EACJ,GAEM,IAAkC,CAAC,EAAS,QAAQ,EAAS,KAAK,GAClE,IAAQ,IAAI,EAAM,CAAS;EAEjC,OADA,EAAM,MAAM,aAAa,GAClB,CACH,IAAI,EACA,GACA,GACA,KAAK,QACL,GACA,GACA,GACA,EAAM,MAAM,CAChB,CACJ;CACJ;CAEA,YAAoB,GAA6B;EAC7C,IAAM,CAAC,GAAI,KAAM,KAAK,YAChB,EAAE,YAAS,KAAK,UAAU,IAAI,CAAK;EACzC,OAAO,EAAgB,GAAM;GAAC;GAAG;GAAG;GAAI;EAAE,CAAC;CAC/C;CAEA,aAAqB,GAAiC;EAClD,OAAO,KAAK,gBAAgB,EAAQ,CAAG,IAAI,IAAI,aAAa,CAAG;CACnE;AACJ"}
|
package/dist/vision.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./vision/use-camera-stream.cjs"),t=require("./vision/core/exceptions.cjs"),n=require("./vision/types.cjs"),r=require("./vision/core/timing.cjs"),i=require("./vision/results.cjs"),a=require("./vision/labels.cjs"),o=require("./vision/core/graph.cjs"),s=require("./vision/core/metadata.cjs"),c=require("./vision/core/providers.cjs"),l=require("./vision/core/session.cjs"),u=require("./vision/io/image.cjs"),
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./vision/use-camera-stream.cjs"),t=require("./vision/core/exceptions.cjs"),n=require("./vision/types.cjs"),r=require("./vision/core/timing.cjs"),i=require("./vision/results.cjs"),a=require("./vision/labels.cjs"),o=require("./vision/core/graph.cjs"),s=require("./vision/core/metadata.cjs"),c=require("./vision/core/providers.cjs"),l=require("./vision/core/session.cjs"),u=require("./vision/normalization.cjs"),d=require("./vision/io/image.cjs"),f=require("./vision/fusion.cjs"),p=require("./vision/preprocess/image.cjs"),m=require("./vision/preprocess/pipeline.cjs"),h=require("./vision/postprocess/classification.cjs"),g=require("./vision/postprocess/detection.cjs"),_=require("./vision/postprocess/segmentation.cjs"),v=require("./vision/tasks/base.cjs"),y=require("./vision/tasks/classifier.cjs"),b=require("./vision/tasks/detectClassify.cjs"),x=require("./vision/tasks/detector.cjs"),S=require("./vision/tasks/segmenter.cjs"),C=require("./vision/index.cjs"),w=require("./vision/luminance.cjs"),T=require("./vision/use-live-luminance.cjs");exports.BoundingBox=n.BoundingBox,exports.Boxes=i.Boxes,exports.COCO_CLASSES=a.COCO_CLASSES,exports.CUSTOM_NORMALIZATION=u.CUSTOM_NORMALIZATION,exports.ClassificationResults=i.ClassificationResults,exports.Classifier=y.Classifier,exports.DEFAULT_PROVIDERS=c.DEFAULT_PROVIDERS,exports.DetectClassify=b.DetectClassify,exports.DetectClassifyResults=i.DetectClassifyResults,exports.DetectionResults=i.DetectionResults,exports.Detector=x.Detector,exports.FUSION_KIND_DETECT_CLASSIFY=f.FUSION_KIND_DETECT_CLASSIFY,exports.FusionError=t.FusionError,exports.IDENTITY_MEAN=u.IDENTITY_MEAN,exports.IDENTITY_STD=u.IDENTITY_STD,exports.IMAGENET_MEAN=u.IMAGENET_MEAN,exports.IMAGENET_STD=u.IMAGENET_STD,exports.INPUT_IMAGE=f.INPUT_IMAGE,exports.INPUT_PAD=f.INPUT_PAD,exports.INPUT_SCALE=f.INPUT_SCALE,exports.INPUT_SOURCE=f.INPUT_SOURCE,exports.ImageLoadError=t.ImageLoadError,exports.InferenceError=t.InferenceError,exports.LUMINANCE_SAMPLE_MAX_EDGE=w.LUMINANCE_SAMPLE_MAX_EDGE,exports.LabelMapError=t.LabelMapError,exports.LetterboxPipeline=m.LetterboxPipeline,exports.LowLuminanceError=w.LowLuminanceError,exports.METADATA_PREFIX=f.METADATA_PREFIX,exports.Mask=n.Mask,exports.Masks=i.Masks,exports.ModelLoadError=t.ModelLoadError,exports.NoDetectionsError=t.NoDetectionsError,exports.OUTPUT_BOXES=f.OUTPUT_BOXES,exports.OUTPUT_CLASSES=f.OUTPUT_CLASSES,exports.OUTPUT_NUM_DETECTIONS=f.OUTPUT_NUM_DETECTIONS,exports.OUTPUT_PROBS=f.OUTPUT_PROBS,exports.OUTPUT_SCORES=f.OUTPUT_SCORES,exports.OrtSession=l.OrtSession,exports.OrtVisionError=t.OrtVisionError,exports.Probs=i.Probs,exports.ProviderNotAvailableError=t.ProviderNotAvailableError,exports.RGBImage=n.RGBImage,exports.ResizePipeline=m.ResizePipeline,exports.SegmentationResults=i.SegmentationResults,exports.Segmenter=S.Segmenter,exports.SpeedTimer=r.SpeedTimer,exports.VERSION=C.VERSION,exports.VisionTask=v.VisionTask,exports.batchedNms=g.batchedNms,exports.classificationNumClasses=o.classificationNumClasses,exports.computeImageLuminance=w.computeImageLuminance,exports.declaredShapesFrom=o.declaredShapesFrom,exports.decodeYolo=g.decodeYolo,exports.decodeYoloAnchors=g.decodeYoloAnchors,exports.decodeYoloSeg=_.decodeYoloSeg,exports.defaultLabels=a.defaultLabels,exports.detectProviders=c.detectProviders,exports.detectionNumClasses=o.detectionNumClasses,exports.fromCv2=p.fromCv2,exports.isLuminanceAcceptable=w.isLuminanceAcceptable,exports.isUltralyticsClassifier=u.isUltralyticsClassifier,exports.letterbox=p.letterbox,exports.letterboxToTensorData=m.letterboxToTensorData,exports.loadImage=d.loadImage,exports.modelNames=s.modelNames,exports.nms=g.nms,exports.normalize=p.normalize,exports.parseNames=s.parseNames,exports.readFusionSpec=f.readFusionSpec,exports.readModelMetadata=s.readModelMetadata,exports.requireDetections=v.requireDetections,exports.resize=p.resize,exports.resizeToTensorData=m.resizeToTensorData,exports.resolveInputSize=o.resolveInputSize,exports.resolveLabels=a.resolveLabels,exports.resolveNormalization=u.resolveNormalization,exports.resolveProviders=c.resolveProviders,exports.softmax=h.softmax,exports.spatialInputSize=o.spatialInputSize,exports.toCHW=p.toCHW,exports.toCv2=p.toCv2,exports.toFloat32=p.toFloat32,exports.toFloat32Tensor=p.toFloat32Tensor,exports.toTensor=p.toTensor,exports.topK=h.topK,exports.useCameraStream=e.useCameraStream,exports.useLiveLuminance=T.useLiveLuminance,exports.writePlanarFloat32=m.writePlanarFloat32,exports.zeroTensorData=m.zeroTensorData;
|