@livemira/target-rating 0.0.0-stage → 0.5.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,175 @@
1
+ # Changelog
2
+
3
+ All notable changes are listed here, following [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions
4
+ follow [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.5.1] — 2026-11-04
9
+
10
+ The camera UI learns two things at runtime: a language button and a relocated sound button. The demo is now in
11
+ English by default and starts scanning on open.
12
+
13
+ ### Added
14
+
15
+ - A language button in the camera view (top right): switches the interface between English and Simplified Chinese
16
+ live, without restarting the session. It shows the language it switches to ("中" on an English interface, "EN" on
17
+ a Chinese one), and the label carries its own `lang` so screen readers pronounce it right. The root element's
18
+ `lang` follows the active language.
19
+ - `update({ locale })` on the view: the host page can change the language itself (the button does exactly this).
20
+
21
+ ### Changed
22
+
23
+ - The sound button moved from the top right to the bottom right (clear of the bottom controls; safe-area aware).
24
+ - The demo starts the camera as soon as the page opens (no start button, no settings), is in English by default
25
+ (`?lang=zh-CN` for Chinese), and its target page shows each image's tracking rating as stars beside the pager
26
+ (half stars included).
27
+
28
+ ## [0.5.0] — 2026-10-26
29
+
30
+ The 0.5.0 release: the engine, camera UI and rating of 0.5.0-rc.2 (accepted on phones inside LiveMorae), with the
31
+ rating made a module of its own and the engine reduced to its core.
32
+
33
+ ### Added
34
+
35
+ - `@livemira/target-rating` (`files/livemira-target-rating.min.mjs`, with its Worker file and declarations): the
36
+ target rating as a module of its own, for pages that choose pictures without the engine (a work editor).
37
+ `rateTargetImage(blob)` decodes and compiles the picture as the engine's `compileTargetImage` would, in the module's
38
+ own Worker, and rates it; `rateTarget(bundle | bytes)` rates a compiled target. Errors are `RatingError`s
39
+ (`UNSUITABLE_TARGET` for a picture the engine would refuse). Same ratings as rc.2. The release manifest lists the
40
+ engine's and the rating's build ids apart (`modules`): a change to one leaves the other's files as they are.
41
+
42
+ ### Removed
43
+
44
+ - `rateTarget` and its types are no longer in the engine (`@livemira/engine`); use `@livemira/target-rating`.
45
+
46
+ ### Changed
47
+
48
+ - The engine is 7 KB smaller (123 KB, was 130 KB): besides the rating, device-test diagnostics (frame strips, per-frame traces,
49
+ orientation thumbnails) are compiled out of releases, and the vision Worker no longer estimates a 6-DoF pose every
50
+ frame (nothing used it). Recognition, tracking and presentation are unchanged.
51
+ - The demo's rating page uses the rating module; the engine is not loaded there.
52
+ - The engine and the camera UI are on npm (`@livemira/engine`, `@livemira/ui`). Their packages hold the minified
53
+ modules, the engine's Worker file, the declarations and the guides (links pointing to the release on GitHub), with
54
+ repository metadata; the readable builds stay in the release's `files/`. The target rating is an offline package in
55
+ the release's `npm/` only.
56
+
57
+ ## [0.5.0-rc.2] — 2026-10-25
58
+
59
+ Second release candidate of 0.5.0: small photos kept and found again, recognition on the camera's own size by
60
+ default (both accepted on a phone with the ⑩ comparison), and target rating. For the acceptance inside LiveMorae;
61
+ 0.5.0 will differ only in its version.
62
+
63
+ ### Added
64
+
65
+ - `rateTarget(bundle)`: target rating in stars (0.5–5) from the compiled target and the engine's own detector on
66
+ synthetic views, with four factors (detail, spread, distinctiveness, recognition), five recognition tests (size,
67
+ tilt, motion blur, dim light, partly covered; each a ladder from easy to hard, each view tried twice and counted by
68
+ its inlier margin), advice codes and the counted points. Detail crowded in one place caps the stars. Weights
69
+ calibrated on 28 public pictures (the set 0.4.1's demo pictures come from) and the LiveMorae demo photo against
70
+ their measured difficulty in the bench's scene (bench/src/measure-targets.ts; rank correlation ~0.6). The stars sit
71
+ between a first, lenient version (most photos 5) and a strict one (most 3–4), fitted to their midpoint: those
72
+ pictures average 4 (2 rate 5, 12 rate 4.5, 7 rate 4, 3–4 rate 3.5, 3–4 rate 3 or less); 0.4.1's samples rate 4.5
73
+ (bird), 4.5 (forest), 3–3.5 (mountain), 2.5 (ship), the LiveMorae demo photo 4. Pictures with detail kept in a
74
+ quarter or the centre rate 0.5, in a half 1.5, all but a quarter 3; low-texture 0.5, a repeating tile 1. The demo gains `rate.html`: a picture or a video frame
75
+ (first, last or any), its rating drawn over it with the five tests, what the stars mean, and the ratings of the 0.4.1
76
+ samples next to 0.4.1's own scores and their measured difficulty.
77
+ - The demo's `targets.html` shows one picture per page, as large as the page allows, turned by swiping, the arrows or
78
+ the arrow keys (`#2` opens a page); printed, one picture per sheet.
79
+ - `camera.processingScale` (1, 0.75, 0.5; default 1; in `@livemira/ui` through `engineOptions.camera`): recognition and tracking work on the camera's own size by
80
+ default, no longer on a fixed 640 px long edge (0.5 of a 720p camera). In simulation (a 1280 × 720 camera, the
81
+ LiveMorae demo photo) the reliable range starts at about 25% of the frame's short edge instead of 40%. On an iPhone
82
+ (⑩, 2.5 minutes each) the own size lost the photo 0 times, 0.5 six times, for 3.4–4.6 ms per frame instead of
83
+ 1.7–2.7 ms at 30 fps. A quarter size recognised no photo in simulation and is not offered.
84
+
85
+ ### Changed
86
+
87
+ - The detector takes features from a whole frame at the density of 700 per 640 × 360 (never fewer than 700), so a
88
+ larger processed picture is not searched more thinly.
89
+ - The luma resample of integer ratios (the camera's size, half, quarter) averages and turns by index steps instead of
90
+ interpolating; RGB frames reuse their gray buffer.
91
+
92
+ ### Fixed
93
+
94
+ - Photos small on screen were lost more often and came back slowly (found with the ⑩ comparison on a phone: below
95
+ about half of the frame's short edge). After a short tracking failure (a jerk, a refocus) the engine searched the
96
+ whole frame at its own size, where a photo under about 140 px long edge cannot be recognised. It now searches
97
+ around the photo's last place for up to 2 s (the region growing with time; the whole frame every third frame),
98
+ and enlarges a small photo's region up to 3× before taking its features; the coasting search and the periodic
99
+ relocalisation enlarge it too. In simulation the detector finds 80–120 px photos in 85–100% of frames instead of
100
+ 0–25%.
101
+
102
+ ## [0.5.0-rc.1] — 2026-10-23
103
+
104
+ Release candidate of 0.5.0: the code of 0.5.0-preview.3 (accepted on a phone with the test page), for the acceptance
105
+ inside LiveMorae. 0.5.0 will differ only in its version.
106
+
107
+ ### Changed
108
+
109
+ - The guides and release notes no longer describe a preview; the release manifest marks neither `stable` nor
110
+ `preview`.
111
+ - The upgrade notes also list the version assertion in LiveMorae's `tests/scanTargets.test.ts` and the documents that
112
+ name the current version.
113
+
114
+ ## [0.5.0-preview.3] — 2026-10-23
115
+
116
+ ### Changed
117
+
118
+ - Videos stream: a video URL goes to the browser's player, which fetches it in ranges and starts as soon as enough has
119
+ arrived (it used to be downloaded whole first). Camera UI: `video.isStreamed`, default true, or false when the host
120
+ gives its own `loadMedia` (media behind header authentication keeps being downloaded whole). A streamed video that
121
+ cannot be fetched is a `video-load` error the host may classify.
122
+ - The loading look follows the video: right on recognition a see-through dark region in the video's shape (the
123
+ photo's until the browser knows the video's size, then easing to it) with the spinner in its centre; the reveal
124
+ opens that region from its centre once the video can play, its wavefront kept inside it.
125
+ - The engine asks a recognised photo's video to play at once (some browsers load a video only when asked to play).
126
+
127
+ ### Added
128
+
129
+ - The spinner shows again over a playing video that runs short of data for more than 0.4 s (the browser's `waiting`).
130
+
131
+ ## [0.5.0-preview.2] — 2026-10-23
132
+
133
+ ### Fixed
134
+
135
+ - The camera UI's default `loadMedia` sends cookies to the page's own origin (never to another origin). With
136
+ `credentials: 'omit'` a page behind a login or an access cookie could not load its own photos and videos, and the
137
+ run ended with "the photos could not be loaded" (found in the first phone test).
138
+
139
+ ## [0.5.0-preview.1] — 2026-10-23
140
+
141
+ A preview of the next-generation engine for LiveMorae's internal testing. The engine is new; the camera UI keeps the
142
+ 0.4.1 API.
143
+
144
+ ### Added
145
+
146
+ - Engine profiles: `'swift'` (default), `'hawk'` and `'wren'`, with fallback by device capability and Hawk stepping
147
+ down to Swift at run time. Devices without WebGL2 and `VideoFrame` are refused with `UNSUPPORTED_DEVICE`.
148
+ - Frame-locked composition: the camera picture and everything drawn on a photo come from the same processed frame in
149
+ one WebGL2 canvas, so videos do not drift against their photos.
150
+ - On the photo: recognition glow, loading veil with a progress ring (`setTargetProgress`), a play mark when playback
151
+ needs a tap, and the centre-out reveal with a light wavefront; perspective-correct and anti-aliased; a 0.2 s fade
152
+ with reduced motion.
153
+ - `setTargets` while running (loaded in the background, `targetsReady`), `probeDevice()`, `parseTarget` for stored
154
+ targets, the Worker file for strict CSPs (`workerUrl`).
155
+ - Camera UI: a loader card with real progress, a scanning guide, recognition vibration (`isHapticEnabled`), download
156
+ progress through `loadMedia`'s `onProgress`, state fields `readiness`, `isCameraOn`, `videoProgress`.
157
+
158
+ ### Changed
159
+
160
+ - Recognition and tracking: C1 oriented multi-scale binary features with view synthesis, ESM fast loop, corner-space
161
+ Kalman filter, concurrent relocalisation, WebAssembly SIMD kernels (see the design document's measured results).
162
+ - Photos compile in a pool of up to three short-lived Workers, at the same time as the camera opens.
163
+ - Target format v2 (`livemira-target/2`, SHA-256, descriptor version); 0.4 targets must be compiled again.
164
+ - Engine API: new events (`targetFound`, `targetLost`, `media`, `viewport`, `ended`, …) and error codes; see the
165
+ integration guide.
166
+
167
+ ### Removed
168
+
169
+ - 0.4 engine options without a counterpart (`processingLongEdge`, `capture`, `timestamps`, `maxPredictionMs`,
170
+ `adapters`, `extensions`, `diagnostics`) and the optional extensions (tracking visuals, recognition diagnostics,
171
+ target quality).
172
+
173
+ ## [0.4.1] — 2026-10-18
174
+
175
+ See the 0.4.1 release.
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2026 Andy (@andy-mira)
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/NOTICE ADDED
@@ -0,0 +1,18 @@
1
+ LiveMira
2
+ Copyright 2026 Andy
3
+
4
+ This product includes software developed by Andy.
5
+
6
+ All LiveMira source code, including the Rust sources of the WebAssembly SIMD
7
+ kernels (kernels/vision) and the modules generated from them, build tools and
8
+ documentation, is licensed under the Apache License, Version 2.0. See the
9
+ LICENSE file.
10
+
11
+ The WebAssembly module is compiled from those sources with the Rust toolchain,
12
+ a development tool that is not redistributed. No third-party code is bundled
13
+ into the engine or the camera UI.
14
+
15
+ The sample photographs of the demo (demo/assets) are public-domain (CC0 1.0)
16
+ works by their authors; see demo/assets/CREDITS.md. They are not covered by the
17
+ Apache License of this project. The demo video is an original work of this
18
+ project (Apache-2.0).
package/README.md CHANGED
@@ -1,3 +1,87 @@
1
- # Temporary Holding Version
1
+ # @livemira/target-rating — target rating
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [English](https://github.com/andy-mira/livemira/blob/v0.5.1/release/0.5.1/documentation/target-rating.md) | [简体中文](https://github.com/andy-mira/livemira/blob/v0.5.1/release/0.5.1/documentation/target-rating.zh-CN.md)
4
+
5
+ > **Offline package**, not on npm: `npm install ./livemira-target-rating-0.5.1.tgz` from the [release](https://github.com/andy-mira/livemira/tree/v0.5.1/release/0.5.1).
6
+
7
+ Rates a picture for scanning (0.5–5 stars), so a page where the user picks the target picture (an uploaded photo, or
8
+ the first, last or any frame of a video) can suggest a better one.
9
+
10
+ The rating is a separate module and **needs no engine**: a page that never opens the camera, such as a work editor,
11
+ loads this one file. In its own Worker it decodes, scales and compiles the picture as the engine's
12
+ `compileTargetImage` does, then runs the engine's own detector on synthetic views, so the rating is of exactly the
13
+ target the engine would track.
14
+
15
+ ## Files
16
+
17
+ | File | Purpose |
18
+ | -------------------------------------------- | -------------------------------------------------------------------------- |
19
+ | `files/livemira-target-rating.min.mjs` | One ES module, Worker embedded (about 47 KB). |
20
+ | `files/livemira-target-rating.mjs` | The same module, readable. |
21
+ | `files/livemira-target-rating-worker.min.js` | The rating Worker script (classic), for pages whose CSP forbids `blob:`. |
22
+ | `files/livemira-target-rating.d.ts` | Declarations. |
23
+ | `npm/livemira-target-rating-*.tgz` | Offline package `@livemira/target-rating` (not on npm; `npm install` the file). |
24
+
25
+ Importing the module creates nothing; the first rating starts its Worker, which closes after 4 s idle. One picture is
26
+ rated at a time; the rest wait in order.
27
+
28
+ ## Use
29
+
30
+ ```js
31
+ import { rateTargetImage, RatingError } from './livemira-target-rating.min.mjs';
32
+
33
+ try {
34
+ const rating = await rateTargetImage(photoFile, { signal });
35
+ showStars(rating.stars); // 0.5…5 in halves
36
+ if (rating.stars < 3) suggestAnotherFrame(rating.advice);
37
+ } catch (error) {
38
+ if (error instanceof RatingError && error.code === 'UNSUITABLE_TARGET') showCannotUse(); // the engine would refuse it
39
+ else if (error?.code !== 'ABORTED') throw error;
40
+ }
41
+ ```
42
+
43
+ - `rateTargetImage(image, { signal?, workerUrl?, maxEdgePx = 640 })`: a picture file (JPEG, PNG, WebP, …; its own
44
+ orientation applied). Keep `maxEdgePx` equal to the engine's `compileTargetImage`.
45
+ - `rateTarget(target, { signal?, workerUrl? })`: a compiled target, the engine's bundle (`compileTargetImage`,
46
+ `parseTarget`) or its `bytes`.
47
+ - Abort the previous rating with `signal` when the picture changes. About 0.5 s per picture on a desktop, 1–2 s on a
48
+ phone.
49
+ - `RatingError.code`: `UNSUITABLE_TARGET` (too small, or under 48 recognition points: the engine would refuse it),
50
+ `DECODE_FAILED`, `INVALID_TARGET`, `INVALID_INPUT`, `WORKER_FAILED`, `ABORTED`.
51
+
52
+ ## Result
53
+
54
+ `{ stars, score, factors: { detail, spread, distinctiveness, recognition }, metrics, advice, points, width, height }`.
55
+ 5 stars: near the best on every count; 4–4.5 good; 3–3.5 usable (steady when frontal and near, loses the picture when
56
+ small, tilted or shaken); 2–2.5 better replaced; below, not recommended. Suggest another picture below 3 stars.
57
+
58
+ Factors (0..1): `detail` (points found in at least 5 of the compiler's 14 views), `spread` (those points over the
59
+ picture: grid cells, evenness, the weakest quarter), `distinctiveness` (no look-alikes far apart), `recognition` (the
60
+ detector on synthetic views, five tests from easy to hard: smaller, tilted, motion-blurred, dimmer, partly covered;
61
+ each view tried twice and counted by its margin; per test in `metrics.tests`). Score = 100 × (0.15 detail + 0.4 spread
62
+ + 0.05 distinctiveness + 0.4 recognition); stars = 0.5 + 4.5 × the score's place between 15 and 95, capped at
63
+ 1 + 4 × min(spread, recognition)^0.4: detail crowded in one place, or hardly found in the views, cannot rate high.
64
+
65
+ `advice`, most important first: `HARD_TO_FIND`, `CONCENTRATED`, `WEAK_QUARTER` (`metrics.weakestQuarter`),
66
+ `FEW_DETAILS`, `REPETITIVE`, and `FAILS_SMALL`, `FAILS_TILTED`, `FAILS_BLURRED`, `FAILS_DIM`, `FAILS_COVERED` (that
67
+ test clearly weaker than for most photos). `points` are the counted points in target pixels (`width` × `height`), for
68
+ drawing the spread over the picture.
69
+
70
+ Calibrated on 28 public pictures (the set 0.4.1's samples come from) and the LiveMorae demo photo against their
71
+ measured difficulty in simulation (rank correlation ~0.6); the stars were tuned in two rounds of use on phones,
72
+ between a lenient and a strict version (those pictures average 4). The demo's `rate.html` is a complete rating page.
73
+
74
+ ## CSP and browsers
75
+
76
+ The Worker starts from a `blob:` URL: allow `worker-src blob:`, or serve `livemira-target-rating-worker.min.js` and
77
+ pass `workerUrl`. No WebAssembly, no network requests. Needs Workers and `createImageBitmap`; pictures are decoded in
78
+ the Worker with `OffscreenCanvas` 2D, else on the page.
79
+
80
+ ## Version
81
+
82
+ Built apart from the engine (its own build id; `release-manifest.json` lists both under `modules`): a change to the
83
+ rating leaves the engine's files as they are. `RATING_VERSION` and `ratingBuildInfo` give the version and build id.
84
+
85
+ ## License
86
+
87
+ Apache-2.0. See [LICENSE](https://github.com/andy-mira/livemira/blob/v0.5.1/release/0.5.1/LICENSE) and [NOTICE](https://github.com/andy-mira/livemira/blob/v0.5.1/release/0.5.1/NOTICE).
@@ -0,0 +1,117 @@
1
+ # @livemira/target-rating —— 目标图评分
2
+
3
+ [English](https://github.com/andy-mira/livemira/blob/v0.5.1/release/0.5.1/documentation/target-rating.md) | [简体中文](https://github.com/andy-mira/livemira/blob/v0.5.1/release/0.5.1/documentation/target-rating.zh-CN.md)
4
+
5
+ > **离线包**,不在 npm 上:从[发布包](https://github.com/andy-mira/livemira/tree/v0.5.1/release/0.5.1)中 `npm install ./livemira-target-rating-0.5.1.tgz`。
6
+
7
+ 给扫描用的照片打分(0.5–5 星),在用户选目标图时(上传的图片,或视频的首帧、尾帧、任意一帧)提示他换一张更好的。
8
+
9
+ 评分是独立模块,**不需要引擎**:作品编辑页这类页面不打开相机,只加载这一个文件即可。它在自己的 Worker 里按引擎 `compileTargetImage` 的方式解码、缩放、编译图片,再用引擎自己的检测器在合成画面上实测,所以分数针对的正是引擎将要跟踪的那份目标。
10
+
11
+ ## 文件
12
+
13
+ | 文件 | 用途 |
14
+ | -------------------------------------------- | ---------------------------------------------------------------------- |
15
+ | `files/livemira-target-rating.min.mjs` | 单个 ES 模块,Worker 已内嵌(约 47 KB)。 |
16
+ | `files/livemira-target-rating.mjs` | 同一模块的可读版本。 |
17
+ | `files/livemira-target-rating-worker.min.js` | 评分的 Worker 脚本(经典脚本),供 CSP 禁止 `blob:` Worker 的页面使用。 |
18
+ | `files/livemira-target-rating.d.ts` | 类型声明。 |
19
+ | `npm/livemira-target-rating-*.tgz` | 离线包 `@livemira/target-rating`(不在 npm 上,可 `npm install` 这个文件)。 |
20
+
21
+ 导入模块不会创建任何东西;第一次评分时才启动 Worker,空闲 4 秒后关闭。同一时间只评一张,其余排队。
22
+
23
+ ## 用法
24
+
25
+ ```js
26
+ import { rateTargetImage, RatingError } from './livemira-target-rating.min.mjs';
27
+
28
+ const controller = new AbortController();
29
+ try {
30
+ const rating = await rateTargetImage(photoFile, { signal: controller.signal });
31
+ showStars(rating.stars); // 0.5…5,半星
32
+ if (rating.stars < 3) suggestAnotherFrame(rating.advice);
33
+ } catch (error) {
34
+ if (error instanceof RatingError && error.code === 'UNSUITABLE_TARGET') showCannotUse(); // 引擎不会接受这张图
35
+ else if (error?.code !== 'ABORTED') throw error;
36
+ }
37
+ ```
38
+
39
+ - `rateTargetImage(image, { signal?, workerUrl?, maxEdgePx = 640 })`:图片文件(JPEG、PNG、WebP…,按图片自身的方向)。`maxEdgePx` 要与引擎 `compileTargetImage` 用的一致。
40
+ - `rateTarget(target, { signal?, workerUrl? })`:已编译的目标——引擎 `compileTargetImage`、`parseTarget` 得到的 bundle,或其 `bytes`。
41
+ - 换图时用 `signal` 取消上一次评分,过时的结果不会回来。
42
+ - 桌面每张约 0.5 秒,手机约 1–2 秒。
43
+
44
+ ### 错误
45
+
46
+ `RatingError` 有 `code` 与 `message`:
47
+
48
+ | `code` | 含义 |
49
+ | ------------------- | ---------------------------------------------------------- |
50
+ | `UNSUITABLE_TARGET` | 引擎不会接受这张图:太小,或细节太少(识别点不足 48 个)。 |
51
+ | `DECODE_FAILED` | 图片无法解码,或文件为空。 |
52
+ | `INVALID_TARGET` | 目标数据损坏(`rateTarget`)。 |
53
+ | `INVALID_INPUT` | 不是图片文件或目标,或选项超出范围。 |
54
+ | `WORKER_FAILED` | Worker 无法启动(多见于 CSP 禁止 `blob:`)或运行出错。 |
55
+ | `ABORTED` | 通过 `signal` 取消。 |
56
+
57
+ ## 结果
58
+
59
+ ```ts
60
+ { stars, score, factors: { detail, spread, distinctiveness, recognition }, metrics, advice, points, width, height }
61
+ ```
62
+
63
+ | 星级 | 含义 |
64
+ | ------- | ------------------------------------------------------ |
65
+ | 5 | 各方面都接近最好:小、斜、晃、暗、被挡时也多能认出 |
66
+ | 4–4.5 | 好,适合作为目标图 |
67
+ | 3–3.5 | 可用:正对、距离适中时稳定,偏小、斜拍或晃动时容易丢失 |
68
+ | 2–2.5 | 勉强,建议换图或换帧 |
69
+ | 0.5–1.5 | 不建议 |
70
+
71
+ 建议:低于 3 星时提示换一张;3–3.5 星可以接受,但提示"扫描时正对、靠近"。
72
+
73
+ 四项各 0..1:
74
+
75
+ | 项目 | 含义 |
76
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
77
+ | `detail` 细节 | 编译器 14 个模拟视角中,至少 5 个都能检出的"稳定点"的数量(40 个以下为 0,250 个以上为满分) |
78
+ | `spread` 分布 | 稳定点在画面网格(约 16 格,随长宽比)里铺开的程度:有足够点的格子占比、各格均匀度,再乘上最弱一角的系数(只要有一角几乎没有点,最多扣 40%) |
79
+ | `distinctiveness` 独特性 | 稳定点中,在远处找不到相似描述子的比例;同一角点在旁边几个像素处的近亲不算 |
80
+ | `recognition` 实测识别 | 用引擎自己的检测器认 640 × 360 的合成画面,五项测试各由易到难:缩小(长边 160/120/90/70 px)、斜拍(45°/60°/70°)、晃动模糊(6/10/16 px)、暗光(对比降到 35%/20% 并加噪)、部分遮挡(遮住任一角或任一半);每个画面换两种握持各试一次,按内点数计余量(刚好认出只算一部分)。各项结果见 `metrics.tests` |
81
+
82
+ 分数 = 100 × (0.15 细节 + 0.4 分布 + 0.05 独特性 + 0.4 实测识别);星级 = 0.5 + 4.5 × (分数从 15 到 95 线性对应),并封顶于 1 + 4 × min(分布, 实测识别)^0.4,按半星取整。所以细节再多,只要挤在一处,或在合成画面里几乎认不出,也给不了高分。
83
+
84
+ `advice` 按重要性列出原因:
85
+
86
+ | 代码 | 含义 |
87
+ | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
88
+ | `HARD_TO_FIND` | 合成画面中多数认不出或很勉强 |
89
+ | `CONCENTRATED` | 细节集中在画面的一部分 |
90
+ | `WEAK_QUARTER` | 某一角几乎没有细节(`metrics.weakestQuarter`) |
91
+ | `FEW_DETAILS` | 能从不同角度稳定认出的细节点偏少 |
92
+ | `REPETITIVE` | 相似图案多(格子、砖墙、条纹等),容易认错位置 |
93
+ | `FAILS_SMALL`、`FAILS_TILTED`、`FAILS_BLURRED`、`FAILS_DIM`、`FAILS_COVERED` | 缩小、斜拍、晃动模糊、暗光、部分遮挡这一项明显差于一般照片 |
94
+
95
+ 中文提示文字可参考示例 `demo/rate.js` 里的 `ADVICE`。`points` 是计入细节的点(目标像素坐标,`width` × `height`),可画在图上说明分布;`metrics.grid` 是各格的点数。
96
+
97
+ ## 校准
98
+
99
+ 权重与阈值按 28 张公开测试图(0.4.1 示例图所在的整套图,CC0)和 LiveMorae 演示照片校准:以仿真场景中引擎在较难条件下的检测率与手持跟踪的实测为准,评分与实测的等级相关约 0.6。星级的松紧经两轮真机体验调整,取在偏松与偏严两版的中间:这 28 张平均 4 星,其中 5 星 2 张、4.5 星 12 张、4 星 7 张、3.5 星 3–4 张、3 星及以下 3–4 张;0.4.1 的四张示例为鸟屋 4.5、森林 4.5、山脉 3–3.5、船 2.5,LiveMorae 演示照片 4。浏览器与 Node 的图片解码略有差别,个别图可能差半星。
100
+
101
+ 示例里的 `rate.html` 是一个完整的评分页面:上传图片或视频(选首帧、尾帧、任意帧),显示星级、四项与五项识别明细、原因,以及稳定点与网格密度叠加图。
102
+
103
+ ## 内容安全策略(CSP)
104
+
105
+ 评分模块用 `blob:` 地址启动 Worker:请允许 `worker-src blob:`。不允许时,部署 `livemira-target-rating-worker.min.js` 并传 `workerUrl`。评分不需要 WebAssembly,也不发出任何网络请求。
106
+
107
+ ## 浏览器要求
108
+
109
+ Worker、`createImageBitmap`;Worker 中的 `OffscreenCanvas` 2D 可用时在 Worker 内解码,否则在页面上解码后把灰度像素交给 Worker。
110
+
111
+ ## 版本
112
+
113
+ 评分模块与引擎分开构建(各自的构建 ID,见 `release-manifest.json` 的 `modules`):评分的改动不会改变引擎文件。`RATING_VERSION`、`ratingBuildInfo` 给出版本与构建 ID。
114
+
115
+ ## 许可
116
+
117
+ Apache-2.0。见 [LICENSE](https://github.com/andy-mira/livemira/blob/v0.5.1/release/0.5.1/LICENSE) 与 [NOTICE](https://github.com/andy-mira/livemira/blob/v0.5.1/release/0.5.1/NOTICE)。
@@ -0,0 +1 @@
1
+ "use strict";(()=>{var le=Object.defineProperty;var Ae=(e,t,r)=>t in e?le(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var F=(e,t,r)=>Ae(e,typeof t!="symbol"?t+"":t,r);var X=class{constructor(){F(this,"rows",new Int32Array(0));F(this,"levels",[])}build(t,r,n=24){let o=[{...t,scale:1}];for(let l=1;l<r;l++){let c=o[l-1],s=c.width>>1,a=c.height>>1;if(s<n||a<n)break;this.rows.length<c.width*a&&(this.rows=new Int32Array(c.width*a));let i=this.levels[l]=this.levels[l]&&this.levels[l].length===s*a?this.levels[l]:new Uint8Array(s*a);me(c,s,a,this.rows,i),o.push({width:s,height:a,stride:s,data:i,scale:c.scale*2})}return{levels:o}}};function me(e,t,r,n,o){let l=e.width,c=e.height,s=e.data,a=e.stride;for(let i=0;i<r;i++){let A=2*i,u=Math.max(0,A-1)*a,m=A*a,h=Math.min(c-1,A+1)*a,g=Math.min(c-1,A+2)*a,y=i*l;for(let f=0;f<l;f++)n[y+f]=s[u+f]+3*s[m+f]+3*s[h+f]+s[g+f]}for(let i=0;i<r;i++){let A=i*l;for(let u=0;u<t;u++){let m=2*u,h=n[A+Math.max(0,m-1)],g=n[A+m],y=n[A+Math.min(l-1,m+1)],f=n[A+Math.min(l-1,m+2)];o[i*t+u]=h+3*g+3*y+f+32>>6}}}function Ct(e,t,r=24){return new X().build(e,t,r)}function tt(e,t,r){let n=t-.5,o=r-.5,l=Math.floor(n),c=Math.floor(o);if(l<0||c<0||l+1>=e.width||c+1>=e.height)return NaN;let s=n-l,a=o-c,i=e.data,A=c*e.stride+l,u=i[A]+s*(i[A+1]-i[A]),m=i[A+e.stride]+s*(i[A+e.stride+1]-i[A+e.stride]);return u+a*(m-u)}var Kt=Object.freeze({sha256:"d51fe1439175bb1343361385d7910036f36a63ed17a83311619a3b04cfa3e837",byteLength:4375,base64:"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"});function ue(e){let t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n++)r[n]=t.charCodeAt(n);return r}var et;function ut(){if(typeof WebAssembly>"u")return null;try{if(et===void 0){let e=ue(Kt.base64);et=WebAssembly.validate(e)?new WebAssembly.Module(e):null}return et?new WebAssembly.Instance(et,{}).exports:null}catch{return et=null,null}}var fe=[[0,-3],[1,-3],[2,-2],[3,-1],[3,0],[3,1],[2,2],[1,3],[0,3],[-1,3],[-2,2],[-3,1],[-3,0],[-3,-1],[-2,-2],[-1,-3]];function ye(e,t,r,n){let o=e[t],l=o+n,c=o-n,s=e[t+r[0]],a=e[t+r[8]];if(s<=l&&s>=c&&a<=l&&a>=c)return 0;let i=e[t+r[4]],A=e[t+r[12]];if(i<=l&&i>=c&&A<=l&&A>=c)return 0;let u=0,m=0,h=0,g=0;for(let y=0;y<16;y++){let f=e[t+r[y]];f>l?(u|=1<<y,h+=f-l):f<c&&(m|=1<<y,g+=c-f)}return qt(u)?h+1:qt(m)?g+1:0}function qt(e){if(!e)return!1;let t=(e|e<<16)>>>0,r=t;for(let n=1;n<9;n++)r&=t>>>n;return r!==0}var yt=class{constructor(){F(this,"backend","js");F(this,"map",new Uint16Array(0));F(this,"image",null);F(this,"offsets",new Int32Array(16))}begin(t){return this.map.length<t.width*t.height&&(this.map=new Uint16Array(t.width*t.height)),this.image=t,this.offsets=Int32Array.from(fe.map(([r,n])=>n*t.stride+r)),this.map}score(t,r,n,o,l,c){let{width:s,stride:a,data:i}=this.image;for(let A=r;A<o;A++)for(let u=t;u<n;u++){let m=ye(i,A*a+u,this.offsets,l);m>0&&(this.map[A*s+u]=m,c.push(A*s+u))}}},Qt=class{constructor(t){F(this,"backend","wasm-simd");F(this,"k");F(this,"capacity",0);F(this,"img",0);F(this,"scores",0);F(this,"found",0);F(this,"map",new Uint16Array(0));F(this,"image",null);this.k=t}begin(t){let r=t.stride*t.height;if(r>this.capacity){let n=this.k;if(n.reset_heap(),this.img=n.reserve(r+16),this.scores=n.reserve(2*r),this.found=n.reserve(4*r),!this.img||!this.scores||!this.found)throw new Error("fast9: out of memory");this.capacity=r,new Uint16Array(n.memory.buffer,this.scores,r).fill(0)}return new Uint8Array(this.k.memory.buffer,this.img,r).set(t.data.subarray(0,r)),this.map=new Uint16Array(this.k.memory.buffer,this.scores,t.width*t.height),this.image=t,this.map}score(t,r,n,o,l,c){let s=this.image,a=this.k.fast9(this.img,s.stride,t,r,n,o,l,this.scores,s.width,this.found),i=new Uint32Array(this.k.memory.buffer,this.found,a);for(let A=0;A<a;A++)c.push(i[A])}};function he(e){let n=new Uint8Array(2867),o=2654435769;for(let s=0;s<47;s++)for(let a=0;a<61;a++){o^=o<<13,o^=o>>>17,o^=o<<5;let i=(o>>>0)%64;n[s*61+a]=a<20?128:a<40?((a>>2)+(s>>2))%2?230-i:20+i:i*4}let l={width:61,height:47,stride:61,data:n},c=new yt;for(let s of[4,16,40]){let a=[],i=[],A=c.begin(l),u=e.begin(l);if(c.score(3,3,43,44,s,a),e.score(3,3,43,44,s,i),a.length!==i.length||a.some((m,h)=>m!==i[h]||A[m]!==u[m]))return!1;for(let m of a)A[m]=0;for(let m of i)u[m]=0;if(s===16&&a.length<10)return!1}return!0}var ft=null;function Yt(e=!0){if(!ft){let t=ut(),r=null;try{r=t?new Qt(t):null,r&&!he(r)&&(r=null)}catch{r=null}ft={wasm:r,js:new yt}}return e&&ft.wasm||ft.js}var _=15,ht=_+3,V=32,ge=(()=>{let e=625341585,t=()=>(e^=e<<13,e>>>=0,e^=e>>>17,e^=e<<5,e>>>=0,(e+.5)/4294967296),r=()=>Math.sqrt(-2*Math.log(t()))*Math.cos(2*Math.PI*t()),n=new Int8Array(1024);for(let o=0;o<256;){let l=[0,1,2,3].map(()=>Math.round(r()*8.5));Math.hypot(l[0],l[1])>15||Math.hypot(l[2],l[3])>15||Math.hypot(l[0]-l[2],l[1]-l[3])<2||(n.set(l,4*o),o++)}return n})(),dt=2;function de(e){return Array.from({length:V},(t,r)=>{let n=2*Math.PI*r/V,o=Math.cos(n),l=Math.sin(n),c=new Int8Array(1024);for(let s=0;s<512;s++){let a=e[2*s],i=e[2*s+1];c[2*s]=Math.round(o*a-l*i),c[2*s+1]=Math.round(l*a+o*i)}return c})}var _t=new WeakMap;function pe(e){let t=_t.get(e);if(!t){let r=e.length===1024;for(let n=0;n<512&&r;n++)r=Math.hypot(e[2*n],e[2*n+1])<=15;if(!r)throw new Error("BRIEF pattern: 256 tests with box centres within 15 px");t=de(e),_t.set(e,t)}return t}var Ie=(()=>{let e=new Int32Array(_+1);for(let t=0;t<=_;t++)e[t]=Math.floor(Math.sqrt(_*_-t*t)+.5);return e})(),gt=class{constructor(){F(this,"octaves",new X);F(this,"halfOctaves",new X);F(this,"horizontal",new Uint16Array(0));F(this,"blur",new Uint8Array(0));F(this,"half",new Uint8Array(0));F(this,"integral",new Int32Array(0))}},Jt=new gt;function be(e,t){let r=e.width,n=e.height,o=Math.floor(r/Math.SQRT2),l=Math.floor(n/Math.SQRT2),c=e.data;t.horizontal.length<r*n&&(t.horizontal=new Uint16Array(r*n),t.blur=new Uint8Array(r*n)),t.half.length!==o*l&&(t.half=new Uint8Array(o*l));let s=t.horizontal;for(let m=0;m<n;m++){let h=m*e.stride,g=m*r;s[g]=3*c[h]+c[h+1];for(let y=1;y<r-1;y++)s[g+y]=c[h+y-1]+2*c[h+y]+c[h+y+1];s[g+r-1]=c[h+r-2]+3*c[h+r-1]}let a=t.blur;for(let m=0;m<n;m++){let h=Math.max(0,m-1)*r,g=m*r,y=Math.min(n-1,m+1)*r;for(let f=0;f<r;f++)a[g+f]=s[h+f]+2*s[g+f]+s[y+f]+8>>4}let i=new Int32Array(o),A=new Float32Array(o);for(let m=0;m<o;m++){let h=(m+.5)*Math.SQRT2-.5;i[m]=Math.min(r-2,Math.max(0,Math.floor(h))),A[m]=h-i[m]}let u=t.half;for(let m=0;m<l;m++){let h=(m+.5)*Math.SQRT2-.5,g=Math.min(n-2,Math.max(0,Math.floor(h))),y=h-g,f=g*r,d=f+r;for(let p=0;p<o;p++){let x=i[p],b=A[p],M=a[f+x]+b*(a[f+x+1]-a[f+x]),I=a[d+x]+b*(a[d+x+1]-a[d+x]);u[m*o+p]=M+y*(I-M)+.5|0}}return{width:o,height:l,stride:o,data:u}}function we(e,t,r=new gt){let n=Math.ceil(t/2),o=r.octaves.build(e,n,24).levels,l=r.halfOctaves.build(be(e,r),n,24).levels,c=[];for(let s=0;s<n;s++)o[s]&&c.push({image:o[s],scale:2**s}),l[s]&&c.push({image:l[s],scale:Math.SQRT2*2**s});return c.slice(0,t)}function xe(e,t,r,n){let o=0,l=0,c=0;for(let s=-3;s<=3;s++)for(let a=-3;a<=3;a++){let i=(n+s)*t+r+a,A=e[i+1]-e[i-1],u=e[i+t]-e[i-t];o+=A*A,l+=u*u,c+=A*u}return o*l-c*c-.04*(o+l)**2}function Ee(e,t){let r=e.width+1;t.integral.length<r*(e.height+1)&&(t.integral=new Int32Array(r*(e.height+1)));let n=t.integral;n.fill(0,0,r);for(let o=0;o<e.height;o++){n[(o+1)*r]=0;let l=0;for(let c=0;c<e.width;c++)l+=e.data[o*e.stride+c],n[(o+1)*r+c+1]=n[o*r+c+1]+l}return n}function Me(e,t,r,n,o){let{width:l,height:c,stride:s,data:a}=e,i=r.cell,A=[],u=Math.max(ht,Math.floor(n.x0)),m=Math.max(ht,Math.floor(n.y0)),h=Math.min(l-ht,Math.ceil(n.x1)),g=Math.min(c-ht,Math.ceil(n.y1));if(h<=u||g<=m)return A;let y=o.begin(e),f=[];for(let d=m;d<g;d+=i)for(let p=u;p<h;p+=i){let x=Math.min(g,d+i),b=Math.min(h,p+i);f.length=0;let M=255,I=0;for(let E=d;E<x;E+=2)for(let B=p;B<b;B+=2){let C=a[E*s+B];C<M&&(M=C),C>I&&(I=C)}if(I-M<2*r.minFastThreshold)continue;for(let E=r.fastThreshold;o.score(p,d,b,x,E,f),!(f.length>=2||E===r.minFastThreshold);E=r.minFastThreshold){for(let B of f)y[B]=0;f.length=0}let w=[];for(let E of f){let B=y[E],C=!0;for(let P=-1;P<=1&&C;P++)for(let k=-1;k<=1;k++){if(!k&&!P)continue;let v=y[E+P*l+k];if(v>B||v===B&&(P<0||P===0&&k<0)){C=!1;break}}C&&w.push({i:E,s:B})}for(let E of f)y[E]=0;w.sort((E,B)=>B.s-E.s||E.i-B.i);let Q=[];for(let E of w.slice(0,8)){let B=E.i%l,C=(E.i-B)/l,P=xe(a,s,B,C);P>0&&Q.push({x:B,y:C,score:P})}Q.sort((E,B)=>B.score-E.score||E.y-B.y||E.x-B.x),A.push(...Q.slice(0,2))}return A.sort((d,p)=>p.score-d.score||d.y-p.y||d.x-p.x),A.slice(0,t)}function Be(e,t,r){let n=e.data,o=e.stride,l=0,c=0,s=r*o+t;for(let a=-_;a<=_;a++)c+=a*n[s+a];for(let a=1;a<=_;a++){let i=0,A=Ie[a];for(let u=-A;u<=A;u++){let m=n[s-a*o+u],h=n[s+a*o+u];i+=h-m,c+=u*(m+h)}l+=a*i}return Math.atan2(l,c)}function Ce(e){return(Math.round(e*V/(2*Math.PI))%V+V)%V}function Qe(e,t,r,n,o,l,c,s){let a=l[Ce(o)],i=(n-2)*t+(r-2),A=5*t;for(let u=0;u<32;u++){let m=0;for(let h=0;h<8;h++){let g=4*(8*u+h),y=i+a[g+1]*t+a[g],f=i+a[g+3]*t+a[g+2],d=e[y+A+5]-e[y+5]-e[y+A]+e[y],p=e[f+A+5]-e[f+5]-e[f+A]+e[f];d<p&&(m|=1<<h)}c[s+u]=m}}function rt(e,t={}){let r=t.budget??700,n=we(e,t.levels??6,Jt),o={fastThreshold:t.fastThreshold??16,minFastThreshold:t.minFastThreshold??4,cell:t.cell??24},l=Yt(t.wasm!==!1),c=pe(t.pattern??ge),s=n.reduce((d,p)=>d+p.image.width*p.image.height,0),a=t.roi??{x:0,y:0,width:e.width,height:e.height},i=[],A=[],u=[],m=[],h=[],g=[];n.forEach((d,p)=>{let x=Math.max(16,Math.round(r*d.image.width*d.image.height/s)),b=d.scale,M=Me(d.image,x,o,{x0:a.x/b,y0:a.y/b,x1:(a.x+a.width)/b,y1:(a.y+a.height)/b},l);if(!M.length)return;let I=Ee(d.image,Jt),w=new Uint8Array(32*M.length);M.forEach((Q,E)=>{let B=Be(d.image,Q.x,Q.y);Qe(I,d.image.width+1,Q.x,Q.y,B,c,w,32*E),i.push((Q.x+.5)*b),A.push((Q.y+.5)*b),u.push(p),m.push(B),h.push(Q.score)}),g.push(w)});let y=new Uint8Array(32*i.length),f=0;for(let d of g)y.set(d,f),f+=d.length;return{count:i.length,x:Float32Array.from(i),y:Float32Array.from(A),level:Uint8Array.from(u),angle:Float32Array.from(m),score:Float32Array.from(h),descriptors:y,descriptorBytes:32}}function Ue(e,t,r){let n=r*Math.PI/180,o=Math.cos(n),l=Math.sin(n),c=o*o/t+l*l,s=o*l/t-o*l,a=l*l/t+o*o,i=[[0,0],[e.width,0],[e.width,e.height],[0,e.height]].map(([I,w])=>[c*I+s*w,s*I+a*w]),A=Math.min(...i.map(I=>I[0])),u=Math.min(...i.map(I=>I[1])),m=Math.ceil(Math.max(...i.map(I=>I[0]))-A),h=Math.ceil(Math.max(...i.map(I=>I[1]))-u),g=[c,s,-A,s,a,-u],y=.8*Math.sqrt(Math.max(0,t*t-1)),f=y>.3?jt(e,y):e,d=c*a-s*s,p=a/d,x=-s/d,b=c/d,M=new Uint8Array(m*h).fill(128);for(let I=0;I<h;I++)for(let w=0;w<m;w++){let Q=w+.5-g[2],E=I+.5-g[5],B=p*Q+x*E-.5,C=x*Q+b*E-.5,P=Math.floor(B),k=Math.floor(C);if(P<0||k<0||P+1>=e.width||k+1>=e.height)continue;let v=B-P,T=C-k,D=k*f.stride+P,R=f.data,L=R[D]+v*(R[D+1]-R[D]),O=R[D+f.stride]+v*(R[D+f.stride+1]-R[D+f.stride]);M[I*m+w]=Math.round(L+T*(O-L))}return{image:{width:m,height:h,stride:m,data:M},A:g}}function jt(e,t){let r=Math.ceil(3*t),n=Array.from({length:2*r+1},(a,i)=>Math.exp(-((i-r)**2)/(2*t*t))),o=n.reduce((a,i)=>a+i,0),l=n.map(a=>a/o),c=new Float32Array(e.width*e.height);for(let a=0;a<e.height;a++)for(let i=0;i<e.width;i++){let A=0;for(let u=-r;u<=r;u++)A+=l[u+r]*e.data[a*e.stride+Math.min(e.width-1,Math.max(0,i+u))];c[a*e.width+i]=A}let s=new Uint8Array(e.width*e.height);for(let a=0;a<e.height;a++)for(let i=0;i<e.width;i++){let A=0;for(let u=-r;u<=r;u++)A+=l[u+r]*c[Math.min(e.height-1,Math.max(0,a+u))*e.width+i];s[a*e.width+i]=Math.round(A)}return{width:e.width,height:e.height,stride:e.width,data:s}}function Fe(e,t,r,n){let o=0;for(let l=0;l<32;l++){let c=e[t+l]^r[n+l];for(;c;)c&=c-1,o++}return o}function nt(e,t={}){let r=t.tilts??[1.4,2,2.8],n=t.longitudes??[0,45,90,135],o=[{image:e.image,A:[1,0,0,0,1,0]}];for(let d of r)for(let p of n)o.push(Ue(e.image,d,p));for(let d of t.blurs??[2.5])o.push({image:jt(e.image,d),A:[1,0,0,0,1,0]});let l=[],c=new Map,s=4,a=(d,p)=>Math.floor(p/s)*65536+Math.floor(d/s);o.forEach((d,p)=>{let x=rt(d.image,{budget:900,...t.orb}),[b,M,I,w,Q,E]=d.A,B=b*Q-M*w;for(let C=0;C<x.count;C++){let P=x.x[C]-I,k=x.y[C]-E,v=(Q*P-M*k)/B,T=(-w*P+b*k)/B;if(v<0||T<0||v>=e.info.width||T>=e.info.height)continue;let D=2+1.5*(2**(x.level[C]/2)-1),R=-1;for(let O=-1;O<=1&&R<0;O++)for(let N=-1;N<=1&&R<0;N++)for(let W of c.get(a(v+N*s,T+O*s))??[]){let S=l[W];if(Math.hypot(S.x-v,S.y-T)<=D){R=W;break}}let L=x.descriptors.slice(32*C,32*C+32);if(R<0){l.push({x:v,y:T,n:1,views:new Set([p]),score:x.score[C],desc:[L]});let O=a(v,T);c.set(O,[...c.get(O)??[],l.length-1])}else{let O=l[R];O.views.add(p),O.n++,O.score=Math.max(O.score,x.score[C]),O.desc.push(L)}}});let i=t.maxPoints??700,A=t.descriptorsPerPoint??3,u=l.map((d,p)=>({g:d,i:p})).sort((d,p)=>p.g.views.size-d.g.views.size||p.g.score-d.g.score||d.i-p.i).slice(0,i).map(d=>d.g),m=new Float32Array(2*u.length),h=new Uint8Array(u.length),g=[],y=[];u.forEach((d,p)=>{m[2*p]=d.x,m[2*p+1]=d.y,h[p]=d.views.size;let x=[];for(let b of d.desc){if(x.length>=A)break;x.every(M=>Fe(M,0,b,0)>24)&&x.push(b)}for(let b of x)g.push(b),y.push(p)});let f=new Uint8Array(32*g.length);return g.forEach((d,p)=>f.set(d,32*p)),{info:e.info,points:m,repeatability:h,descriptors:f,descriptorPoint:Uint32Array.from(y)}}function ot(e,t,r){let n=e[6]*t+e[7]*r+e[8];return Math.abs(n)<1e-12?[NaN,NaN]:[(e[0]*t+e[1]*r+e[2])/n,(e[3]*t+e[4]*r+e[5])/n]}function at(e,t,r){return[ot(e,0,0),ot(e,t,0),ot(e,t,r),ot(e,0,r)]}function pt(e,t,r){for(let n=0;n<r;n++){let o=n,l=Math.abs(e[n*r+n]);for(let s=n+1;s<r;s++){let a=Math.abs(e[s*r+n]);a>l&&(l=a,o=s)}if(l<1e-12)return!1;if(o!==n){for(let a=0;a<r;a++){let i=e[n*r+a];e[n*r+a]=e[o*r+a],e[o*r+a]=i}let s=t[n];t[n]=t[o],t[o]=s}let c=e[n*r+n];for(let s=n+1;s<r;s++){let a=e[s*r+n]/c;if(a!==0){for(let i=n;i<r;i++)e[s*r+i]-=a*e[n*r+i];t[s]-=a*t[n]}}}for(let n=r-1;n>=0;n--){let o=t[n];for(let l=n+1;l<r;l++)o-=e[n*r+l]*t[l];t[n]=o/e[n*r+n]}return t.every(Number.isFinite)}function Xt(e,t){let r=new Float64Array(e),n=new Float64Array(t*t);for(let o=0;o<t;o++)n[o*t+o]=1;for(let o=0;o<t;o++){let l=o;for(let s=o+1;s<t;s++)Math.abs(r[s*t+o])>Math.abs(r[l*t+o])&&(l=s);if(Math.abs(r[l*t+o])<1e-15)return null;if(l!==o)for(let s=0;s<t;s++){let a=r[o*t+s];r[o*t+s]=r[l*t+s],r[l*t+s]=a,a=n[o*t+s],n[o*t+s]=n[l*t+s],n[l*t+s]=a}let c=r[o*t+o];for(let s=0;s<t;s++)r[o*t+s]/=c,n[o*t+s]/=c;for(let s=0;s<t;s++){if(s===o)continue;let a=r[s*t+o];if(a!==0)for(let i=0;i<t;i++)r[s*t+i]-=a*r[o*t+i],n[s*t+i]-=a*n[o*t+i]}}return n}function zt(e,t){let r=new Float64Array(e),n=new Float64Array(t*t);for(let c=0;c<t;c++)n[c*t+c]=1;for(let c=0;c<50;c++){let s=0;for(let a=0;a<t;a++)for(let i=a+1;i<t;i++)s+=r[a*t+i]**2;if(s<1e-24)break;for(let a=0;a<t;a++)for(let i=a+1;i<t;i++){let A=r[a*t+i];if(Math.abs(A)<1e-300)continue;let u=(r[i*t+i]-r[a*t+a])/(2*A),m=Math.sign(u||1)/(Math.abs(u)+Math.sqrt(u*u+1)),h=1/Math.sqrt(m*m+1),g=m*h;for(let y=0;y<t;y++){let f=r[y*t+a],d=r[y*t+i];r[y*t+a]=h*f-g*d,r[y*t+i]=g*f+h*d}for(let y=0;y<t;y++){let f=r[a*t+y],d=r[i*t+y];r[a*t+y]=h*f-g*d,r[i*t+y]=g*f+h*d}for(let y=0;y<t;y++){let f=n[y*t+a],d=n[y*t+i];n[y*t+a]=h*f-g*d,n[y*t+i]=g*f+h*d}}}let o=0;for(let c=1;c<t;c++)r[c*t+c]<r[o*t+o]&&(o=c);let l=new Float64Array(t);for(let c=0;c<t;c++)l[c]=n[c*t+o];return l}function Ft(e,t){let r=new Float64Array(9);for(let n=0;n<3;n++)for(let o=0;o<3;o++)r[n*3+o]=e[n*3]*t[o]+e[n*3+1]*t[3+o]+e[n*3+2]*t[6+o];return r}function vt(e){let[t,r,n,o,l,c,s,a,i]=[e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8]],A=[l*i-c*a,n*a-r*i,r*c-n*l,c*s-o*i,t*i-n*s,n*o-t*c,o*a-l*s,r*s-t*a,t*l-r*o],u=t*A[0]+r*A[3]+n*A[6];return!Number.isFinite(u)||Math.abs(u)<1e-300?null:Float64Array.from(A,m=>m/u)}function Vt(e){let t=e[8];if(!Number.isFinite(t)||Math.abs(t)<1e-12)return null;for(let r=0;r<9;r++)e[r]/=t;return e.every(Number.isFinite)?e:null}function wt(e,t,r){let n=0,o=0;for(let c=0;c<r;c++){let s=t[c];n+=e[2*s],o+=e[2*s+1]}n/=r,o/=r;let l=0;for(let c=0;c<r;c++){let s=t[c];l+=Math.hypot(e[2*s]-n,e[2*s+1]-o)}return l/=r,l<1e-9?null:[Math.SQRT2/l,n,o]}function Zt(e,t,r){let[n,o,l]=t,[c,s,a]=r,i=[n,0,-n*o,0,n,-n*l,0,0,1],A=[1/c,0,s,0,1/c,a,0,0,1];return Vt(Ft(Ft(A,e),i))}function Pt(e,t,r,n,o){if(n<4)return null;let l=wt(e,r,n),c=wt(t,r,n);if(!l||!c)return null;let s=new Float64Array(81),a=new Float64Array(9);for(let i=0;i<n;i++){let A=r[i],u=o?o[A]:1;if(u<=0)continue;let m=l[0]*(e[2*A]-l[1]),h=l[0]*(e[2*A+1]-l[2]),g=c[0]*(t[2*A]-c[1]),y=c[0]*(t[2*A+1]-c[2]);for(let f=0;f<2;f++){f===0?a.set([m,h,1,0,0,0,-g*m,-g*h,-g]):a.set([0,0,0,m,h,1,-y*m,-y*h,-y]);for(let d=0;d<9;d++){let p=a[d]*u;if(p!==0)for(let x=d;x<9;x++)s[d*9+x]+=p*a[x]}}}for(let i=0;i<9;i++)for(let A=0;A<i;A++)s[i*9+A]=s[A*9+i];return Zt(zt(s,9),l,c)}var It=new Float64Array(64),bt=new Float64Array(8);function st(e,t,r){let n=wt(e,r,4),o=wt(t,r,4);if(!n||!o)return null;It.fill(0);for(let l=0;l<4;l++){let c=r[l],s=n[0]*(e[2*c]-n[1]),a=n[0]*(e[2*c+1]-n[2]),i=o[0]*(t[2*c]-o[1]),A=o[0]*(t[2*c+1]-o[2]);It.set([s,a,1,0,0,0,-i*s,-i*a],16*l),It.set([0,0,0,s,a,1,-A*s,-A*a],16*l+8),bt[2*l]=i,bt[2*l+1]=A}return pt(It,bt,8)?Zt([...bt,1],n,o):null}function $t(e,t,r,n){let o=e[6]*t+e[7]*r+e[8];return o>1e-12?(n[0]=(e[0]*t+e[1]*r+e[2])/o,n[1]=(e[3]*t+e[4]*r+e[5])/o,!0):!1}var J=new Float64Array(8),Ut=new Float64Array(2);function it(e,t,r,n=64,o=30){let l=[0,t,t,0],c=[0,0,r,r];for(let A=0;A<4;A++){if(!$t(e,l[A],c[A],Ut))return!1;J[2*A]=Ut[0],J[2*A+1]=Ut[1]}let s=0,a=1/0,i=0;for(let A=0;A<4;A++){let u=J[2*A],m=J[2*A+1],h=J[(2*A+2)%8],g=J[(2*A+3)%8],y=J[(2*A+4)%8],f=J[(2*A+5)%8];if((h-u)*(f-g)-(g-m)*(y-h)<=0)return!1;s+=u*g-h*m;let d=Math.hypot(h-u,g-m);a=Math.min(a,d),i=Math.max(i,d)}return s/2>=n&&i<=o*Math.max(a,1e-9)}function Tt(e,t,r){let n=[];for(let i=0;i<r;i++)(!t||t[i])&&n.push([e[2*i],e[2*i+1]]);if(n.length<3)return 0;n.sort((i,A)=>i[0]-A[0]||i[1]-A[1]);let o=(i,A,u)=>(A[0]-i[0])*(u[1]-i[1])-(A[1]-i[1])*(u[0]-i[0]),l=[];for(let i of n){for(;l.length>=2&&o(l.at(-2),l.at(-1),i)<=0;)l.pop();l.push(i)}let c=[];for(let i=n.length-1;i>=0;i--){let A=n[i];for(;c.length>=2&&o(c.at(-2),c.at(-1),A)<=0;)c.pop();c.push(A)}let s=[...l.slice(0,-1),...c.slice(0,-1)],a=0;for(let i=0;i<s.length;i++){let A=s[i],u=s[(i+1)%s.length];a+=A[0]*u[1]-u[0]*A[1]}return Math.abs(a)/2}var ve=(e,t)=>e<=t?1:t/e;function Rt(e,t,r,n,o,l={}){let c=l.iterations??8,s=l.huberPx??1.5,a=Float64Array.from(e.subarray(0,8)),i=.001,A=new Float64Array(64),u=new Float64Array(8),m=new Float64Array(8),h=new Float64Array(8),g=b=>{let M=0;for(let I=0;I<o;I++){if(!n[I])continue;let w=t[2*I],Q=t[2*I+1],E=b[6]*w+b[7]*Q+1;if(!(E>1e-12))return 1/0;let B=(b[0]*w+b[1]*Q+b[2])/E-r[2*I],C=(b[3]*w+b[4]*Q+b[5])/E-r[2*I+1],P=Math.hypot(B,C);M+=P<=s?P*P:2*s*P-s*s}return M},y=g(a);for(let b=0;b<c;b++){A.fill(0),u.fill(0);for(let I=0;I<o;I++){if(!n[I])continue;let w=t[2*I],Q=t[2*I+1],E=a[6]*w+a[7]*Q+1,B=(a[0]*w+a[1]*Q+a[2])/E,C=(a[3]*w+a[4]*Q+a[5])/E,P=B-r[2*I],k=C-r[2*I+1],v=ve(Math.hypot(P,k),s);m.set([w/E,Q/E,1/E,0,0,0,-B*w/E,-B*Q/E]),h.set([0,0,0,w/E,Q/E,1/E,-C*w/E,-C*Q/E]);for(let T=0;T<8;T++){u[T]+=v*(m[T]*P+h[T]*k);for(let D=T;D<8;D++)A[T*8+D]+=v*(m[T]*m[D]+h[T]*h[D])}}for(let I=0;I<8;I++)for(let w=0;w<I;w++)A[I*8+w]=A[w*8+I];let M=!1;for(let I=0;I<4&&!M;I++){let w=new Float64Array(A);for(let C=0;C<8;C++)w[C*9]*=1+i;let Q=Float64Array.from(u,C=>-C);if(!pt(w,Q,8)){i*=10;continue}let E=Float64Array.from(a,(C,P)=>C+Q[P]),B=g(E);B<y?(a=E,y=B,i=Math.max(1e-7,i/10),M=!0):i*=10}if(!M)break}let f=0,d=0;A.fill(0);for(let b=0;b<o;b++){if(!n[b])continue;let M=t[2*b],I=t[2*b+1],w=a[6]*M+a[7]*I+1,Q=(a[0]*M+a[1]*I+a[2])/w,E=(a[3]*M+a[4]*I+a[5])/w;d+=(Q-r[2*b])**2+(E-r[2*b+1])**2,f++,m.set([M/w,I/w,1/w,0,0,0,-Q*M/w,-Q*I/w]),h.set([0,0,0,M/w,I/w,1/w,-E*M/w,-E*I/w]);for(let B=0;B<8;B++)for(let C=0;C<8;C++)A[B*8+C]+=m[B]*m[C]+h[B]*h[C]}let p=f>4?d/(2*f-8):d,x=Xt(A,8);return{H:Float64Array.from([...a,1]),rmsPx:f?Math.sqrt(d/f):1/0,paramCovariance:x?x.map(b=>b*p):null}}function Pe(e){let t=e>>>0||625341585;return()=>(t^=t<<13,t>>>=0,t^=t>>>17,t^=t<<5,t>>>=0,t)}function Gt(e,t,r,n,o,l){let c=0,s=0;for(let a=0;a<n;a++){let i=t[2*a],A=t[2*a+1],u=e[6]*i+e[7]*A+e[8],m=o;if(u>1e-12){let g=(e[0]*i+e[1]*A+e[2])/u-r[2*a],y=(e[3]*i+e[4]*A+e[5])/u-r[2*a+1];m=Math.min(o,g*g+y*y)}let h=m<o;l[a]=h?1:0,h&&s++,c+=m}return{score:c,inliers:s}}function Te(e,t){let r=0;for(let o=0;o<t;o++)e[o]&&r++;let n=new Int32Array(r);for(let o=0,l=0;o<t;o++)e[o]&&(n[l++]=o);return n}function xt(e,t,r,n){let o=(e[2*r]-e[2*t])*(e[2*n+1]-e[2*t+1])-(e[2*r+1]-e[2*t+1])*(e[2*n]-e[2*t]);return Math.abs(o)<.001*(1+Math.abs(e[2*t])+Math.abs(e[2*r]))}function kt(e,t,r,n,o,l={}){let c=l.thresholdPx??3,s=c*c,a=l.confidence??.995,i=l.maxIterations??500,A=l.minInliers??12,u=l.minInlierRatio??.2,m=l.minCoverage??.08;if(r<Math.max(4,A))return{accepted:!1,reason:"INSUFFICIENT_MATCHES",iterations:0};let h=Pe(l.seed??12345),g=new Uint8Array(r),y=new Uint8Array(r),f=null,d=1/0,p=0,x=i,b=4,M=i;for(let v=0;v<4;v++)M*=(b-v)/(r-v);let I=1,w=new Int32Array(4),Q=0,E=v=>{if(!v||!it(v,n,o))return;let{score:T,inliers:D}=Gt(v,e,t,r,s,g);if(T>=d)return;f=v,d=T,p=D,y.set(g);for(let O=0;O<3&&p>=8;O++){let N=Pt(e,t,Te(y,r),p);if(!N||!it(N,n,o))break;let W=Gt(N,e,t,r,s,g);if(W.score>=d)break;f=N,d=W.score,p=W.inliers,y.set(g)}let R=p/r,L=Math.log(1-a)/Math.log(Math.max(1e-12,1-R**4));x=Math.min(i,Math.max(16,Math.ceil(L)))};for(;Q<x;){if(Q++,Q>=I&&b<r){let W=M*(b+1)/(b+1-4);b++,I+=Math.ceil(W-M),M=W}let v=I>Q?b-1:b,T=0;I>Q&&(w[T++]=b-1);let D=0;for(;T<4&&D++<64;){let W=h()%v,S=!1;for(let U=0;U<T;U++)w[U]===W&&(S=!0);S||(w[T++]=W)}if(T<4)continue;let[R,L,O,N]=[w[0],w[1],w[2],w[3]];xt(e,R,L,O)||xt(e,R,L,N)||xt(e,R,O,N)||xt(e,L,O,N)||E(st(e,t,w))}if(!f||p<A)return{accepted:!1,reason:"NO_MODEL",iterations:Q};let B=f,C=Rt(B,e,t,y,r,{huberPx:c/2});for(let v=0;v<2;v++){if(!it(C.H,n,o))return{accepted:!1,reason:"IMPLAUSIBLE_MODEL",iterations:Q};B=C.H,p=Gt(B,e,t,r,s,y).inliers,v===0&&(C=Rt(B,e,t,y,r,{huberPx:c/2}))}let P=p/r;if(p<A||P<u)return{accepted:!1,reason:"LOW_INLIER_SUPPORT",iterations:Q};let k=Tt(e,y,r)/(n*o);return k<m?{accepted:!1,reason:"LOW_SPATIAL_COVERAGE",iterations:Q}:{accepted:!0,H:B,mask:y,inliers:p,ratio:P,rmsPx:C.rmsPx,coverage:k,paramCovariance:C.paramCovariance,iterations:Q}}var te=844385612;function Re(e,t,r){if(e.width===t&&e.height===r)return e;let n=new Uint8Array(t*r),o=e.width/t,l=e.height/r;for(let c=0;c<r;c++){let s=Math.min(e.height-1.001,Math.max(0,(c+.5)*l-.5)),a=Math.floor(s),i=s-a;for(let A=0;A<t;A++){let u=Math.min(e.width-1.001,Math.max(0,(A+.5)*o-.5)),m=Math.floor(u),h=u-m,g=a*e.stride+m,y=e.data,f=y[g]+h*(y[g+1]-y[g]),d=y[g+e.stride]+h*(y[g+e.stride+1]-y[g+e.stride]);n[c*t+A]=Math.round(f+i*(d-f))}}return{width:t,height:r,stride:t,data:n}}function Ge(e,t){let r=Math.max(e.width,e.height)/t;if(r<=1)return e;let n=Math.round(e.width/r),o=Math.round(e.height/r),l=new Uint8Array(n*o);for(let c=0;c<o;c++)for(let s=0;s<n;s++){let a=Math.floor(s*r),i=Math.max(a+1,Math.floor((s+1)*r)),A=Math.floor(c*r),u=Math.max(A+1,Math.floor((c+1)*r)),m=0;for(let h=A;h<u;h++)for(let g=a;g<i;g++)m+=e.data[h*e.stride+g];l[c*n+s]=Math.round(m/((i-a)*(u-A)))}return{width:n,height:o,stride:n,data:l}}async function ct(e,t,r={}){let n=Ge(t,r.templateMaxEdge??480),o=new TextEncoder().encode(e.info.id),l=e.points.length/2,c=e.descriptorPoint.length,s=10+o.length+8+8+8*l+l+4*c+32*c+4+n.width*n.height,a=new Uint8Array(s+32),i=new DataView(a.buffer),A=0;i.setUint32(A,te,!0),i.setUint16(A+4,2,!0),i.setUint16(A+6,dt,!0),A+=8,i.setUint16(A,o.length,!0),a.set(o,A+2),A+=2+o.length,i.setUint16(A,e.info.width,!0),i.setUint16(A+2,e.info.height,!0),i.setFloat32(A+4,e.info.physicalWidthMeters??NaN,!0),A+=8,i.setUint32(A,l,!0),i.setUint32(A+4,c,!0),A+=8;for(let m=0;m<2*l;m++,A+=4)i.setFloat32(A,e.points[m],!0);a.set(e.repeatability,A),A+=l;for(let m=0;m<c;m++,A+=4)i.setUint32(A,e.descriptorPoint[m],!0);a.set(e.descriptors,A),A+=32*c,i.setUint16(A,n.width,!0),i.setUint16(A+2,n.height,!0),A+=4;for(let m=0;m<n.height;m++)a.set(n.data.subarray(m*n.stride,m*n.stride+n.width),A+m*n.width);A+=n.width*n.height;let u=new Uint8Array(await crypto.subtle.digest("SHA-256",a.subarray(0,A)));return a.set(u,A),a}async function Z(e){let t=new DataView(e.buffer,e.byteOffset,e.byteLength),r=M=>{throw new Error(`Invalid target asset: ${M}`)};(e.length<64||t.getUint32(0,!0)!==te||t.getUint16(4,!0)!==2)&&r("header");let n=t.getUint16(6,!0)&255;n!==dt&&r(`descriptor pattern v${n}, this engine uses v${dt}; recompile the target`);let o=e.subarray(0,e.length-32);new Uint8Array(await crypto.subtle.digest("SHA-256",new Uint8Array(o))).every((M,I)=>M===e[e.length-32+I])||r("checksum");let c=8,s=t.getUint16(c,!0),a=new TextDecoder().decode(e.subarray(c+2,c+2+s));c+=2+s;let i=t.getUint16(c,!0),A=t.getUint16(c+2,!0),u=t.getFloat32(c+4,!0);c+=8;let m=t.getUint32(c,!0),h=t.getUint32(c+4,!0);c+=8;let g=new Float32Array(2*m);for(let M=0;M<2*m;M++,c+=4)g[M]=t.getFloat32(c,!0);let y=e.slice(c,c+m);c+=m;let f=new Uint32Array(h);for(let M=0;M<h;M++,c+=4)f[M]=t.getUint32(c,!0);let d=e.slice(c,c+32*h);c+=32*h;let p=t.getUint16(c,!0),x=t.getUint16(c+2,!0);c+=4;let b={width:p,height:x,stride:p,data:e.slice(c,c+p*x)};return{compiled:{info:{id:a,width:i,height:A,physicalWidthMeters:Number.isNaN(u)?null:u},points:g,repeatability:y,descriptors:d,descriptorPoint:f},template:Re(b,i,A)}}function Ot(e,t){let r=e.length/32,n=t.length/32,o=new Uint32Array(3*r),l=new Uint32Array(e.buffer,e.byteOffset,e.length/4),c=new Uint32Array(t.buffer,t.byteOffset,t.length/4);for(let s=0;s<r;s++){let a=257,i=257,A=4294967295,u=8*s;for(let m=0;m<n;m++){let h=8*m,g=0;for(let y=0;y<8;y++){let f=(l[u+y]^c[h+y])>>>0;f-=f>>>1&1431655765,f=(f&858993459)+(f>>>2&858993459),g+=(f+(f>>>4)&252645135)*16843009>>>24}g<a?(i=a,a=g,A=m):g<i&&(i=g)}o[3*s]=A,o[3*s+1]=a,o[3*s+2]=i}return o}function Dt(e,t,r){let n=e.length/32,o=t.length/32,l=new Uint32Array(3*n),c=new Uint32Array(e.buffer,e.byteOffset,e.length/4),s=new Uint32Array(t.buffer,t.byteOffset,t.length/4);for(let a=0;a<n;a++){let i=257,A=4294967295,u=257,m=4294967295,h=8*a;for(let g=0;g<o;g++){let y=8*g,f=0;for(let p=0;p<8;p++){let x=(c[h+p]^s[y+p])>>>0;x-=x>>>1&1431655765,x=(x&858993459)+(x>>>2&858993459),f+=(x+(x>>>4)&252645135)*16843009>>>24}let d=r[g];d===A?f<i&&(i=f,m=g):f<i?(u=i,i=f,A=d,m=g):f<u&&(u=f)}l[3*a]=m,l[3*a+1]=i,l[3*a+2]=u}return l}var Et=class e{constructor(t){F(this,"backend");F(this,"kernel");this.kernel=t,this.backend=t?"wasm-simd":"js"}static create(t={}){let r=t.allowWasm===!1?null:ut();if(!r)return new e(null);try{let n=new e(r);return n.selfTest()?n:new e(null)}catch{return new e(null)}}selfTest(){let t=19088743,r=A=>Uint8Array.from({length:A},()=>(t^=t<<13,t^=t>>>17,t^=t<<5,t&255)),n=r(1184),o=new Uint8Array(352);o.set(r(320)),o.set(n.subarray(160,192),320);let l=Ot(o,n),c=this.nearest2(o,n),s=Uint32Array.from({length:37},(A,u)=>u>>1),a=Dt(o,n,s),i=this.nearest2Grouped(o,n,s);return c.length===l.length&&c.every((A,u)=>A===l[u])&&i.length===a.length&&i.every((A,u)=>A===a[u])}nearest2(t,r){let n=this.kernel;if(!n)return Ot(t,r);let o=t.length/32,l=r.length/32;n.reset_heap();let c=n.reserve(t.length),s=n.reserve(r.length),a=n.reserve(12*o);return!c||!s||!a?Ot(t,r):(new Uint8Array(n.memory.buffer).set(t,c),new Uint8Array(n.memory.buffer).set(r,s),n.nearest2(c,o,s,l,a),new Uint32Array(n.memory.buffer.slice(a,a+12*o)))}nearest2Grouped(t,r,n){let o=this.kernel;if(!o)return Dt(t,r,n);let l=t.length/32;o.reset_heap();let c=o.reserve(t.length),s=o.reserve(r.length),a=o.reserve(n.byteLength),i=o.reserve(12*l);if(!c||!s||!a||!i)return Dt(t,r,n);let A=o.memory.buffer;return new Uint8Array(A).set(t,c),new Uint8Array(A).set(r,s),new Uint8Array(A).set(new Uint8Array(n.buffer,n.byteOffset,n.byteLength),a),o.nearest2_grouped(c,l,s,a,r.length/32,i),new Uint32Array(o.memory.buffer.slice(i,i+12*l))}};var ke=e=>Math.max(700,Math.round(700*e.width*e.height/(640*360))),Oe=36e4;function De(e,t,r,n){let o=Math.min(r,3,Math.sqrt(Oe/(t.width*t.height)));if(o<1.2)return null;let l=Math.round(t.width*o),c=Math.round(t.height*o),s=new Uint8Array(l*c),a=e.width-1.001,i=e.height-1.001;for(let u=0;u<c;u++){let m=Math.min(i,Math.max(.5,t.y+(u+.5)/o));for(let h=0;h<l;h++)s[u*l+h]=Math.round(tt(e,Math.min(a,Math.max(.5,t.x+(h+.5)/o)),m))}let A=rt({width:l,height:c,stride:l,data:s},{budget:500,...n});return{...A,x:A.x.map(u=>t.x+(u+.5)/o-.5),y:A.y.map(u=>t.y+(u+.5)/o-.5)}}var lt=class{constructor(t={}){F(this,"info",{id:"C1.orb-views",layer:"L2",route:"light",determinism:"bit-exact",requires:[]});F(this,"options");F(this,"matcher");F(this,"targets",[]);this.options=t,this.matcher=Et.create(t.allowWasm===!1?{allowWasm:!1}:{})}get backend(){return this.matcher.backend}probe(t){return{isAvailable:!0}}async load(t){let r=[];this.targets=[];for(let n of t){let o=performance.now(),l=nt(n,this.options.compile),c=await ct(l,n.image,{templateMaxEdge:this.options.templateMaxEdge??480}),s=await Z(c);this.targets.push(s.compiled),r.push({id:n.info.id,compileUs:(performance.now()-o)*1e3,serialized:c,template:s.template})}return{targets:r}}async loadEncoded(t){let r=[];this.targets=[];for(let n of t){let o=performance.now(),l=await Z(n);this.targets.push(l.compiled),r.push({id:l.compiled.info.id,compileUs:(performance.now()-o)*1e3,serialized:n,template:l.template,info:l.compiled.info})}return{targets:r}}async detect(t,r={}){if(t.image.kind!=="cpu-gray")throw new Error("OrbDetector needs cpu-gray frames");let n=r.roi??null,o=(n&&(r.upscale??1)>1?De(t.image.image,n,r.upscale,this.options.orb??{}):null)??rt(t.image.image,{budget:n?500:ke(t.image.image),...this.options.orb,roi:n});if(o.count<8)return[];let l=this.options.ratio??.85,c=this.options.maxDistance??80,s=[];for(let a of this.targets){let i=this.matcher.nearest2Grouped(o.descriptors,a.descriptors,a.descriptorPoint),A=new Map;for(let y=0;y<o.count;y++){let f=i[3*y+1],d=i[3*y+2];if(f>c||l<1&&f>=l*d)continue;let p=a.descriptorPoint[i[3*y]],x=f/Math.max(1,d),b=A.get(p);(!b||x<b.r)&&A.set(p,{q:y,r:x})}let u=[...A].sort((y,f)=>y[1].r-f[1].r||y[0]-f[0]);if(u.length<12)continue;let m=new Float64Array(2*u.length),h=new Float64Array(2*u.length);u.forEach(([y,{q:f}],d)=>{m[2*d]=a.points[2*y],m[2*d+1]=a.points[2*y+1],h[2*d]=o.x[f],h[2*d+1]=o.y[f]});let g=kt(m,h,u.length,a.info.width,a.info.height,{thresholdPx:this.options.thresholdPx??4,maxIterations:1e3,minInliers:12,minInlierRatio:.1,minCoverage:.05});g.accepted&&s.push({inliers:g.inliers,pose:{targetId:a.info.id,frameId:t.frameId,timeUs:t.time.captureUs,H_imageFromTarget:g.H,corners:at(g.H,a.info.width,a.info.height),covariance:null,quality:{support:g.inliers,ratio:g.ratio,residual:g.rmsPx,residualKind:"px",coverage:g.coverage},origin:"detector"}})}return s.sort((a,i)=>i.inliers-a.inliers||a.pose.targetId.localeCompare(i.pose.targetId)),s.length>1&&s[1].inliers>=.85*s[0].inliers?[]:s.map(a=>a.pose)}};var Se=48,Le=64,z=class extends Error{constructor(r,n,o){super(n,o);F(this,"code");this.name="PictureError",this.code=r}};function Ne(e,t,r){let n=Math.min(1,r/Math.max(e,t));return[Math.max(1,Math.round(e*n)),Math.max(1,Math.round(t*n))]}function He(e,t,r){let n=new Uint8Array(t*r);for(let o=0;o<n.length;o++)n[o]=77*e[4*o]+150*e[4*o+1]+29*e[4*o+2]+128>>8;return n}function ee(){try{return typeof OffscreenCanvas=="function"&&!!new OffscreenCanvas(1,1).getContext("2d")}catch{return!1}}async function re(e,t){let r;try{r=await createImageBitmap(e,{imageOrientation:"from-image"})}catch{try{r=await createImageBitmap(e)}catch(n){throw new z("DECODE_FAILED",`The picture cannot be decoded: ${String(n)}`,{cause:n})}}try{let[n,o]=Ne(r.width,r.height,t),l=r,c=r.width,s=r.height;for(;c>2*n&&s>2*o;){let u=new OffscreenCanvas(Math.ceil(c/2),Math.ceil(s/2)),m=u.getContext("2d");m.imageSmoothingQuality="high",m.drawImage(l,0,0,u.width,u.height),l=u,c=u.width,s=u.height}let i=new OffscreenCanvas(n,o).getContext("2d",{willReadFrequently:!0});i.imageSmoothingQuality="high",i.drawImage(l,0,0,n,o);let A=i.getImageData(0,0,n,o).data;return{width:n,height:o,stride:n,data:He(A,n,o)}}finally{r.close()}}async function ne(e,t){if(Math.min(t.width,t.height)<Le)throw new z("UNSUITABLE_TARGET",`The picture is too small (${t.width}×${t.height} px)`);let r=nt({info:{id:e,width:t.width,height:t.height,physicalWidthMeters:null},image:t}),n=r.points.length/2;if(n<Se)throw new z("UNSUITABLE_TARGET",`The picture has too little detail (${n} recognition points)`);return{bytes:await ct(r,t),pointCount:n}}var We=5,Ke=24,qe=.08,Mt={detail:.15,spread:.4,distinctiveness:.05,recognition:.4},Ye=[.1,.7],_e=[15,95],Je=.4,At={size:.08,tilt:.15,blur:.33,dim:.6,covered:.6},j=(e,t,r)=>e<=t?0:e>=r?1:(e-t)/(r-t),q=640,mt=360,St=500,Lt=118,je=[...[160,120,90,70].map(e=>({name:`size-${e}`,test:"size",longPx:e})),...[45,60,70].map(e=>({name:`tilt-${e}`,test:"tilt",longPx:240,tiltDeg:e})),...[6,10,16].map(e=>({name:`blur-${e}`,test:"blur",longPx:240,blurPx:e})),...[.35,.2].map(e=>({name:`dim-${e}`,test:"dim",longPx:240,gain:e})),...[[0],[1],[2],[3],[0,2],[1,3],[0,1],[2,3]].map(e=>({name:`covered-${e.join("")}`,test:"covered",longPx:240,covered:e}))].flatMap(e=>[{...e,rollDeg:8,offset:[24,12]},{...e,rollDeg:-12,offset:[-30,-8]}]),oe=[12,40],Nt={size:.25,tilt:.2,blur:.2,dim:.15,covered:.2};function Xe(e,t,r){let n=e.longPx/Math.max(t,r),o=t*n,l=r*n,c=q/2+e.offset[0],s=mt/2+e.offset[1],a=[[c-o/2,s-l/2],[c+o/2,s-l/2],[c+o/2,s+l/2],[c-o/2,s+l/2]];if(e.tiltDeg){let m=e.tiltDeg*Math.PI/180;a=a.map(([h,g])=>{let y=St+(g-s)*Math.sin(m);return[c+(h-c)*St/y,s+(g-s)*Math.cos(m)*St/y]})}let i=e.rollDeg*Math.PI/180;a=a.map(([m,h])=>[c+(m-c)*Math.cos(i)-(h-s)*Math.sin(i),s+(m-c)*Math.sin(i)+(h-s)*Math.cos(i)]);let A=Float64Array.from([0,0,t,0,t,r,0,r]),u=Float64Array.from(a.flat());return st(A,u,[0,1,2,3])}function ze(e,t,r){let n=e.levels[0],o=t.longPx/Math.max(n.width,n.height),l=Math.max(0,Math.min(e.levels.length-1,Math.floor(Math.log2(1/o)))),c=e.levels[l],s=2**l,a=vt(r),i=new Uint8Array(q*mt),A=12345,u=n.width/2,m=n.height/2;for(let h=0;h<mt;h++)for(let g=0;g<q;g++){A=A*1103515245+12345>>>0;let y=Lt+(A>>>16)%9-4,f=g+.5,d=h+.5,p=a[6]*f+a[7]*d+a[8],x=(a[0]*f+a[1]*d+a[2])/p,b=(a[3]*f+a[4]*d+a[5])/p;if(x>=0&&b>=0&&x<n.width&&b<n.height){let M=(b<m?0:2)+(x<u?0:1);if(!t.covered?.includes(M)){let I=tt(c,Math.min(c.width-.51,Math.max(.5,x/s)),Math.min(c.height-.51,Math.max(.5,b/s)));Number.isNaN(I)||(y=I)}}t.gain!==void 0&&(A=A*1103515245+12345>>>0,y=Lt+(y-Lt)*t.gain+(A>>>16)%13-6),i[h*q+g]=Math.max(0,Math.min(255,Math.round(y)))}if(t.blurPx){let h=Math.floor(t.blurPx/2),g=new Float64Array(q+1);for(let y=0;y<mt;y++){for(let f=0;f<q;f++)g[f+1]=g[f]+i[y*q+f];for(let f=0;f<q;f++){let d=Math.max(0,f-h),p=Math.min(q,f-h+t.blurPx);i[y*q+f]=Math.round((g[p]-g[d])/(p-d))}}}return{width:q,height:mt,stride:q,data:i}}async function ae(e){let t=await Z(e),{compiled:r,template:n}=t,{width:o,height:l}=r.info,c=r.points.length/2,s=[];for(let U=0;U<c;U++)r.repeatability[U]>=We&&s.push(U);let a=new Float32Array(2*s.length);s.forEach((U,G)=>{a[2*G]=r.points[2*U],a[2*G+1]=r.points[2*U+1]});let i=j(s.length,40,250),A=o/l,u=Math.max(2,Math.round(4*Math.sqrt(A))),m=Math.max(2,Math.round(4/Math.sqrt(A))),h=new Array(u*m).fill(0),g=[0,0,0,0];for(let U=0;U<s.length;U++){let G=a[2*U],K=a[2*U+1];h[Math.min(m-1,Math.floor(K/l*m))*u+Math.min(u-1,Math.floor(G/o*u))]++,g[(K<l/2?0:2)+(G<o/2?0:1)]++}let y=Math.max(1,s.length),f=u*m,d=h.filter(U=>U>=Math.max(3,.3*y/f)).length,p=h.reduce((U,G)=>U+(G/y)**2,0),x=s.length?1/p/f:0,b=g.indexOf(Math.min(...g)),M=g[b]/y,I=(.5*j(d/f,.3,.85)+.5*j(x,.25,.65))*(.6+.4*j(M,.03,.15)),w=new Uint32Array(r.descriptors.buffer,r.descriptors.byteOffset,r.descriptors.length/4),Q=Array.from({length:c},()=>[]);r.descriptorPoint.forEach((U,G)=>Q[U].push(G));let E=(qe*Math.hypot(o,l))**2,B=(U,G)=>{let K=0;for(let H=0;H<8;H++){let Y=(w[8*U+H]^w[8*G+H])>>>0;Y-=Y>>>1&1431655765,Y=(Y&858993459)+(Y>>>2&858993459),K+=(Y+(Y>>>4)&252645135)*16843009>>>24}return K},C=U=>{let G=r.points[2*U],K=r.points[2*U+1];for(let H=0;H<c;H++)if(!((r.points[2*H]-G)**2+(r.points[2*H+1]-K)**2<E)){for(let Y of Q[U])for(let $ of Q[H])if(B(Y,$)<=Ke)return!0}return!1},P=s.length?s.filter(U=>!C(U)).length/s.length:0,k=j(P,.35,.7),v=new lt;await v.loadEncoded([e]);let T=Ct(n,6,16),D=[];for(let[U,G]of je.entries()){let K=Xe(G,o,l),H=at(K,o,l),$=(await v.detect({sessionId:"rate",frameId:U+1,time:{captureUs:U,receiveUs:U,source:"replay"},image:{kind:"cpu-gray",image:ze(T,G,K)}})).find(ie=>ie.corners.reduce((ce,Ht,Wt)=>ce+Math.hypot(Ht[0]-H[Wt][0],Ht[1]-H[Wt][1]),0)/4<.08*G.longPx);D.push({name:G.name,test:G.test,found:!!$,margin:$?j($.quality.support,oe[0],oe[1]):0})}let R=Object.fromEntries(Object.keys(Nt).map(U=>{let G=D.filter(K=>K.test===U);return[U,G.reduce((K,H)=>K+H.margin,0)/G.length]})),L=j(Object.keys(Nt).reduce((U,G)=>U+Nt[G]*R[G],0),...Ye),O=100*(Mt.detail*i+Mt.spread*I+Mt.distinctiveness*k+Mt.recognition*L),N=Math.min(.5+4.5*j(O,..._e),1+4*Math.min(I,L)**Je),W=Math.min(5,Math.max(.5,Math.round(N*2)/2)),S=[];return L<.4&&S.push("HARD_TO_FIND"),I<.6&&(d/f<.6||x<.45)&&S.push("CONCENTRATED"),M<.08&&S.push("WEAK_QUARTER"),i<.5&&S.push("FEW_DETAILS"),k<.4&&S.push("REPETITIVE"),R.size<At.size&&S.push("FAILS_SMALL"),R.tilt<At.tilt&&S.push("FAILS_TILTED"),R.blur<At.blur&&S.push("FAILS_BLURRED"),R.dim<At.dim&&S.push("FAILS_DIM"),R.covered<At.covered&&S.push("FAILS_COVERED"),{stars:W,score:Math.round(20*N),factors:{detail:i,spread:I,distinctiveness:k,recognition:L},metrics:{robustPoints:s.length,grid:{columns:u,rows:m,counts:h},populatedCells:d,evenness:x,weakestQuarter:{index:b,share:M},distinctShare:P,tests:R,views:D},advice:S,points:a,width:o,height:l}}var Bt=class extends Error{constructor(r,n){super(n);F(this,"code");this.code=r}};async function Ve(e){if(e.bytes)return new Uint8Array(e.bytes);let t;if(e.gray)t={width:e.gray.width,height:e.gray.height,stride:e.gray.width,data:new Uint8Array(e.gray.data)};else if(ee())t=await re(e.image,e.maxEdgePx);else return null;return(await ne("rated",t)).bytes}function se(e){let t=Promise.resolve();e.addEventListener("message",r=>{let n=r.data;n.type==="rate"&&(t=t.then(async()=>{try{let o=await Ve(n);if(!o){e.postMessage({type:"need-gray",id:n.id});return}let l;try{l=await ae(o)}catch(c){throw n.bytes?new Bt("INVALID_TARGET",c instanceof Error?c.message:String(c)):c}e.postMessage({type:"rated",id:n.id,rating:l},[l.points.buffer])}catch(o){e.postMessage({type:"failed",id:n.id,code:o instanceof z||o instanceof Bt?o.code:"WORKER_FAILED",message:o instanceof Error?o.message:String(o)})}}))})}se(globalThis);})();
@@ -0,0 +1,105 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // LiveMira 0.5.1
3
+
4
+ /**
5
+ * Why a picture rated as it did, most important first:
6
+ * - `'HARD_TO_FIND'`: the detector misses the picture, or finds it narrowly, in most synthetic views;
7
+ * - `'CONCENTRATED'`: the detail sits in part of the picture;
8
+ * - `'WEAK_QUARTER'`: one quarter has almost no detail (`metrics.weakestQuarter`);
9
+ * - `'FEW_DETAILS'`: few points the engine finds again from other angles;
10
+ * - `'REPETITIVE'`: repeating patterns, points that look alike;
11
+ * - `'FAILS_SMALL'`, `'FAILS_TILTED'`, `'FAILS_BLURRED'`, `'FAILS_DIM'`, `'FAILS_COVERED'`: that recognition test
12
+ * (`metrics.tests`) clearly weaker than for most photos: small, tilted, blurred by motion, in dim light, partly
13
+ * covered.
14
+ */
15
+ export type RatingAdvice = 'HARD_TO_FIND' | 'CONCENTRATED' | 'WEAK_QUARTER' | 'FEW_DETAILS' | 'REPETITIVE' | 'FAILS_SMALL' | 'FAILS_TILTED' | 'FAILS_BLURRED' | 'FAILS_DIM' | 'FAILS_COVERED';
16
+ /** The recognition tests, each a ladder of synthetic views from easy to hard. */
17
+ export type RecognitionTest = 'size' | 'tilt' | 'blur' | 'dim' | 'covered';
18
+ /**
19
+ * How well the engine will find and keep a picture. Four factors, each 0..1: `detail` (points found again from other
20
+ * angles), `spread` (those points over the whole picture: grid cells, evenness, the weakest quarter),
21
+ * `distinctiveness` (no look-alikes far apart) and `recognition` (the engine's detector on synthetic views: smaller,
22
+ * tilted, motion-blurred, dimmer, partly covered). The stars weigh them and are capped by the weaker of spread and
23
+ * recognition, so detail crowded in one place cannot rate high.
24
+ */
25
+ export interface TargetRating {
26
+ /** 0.5 … 5 in halves: 5 near the best on every count, 4–4.5 good, 3–3.5 usable, 2–2.5 better replaced. */
27
+ readonly stars: number;
28
+ /** 0 … 100 before rounding to stars. */
29
+ readonly score: number;
30
+ readonly factors: {
31
+ readonly detail: number;
32
+ readonly spread: number;
33
+ readonly distinctiveness: number;
34
+ readonly recognition: number;
35
+ };
36
+ readonly metrics: {
37
+ readonly robustPoints: number;
38
+ readonly grid: {
39
+ readonly columns: number;
40
+ readonly rows: number;
41
+ readonly counts: readonly number[];
42
+ };
43
+ readonly populatedCells: number;
44
+ /** Effective share of cells holding the points (1: even, 1/cells: all in one). */
45
+ readonly evenness: number;
46
+ /** 0 top-left, 1 top-right, 2 bottom-left, 3 bottom-right, and its share of the points. */
47
+ readonly weakestQuarter: {
48
+ readonly index: number;
49
+ readonly share: number;
50
+ };
51
+ readonly distinctShare: number;
52
+ /** Each recognition test's views found, counted by their margin (0..1). */
53
+ readonly tests: Readonly<Record<RecognitionTest, number>>;
54
+ readonly views: readonly {
55
+ readonly name: string;
56
+ readonly test: RecognitionTest;
57
+ readonly found: boolean;
58
+ }[];
59
+ };
60
+ readonly advice: readonly RatingAdvice[];
61
+ /** The points counted as detail, in target pixels (x, y interleaved), for drawing over the picture. */
62
+ readonly points: Float32Array;
63
+ /** Size of the compiled picture (target pixels). */
64
+ readonly width: number;
65
+ readonly height: number;
66
+ }
67
+ export interface RateOptions {
68
+ readonly signal?: AbortSignal;
69
+ /** The rating Worker file, for pages whose CSP forbids `blob:` Workers. */
70
+ readonly workerUrl?: string | URL;
71
+ }
72
+ export interface RateImageOptions extends RateOptions {
73
+ /** Long edge the picture is compiled at; keep it equal to the engine's `compileTargetImage` (default 640). */
74
+ readonly maxEdgePx?: number;
75
+ }
76
+ export type RatingErrorCode =
77
+ /** Not a picture file or target bytes, or an option out of range. */
78
+ 'INVALID_INPUT' | 'DECODE_FAILED'
79
+ /** The engine would refuse this picture: too small, or too little detail to track. */
80
+ | 'UNSUITABLE_TARGET'
81
+ /** Damaged target bytes. */
82
+ | 'INVALID_TARGET' | 'WORKER_FAILED' | 'ABORTED';
83
+ export interface RatingErrorShape extends Error {
84
+ readonly name: 'RatingError';
85
+ readonly code: RatingErrorCode;
86
+ }
87
+ export interface RatingBuildInfo {
88
+ readonly version: string;
89
+ readonly buildId: string;
90
+ readonly variant: 'minified' | 'readable' | 'development';
91
+ }
92
+
93
+ export declare const RATING_VERSION: string;
94
+ export declare const ratingBuildInfo: RatingBuildInfo;
95
+ /** Rates a picture file as a target (decoded and compiled as the engine's `compileTargetImage` would), in a Worker. */
96
+ export declare function rateTargetImage(image: Blob, options?: RateImageOptions): Promise<TargetRating>;
97
+ /** Rates an already compiled target: the engine's target bundle or its bytes. */
98
+ export declare function rateTarget(target: { readonly bytes: Uint8Array } | Uint8Array, options?: RateOptions): Promise<TargetRating>;
99
+ export declare class RatingError extends Error implements RatingErrorShape {
100
+ readonly name: 'RatingError';
101
+ readonly code: RatingErrorCode;
102
+ constructor(code: RatingErrorCode, message: string, options?: { cause?: unknown });
103
+ }
104
+
105
+ export {};
@@ -0,0 +1 @@
1
+ var _=Object.defineProperty;var R=(n,t,e)=>t in n?_(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var o=(n,t,e)=>R(n,typeof t!="symbol"?t+"":t,e);var g="0.5.1",y=Object.freeze({version:g,buildId:"d07d146e702d07a629d46fa828db292b0a2909338e0bd671e05a59d54fa55f82",variant:"minified"});var c=class extends Error{constructor(e,r,i){super(r,i);o(this,"code");this.name="PictureError",this.code=e}};function w(n,t,e){let r=Math.min(1,e/Math.max(n,t));return[Math.max(1,Math.round(n*r)),Math.max(1,Math.round(t*r))]}function E(n,t,e){let r=new Uint8Array(t*e);for(let i=0;i<r.length;i++)r[i]=77*n[4*i]+150*n[4*i+1]+29*n[4*i+2]+128>>8;return r}async function h(n,t){let e;try{e=await createImageBitmap(n)}catch(I){throw new c("DECODE_FAILED","The picture cannot be decoded",{cause:I})}let[r,i]=w(e.width,e.height,t),s=document.createElement("canvas");s.width=r,s.height=i;let u=s.getContext("2d",{willReadFrequently:!0});u.imageSmoothingQuality="high",u.drawImage(e,0,0,r,i),e.close();let f=E(u.getImageData(0,0,r,i).data,r,i);return{width:r,height:i,data:f.buffer}}var a=class extends Error{constructor(e,r,i={}){super(r,i.cause===void 0?void 0:{cause:i.cause});o(this,"name","RatingError");o(this,"code");this.code=e}};var b=4e3,d=null;function T(){return d||(d=URL.createObjectURL(new Blob(['"use strict";(()=>{var le=Object.defineProperty;var Ae=(e,t,r)=>t in e?le(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var F=(e,t,r)=>Ae(e,typeof t!="symbol"?t+"":t,r);var X=class{constructor(){F(this,"rows",new Int32Array(0));F(this,"levels",[])}build(t,r,n=24){let o=[{...t,scale:1}];for(let l=1;l<r;l++){let c=o[l-1],s=c.width>>1,a=c.height>>1;if(s<n||a<n)break;this.rows.length<c.width*a&&(this.rows=new Int32Array(c.width*a));let i=this.levels[l]=this.levels[l]&&this.levels[l].length===s*a?this.levels[l]:new Uint8Array(s*a);me(c,s,a,this.rows,i),o.push({width:s,height:a,stride:s,data:i,scale:c.scale*2})}return{levels:o}}};function me(e,t,r,n,o){let l=e.width,c=e.height,s=e.data,a=e.stride;for(let i=0;i<r;i++){let A=2*i,u=Math.max(0,A-1)*a,m=A*a,h=Math.min(c-1,A+1)*a,g=Math.min(c-1,A+2)*a,y=i*l;for(let f=0;f<l;f++)n[y+f]=s[u+f]+3*s[m+f]+3*s[h+f]+s[g+f]}for(let i=0;i<r;i++){let A=i*l;for(let u=0;u<t;u++){let m=2*u,h=n[A+Math.max(0,m-1)],g=n[A+m],y=n[A+Math.min(l-1,m+1)],f=n[A+Math.min(l-1,m+2)];o[i*t+u]=h+3*g+3*y+f+32>>6}}}function Ct(e,t,r=24){return new X().build(e,t,r)}function tt(e,t,r){let n=t-.5,o=r-.5,l=Math.floor(n),c=Math.floor(o);if(l<0||c<0||l+1>=e.width||c+1>=e.height)return NaN;let s=n-l,a=o-c,i=e.data,A=c*e.stride+l,u=i[A]+s*(i[A+1]-i[A]),m=i[A+e.stride]+s*(i[A+e.stride+1]-i[A+e.stride]);return u+a*(m-u)}var Kt=Object.freeze({sha256:"d51fe1439175bb1343361385d7910036f36a63ed17a83311619a3b04cfa3e837",byteLength:4375,base64:"AGFzbQEAAAABKAVgCn9/f39/f39/f38Bf2AFf39/f38AYAZ/f39/f38AYAF/AX9gAAADBgUAAQIDBAUDAQARBhkDfwFBgIDAAAt/AEGQgMAAC38AQYSAwAALB2IIBm1lbW9yeQIABWZhc3Q5AAAIbmVhcmVzdDIAARBuZWFyZXN0Ml9ncm91cGVkAAIHcmVzZXJ2ZQADC19faGVhcF9iYXNlAwEKcmVzZXRfaGVhcAAECl9fZGF0YV9lbmQDAgr5HQW/EAwIfwF7BX8EewF/DXsBfwJ7AX8HewF/FXsjgICAgABBwAJrIgokgICAgABBACELAkAgAyAFTw0AIAIgBE8NAEF9IAFrIQwgAUEDbCENQQMgAWshDiABQX1sIQ9BACABQQF0IhBrIREgBkH/ASAGQf8BSRv9DyESQQAhCwNAIAMgCGwhEyAAIAMgAWxqIRQgAiEVA0ACQEH//wNBfyAEIBVrIgZ0QX9zQf//A3EgBkEPSxsiFiAUIBVqIgYgDWoiF/0AAAAiGCAG/QAAACIZIBL9cyIa/SYiGyAGIA9qIhz9AAAAIh0gGv0mIh79UCAGQX1q/QAAACIfIBr9JiIgIAb9AAADIiEgGv0mIiL9UP1OIBggGSAS/XAiGf0oIiMgHSAZ/SgiJP1QICEgGf0oIiUgHyAZ/SgiJv1Q/U79UP1kcUUNACAWICIgBiAOav0AAAAiJyAa/SYiKP1OIikgBiAQaiIqQQJq/QAAACIrIBr9JiIsIAYgAWoiLUEDav0AAAAiLiAa/SYiL/1OIjD9TiIxIB4gHEF/av0AAAAiMiAa/SYiM/1OIjQgBiARaiI1QQJq/QAAACI2IBr9JiI3IBxBAWr9AAAAIjggGv0mIjn9TiI6/U4iO/1OIBdBAWr9AAAAIjwgGv0mIj39TiAsICggN/1OIj4gLyAi/U4iP/1OIkAgMyA1QX5q/QAAACJBIBr9JiJC/U4iQyA5IB79TiJE/U4iRf1O/U4gOiAp/U4iRiBCIAYgDGr9AAAAIikgGv0mIjr9TiJHIDT9TiJI/U4gL/1OICIgPiBE/U4iPiBDIDogIP1OIi/9TiJD/U79TiA7ICAgLUF9av0AAAAiIiAa/SYiNP1OIkQgR/1OIkf9TiAo/U4gNyBFIDQgKkF+av0AAAAiKCAa/SYiO/1OIkkgL/1OIkr9Tv1OIEggOyAXQX9q/QAAACIvIBr9JiI3/U4iRSBE/U4iRP1OIDn9TiAeIEMgSSA3IBv9TiI5/U4iSP1O/U4gMyBH/U4gRSAbID39TiIe/U4iM/1OIEIgSiA9ICz9TiIsIDn9TiI5/U79TiA6IET9TiAwIB79TiIe/U4gICBIICwgP/1OIiz9Tv1OIDQgMf1OIDP9TiA7IDkgQP1O/U4gNyBG/U4gHv1OIBsgLCA+/U79Tv1Q/VD9UP1Q/VD9UP1Q/VD9UP1Q/VD9UP1Q/VD9UP1kICUgJyAZ/SgiG/1OIkIgKyAZ/SgiHiAuIBn9KCIg/U4iOv1OIjQgJCAyIBn9KCIs/U4iOyA2IBn9KCIzIDggGf0oIjf9TiIw/U4iMf1OIDwgGf0oIjn9TiAeIBsgM/1OIj4gICAl/U4iP/1OIkAgLCBBIBn9KCI9/U4iQyA3ICT9TiJE/U4iRf1O/U4gMCBC/U4iMCA9ICkgGf0oIkL9TiJGIDv9TiI7/U4gIP1OICUgPiBE/U4iPiBDIEIgJv1OIkT9TiJD/U79TiAxICYgIiAZ/SgiIP1OIkcgRv1OIkb9TiAb/U4gMyBFICAgKCAZ/SgiG/1OIjEgRP1OIkT9Tv1OIDsgGyAvIBn9KCIl/U4iMyBH/U4iRf1OIDf9TiAkIEMgMSAlICP9TiI3/U4iO/1O/U4gLCBG/U4gMyAjIDn9TiIk/U4iLP1OID0gRCA5IB79TiIeIDf9TiIz/U79TiBCIEX9TiA6ICT9TiIk/U4gJiA7IB4gP/1OIh79Tv1OICAgNP1OICz9TiAbIDMgQP1O/U4gJSAw/U4gJP1OICMgHiA+/U79Tv1Q/VD9UP1Q/VD9UP1Q/VD9UP1Q/VD9UP1Q/VD9UP1kIhxycSIGRQ0AIAogMiAZ/XP9CwTwASAKIEEgGf1z/QsE4AEgCiApIBn9c/0LBNABIAogHyAZ/XP9CwTAASAKICIgGf1z/QsEsAEgCiAoIBn9c/0LBKABIAogLyAZ/XP9CwSQASAKIBggGf1z/QsEgAEgCiA8IBn9c/0LBHAgCiArIBn9c/0LBGAgCiAuIBn9c/0LBFAgCiAhIBn9c/0LBEAgCiAnIBn9c/0LBDAgCiA2IBn9c/0LBCAgCiA4IBn9c/0LBBAgCiAdIBn9c/0LBABBACEX/QwAAAAAAAAAAAAAAAAAAAAAIhkhGwNAIBsgCiAXav0ABAAiHv2KAf2OASEbIBkgHv2JAf2OASEZIBdBEGoiF0GAAkcNAAsgCiAaIDL9c/0LBPABIAogGiBB/XP9CwTgASAKIBogKf1z/QsE0AEgCiAaIB/9c/0LBMABIAogGiAi/XP9CwSwASAKIBogKP1z/QsEoAEgCiAaIC/9c/0LBJABIAogGiAY/XP9CwSAASAKIBogPP1z/QsEcCAKIBogK/1z/QsEYCAKIBogLv1z/QsEUCAKIBogIf1z/QsEQCAKIBogJ/1z/QsEMCAKIBogNv1z/QsEICAKIBogOP1z/QsEECAKIBogHf1z/QsEAEEAIRf9DAAAAAAAAAAAAAAAAAAAAAAiHiEaA0AgGiAKIBdq/QAEACIg/YoB/Y4BIRogHiAg/YkB/Y4BIR4gF0EQaiIXQYACRw0ACyAKIBv9CwSQAiAKIBn9CwSAAiAKIBr9CwSwAiAKIB79CwSgAiAcIBZxISogFSATaiEtIAkgC0ECdGohFwNAIAcgLSAGaCIcaiIWQQF0aiAKQYACaiAKQaACaiAqIBx2QQFxGyAcQQF0ai8BAEEBajsBACAXIBY2AgAgF0EEaiEXIAtBAWohCyAGQX9qIAZxIgYNAAsLIBVBEGoiFSAESQ0ACyADQQFqIgMgBUcNAAsLIApBwAJqJICAgIAAIAsL/wUGAn8CewR/AXsCfwF+AkAgAUUNAAJAIANFDQBBACEFA0AgACAFQQV0aiIG/QAAECEHIAb9AAAAIQhBfyEJQYECIQYgAiEKQQAhC0GBAiEMA0AgBiAKQRBq/QAAACAH/VH9YiAK/QAAACAI/VH9Yv1u/X39fyIN/RsAIA39GwFqIA39GwJqIA39GwNqIg4gDCAOIAxJGyAOIAZJIg8bIQwgCyAJIA8bIQkgCkEgaiEKIA4gBiAPGyIOIQYgAyALQQFqIgtHDQALIAQgBUEMbGoiBiAJNgIAIAZBCGogDDYCACAGQQRqIA42AgAgBUEBaiIFIAFHDQAMAgsLQQAhDwJAIAFBGEkNAEEAIQ8gBEEEaiIGIAFBf2qtQgx+IhCnIgpqIAZJDQAgBEEIaiIGIApqIAZJDQAgEEIgiKdBAEcNAP0MAAAAAAEAAAACAAAAAwAAACEHIAFBfHEiDyELA0AgBCAH/QwMAAAADAAAAAwAAAAMAAAA/bUBIg39GwBqIgZBfzYCACAEIA39GwFqIgpBfzYCACAEIA39GwJqIg5BfzYCACAEIA39GwNqIgxBfzYCACAGQQRqQYECNgIAIApBBGpBgQI2AgAgDkEEakGBAjYCACAMQQRqQYECNgIAIAZBCGpBgQI2AgAgCkEIakGBAjYCACAOQQhqQYECNgIAIAxBCGpBgQI2AgAgB/0MBAAAAAQAAAAEAAAABAAAAP2uASEHIAtBfGoiCw0ACyABIA9GDQELIA8hDgJAIAFBA3EiCkUNACAPIApqIQ4gBCAPQQxsaiEGA0AgBkL/////nyA3AgAgBkEIakGBAjYCACAGQQxqIQYgCkF/aiIKDQALCyAPIAFrQXxLDQAgASAOayEKIAQgDkEMbGohBgNAIAb9DP////8BAQAAAQEAAP/////9CwIAIAZBIGr9DAEBAAD/////AQEAAAEBAAD9CwIAIAZBEGr9DAEBAAABAQAA/////wEBAAD9CwIAIAZBMGohBiAKQXxqIgoNAAsLC7kGBgJ/AnsGfwF7An8BfgJAIAFFDQACQCAERQ0AQQAhBgNAIAAgBkEFdGoiB/0AABAhCCAH/QAAACEJQX8hCkGBAiELIAIhByADIQxBACENQYECIQ5BfyEPA0AgB0EQav0AAAAgCP1R/WIgB/0AAAAgCf1R/WL9bv19/X8iEP0bACAQ/RsBaiAQ/RsCaiAQ/RsDaiERAkACQCAMKAIAIhIgCkYNAAJAIBEgC08NACANIQ8gCyEOIBIhCiARIQsMAgsgESAOIBEgDkkbIQ4MAQsgESALIBEgC0kiEhshCyANIA8gEhshDwsgB0EgaiEHIAxBBGohDCAEIA1BAWoiDUcNAAsgBSAGQQxsaiIHIA82AgAgB0EIaiAONgIAIAdBBGogCzYCACAGQQFqIgYgAUcNAAwCCwtBACEPAkAgAUEYSQ0AQQAhDyAFQQRqIgcgAUF/aq1CDH4iE6ciEWogB0kNACAFQQhqIgcgEWogB0kNACATQiCIp0EARw0A/QwAAAAAAQAAAAIAAAADAAAAIQggAUF8cSIPIQsDQCAFIAj9DAwAAAAMAAAADAAAAAwAAAD9tQEiEP0bAGoiB0F/NgIAIAUgEP0bAWoiEUF/NgIAIAUgEP0bAmoiDEF/NgIAIAUgEP0bA2oiDUF/NgIAIAdBBGpBgQI2AgAgEUEEakGBAjYCACAMQQRqQYECNgIAIA1BBGpBgQI2AgAgB0EIakGBAjYCACARQQhqQYECNgIAIAxBCGpBgQI2AgAgDUEIakGBAjYCACAI/QwEAAAABAAAAAQAAAAEAAAA/a4BIQggC0F8aiILDQALIAEgD0YNAQsgDyEMAkAgAUEDcSIRRQ0AIA8gEWohDCAFIA9BDGxqIQcDQCAHQv////+fIDcCACAHQQhqQYECNgIAIAdBDGohByARQX9qIhENAAsLIA8gAWtBfEsNACABIAxrIREgBSAMQQxsaiEHA0AgB/0M/////wEBAAABAQAA//////0LAgAgB0Egav0MAQEAAP////8BAQAAAQEAAP0LAgAgB0EQav0MAQEAAAEBAAD/////AQEAAP0LAgAgB0EwaiEHIBFBfGoiEQ0ACwsLZQEDfwJAQQAoAoCAwIAAIgENAEEAQZ+AwIAAQXBxIgE2AoCAwIAACwJAIAAgAWpBD2pBcHEiAEH//wNqQRB2IgI/ACIDTQ0AIAIgA2tAAEF/Rw0AQQAPC0EAIAA2AoCAwIAAIAELFABBAEGfgMCAAEFwcTYCgIDAgAALAGwEbmFtZQAWFWxpdmVtaXJhX2tlcm5lbHMud2FzbQE5BQAFZmFzdDkBCG5lYXJlc3QyAhBuZWFyZXN0Ml9ncm91cGVkAwdyZXNlcnZlBApyZXNldF9oZWFwBxIBAA9fX3N0YWNrX3BvaW50ZXIATQlwcm9kdWNlcnMCCGxhbmd1YWdlAQRSdXN0AAxwcm9jZXNzZWQtYnkBBXJ1c3RjHTEuOTUuMCAoNTk4MDc2MTZlIDIwMjYtMDQtMTQpAJ0BD3RhcmdldF9mZWF0dXJlcwkrC2J1bGstbWVtb3J5Kw9idWxrLW1lbW9yeS1vcHQrFmNhbGwtaW5kaXJlY3Qtb3ZlcmxvbmcrCm11bHRpdmFsdWUrD211dGFibGUtZ2xvYmFscysTbm9udHJhcHBpbmctZnB0b2ludCsPcmVmZXJlbmNlLXR5cGVzKwhzaWduLWV4dCsHc2ltZDEyOA=="});function ue(e){let t=atob(e),r=new Uint8Array(t.length);for(let n=0;n<t.length;n++)r[n]=t.charCodeAt(n);return r}var et;function ut(){if(typeof WebAssembly>"u")return null;try{if(et===void 0){let e=ue(Kt.base64);et=WebAssembly.validate(e)?new WebAssembly.Module(e):null}return et?new WebAssembly.Instance(et,{}).exports:null}catch{return et=null,null}}var fe=[[0,-3],[1,-3],[2,-2],[3,-1],[3,0],[3,1],[2,2],[1,3],[0,3],[-1,3],[-2,2],[-3,1],[-3,0],[-3,-1],[-2,-2],[-1,-3]];function ye(e,t,r,n){let o=e[t],l=o+n,c=o-n,s=e[t+r[0]],a=e[t+r[8]];if(s<=l&&s>=c&&a<=l&&a>=c)return 0;let i=e[t+r[4]],A=e[t+r[12]];if(i<=l&&i>=c&&A<=l&&A>=c)return 0;let u=0,m=0,h=0,g=0;for(let y=0;y<16;y++){let f=e[t+r[y]];f>l?(u|=1<<y,h+=f-l):f<c&&(m|=1<<y,g+=c-f)}return qt(u)?h+1:qt(m)?g+1:0}function qt(e){if(!e)return!1;let t=(e|e<<16)>>>0,r=t;for(let n=1;n<9;n++)r&=t>>>n;return r!==0}var yt=class{constructor(){F(this,"backend","js");F(this,"map",new Uint16Array(0));F(this,"image",null);F(this,"offsets",new Int32Array(16))}begin(t){return this.map.length<t.width*t.height&&(this.map=new Uint16Array(t.width*t.height)),this.image=t,this.offsets=Int32Array.from(fe.map(([r,n])=>n*t.stride+r)),this.map}score(t,r,n,o,l,c){let{width:s,stride:a,data:i}=this.image;for(let A=r;A<o;A++)for(let u=t;u<n;u++){let m=ye(i,A*a+u,this.offsets,l);m>0&&(this.map[A*s+u]=m,c.push(A*s+u))}}},Qt=class{constructor(t){F(this,"backend","wasm-simd");F(this,"k");F(this,"capacity",0);F(this,"img",0);F(this,"scores",0);F(this,"found",0);F(this,"map",new Uint16Array(0));F(this,"image",null);this.k=t}begin(t){let r=t.stride*t.height;if(r>this.capacity){let n=this.k;if(n.reset_heap(),this.img=n.reserve(r+16),this.scores=n.reserve(2*r),this.found=n.reserve(4*r),!this.img||!this.scores||!this.found)throw new Error("fast9: out of memory");this.capacity=r,new Uint16Array(n.memory.buffer,this.scores,r).fill(0)}return new Uint8Array(this.k.memory.buffer,this.img,r).set(t.data.subarray(0,r)),this.map=new Uint16Array(this.k.memory.buffer,this.scores,t.width*t.height),this.image=t,this.map}score(t,r,n,o,l,c){let s=this.image,a=this.k.fast9(this.img,s.stride,t,r,n,o,l,this.scores,s.width,this.found),i=new Uint32Array(this.k.memory.buffer,this.found,a);for(let A=0;A<a;A++)c.push(i[A])}};function he(e){let n=new Uint8Array(2867),o=2654435769;for(let s=0;s<47;s++)for(let a=0;a<61;a++){o^=o<<13,o^=o>>>17,o^=o<<5;let i=(o>>>0)%64;n[s*61+a]=a<20?128:a<40?((a>>2)+(s>>2))%2?230-i:20+i:i*4}let l={width:61,height:47,stride:61,data:n},c=new yt;for(let s of[4,16,40]){let a=[],i=[],A=c.begin(l),u=e.begin(l);if(c.score(3,3,43,44,s,a),e.score(3,3,43,44,s,i),a.length!==i.length||a.some((m,h)=>m!==i[h]||A[m]!==u[m]))return!1;for(let m of a)A[m]=0;for(let m of i)u[m]=0;if(s===16&&a.length<10)return!1}return!0}var ft=null;function Yt(e=!0){if(!ft){let t=ut(),r=null;try{r=t?new Qt(t):null,r&&!he(r)&&(r=null)}catch{r=null}ft={wasm:r,js:new yt}}return e&&ft.wasm||ft.js}var _=15,ht=_+3,V=32,ge=(()=>{let e=625341585,t=()=>(e^=e<<13,e>>>=0,e^=e>>>17,e^=e<<5,e>>>=0,(e+.5)/4294967296),r=()=>Math.sqrt(-2*Math.log(t()))*Math.cos(2*Math.PI*t()),n=new Int8Array(1024);for(let o=0;o<256;){let l=[0,1,2,3].map(()=>Math.round(r()*8.5));Math.hypot(l[0],l[1])>15||Math.hypot(l[2],l[3])>15||Math.hypot(l[0]-l[2],l[1]-l[3])<2||(n.set(l,4*o),o++)}return n})(),dt=2;function de(e){return Array.from({length:V},(t,r)=>{let n=2*Math.PI*r/V,o=Math.cos(n),l=Math.sin(n),c=new Int8Array(1024);for(let s=0;s<512;s++){let a=e[2*s],i=e[2*s+1];c[2*s]=Math.round(o*a-l*i),c[2*s+1]=Math.round(l*a+o*i)}return c})}var _t=new WeakMap;function pe(e){let t=_t.get(e);if(!t){let r=e.length===1024;for(let n=0;n<512&&r;n++)r=Math.hypot(e[2*n],e[2*n+1])<=15;if(!r)throw new Error("BRIEF pattern: 256 tests with box centres within 15 px");t=de(e),_t.set(e,t)}return t}var Ie=(()=>{let e=new Int32Array(_+1);for(let t=0;t<=_;t++)e[t]=Math.floor(Math.sqrt(_*_-t*t)+.5);return e})(),gt=class{constructor(){F(this,"octaves",new X);F(this,"halfOctaves",new X);F(this,"horizontal",new Uint16Array(0));F(this,"blur",new Uint8Array(0));F(this,"half",new Uint8Array(0));F(this,"integral",new Int32Array(0))}},Jt=new gt;function be(e,t){let r=e.width,n=e.height,o=Math.floor(r/Math.SQRT2),l=Math.floor(n/Math.SQRT2),c=e.data;t.horizontal.length<r*n&&(t.horizontal=new Uint16Array(r*n),t.blur=new Uint8Array(r*n)),t.half.length!==o*l&&(t.half=new Uint8Array(o*l));let s=t.horizontal;for(let m=0;m<n;m++){let h=m*e.stride,g=m*r;s[g]=3*c[h]+c[h+1];for(let y=1;y<r-1;y++)s[g+y]=c[h+y-1]+2*c[h+y]+c[h+y+1];s[g+r-1]=c[h+r-2]+3*c[h+r-1]}let a=t.blur;for(let m=0;m<n;m++){let h=Math.max(0,m-1)*r,g=m*r,y=Math.min(n-1,m+1)*r;for(let f=0;f<r;f++)a[g+f]=s[h+f]+2*s[g+f]+s[y+f]+8>>4}let i=new Int32Array(o),A=new Float32Array(o);for(let m=0;m<o;m++){let h=(m+.5)*Math.SQRT2-.5;i[m]=Math.min(r-2,Math.max(0,Math.floor(h))),A[m]=h-i[m]}let u=t.half;for(let m=0;m<l;m++){let h=(m+.5)*Math.SQRT2-.5,g=Math.min(n-2,Math.max(0,Math.floor(h))),y=h-g,f=g*r,d=f+r;for(let p=0;p<o;p++){let x=i[p],b=A[p],M=a[f+x]+b*(a[f+x+1]-a[f+x]),I=a[d+x]+b*(a[d+x+1]-a[d+x]);u[m*o+p]=M+y*(I-M)+.5|0}}return{width:o,height:l,stride:o,data:u}}function we(e,t,r=new gt){let n=Math.ceil(t/2),o=r.octaves.build(e,n,24).levels,l=r.halfOctaves.build(be(e,r),n,24).levels,c=[];for(let s=0;s<n;s++)o[s]&&c.push({image:o[s],scale:2**s}),l[s]&&c.push({image:l[s],scale:Math.SQRT2*2**s});return c.slice(0,t)}function xe(e,t,r,n){let o=0,l=0,c=0;for(let s=-3;s<=3;s++)for(let a=-3;a<=3;a++){let i=(n+s)*t+r+a,A=e[i+1]-e[i-1],u=e[i+t]-e[i-t];o+=A*A,l+=u*u,c+=A*u}return o*l-c*c-.04*(o+l)**2}function Ee(e,t){let r=e.width+1;t.integral.length<r*(e.height+1)&&(t.integral=new Int32Array(r*(e.height+1)));let n=t.integral;n.fill(0,0,r);for(let o=0;o<e.height;o++){n[(o+1)*r]=0;let l=0;for(let c=0;c<e.width;c++)l+=e.data[o*e.stride+c],n[(o+1)*r+c+1]=n[o*r+c+1]+l}return n}function Me(e,t,r,n,o){let{width:l,height:c,stride:s,data:a}=e,i=r.cell,A=[],u=Math.max(ht,Math.floor(n.x0)),m=Math.max(ht,Math.floor(n.y0)),h=Math.min(l-ht,Math.ceil(n.x1)),g=Math.min(c-ht,Math.ceil(n.y1));if(h<=u||g<=m)return A;let y=o.begin(e),f=[];for(let d=m;d<g;d+=i)for(let p=u;p<h;p+=i){let x=Math.min(g,d+i),b=Math.min(h,p+i);f.length=0;let M=255,I=0;for(let E=d;E<x;E+=2)for(let B=p;B<b;B+=2){let C=a[E*s+B];C<M&&(M=C),C>I&&(I=C)}if(I-M<2*r.minFastThreshold)continue;for(let E=r.fastThreshold;o.score(p,d,b,x,E,f),!(f.length>=2||E===r.minFastThreshold);E=r.minFastThreshold){for(let B of f)y[B]=0;f.length=0}let w=[];for(let E of f){let B=y[E],C=!0;for(let P=-1;P<=1&&C;P++)for(let k=-1;k<=1;k++){if(!k&&!P)continue;let v=y[E+P*l+k];if(v>B||v===B&&(P<0||P===0&&k<0)){C=!1;break}}C&&w.push({i:E,s:B})}for(let E of f)y[E]=0;w.sort((E,B)=>B.s-E.s||E.i-B.i);let Q=[];for(let E of w.slice(0,8)){let B=E.i%l,C=(E.i-B)/l,P=xe(a,s,B,C);P>0&&Q.push({x:B,y:C,score:P})}Q.sort((E,B)=>B.score-E.score||E.y-B.y||E.x-B.x),A.push(...Q.slice(0,2))}return A.sort((d,p)=>p.score-d.score||d.y-p.y||d.x-p.x),A.slice(0,t)}function Be(e,t,r){let n=e.data,o=e.stride,l=0,c=0,s=r*o+t;for(let a=-_;a<=_;a++)c+=a*n[s+a];for(let a=1;a<=_;a++){let i=0,A=Ie[a];for(let u=-A;u<=A;u++){let m=n[s-a*o+u],h=n[s+a*o+u];i+=h-m,c+=u*(m+h)}l+=a*i}return Math.atan2(l,c)}function Ce(e){return(Math.round(e*V/(2*Math.PI))%V+V)%V}function Qe(e,t,r,n,o,l,c,s){let a=l[Ce(o)],i=(n-2)*t+(r-2),A=5*t;for(let u=0;u<32;u++){let m=0;for(let h=0;h<8;h++){let g=4*(8*u+h),y=i+a[g+1]*t+a[g],f=i+a[g+3]*t+a[g+2],d=e[y+A+5]-e[y+5]-e[y+A]+e[y],p=e[f+A+5]-e[f+5]-e[f+A]+e[f];d<p&&(m|=1<<h)}c[s+u]=m}}function rt(e,t={}){let r=t.budget??700,n=we(e,t.levels??6,Jt),o={fastThreshold:t.fastThreshold??16,minFastThreshold:t.minFastThreshold??4,cell:t.cell??24},l=Yt(t.wasm!==!1),c=pe(t.pattern??ge),s=n.reduce((d,p)=>d+p.image.width*p.image.height,0),a=t.roi??{x:0,y:0,width:e.width,height:e.height},i=[],A=[],u=[],m=[],h=[],g=[];n.forEach((d,p)=>{let x=Math.max(16,Math.round(r*d.image.width*d.image.height/s)),b=d.scale,M=Me(d.image,x,o,{x0:a.x/b,y0:a.y/b,x1:(a.x+a.width)/b,y1:(a.y+a.height)/b},l);if(!M.length)return;let I=Ee(d.image,Jt),w=new Uint8Array(32*M.length);M.forEach((Q,E)=>{let B=Be(d.image,Q.x,Q.y);Qe(I,d.image.width+1,Q.x,Q.y,B,c,w,32*E),i.push((Q.x+.5)*b),A.push((Q.y+.5)*b),u.push(p),m.push(B),h.push(Q.score)}),g.push(w)});let y=new Uint8Array(32*i.length),f=0;for(let d of g)y.set(d,f),f+=d.length;return{count:i.length,x:Float32Array.from(i),y:Float32Array.from(A),level:Uint8Array.from(u),angle:Float32Array.from(m),score:Float32Array.from(h),descriptors:y,descriptorBytes:32}}function Ue(e,t,r){let n=r*Math.PI/180,o=Math.cos(n),l=Math.sin(n),c=o*o/t+l*l,s=o*l/t-o*l,a=l*l/t+o*o,i=[[0,0],[e.width,0],[e.width,e.height],[0,e.height]].map(([I,w])=>[c*I+s*w,s*I+a*w]),A=Math.min(...i.map(I=>I[0])),u=Math.min(...i.map(I=>I[1])),m=Math.ceil(Math.max(...i.map(I=>I[0]))-A),h=Math.ceil(Math.max(...i.map(I=>I[1]))-u),g=[c,s,-A,s,a,-u],y=.8*Math.sqrt(Math.max(0,t*t-1)),f=y>.3?jt(e,y):e,d=c*a-s*s,p=a/d,x=-s/d,b=c/d,M=new Uint8Array(m*h).fill(128);for(let I=0;I<h;I++)for(let w=0;w<m;w++){let Q=w+.5-g[2],E=I+.5-g[5],B=p*Q+x*E-.5,C=x*Q+b*E-.5,P=Math.floor(B),k=Math.floor(C);if(P<0||k<0||P+1>=e.width||k+1>=e.height)continue;let v=B-P,T=C-k,D=k*f.stride+P,R=f.data,L=R[D]+v*(R[D+1]-R[D]),O=R[D+f.stride]+v*(R[D+f.stride+1]-R[D+f.stride]);M[I*m+w]=Math.round(L+T*(O-L))}return{image:{width:m,height:h,stride:m,data:M},A:g}}function jt(e,t){let r=Math.ceil(3*t),n=Array.from({length:2*r+1},(a,i)=>Math.exp(-((i-r)**2)/(2*t*t))),o=n.reduce((a,i)=>a+i,0),l=n.map(a=>a/o),c=new Float32Array(e.width*e.height);for(let a=0;a<e.height;a++)for(let i=0;i<e.width;i++){let A=0;for(let u=-r;u<=r;u++)A+=l[u+r]*e.data[a*e.stride+Math.min(e.width-1,Math.max(0,i+u))];c[a*e.width+i]=A}let s=new Uint8Array(e.width*e.height);for(let a=0;a<e.height;a++)for(let i=0;i<e.width;i++){let A=0;for(let u=-r;u<=r;u++)A+=l[u+r]*c[Math.min(e.height-1,Math.max(0,a+u))*e.width+i];s[a*e.width+i]=Math.round(A)}return{width:e.width,height:e.height,stride:e.width,data:s}}function Fe(e,t,r,n){let o=0;for(let l=0;l<32;l++){let c=e[t+l]^r[n+l];for(;c;)c&=c-1,o++}return o}function nt(e,t={}){let r=t.tilts??[1.4,2,2.8],n=t.longitudes??[0,45,90,135],o=[{image:e.image,A:[1,0,0,0,1,0]}];for(let d of r)for(let p of n)o.push(Ue(e.image,d,p));for(let d of t.blurs??[2.5])o.push({image:jt(e.image,d),A:[1,0,0,0,1,0]});let l=[],c=new Map,s=4,a=(d,p)=>Math.floor(p/s)*65536+Math.floor(d/s);o.forEach((d,p)=>{let x=rt(d.image,{budget:900,...t.orb}),[b,M,I,w,Q,E]=d.A,B=b*Q-M*w;for(let C=0;C<x.count;C++){let P=x.x[C]-I,k=x.y[C]-E,v=(Q*P-M*k)/B,T=(-w*P+b*k)/B;if(v<0||T<0||v>=e.info.width||T>=e.info.height)continue;let D=2+1.5*(2**(x.level[C]/2)-1),R=-1;for(let O=-1;O<=1&&R<0;O++)for(let N=-1;N<=1&&R<0;N++)for(let W of c.get(a(v+N*s,T+O*s))??[]){let S=l[W];if(Math.hypot(S.x-v,S.y-T)<=D){R=W;break}}let L=x.descriptors.slice(32*C,32*C+32);if(R<0){l.push({x:v,y:T,n:1,views:new Set([p]),score:x.score[C],desc:[L]});let O=a(v,T);c.set(O,[...c.get(O)??[],l.length-1])}else{let O=l[R];O.views.add(p),O.n++,O.score=Math.max(O.score,x.score[C]),O.desc.push(L)}}});let i=t.maxPoints??700,A=t.descriptorsPerPoint??3,u=l.map((d,p)=>({g:d,i:p})).sort((d,p)=>p.g.views.size-d.g.views.size||p.g.score-d.g.score||d.i-p.i).slice(0,i).map(d=>d.g),m=new Float32Array(2*u.length),h=new Uint8Array(u.length),g=[],y=[];u.forEach((d,p)=>{m[2*p]=d.x,m[2*p+1]=d.y,h[p]=d.views.size;let x=[];for(let b of d.desc){if(x.length>=A)break;x.every(M=>Fe(M,0,b,0)>24)&&x.push(b)}for(let b of x)g.push(b),y.push(p)});let f=new Uint8Array(32*g.length);return g.forEach((d,p)=>f.set(d,32*p)),{info:e.info,points:m,repeatability:h,descriptors:f,descriptorPoint:Uint32Array.from(y)}}function ot(e,t,r){let n=e[6]*t+e[7]*r+e[8];return Math.abs(n)<1e-12?[NaN,NaN]:[(e[0]*t+e[1]*r+e[2])/n,(e[3]*t+e[4]*r+e[5])/n]}function at(e,t,r){return[ot(e,0,0),ot(e,t,0),ot(e,t,r),ot(e,0,r)]}function pt(e,t,r){for(let n=0;n<r;n++){let o=n,l=Math.abs(e[n*r+n]);for(let s=n+1;s<r;s++){let a=Math.abs(e[s*r+n]);a>l&&(l=a,o=s)}if(l<1e-12)return!1;if(o!==n){for(let a=0;a<r;a++){let i=e[n*r+a];e[n*r+a]=e[o*r+a],e[o*r+a]=i}let s=t[n];t[n]=t[o],t[o]=s}let c=e[n*r+n];for(let s=n+1;s<r;s++){let a=e[s*r+n]/c;if(a!==0){for(let i=n;i<r;i++)e[s*r+i]-=a*e[n*r+i];t[s]-=a*t[n]}}}for(let n=r-1;n>=0;n--){let o=t[n];for(let l=n+1;l<r;l++)o-=e[n*r+l]*t[l];t[n]=o/e[n*r+n]}return t.every(Number.isFinite)}function Xt(e,t){let r=new Float64Array(e),n=new Float64Array(t*t);for(let o=0;o<t;o++)n[o*t+o]=1;for(let o=0;o<t;o++){let l=o;for(let s=o+1;s<t;s++)Math.abs(r[s*t+o])>Math.abs(r[l*t+o])&&(l=s);if(Math.abs(r[l*t+o])<1e-15)return null;if(l!==o)for(let s=0;s<t;s++){let a=r[o*t+s];r[o*t+s]=r[l*t+s],r[l*t+s]=a,a=n[o*t+s],n[o*t+s]=n[l*t+s],n[l*t+s]=a}let c=r[o*t+o];for(let s=0;s<t;s++)r[o*t+s]/=c,n[o*t+s]/=c;for(let s=0;s<t;s++){if(s===o)continue;let a=r[s*t+o];if(a!==0)for(let i=0;i<t;i++)r[s*t+i]-=a*r[o*t+i],n[s*t+i]-=a*n[o*t+i]}}return n}function zt(e,t){let r=new Float64Array(e),n=new Float64Array(t*t);for(let c=0;c<t;c++)n[c*t+c]=1;for(let c=0;c<50;c++){let s=0;for(let a=0;a<t;a++)for(let i=a+1;i<t;i++)s+=r[a*t+i]**2;if(s<1e-24)break;for(let a=0;a<t;a++)for(let i=a+1;i<t;i++){let A=r[a*t+i];if(Math.abs(A)<1e-300)continue;let u=(r[i*t+i]-r[a*t+a])/(2*A),m=Math.sign(u||1)/(Math.abs(u)+Math.sqrt(u*u+1)),h=1/Math.sqrt(m*m+1),g=m*h;for(let y=0;y<t;y++){let f=r[y*t+a],d=r[y*t+i];r[y*t+a]=h*f-g*d,r[y*t+i]=g*f+h*d}for(let y=0;y<t;y++){let f=r[a*t+y],d=r[i*t+y];r[a*t+y]=h*f-g*d,r[i*t+y]=g*f+h*d}for(let y=0;y<t;y++){let f=n[y*t+a],d=n[y*t+i];n[y*t+a]=h*f-g*d,n[y*t+i]=g*f+h*d}}}let o=0;for(let c=1;c<t;c++)r[c*t+c]<r[o*t+o]&&(o=c);let l=new Float64Array(t);for(let c=0;c<t;c++)l[c]=n[c*t+o];return l}function Ft(e,t){let r=new Float64Array(9);for(let n=0;n<3;n++)for(let o=0;o<3;o++)r[n*3+o]=e[n*3]*t[o]+e[n*3+1]*t[3+o]+e[n*3+2]*t[6+o];return r}function vt(e){let[t,r,n,o,l,c,s,a,i]=[e[0],e[1],e[2],e[3],e[4],e[5],e[6],e[7],e[8]],A=[l*i-c*a,n*a-r*i,r*c-n*l,c*s-o*i,t*i-n*s,n*o-t*c,o*a-l*s,r*s-t*a,t*l-r*o],u=t*A[0]+r*A[3]+n*A[6];return!Number.isFinite(u)||Math.abs(u)<1e-300?null:Float64Array.from(A,m=>m/u)}function Vt(e){let t=e[8];if(!Number.isFinite(t)||Math.abs(t)<1e-12)return null;for(let r=0;r<9;r++)e[r]/=t;return e.every(Number.isFinite)?e:null}function wt(e,t,r){let n=0,o=0;for(let c=0;c<r;c++){let s=t[c];n+=e[2*s],o+=e[2*s+1]}n/=r,o/=r;let l=0;for(let c=0;c<r;c++){let s=t[c];l+=Math.hypot(e[2*s]-n,e[2*s+1]-o)}return l/=r,l<1e-9?null:[Math.SQRT2/l,n,o]}function Zt(e,t,r){let[n,o,l]=t,[c,s,a]=r,i=[n,0,-n*o,0,n,-n*l,0,0,1],A=[1/c,0,s,0,1/c,a,0,0,1];return Vt(Ft(Ft(A,e),i))}function Pt(e,t,r,n,o){if(n<4)return null;let l=wt(e,r,n),c=wt(t,r,n);if(!l||!c)return null;let s=new Float64Array(81),a=new Float64Array(9);for(let i=0;i<n;i++){let A=r[i],u=o?o[A]:1;if(u<=0)continue;let m=l[0]*(e[2*A]-l[1]),h=l[0]*(e[2*A+1]-l[2]),g=c[0]*(t[2*A]-c[1]),y=c[0]*(t[2*A+1]-c[2]);for(let f=0;f<2;f++){f===0?a.set([m,h,1,0,0,0,-g*m,-g*h,-g]):a.set([0,0,0,m,h,1,-y*m,-y*h,-y]);for(let d=0;d<9;d++){let p=a[d]*u;if(p!==0)for(let x=d;x<9;x++)s[d*9+x]+=p*a[x]}}}for(let i=0;i<9;i++)for(let A=0;A<i;A++)s[i*9+A]=s[A*9+i];return Zt(zt(s,9),l,c)}var It=new Float64Array(64),bt=new Float64Array(8);function st(e,t,r){let n=wt(e,r,4),o=wt(t,r,4);if(!n||!o)return null;It.fill(0);for(let l=0;l<4;l++){let c=r[l],s=n[0]*(e[2*c]-n[1]),a=n[0]*(e[2*c+1]-n[2]),i=o[0]*(t[2*c]-o[1]),A=o[0]*(t[2*c+1]-o[2]);It.set([s,a,1,0,0,0,-i*s,-i*a],16*l),It.set([0,0,0,s,a,1,-A*s,-A*a],16*l+8),bt[2*l]=i,bt[2*l+1]=A}return pt(It,bt,8)?Zt([...bt,1],n,o):null}function $t(e,t,r,n){let o=e[6]*t+e[7]*r+e[8];return o>1e-12?(n[0]=(e[0]*t+e[1]*r+e[2])/o,n[1]=(e[3]*t+e[4]*r+e[5])/o,!0):!1}var J=new Float64Array(8),Ut=new Float64Array(2);function it(e,t,r,n=64,o=30){let l=[0,t,t,0],c=[0,0,r,r];for(let A=0;A<4;A++){if(!$t(e,l[A],c[A],Ut))return!1;J[2*A]=Ut[0],J[2*A+1]=Ut[1]}let s=0,a=1/0,i=0;for(let A=0;A<4;A++){let u=J[2*A],m=J[2*A+1],h=J[(2*A+2)%8],g=J[(2*A+3)%8],y=J[(2*A+4)%8],f=J[(2*A+5)%8];if((h-u)*(f-g)-(g-m)*(y-h)<=0)return!1;s+=u*g-h*m;let d=Math.hypot(h-u,g-m);a=Math.min(a,d),i=Math.max(i,d)}return s/2>=n&&i<=o*Math.max(a,1e-9)}function Tt(e,t,r){let n=[];for(let i=0;i<r;i++)(!t||t[i])&&n.push([e[2*i],e[2*i+1]]);if(n.length<3)return 0;n.sort((i,A)=>i[0]-A[0]||i[1]-A[1]);let o=(i,A,u)=>(A[0]-i[0])*(u[1]-i[1])-(A[1]-i[1])*(u[0]-i[0]),l=[];for(let i of n){for(;l.length>=2&&o(l.at(-2),l.at(-1),i)<=0;)l.pop();l.push(i)}let c=[];for(let i=n.length-1;i>=0;i--){let A=n[i];for(;c.length>=2&&o(c.at(-2),c.at(-1),A)<=0;)c.pop();c.push(A)}let s=[...l.slice(0,-1),...c.slice(0,-1)],a=0;for(let i=0;i<s.length;i++){let A=s[i],u=s[(i+1)%s.length];a+=A[0]*u[1]-u[0]*A[1]}return Math.abs(a)/2}var ve=(e,t)=>e<=t?1:t/e;function Rt(e,t,r,n,o,l={}){let c=l.iterations??8,s=l.huberPx??1.5,a=Float64Array.from(e.subarray(0,8)),i=.001,A=new Float64Array(64),u=new Float64Array(8),m=new Float64Array(8),h=new Float64Array(8),g=b=>{let M=0;for(let I=0;I<o;I++){if(!n[I])continue;let w=t[2*I],Q=t[2*I+1],E=b[6]*w+b[7]*Q+1;if(!(E>1e-12))return 1/0;let B=(b[0]*w+b[1]*Q+b[2])/E-r[2*I],C=(b[3]*w+b[4]*Q+b[5])/E-r[2*I+1],P=Math.hypot(B,C);M+=P<=s?P*P:2*s*P-s*s}return M},y=g(a);for(let b=0;b<c;b++){A.fill(0),u.fill(0);for(let I=0;I<o;I++){if(!n[I])continue;let w=t[2*I],Q=t[2*I+1],E=a[6]*w+a[7]*Q+1,B=(a[0]*w+a[1]*Q+a[2])/E,C=(a[3]*w+a[4]*Q+a[5])/E,P=B-r[2*I],k=C-r[2*I+1],v=ve(Math.hypot(P,k),s);m.set([w/E,Q/E,1/E,0,0,0,-B*w/E,-B*Q/E]),h.set([0,0,0,w/E,Q/E,1/E,-C*w/E,-C*Q/E]);for(let T=0;T<8;T++){u[T]+=v*(m[T]*P+h[T]*k);for(let D=T;D<8;D++)A[T*8+D]+=v*(m[T]*m[D]+h[T]*h[D])}}for(let I=0;I<8;I++)for(let w=0;w<I;w++)A[I*8+w]=A[w*8+I];let M=!1;for(let I=0;I<4&&!M;I++){let w=new Float64Array(A);for(let C=0;C<8;C++)w[C*9]*=1+i;let Q=Float64Array.from(u,C=>-C);if(!pt(w,Q,8)){i*=10;continue}let E=Float64Array.from(a,(C,P)=>C+Q[P]),B=g(E);B<y?(a=E,y=B,i=Math.max(1e-7,i/10),M=!0):i*=10}if(!M)break}let f=0,d=0;A.fill(0);for(let b=0;b<o;b++){if(!n[b])continue;let M=t[2*b],I=t[2*b+1],w=a[6]*M+a[7]*I+1,Q=(a[0]*M+a[1]*I+a[2])/w,E=(a[3]*M+a[4]*I+a[5])/w;d+=(Q-r[2*b])**2+(E-r[2*b+1])**2,f++,m.set([M/w,I/w,1/w,0,0,0,-Q*M/w,-Q*I/w]),h.set([0,0,0,M/w,I/w,1/w,-E*M/w,-E*I/w]);for(let B=0;B<8;B++)for(let C=0;C<8;C++)A[B*8+C]+=m[B]*m[C]+h[B]*h[C]}let p=f>4?d/(2*f-8):d,x=Xt(A,8);return{H:Float64Array.from([...a,1]),rmsPx:f?Math.sqrt(d/f):1/0,paramCovariance:x?x.map(b=>b*p):null}}function Pe(e){let t=e>>>0||625341585;return()=>(t^=t<<13,t>>>=0,t^=t>>>17,t^=t<<5,t>>>=0,t)}function Gt(e,t,r,n,o,l){let c=0,s=0;for(let a=0;a<n;a++){let i=t[2*a],A=t[2*a+1],u=e[6]*i+e[7]*A+e[8],m=o;if(u>1e-12){let g=(e[0]*i+e[1]*A+e[2])/u-r[2*a],y=(e[3]*i+e[4]*A+e[5])/u-r[2*a+1];m=Math.min(o,g*g+y*y)}let h=m<o;l[a]=h?1:0,h&&s++,c+=m}return{score:c,inliers:s}}function Te(e,t){let r=0;for(let o=0;o<t;o++)e[o]&&r++;let n=new Int32Array(r);for(let o=0,l=0;o<t;o++)e[o]&&(n[l++]=o);return n}function xt(e,t,r,n){let o=(e[2*r]-e[2*t])*(e[2*n+1]-e[2*t+1])-(e[2*r+1]-e[2*t+1])*(e[2*n]-e[2*t]);return Math.abs(o)<.001*(1+Math.abs(e[2*t])+Math.abs(e[2*r]))}function kt(e,t,r,n,o,l={}){let c=l.thresholdPx??3,s=c*c,a=l.confidence??.995,i=l.maxIterations??500,A=l.minInliers??12,u=l.minInlierRatio??.2,m=l.minCoverage??.08;if(r<Math.max(4,A))return{accepted:!1,reason:"INSUFFICIENT_MATCHES",iterations:0};let h=Pe(l.seed??12345),g=new Uint8Array(r),y=new Uint8Array(r),f=null,d=1/0,p=0,x=i,b=4,M=i;for(let v=0;v<4;v++)M*=(b-v)/(r-v);let I=1,w=new Int32Array(4),Q=0,E=v=>{if(!v||!it(v,n,o))return;let{score:T,inliers:D}=Gt(v,e,t,r,s,g);if(T>=d)return;f=v,d=T,p=D,y.set(g);for(let O=0;O<3&&p>=8;O++){let N=Pt(e,t,Te(y,r),p);if(!N||!it(N,n,o))break;let W=Gt(N,e,t,r,s,g);if(W.score>=d)break;f=N,d=W.score,p=W.inliers,y.set(g)}let R=p/r,L=Math.log(1-a)/Math.log(Math.max(1e-12,1-R**4));x=Math.min(i,Math.max(16,Math.ceil(L)))};for(;Q<x;){if(Q++,Q>=I&&b<r){let W=M*(b+1)/(b+1-4);b++,I+=Math.ceil(W-M),M=W}let v=I>Q?b-1:b,T=0;I>Q&&(w[T++]=b-1);let D=0;for(;T<4&&D++<64;){let W=h()%v,S=!1;for(let U=0;U<T;U++)w[U]===W&&(S=!0);S||(w[T++]=W)}if(T<4)continue;let[R,L,O,N]=[w[0],w[1],w[2],w[3]];xt(e,R,L,O)||xt(e,R,L,N)||xt(e,R,O,N)||xt(e,L,O,N)||E(st(e,t,w))}if(!f||p<A)return{accepted:!1,reason:"NO_MODEL",iterations:Q};let B=f,C=Rt(B,e,t,y,r,{huberPx:c/2});for(let v=0;v<2;v++){if(!it(C.H,n,o))return{accepted:!1,reason:"IMPLAUSIBLE_MODEL",iterations:Q};B=C.H,p=Gt(B,e,t,r,s,y).inliers,v===0&&(C=Rt(B,e,t,y,r,{huberPx:c/2}))}let P=p/r;if(p<A||P<u)return{accepted:!1,reason:"LOW_INLIER_SUPPORT",iterations:Q};let k=Tt(e,y,r)/(n*o);return k<m?{accepted:!1,reason:"LOW_SPATIAL_COVERAGE",iterations:Q}:{accepted:!0,H:B,mask:y,inliers:p,ratio:P,rmsPx:C.rmsPx,coverage:k,paramCovariance:C.paramCovariance,iterations:Q}}var te=844385612;function Re(e,t,r){if(e.width===t&&e.height===r)return e;let n=new Uint8Array(t*r),o=e.width/t,l=e.height/r;for(let c=0;c<r;c++){let s=Math.min(e.height-1.001,Math.max(0,(c+.5)*l-.5)),a=Math.floor(s),i=s-a;for(let A=0;A<t;A++){let u=Math.min(e.width-1.001,Math.max(0,(A+.5)*o-.5)),m=Math.floor(u),h=u-m,g=a*e.stride+m,y=e.data,f=y[g]+h*(y[g+1]-y[g]),d=y[g+e.stride]+h*(y[g+e.stride+1]-y[g+e.stride]);n[c*t+A]=Math.round(f+i*(d-f))}}return{width:t,height:r,stride:t,data:n}}function Ge(e,t){let r=Math.max(e.width,e.height)/t;if(r<=1)return e;let n=Math.round(e.width/r),o=Math.round(e.height/r),l=new Uint8Array(n*o);for(let c=0;c<o;c++)for(let s=0;s<n;s++){let a=Math.floor(s*r),i=Math.max(a+1,Math.floor((s+1)*r)),A=Math.floor(c*r),u=Math.max(A+1,Math.floor((c+1)*r)),m=0;for(let h=A;h<u;h++)for(let g=a;g<i;g++)m+=e.data[h*e.stride+g];l[c*n+s]=Math.round(m/((i-a)*(u-A)))}return{width:n,height:o,stride:n,data:l}}async function ct(e,t,r={}){let n=Ge(t,r.templateMaxEdge??480),o=new TextEncoder().encode(e.info.id),l=e.points.length/2,c=e.descriptorPoint.length,s=10+o.length+8+8+8*l+l+4*c+32*c+4+n.width*n.height,a=new Uint8Array(s+32),i=new DataView(a.buffer),A=0;i.setUint32(A,te,!0),i.setUint16(A+4,2,!0),i.setUint16(A+6,dt,!0),A+=8,i.setUint16(A,o.length,!0),a.set(o,A+2),A+=2+o.length,i.setUint16(A,e.info.width,!0),i.setUint16(A+2,e.info.height,!0),i.setFloat32(A+4,e.info.physicalWidthMeters??NaN,!0),A+=8,i.setUint32(A,l,!0),i.setUint32(A+4,c,!0),A+=8;for(let m=0;m<2*l;m++,A+=4)i.setFloat32(A,e.points[m],!0);a.set(e.repeatability,A),A+=l;for(let m=0;m<c;m++,A+=4)i.setUint32(A,e.descriptorPoint[m],!0);a.set(e.descriptors,A),A+=32*c,i.setUint16(A,n.width,!0),i.setUint16(A+2,n.height,!0),A+=4;for(let m=0;m<n.height;m++)a.set(n.data.subarray(m*n.stride,m*n.stride+n.width),A+m*n.width);A+=n.width*n.height;let u=new Uint8Array(await crypto.subtle.digest("SHA-256",a.subarray(0,A)));return a.set(u,A),a}async function Z(e){let t=new DataView(e.buffer,e.byteOffset,e.byteLength),r=M=>{throw new Error(`Invalid target asset: ${M}`)};(e.length<64||t.getUint32(0,!0)!==te||t.getUint16(4,!0)!==2)&&r("header");let n=t.getUint16(6,!0)&255;n!==dt&&r(`descriptor pattern v${n}, this engine uses v${dt}; recompile the target`);let o=e.subarray(0,e.length-32);new Uint8Array(await crypto.subtle.digest("SHA-256",new Uint8Array(o))).every((M,I)=>M===e[e.length-32+I])||r("checksum");let c=8,s=t.getUint16(c,!0),a=new TextDecoder().decode(e.subarray(c+2,c+2+s));c+=2+s;let i=t.getUint16(c,!0),A=t.getUint16(c+2,!0),u=t.getFloat32(c+4,!0);c+=8;let m=t.getUint32(c,!0),h=t.getUint32(c+4,!0);c+=8;let g=new Float32Array(2*m);for(let M=0;M<2*m;M++,c+=4)g[M]=t.getFloat32(c,!0);let y=e.slice(c,c+m);c+=m;let f=new Uint32Array(h);for(let M=0;M<h;M++,c+=4)f[M]=t.getUint32(c,!0);let d=e.slice(c,c+32*h);c+=32*h;let p=t.getUint16(c,!0),x=t.getUint16(c+2,!0);c+=4;let b={width:p,height:x,stride:p,data:e.slice(c,c+p*x)};return{compiled:{info:{id:a,width:i,height:A,physicalWidthMeters:Number.isNaN(u)?null:u},points:g,repeatability:y,descriptors:d,descriptorPoint:f},template:Re(b,i,A)}}function Ot(e,t){let r=e.length/32,n=t.length/32,o=new Uint32Array(3*r),l=new Uint32Array(e.buffer,e.byteOffset,e.length/4),c=new Uint32Array(t.buffer,t.byteOffset,t.length/4);for(let s=0;s<r;s++){let a=257,i=257,A=4294967295,u=8*s;for(let m=0;m<n;m++){let h=8*m,g=0;for(let y=0;y<8;y++){let f=(l[u+y]^c[h+y])>>>0;f-=f>>>1&1431655765,f=(f&858993459)+(f>>>2&858993459),g+=(f+(f>>>4)&252645135)*16843009>>>24}g<a?(i=a,a=g,A=m):g<i&&(i=g)}o[3*s]=A,o[3*s+1]=a,o[3*s+2]=i}return o}function Dt(e,t,r){let n=e.length/32,o=t.length/32,l=new Uint32Array(3*n),c=new Uint32Array(e.buffer,e.byteOffset,e.length/4),s=new Uint32Array(t.buffer,t.byteOffset,t.length/4);for(let a=0;a<n;a++){let i=257,A=4294967295,u=257,m=4294967295,h=8*a;for(let g=0;g<o;g++){let y=8*g,f=0;for(let p=0;p<8;p++){let x=(c[h+p]^s[y+p])>>>0;x-=x>>>1&1431655765,x=(x&858993459)+(x>>>2&858993459),f+=(x+(x>>>4)&252645135)*16843009>>>24}let d=r[g];d===A?f<i&&(i=f,m=g):f<i?(u=i,i=f,A=d,m=g):f<u&&(u=f)}l[3*a]=m,l[3*a+1]=i,l[3*a+2]=u}return l}var Et=class e{constructor(t){F(this,"backend");F(this,"kernel");this.kernel=t,this.backend=t?"wasm-simd":"js"}static create(t={}){let r=t.allowWasm===!1?null:ut();if(!r)return new e(null);try{let n=new e(r);return n.selfTest()?n:new e(null)}catch{return new e(null)}}selfTest(){let t=19088743,r=A=>Uint8Array.from({length:A},()=>(t^=t<<13,t^=t>>>17,t^=t<<5,t&255)),n=r(1184),o=new Uint8Array(352);o.set(r(320)),o.set(n.subarray(160,192),320);let l=Ot(o,n),c=this.nearest2(o,n),s=Uint32Array.from({length:37},(A,u)=>u>>1),a=Dt(o,n,s),i=this.nearest2Grouped(o,n,s);return c.length===l.length&&c.every((A,u)=>A===l[u])&&i.length===a.length&&i.every((A,u)=>A===a[u])}nearest2(t,r){let n=this.kernel;if(!n)return Ot(t,r);let o=t.length/32,l=r.length/32;n.reset_heap();let c=n.reserve(t.length),s=n.reserve(r.length),a=n.reserve(12*o);return!c||!s||!a?Ot(t,r):(new Uint8Array(n.memory.buffer).set(t,c),new Uint8Array(n.memory.buffer).set(r,s),n.nearest2(c,o,s,l,a),new Uint32Array(n.memory.buffer.slice(a,a+12*o)))}nearest2Grouped(t,r,n){let o=this.kernel;if(!o)return Dt(t,r,n);let l=t.length/32;o.reset_heap();let c=o.reserve(t.length),s=o.reserve(r.length),a=o.reserve(n.byteLength),i=o.reserve(12*l);if(!c||!s||!a||!i)return Dt(t,r,n);let A=o.memory.buffer;return new Uint8Array(A).set(t,c),new Uint8Array(A).set(r,s),new Uint8Array(A).set(new Uint8Array(n.buffer,n.byteOffset,n.byteLength),a),o.nearest2_grouped(c,l,s,a,r.length/32,i),new Uint32Array(o.memory.buffer.slice(i,i+12*l))}};var ke=e=>Math.max(700,Math.round(700*e.width*e.height/(640*360))),Oe=36e4;function De(e,t,r,n){let o=Math.min(r,3,Math.sqrt(Oe/(t.width*t.height)));if(o<1.2)return null;let l=Math.round(t.width*o),c=Math.round(t.height*o),s=new Uint8Array(l*c),a=e.width-1.001,i=e.height-1.001;for(let u=0;u<c;u++){let m=Math.min(i,Math.max(.5,t.y+(u+.5)/o));for(let h=0;h<l;h++)s[u*l+h]=Math.round(tt(e,Math.min(a,Math.max(.5,t.x+(h+.5)/o)),m))}let A=rt({width:l,height:c,stride:l,data:s},{budget:500,...n});return{...A,x:A.x.map(u=>t.x+(u+.5)/o-.5),y:A.y.map(u=>t.y+(u+.5)/o-.5)}}var lt=class{constructor(t={}){F(this,"info",{id:"C1.orb-views",layer:"L2",route:"light",determinism:"bit-exact",requires:[]});F(this,"options");F(this,"matcher");F(this,"targets",[]);this.options=t,this.matcher=Et.create(t.allowWasm===!1?{allowWasm:!1}:{})}get backend(){return this.matcher.backend}probe(t){return{isAvailable:!0}}async load(t){let r=[];this.targets=[];for(let n of t){let o=performance.now(),l=nt(n,this.options.compile),c=await ct(l,n.image,{templateMaxEdge:this.options.templateMaxEdge??480}),s=await Z(c);this.targets.push(s.compiled),r.push({id:n.info.id,compileUs:(performance.now()-o)*1e3,serialized:c,template:s.template})}return{targets:r}}async loadEncoded(t){let r=[];this.targets=[];for(let n of t){let o=performance.now(),l=await Z(n);this.targets.push(l.compiled),r.push({id:l.compiled.info.id,compileUs:(performance.now()-o)*1e3,serialized:n,template:l.template,info:l.compiled.info})}return{targets:r}}async detect(t,r={}){if(t.image.kind!=="cpu-gray")throw new Error("OrbDetector needs cpu-gray frames");let n=r.roi??null,o=(n&&(r.upscale??1)>1?De(t.image.image,n,r.upscale,this.options.orb??{}):null)??rt(t.image.image,{budget:n?500:ke(t.image.image),...this.options.orb,roi:n});if(o.count<8)return[];let l=this.options.ratio??.85,c=this.options.maxDistance??80,s=[];for(let a of this.targets){let i=this.matcher.nearest2Grouped(o.descriptors,a.descriptors,a.descriptorPoint),A=new Map;for(let y=0;y<o.count;y++){let f=i[3*y+1],d=i[3*y+2];if(f>c||l<1&&f>=l*d)continue;let p=a.descriptorPoint[i[3*y]],x=f/Math.max(1,d),b=A.get(p);(!b||x<b.r)&&A.set(p,{q:y,r:x})}let u=[...A].sort((y,f)=>y[1].r-f[1].r||y[0]-f[0]);if(u.length<12)continue;let m=new Float64Array(2*u.length),h=new Float64Array(2*u.length);u.forEach(([y,{q:f}],d)=>{m[2*d]=a.points[2*y],m[2*d+1]=a.points[2*y+1],h[2*d]=o.x[f],h[2*d+1]=o.y[f]});let g=kt(m,h,u.length,a.info.width,a.info.height,{thresholdPx:this.options.thresholdPx??4,maxIterations:1e3,minInliers:12,minInlierRatio:.1,minCoverage:.05});g.accepted&&s.push({inliers:g.inliers,pose:{targetId:a.info.id,frameId:t.frameId,timeUs:t.time.captureUs,H_imageFromTarget:g.H,corners:at(g.H,a.info.width,a.info.height),covariance:null,quality:{support:g.inliers,ratio:g.ratio,residual:g.rmsPx,residualKind:"px",coverage:g.coverage},origin:"detector"}})}return s.sort((a,i)=>i.inliers-a.inliers||a.pose.targetId.localeCompare(i.pose.targetId)),s.length>1&&s[1].inliers>=.85*s[0].inliers?[]:s.map(a=>a.pose)}};var Se=48,Le=64,z=class extends Error{constructor(r,n,o){super(n,o);F(this,"code");this.name="PictureError",this.code=r}};function Ne(e,t,r){let n=Math.min(1,r/Math.max(e,t));return[Math.max(1,Math.round(e*n)),Math.max(1,Math.round(t*n))]}function He(e,t,r){let n=new Uint8Array(t*r);for(let o=0;o<n.length;o++)n[o]=77*e[4*o]+150*e[4*o+1]+29*e[4*o+2]+128>>8;return n}function ee(){try{return typeof OffscreenCanvas=="function"&&!!new OffscreenCanvas(1,1).getContext("2d")}catch{return!1}}async function re(e,t){let r;try{r=await createImageBitmap(e,{imageOrientation:"from-image"})}catch{try{r=await createImageBitmap(e)}catch(n){throw new z("DECODE_FAILED",`The picture cannot be decoded: ${String(n)}`,{cause:n})}}try{let[n,o]=Ne(r.width,r.height,t),l=r,c=r.width,s=r.height;for(;c>2*n&&s>2*o;){let u=new OffscreenCanvas(Math.ceil(c/2),Math.ceil(s/2)),m=u.getContext("2d");m.imageSmoothingQuality="high",m.drawImage(l,0,0,u.width,u.height),l=u,c=u.width,s=u.height}let i=new OffscreenCanvas(n,o).getContext("2d",{willReadFrequently:!0});i.imageSmoothingQuality="high",i.drawImage(l,0,0,n,o);let A=i.getImageData(0,0,n,o).data;return{width:n,height:o,stride:n,data:He(A,n,o)}}finally{r.close()}}async function ne(e,t){if(Math.min(t.width,t.height)<Le)throw new z("UNSUITABLE_TARGET",`The picture is too small (${t.width}×${t.height} px)`);let r=nt({info:{id:e,width:t.width,height:t.height,physicalWidthMeters:null},image:t}),n=r.points.length/2;if(n<Se)throw new z("UNSUITABLE_TARGET",`The picture has too little detail (${n} recognition points)`);return{bytes:await ct(r,t),pointCount:n}}var We=5,Ke=24,qe=.08,Mt={detail:.15,spread:.4,distinctiveness:.05,recognition:.4},Ye=[.1,.7],_e=[15,95],Je=.4,At={size:.08,tilt:.15,blur:.33,dim:.6,covered:.6},j=(e,t,r)=>e<=t?0:e>=r?1:(e-t)/(r-t),q=640,mt=360,St=500,Lt=118,je=[...[160,120,90,70].map(e=>({name:`size-${e}`,test:"size",longPx:e})),...[45,60,70].map(e=>({name:`tilt-${e}`,test:"tilt",longPx:240,tiltDeg:e})),...[6,10,16].map(e=>({name:`blur-${e}`,test:"blur",longPx:240,blurPx:e})),...[.35,.2].map(e=>({name:`dim-${e}`,test:"dim",longPx:240,gain:e})),...[[0],[1],[2],[3],[0,2],[1,3],[0,1],[2,3]].map(e=>({name:`covered-${e.join("")}`,test:"covered",longPx:240,covered:e}))].flatMap(e=>[{...e,rollDeg:8,offset:[24,12]},{...e,rollDeg:-12,offset:[-30,-8]}]),oe=[12,40],Nt={size:.25,tilt:.2,blur:.2,dim:.15,covered:.2};function Xe(e,t,r){let n=e.longPx/Math.max(t,r),o=t*n,l=r*n,c=q/2+e.offset[0],s=mt/2+e.offset[1],a=[[c-o/2,s-l/2],[c+o/2,s-l/2],[c+o/2,s+l/2],[c-o/2,s+l/2]];if(e.tiltDeg){let m=e.tiltDeg*Math.PI/180;a=a.map(([h,g])=>{let y=St+(g-s)*Math.sin(m);return[c+(h-c)*St/y,s+(g-s)*Math.cos(m)*St/y]})}let i=e.rollDeg*Math.PI/180;a=a.map(([m,h])=>[c+(m-c)*Math.cos(i)-(h-s)*Math.sin(i),s+(m-c)*Math.sin(i)+(h-s)*Math.cos(i)]);let A=Float64Array.from([0,0,t,0,t,r,0,r]),u=Float64Array.from(a.flat());return st(A,u,[0,1,2,3])}function ze(e,t,r){let n=e.levels[0],o=t.longPx/Math.max(n.width,n.height),l=Math.max(0,Math.min(e.levels.length-1,Math.floor(Math.log2(1/o)))),c=e.levels[l],s=2**l,a=vt(r),i=new Uint8Array(q*mt),A=12345,u=n.width/2,m=n.height/2;for(let h=0;h<mt;h++)for(let g=0;g<q;g++){A=A*1103515245+12345>>>0;let y=Lt+(A>>>16)%9-4,f=g+.5,d=h+.5,p=a[6]*f+a[7]*d+a[8],x=(a[0]*f+a[1]*d+a[2])/p,b=(a[3]*f+a[4]*d+a[5])/p;if(x>=0&&b>=0&&x<n.width&&b<n.height){let M=(b<m?0:2)+(x<u?0:1);if(!t.covered?.includes(M)){let I=tt(c,Math.min(c.width-.51,Math.max(.5,x/s)),Math.min(c.height-.51,Math.max(.5,b/s)));Number.isNaN(I)||(y=I)}}t.gain!==void 0&&(A=A*1103515245+12345>>>0,y=Lt+(y-Lt)*t.gain+(A>>>16)%13-6),i[h*q+g]=Math.max(0,Math.min(255,Math.round(y)))}if(t.blurPx){let h=Math.floor(t.blurPx/2),g=new Float64Array(q+1);for(let y=0;y<mt;y++){for(let f=0;f<q;f++)g[f+1]=g[f]+i[y*q+f];for(let f=0;f<q;f++){let d=Math.max(0,f-h),p=Math.min(q,f-h+t.blurPx);i[y*q+f]=Math.round((g[p]-g[d])/(p-d))}}}return{width:q,height:mt,stride:q,data:i}}async function ae(e){let t=await Z(e),{compiled:r,template:n}=t,{width:o,height:l}=r.info,c=r.points.length/2,s=[];for(let U=0;U<c;U++)r.repeatability[U]>=We&&s.push(U);let a=new Float32Array(2*s.length);s.forEach((U,G)=>{a[2*G]=r.points[2*U],a[2*G+1]=r.points[2*U+1]});let i=j(s.length,40,250),A=o/l,u=Math.max(2,Math.round(4*Math.sqrt(A))),m=Math.max(2,Math.round(4/Math.sqrt(A))),h=new Array(u*m).fill(0),g=[0,0,0,0];for(let U=0;U<s.length;U++){let G=a[2*U],K=a[2*U+1];h[Math.min(m-1,Math.floor(K/l*m))*u+Math.min(u-1,Math.floor(G/o*u))]++,g[(K<l/2?0:2)+(G<o/2?0:1)]++}let y=Math.max(1,s.length),f=u*m,d=h.filter(U=>U>=Math.max(3,.3*y/f)).length,p=h.reduce((U,G)=>U+(G/y)**2,0),x=s.length?1/p/f:0,b=g.indexOf(Math.min(...g)),M=g[b]/y,I=(.5*j(d/f,.3,.85)+.5*j(x,.25,.65))*(.6+.4*j(M,.03,.15)),w=new Uint32Array(r.descriptors.buffer,r.descriptors.byteOffset,r.descriptors.length/4),Q=Array.from({length:c},()=>[]);r.descriptorPoint.forEach((U,G)=>Q[U].push(G));let E=(qe*Math.hypot(o,l))**2,B=(U,G)=>{let K=0;for(let H=0;H<8;H++){let Y=(w[8*U+H]^w[8*G+H])>>>0;Y-=Y>>>1&1431655765,Y=(Y&858993459)+(Y>>>2&858993459),K+=(Y+(Y>>>4)&252645135)*16843009>>>24}return K},C=U=>{let G=r.points[2*U],K=r.points[2*U+1];for(let H=0;H<c;H++)if(!((r.points[2*H]-G)**2+(r.points[2*H+1]-K)**2<E)){for(let Y of Q[U])for(let $ of Q[H])if(B(Y,$)<=Ke)return!0}return!1},P=s.length?s.filter(U=>!C(U)).length/s.length:0,k=j(P,.35,.7),v=new lt;await v.loadEncoded([e]);let T=Ct(n,6,16),D=[];for(let[U,G]of je.entries()){let K=Xe(G,o,l),H=at(K,o,l),$=(await v.detect({sessionId:"rate",frameId:U+1,time:{captureUs:U,receiveUs:U,source:"replay"},image:{kind:"cpu-gray",image:ze(T,G,K)}})).find(ie=>ie.corners.reduce((ce,Ht,Wt)=>ce+Math.hypot(Ht[0]-H[Wt][0],Ht[1]-H[Wt][1]),0)/4<.08*G.longPx);D.push({name:G.name,test:G.test,found:!!$,margin:$?j($.quality.support,oe[0],oe[1]):0})}let R=Object.fromEntries(Object.keys(Nt).map(U=>{let G=D.filter(K=>K.test===U);return[U,G.reduce((K,H)=>K+H.margin,0)/G.length]})),L=j(Object.keys(Nt).reduce((U,G)=>U+Nt[G]*R[G],0),...Ye),O=100*(Mt.detail*i+Mt.spread*I+Mt.distinctiveness*k+Mt.recognition*L),N=Math.min(.5+4.5*j(O,..._e),1+4*Math.min(I,L)**Je),W=Math.min(5,Math.max(.5,Math.round(N*2)/2)),S=[];return L<.4&&S.push("HARD_TO_FIND"),I<.6&&(d/f<.6||x<.45)&&S.push("CONCENTRATED"),M<.08&&S.push("WEAK_QUARTER"),i<.5&&S.push("FEW_DETAILS"),k<.4&&S.push("REPETITIVE"),R.size<At.size&&S.push("FAILS_SMALL"),R.tilt<At.tilt&&S.push("FAILS_TILTED"),R.blur<At.blur&&S.push("FAILS_BLURRED"),R.dim<At.dim&&S.push("FAILS_DIM"),R.covered<At.covered&&S.push("FAILS_COVERED"),{stars:W,score:Math.round(20*N),factors:{detail:i,spread:I,distinctiveness:k,recognition:L},metrics:{robustPoints:s.length,grid:{columns:u,rows:m,counts:h},populatedCells:d,evenness:x,weakestQuarter:{index:b,share:M},distinctShare:P,tests:R,views:D},advice:S,points:a,width:o,height:l}}var Bt=class extends Error{constructor(r,n){super(n);F(this,"code");this.code=r}};async function Ve(e){if(e.bytes)return new Uint8Array(e.bytes);let t;if(e.gray)t={width:e.gray.width,height:e.gray.height,stride:e.gray.width,data:new Uint8Array(e.gray.data)};else if(ee())t=await re(e.image,e.maxEdgePx);else return null;return(await ne("rated",t)).bytes}function se(e){let t=Promise.resolve();e.addEventListener("message",r=>{let n=r.data;n.type==="rate"&&(t=t.then(async()=>{try{let o=await Ve(n);if(!o){e.postMessage({type:"need-gray",id:n.id});return}let l;try{l=await ae(o)}catch(c){throw n.bytes?new Bt("INVALID_TARGET",c instanceof Error?c.message:String(c)):c}e.postMessage({type:"rated",id:n.id,rating:l},[l.points.buffer])}catch(o){e.postMessage({type:"failed",id:n.id,code:o instanceof z||o instanceof Bt?o.code:"WORKER_FAILED",message:o instanceof Error?o.message:String(o)})}}))})}se(globalThis);})();\n'],{type:"text/javascript"})),d)}var l=class{constructor(t){o(this,"worker",null);o(this,"queue",[]);o(this,"current",null);o(this,"nextId",1);o(this,"idleTimer",null);o(this,"workerUrl");this.workerUrl=t}run(t,e){return new Promise((r,i)=>{if(e?.aborted)return i(new a("ABORTED","Rating aborted"));let s={id:this.nextId++,request:t,resolve:r,reject:i};e?.addEventListener("abort",()=>{let u=this.queue.indexOf(s);u>=0&&this.queue.splice(u,1),this.current===s&&(this.current=null,this.pump()),i(new a("ABORTED","Rating aborted"))},{once:!0}),this.queue.push(s),this.pump()})}pump(){if(this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=null),this.current)return;let t=this.queue.shift();if(!t){this.idleTimer=setTimeout(()=>this.close(),b);return}try{this.worker??=this.spawn()}catch(e){for(let r of[t,...this.queue.splice(0)])r.reject(e instanceof a?e:new a("WORKER_FAILED",String(e)));return}this.current=t,this.worker.postMessage({...t.request,id:t.id})}spawn(){let t;try{t=new Worker(this.workerUrl??T(),{name:"LiveMira rating"})}catch(e){throw e instanceof a?e:new a("WORKER_FAILED","Cannot start the rating Worker (a CSP may forbid blob: Workers)",{cause:e})}return t.onmessage=e=>{this.answer(e.data)},t.onerror=e=>{e.preventDefault(),t.terminate(),this.worker===t&&(this.worker=null);let r=this.current;this.current=null,r?.reject(new a("WORKER_FAILED",`The rating Worker failed: ${e.message}`)),this.pump()},t}async answer(t){let e=this.current;if(!(!e||e.id!==t.id)){if(t.type==="need-gray"){try{let r=await h(e.request.image,e.request.maxEdgePx);if(this.current!==e)return;this.worker.postMessage({...e.request,id:e.id,image:null,gray:r},[r.data])}catch(r){this.current=null,e.reject(r instanceof c?new a(r.code,r.message,{cause:r.cause}):new a("DECODE_FAILED",String(r))),this.pump()}return}this.current=null,t.type==="rated"?e.resolve(Object.freeze(t.rating)):e.reject(new a(t.code,t.message)),this.pump()}}close(){this.idleTimer=null,this.worker?.terminate(),this.worker=null}},m=new Map,p=n=>{let t=n?String(n):"",e=m.get(t);return e||m.set(t,e=new l(n)),e};function A(n,t={}){if(!(typeof Blob<"u"&&n instanceof Blob))return Promise.reject(new a("INVALID_INPUT","rateTargetImage needs a Blob or File"));let e=t.maxEdgePx??640;return!Number.isInteger(e)||e<64||e>2048?Promise.reject(new a("INVALID_INPUT","maxEdgePx must be an integer 64..2048")):n.size===0?Promise.reject(new a("DECODE_FAILED","The picture file is empty")):p(t.workerUrl).run({type:"rate",maxEdgePx:e,image:n,gray:null,bytes:null},t.signal)}function x(n,t={}){let e=n instanceof Uint8Array?n:n?.bytes;return e instanceof Uint8Array?p(t.workerUrl).run({type:"rate",maxEdgePx:640,image:null,gray:null,bytes:e.slice().buffer},t.signal):Promise.reject(new a("INVALID_INPUT","rateTarget needs a target bundle or its bytes"))}export{g as RATING_VERSION,a as RatingError,x as rateTarget,A as rateTargetImage,y as ratingBuildInfo};
package/package.json CHANGED
@@ -1,6 +1,42 @@
1
1
  {
2
2
  "name": "@livemira/target-rating",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.5.1",
4
+ "license": "Apache-2.0",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/andy-mira/livemira.git"
10
+ },
11
+ "homepage": "https://github.com/andy-mira/livemira#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/andy-mira/livemira/issues"
14
+ },
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "description": "LiveMira target rating: how well the LiveMira engine will find and keep a picture, in stars, without the engine.",
19
+ "keywords": [
20
+ "webar",
21
+ "image-tracking",
22
+ "target-rating",
23
+ "livemira"
24
+ ],
25
+ "main": "./dist/livemira-target-rating.min.mjs",
26
+ "types": "./dist/livemira-target-rating.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/livemira-target-rating.d.ts",
30
+ "default": "./dist/livemira-target-rating.min.mjs"
31
+ },
32
+ "./worker": "./dist/livemira-target-rating-worker.min.js"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md",
37
+ "README.zh-CN.md",
38
+ "CHANGELOG.md",
39
+ "LICENSE",
40
+ "NOTICE"
41
+ ]
42
+ }