|
1 | 1 | # FeatureSET-Display |
2 | 2 |
|
3 | | -A little javascript lib for display .iset and .fset .fset3 files |
| 3 | +> Display the contents of NFT marker files (`.iset`, `.fset`, `.fset3`) — the |
| 4 | +> image preview plus the feature points used for detection and tracking — in |
| 5 | +> a browser, via WebAssembly. |
4 | 6 |
|
5 | | -## Introduction of the project |
| 7 | +Useful for inspecting markers generated with |
| 8 | +[NFT-Marker-Creator](https://github.com/Carnaux/NFT-Marker-Creator) or [Nft-Marker-Creator-App](https://github.com/webarkit/Nft-Marker-Creator-App) : |
| 9 | +see at a glance whether a marker has enough trackable features, whether |
| 10 | +they're clustered in a corner, or whether the source image lost |
| 11 | +contrast during the dataset build. |
6 | 12 |
|
7 | | -With this little library it is possible to display NFT markers (.fset .iset and .fset3) files, generated with [NFT-Marker-Creator](https://github.com/.Carnaux/NFT-Marker-Creator). For now it may show you the image set from .iset file and the feature points from .fset and .fset3 files. Very useful utility to understand the stength and key points of the NFT marker. |
| 13 | +--- |
8 | 14 |
|
9 | | -### List of working features |
10 | | -- Display of the first the ImageSet. |
11 | | -- Display the features points used in identifying and features points used in continuous tracking. |
| 15 | +## What you get |
12 | 16 |
|
13 | | -Display of various imageSet and FeatureSet infos in the console: |
| 17 | +For any marker triplet (`name.iset` + `name.fset` + `name.fset3`), |
| 18 | +the library: |
14 | 19 |
|
15 | | -- NFT number of ImageSet |
16 | | -- NFT dpi |
17 | | -- NFT marker width |
18 | | -- NFT marker height |
19 | | -- NFT number of Feature sets |
20 | | -- NFT number of feature points |
| 20 | +- Reads the imageSet preview into an HTML5 canvas. |
| 21 | +- Overlays the detection feature points as **light green** circles. |
| 22 | +- Overlays the tracking feature points as **small red** circles. |
| 23 | +- Logs the marker dimensions, DPI, and feature-point counts to the |
| 24 | + browser console. |
21 | 25 |
|
22 | | -### List of features to add |
| 26 | +## Install |
23 | 27 |
|
24 | | -- display the ImageSet (the entire array of images as a choice) |
| 28 | +```bash |
| 29 | +npm install @webarkit/featureset-display |
| 30 | +``` |
25 | 31 |
|
26 | | -### Example |
| 32 | +Or load the UMD bundle directly: |
27 | 33 |
|
28 | | -An example is included in the **example** folder. Run a http server (python or node) and open the **example.html** file. |
| 34 | +```html |
| 35 | +<script src="https://unpkg.com/@webarkit/featureset-display"></script> |
| 36 | +``` |
| 37 | + |
| 38 | +## Quick start (ES module) |
| 39 | + |
| 40 | +```html |
| 41 | +<script type="module"> |
| 42 | + import ARFsetModule from '@webarkit/featureset-display'; |
| 43 | +
|
| 44 | + const ar = new ARFsetModule.ARFset(); |
| 45 | + await ar.initialize(); |
| 46 | + await ar.loadNFTMarker('path/to/marker'); // no extension |
| 47 | + ar.display(); |
| 48 | +</script> |
| 49 | +``` |
| 50 | + |
| 51 | +The library will create a `<canvas id="iSet">` element in the document |
| 52 | +body and render the marker preview into it. Use `attachCanvas(id)` |
| 53 | +before `initialize()` to mount it inside a specific container instead: |
| 54 | + |
| 55 | +```js |
| 56 | +const ar = new ARFsetModule.ARFset(); |
| 57 | +ar.attachCanvas('my-container'); |
| 58 | +await ar.initialize(); |
| 59 | +await ar.loadNFTMarker('path/to/marker'); |
| 60 | +ar.display(); |
| 61 | +``` |
| 62 | + |
| 63 | +## Quick start (`<script>` tag) |
| 64 | + |
| 65 | +```html |
| 66 | +<script src="dist/ARFset.umd.js"></script> |
| 67 | +<script> |
| 68 | + const ar = new ARFset.ARFset(); |
| 69 | + ar.initialize().then(() => { |
| 70 | + ar.loadNFTMarker('path/to/marker'); |
| 71 | + ar.display(); |
| 72 | + }); |
| 73 | +</script> |
| 74 | +``` |
| 75 | + |
| 76 | +`window.ARFset` resolves to the same default export as the ESM build. |
| 77 | + |
| 78 | +## API |
| 79 | + |
| 80 | +### `new ARFset(options?)` |
| 81 | + |
| 82 | +| Option | Type | Default | Description | |
| 83 | +| -------- | ------ | ------- | --------------------------- | |
| 84 | +| `width` | number | `893` | Initial wasm canvas width. | |
| 85 | +| `height` | number | `1117` | Initial wasm canvas height. | |
| 86 | + |
| 87 | +These set the wasm-side initial memory layout. The on-screen canvas is |
| 88 | +resized at marker-load time to the actual reported marker dimensions, |
| 89 | +so the defaults don't need to match your marker. |
| 90 | + |
| 91 | +### `await ar.initialize()` |
| 92 | + |
| 93 | +Loads the WebAssembly runtime and prepares the canvas. Must be awaited |
| 94 | +before anything else. |
| 95 | + |
| 96 | +### `ar.attachCanvas(id)` |
| 97 | + |
| 98 | +Mount the canvas inside an existing DOM element instead of `body`. |
| 99 | +Call before `initialize()`. |
| 100 | + |
| 101 | +### `await ar.loadNFTMarker(urlPrefix)` |
| 102 | + |
| 103 | +Fetches `urlPrefix.iset`, `urlPrefix.fset`, and `urlPrefix.fset3`, |
| 104 | +loads them into the wasm filesystem, and dispatches an `'nftMarker'` |
| 105 | +`CustomEvent` on `document` when ready. |
| 106 | + |
| 107 | +### `await ar.loadNFTMarkerBlob([isetUrl, fset3Url, fsetUrl])` |
| 108 | + |
| 109 | +Same as above but for user-uploaded data — pass an array of three |
| 110 | +URLs (or data URLs from `FileReader.readAsDataURL`) in the order |
| 111 | +`[iset, fset3, fset]`. |
| 112 | + |
| 113 | +### `ar.display()` |
| 114 | + |
| 115 | +Subscribe to the `'nftMarker'` event and render the marker preview |
| 116 | +plus feature-point circles whenever a marker loads. |
| 117 | + |
| 118 | +### Events dispatched on `document` |
| 119 | + |
| 120 | +| Event | Detail | |
| 121 | +| ----------- | ------------------------------------------------------------------- | |
| 122 | +| `nftMarker` | `{ numIset, widthNFT, heightNFT, dpi, numFpoints, nftPoints, ... }` | |
| 123 | +| `imageEv` | (no detail) — fired after the canvas has been painted | |
| 124 | + |
| 125 | +## How it works |
| 126 | + |
| 127 | +```mermaid |
| 128 | +flowchart LR |
| 129 | + user[User code] -->|loadNFTMarker URL| js[ARFset class JS] |
| 130 | + js -->|fetch .iset .fset .fset3| net[network] |
| 131 | + net -->|Uint8Array| fs[wasm FS] |
| 132 | + js -->|_readNFTMarker arId path| wasm[ARimageFsetDisplay wasm] |
| 133 | + wasm -->|reads| fs |
| 134 | + wasm -->|nftMarker struct + nftPoints + nftFsetPoints| js |
| 135 | + js -->|nftMarker event| display[display handler] |
| 136 | + display -->|putImageData + arc| canvas[canvas iSet] |
| 137 | +``` |
| 138 | + |
| 139 | +The C++ side ([`emscripten/ARimageFsetDisplay.cpp`](emscripten/ARimageFsetDisplay.cpp)) |
| 140 | +links against [WebARKitLib](https://github.com/webarkit/WebARKitLib) |
| 141 | +(a maintained fork of jsartoolkit5 / ARToolKit5) to parse the |
| 142 | +`.iset` / `.fset` / `.fset3` files and extract feature points. The |
| 143 | +result is returned through an embind `value_object`, so JS reads the |
| 144 | +data directly from the returned struct — no `EM_ASM` side-channel. |
| 145 | + |
| 146 | +## Build from source |
| 147 | + |
| 148 | +Prerequisites: |
| 149 | + |
| 150 | +- Node.js 22+ |
| 151 | +- [emsdk](https://emscripten.org/docs/getting_started/downloads.html) |
| 152 | + with `EMSDK` set (run `emsdk_env.bat` / `source emsdk_env.sh` once |
| 153 | + per shell). |
| 154 | +- Python 3 on `PATH` (needed by `emcc.py` on Windows). |
| 155 | +- Git submodules initialised: |
| 156 | + |
| 157 | + ```bash |
| 158 | + git submodule update --init --recursive |
| 159 | + ``` |
| 160 | + |
| 161 | +Then: |
| 162 | + |
| 163 | +```bash |
| 164 | +npm install # devDependencies (vite, vitest, playwright) |
| 165 | +npm run build # wasm bundles -> build/ |
| 166 | +npm run build-es6 # JS bundle -> dist/ |
| 167 | +npm test # unit tests (Vitest) |
| 168 | +npm run test:e2e # browser smoke test (Playwright) |
| 169 | +``` |
| 170 | + |
| 171 | +To try the example locally: |
| 172 | + |
| 173 | +```bash |
| 174 | +npm run serve |
| 175 | +# open http://localhost:8080/example/example_es6.html |
| 176 | +``` |
| 177 | + |
| 178 | +## Migration from 0.3.x |
| 179 | + |
| 180 | +`0.4.0` removed the legacy global `window.ARfset` API and the asm.js |
| 181 | +build targets. |
| 182 | + |
| 183 | +**Before (0.3.x):** |
| 184 | + |
| 185 | +```html |
| 186 | +<script src="build/arfset.min.js"></script> |
| 187 | +<script> |
| 188 | + const ar = new ARfset(); |
| 189 | + ar.loadNFTMarker('marker', (nft) => { ... }); |
| 190 | +</script> |
| 191 | +``` |
| 192 | + |
| 193 | +**After (0.4.x), ESM:** |
| 194 | + |
| 195 | +```html |
| 196 | +<script type="module"> |
| 197 | + import ARFsetModule from '@webarkit/featureset-display'; |
| 198 | + const ar = new ARFsetModule.ARFset(); |
| 199 | + await ar.initialize(); |
| 200 | + await ar.loadNFTMarker('marker'); |
| 201 | + ar.display(); |
| 202 | +</script> |
| 203 | +``` |
| 204 | + |
| 205 | +**After (0.4.x), classic script:** |
| 206 | + |
| 207 | +```html |
| 208 | +<script src="dist/ARFset.umd.js"></script> |
| 209 | +<script> |
| 210 | + const ar = new ARFset.ARFset(); |
| 211 | + ar.initialize().then(() => { |
| 212 | + ar.loadNFTMarker('marker'); |
| 213 | + ar.display(); |
| 214 | + }); |
| 215 | +</script> |
| 216 | +``` |
| 217 | + |
| 218 | +Note the new namespace: `window.ARFset` exposes `{ ARFset: class }`, |
| 219 | +so the class is reached as `ARFset.ARFset`. The class also requires |
| 220 | +an `initialize()` await before `loadNFTMarker`, where the legacy |
| 221 | +global used to dispatch a `FeatureSETDisplay-loaded` event instead. |
| 222 | + |
| 223 | +## License |
| 224 | + |
| 225 | +LGPL-3.0 — see [LICENSE.txt](LICENSE.txt). |
0 commit comments