@srsergio/taptapp-ar 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/README.md +62 -0
  2. package/dist/compiler/aframe.d.ts +1 -0
  3. package/dist/compiler/aframe.js +275 -0
  4. package/dist/compiler/compiler-base.d.ts +12 -0
  5. package/dist/compiler/compiler-base.js +165 -0
  6. package/dist/compiler/compiler.d.ts +9 -0
  7. package/dist/compiler/compiler.js +24 -0
  8. package/dist/compiler/compiler.worker.d.ts +1 -0
  9. package/dist/compiler/compiler.worker.js +28 -0
  10. package/dist/compiler/controller.d.ts +101 -0
  11. package/dist/compiler/controller.js +400 -0
  12. package/dist/compiler/controller.worker.d.ts +1 -0
  13. package/dist/compiler/controller.worker.js +61 -0
  14. package/dist/compiler/detector/crop-detector.d.ts +65 -0
  15. package/dist/compiler/detector/crop-detector.js +59 -0
  16. package/dist/compiler/detector/detector.d.ts +98 -0
  17. package/dist/compiler/detector/detector.js +1049 -0
  18. package/dist/compiler/detector/freak.d.ts +1 -0
  19. package/dist/compiler/detector/freak.js +89 -0
  20. package/dist/compiler/detector/kernels/cpu/binomialFilter.d.ts +6 -0
  21. package/dist/compiler/detector/kernels/cpu/binomialFilter.js +51 -0
  22. package/dist/compiler/detector/kernels/cpu/buildExtremas.d.ts +6 -0
  23. package/dist/compiler/detector/kernels/cpu/buildExtremas.js +89 -0
  24. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.d.ts +7 -0
  25. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.js +79 -0
  26. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.d.ts +6 -0
  27. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.js +68 -0
  28. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.d.ts +6 -0
  29. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.js +57 -0
  30. package/dist/compiler/detector/kernels/cpu/computeLocalization.d.ts +6 -0
  31. package/dist/compiler/detector/kernels/cpu/computeLocalization.js +54 -0
  32. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.d.ts +6 -0
  33. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.js +118 -0
  34. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.d.ts +6 -0
  35. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.js +29 -0
  36. package/dist/compiler/detector/kernels/cpu/extremaReduction.d.ts +6 -0
  37. package/dist/compiler/detector/kernels/cpu/extremaReduction.js +50 -0
  38. package/dist/compiler/detector/kernels/cpu/fakeShader.d.ts +20 -0
  39. package/dist/compiler/detector/kernels/cpu/fakeShader.js +80 -0
  40. package/dist/compiler/detector/kernels/cpu/index.d.ts +1 -0
  41. package/dist/compiler/detector/kernels/cpu/index.js +25 -0
  42. package/dist/compiler/detector/kernels/cpu/prune.d.ts +1 -0
  43. package/dist/compiler/detector/kernels/cpu/prune.js +103 -0
  44. package/dist/compiler/detector/kernels/cpu/smoothHistograms.d.ts +6 -0
  45. package/dist/compiler/detector/kernels/cpu/smoothHistograms.js +47 -0
  46. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.d.ts +6 -0
  47. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.js +43 -0
  48. package/dist/compiler/detector/kernels/index.d.ts +1 -0
  49. package/dist/compiler/detector/kernels/index.js +2 -0
  50. package/dist/compiler/detector/kernels/webgl/binomialFilter.d.ts +6 -0
  51. package/dist/compiler/detector/kernels/webgl/binomialFilter.js +67 -0
  52. package/dist/compiler/detector/kernels/webgl/buildExtremas.d.ts +6 -0
  53. package/dist/compiler/detector/kernels/webgl/buildExtremas.js +101 -0
  54. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.d.ts +6 -0
  55. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.js +78 -0
  56. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.d.ts +6 -0
  57. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.js +86 -0
  58. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.d.ts +6 -0
  59. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.js +52 -0
  60. package/dist/compiler/detector/kernels/webgl/computeLocalization.d.ts +6 -0
  61. package/dist/compiler/detector/kernels/webgl/computeLocalization.js +58 -0
  62. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.d.ts +6 -0
  63. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.js +116 -0
  64. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.d.ts +6 -0
  65. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.js +46 -0
  66. package/dist/compiler/detector/kernels/webgl/extremaReduction.d.ts +6 -0
  67. package/dist/compiler/detector/kernels/webgl/extremaReduction.js +48 -0
  68. package/dist/compiler/detector/kernels/webgl/index.d.ts +1 -0
  69. package/dist/compiler/detector/kernels/webgl/index.js +25 -0
  70. package/dist/compiler/detector/kernels/webgl/smoothHistograms.d.ts +6 -0
  71. package/dist/compiler/detector/kernels/webgl/smoothHistograms.js +49 -0
  72. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.d.ts +6 -0
  73. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.js +56 -0
  74. package/dist/compiler/estimation/esimate-experiment.d.ts +5 -0
  75. package/dist/compiler/estimation/esimate-experiment.js +267 -0
  76. package/dist/compiler/estimation/estimate.d.ts +5 -0
  77. package/dist/compiler/estimation/estimate.js +51 -0
  78. package/dist/compiler/estimation/estimator.d.ts +13 -0
  79. package/dist/compiler/estimation/estimator.js +30 -0
  80. package/dist/compiler/estimation/refine-estimate-experiment.d.ts +6 -0
  81. package/dist/compiler/estimation/refine-estimate-experiment.js +429 -0
  82. package/dist/compiler/estimation/refine-estimate.d.ts +6 -0
  83. package/dist/compiler/estimation/refine-estimate.js +299 -0
  84. package/dist/compiler/estimation/utils.d.ts +10 -0
  85. package/dist/compiler/estimation/utils.js +80 -0
  86. package/dist/compiler/image-list.d.ts +13 -0
  87. package/dist/compiler/image-list.js +52 -0
  88. package/dist/compiler/index.d.ts +3 -0
  89. package/dist/compiler/index.js +10 -0
  90. package/dist/compiler/input-loader.d.ts +23 -0
  91. package/dist/compiler/input-loader.js +88 -0
  92. package/dist/compiler/matching/hamming-distance.d.ts +1 -0
  93. package/dist/compiler/matching/hamming-distance.js +20 -0
  94. package/dist/compiler/matching/hierarchical-clustering.d.ts +7 -0
  95. package/dist/compiler/matching/hierarchical-clustering.js +109 -0
  96. package/dist/compiler/matching/hough.d.ts +1 -0
  97. package/dist/compiler/matching/hough.js +169 -0
  98. package/dist/compiler/matching/matcher.d.ts +28 -0
  99. package/dist/compiler/matching/matcher.js +48 -0
  100. package/dist/compiler/matching/matching.d.ts +41 -0
  101. package/dist/compiler/matching/matching.js +197 -0
  102. package/dist/compiler/matching/ransacHomography.d.ts +1 -0
  103. package/dist/compiler/matching/ransacHomography.js +136 -0
  104. package/dist/compiler/offline-compiler.d.ts +10 -0
  105. package/dist/compiler/offline-compiler.js +450 -0
  106. package/dist/compiler/tensorflow-setup.d.ts +7 -0
  107. package/dist/compiler/tensorflow-setup.js +73 -0
  108. package/dist/compiler/three.d.ts +66 -0
  109. package/dist/compiler/three.js +310 -0
  110. package/dist/compiler/tracker/extract-utils.d.ts +1 -0
  111. package/dist/compiler/tracker/extract-utils.js +29 -0
  112. package/dist/compiler/tracker/extract.d.ts +4 -0
  113. package/dist/compiler/tracker/extract.js +349 -0
  114. package/dist/compiler/tracker/tracker.d.ts +38 -0
  115. package/dist/compiler/tracker/tracker.js +327 -0
  116. package/dist/compiler/utils/cumsum.d.ts +5 -0
  117. package/dist/compiler/utils/cumsum.js +39 -0
  118. package/dist/compiler/utils/geometry.d.ts +8 -0
  119. package/dist/compiler/utils/geometry.js +101 -0
  120. package/dist/compiler/utils/homography.d.ts +1 -0
  121. package/dist/compiler/utils/homography.js +138 -0
  122. package/dist/compiler/utils/images.d.ts +24 -0
  123. package/dist/compiler/utils/images.js +99 -0
  124. package/dist/compiler/utils/randomizer.d.ts +5 -0
  125. package/dist/compiler/utils/randomizer.js +25 -0
  126. package/dist/index.d.ts +6 -0
  127. package/dist/index.js +7 -0
  128. package/dist/react/AREditor.d.ts +5 -0
  129. package/dist/react/AREditor.js +159 -0
  130. package/dist/react/ProgressDialog.d.ts +13 -0
  131. package/dist/react/ProgressDialog.js +57 -0
  132. package/dist/react/types.d.ts +22 -0
  133. package/dist/react/types.js +14 -0
  134. package/package.json +53 -0
  135. package/src/astro/ARScene.astro +59 -0
  136. package/src/astro/ARVideoTrigger.astro +73 -0
  137. package/src/astro/overlays/ErrorOverlay.astro +40 -0
  138. package/src/astro/overlays/LoadingOverlay.astro +28 -0
  139. package/src/astro/overlays/ScanningOverlay.astro +119 -0
  140. package/src/astro/scripts/ARScripts.astro +118 -0
  141. package/src/astro/styles/ARStyles.astro +147 -0
  142. package/src/compiler/aframe.js +343 -0
  143. package/src/compiler/compiler-base.js +195 -0
  144. package/src/compiler/compiler.js +25 -0
  145. package/src/compiler/compiler.worker.js +30 -0
  146. package/src/compiler/controller.js +473 -0
  147. package/src/compiler/controller.worker.js +77 -0
  148. package/src/compiler/detector/crop-detector.js +68 -0
  149. package/src/compiler/detector/detector.js +1130 -0
  150. package/src/compiler/detector/freak.js +91 -0
  151. package/src/compiler/detector/kernels/cpu/binomialFilter.js +59 -0
  152. package/src/compiler/detector/kernels/cpu/buildExtremas.js +108 -0
  153. package/src/compiler/detector/kernels/cpu/computeExtremaAngles.js +91 -0
  154. package/src/compiler/detector/kernels/cpu/computeExtremaFreak.js +92 -0
  155. package/src/compiler/detector/kernels/cpu/computeFreakDescriptors.js +68 -0
  156. package/src/compiler/detector/kernels/cpu/computeLocalization.js +71 -0
  157. package/src/compiler/detector/kernels/cpu/computeOrientationHistograms.js +141 -0
  158. package/src/compiler/detector/kernels/cpu/downsampleBilinear.js +33 -0
  159. package/src/compiler/detector/kernels/cpu/extremaReduction.js +53 -0
  160. package/src/compiler/detector/kernels/cpu/fakeShader.js +88 -0
  161. package/src/compiler/detector/kernels/cpu/index.js +26 -0
  162. package/src/compiler/detector/kernels/cpu/prune.js +114 -0
  163. package/src/compiler/detector/kernels/cpu/smoothHistograms.js +57 -0
  164. package/src/compiler/detector/kernels/cpu/upsampleBilinear.js +51 -0
  165. package/src/compiler/detector/kernels/index.js +2 -0
  166. package/src/compiler/detector/kernels/webgl/binomialFilter.js +72 -0
  167. package/src/compiler/detector/kernels/webgl/buildExtremas.js +109 -0
  168. package/src/compiler/detector/kernels/webgl/computeExtremaAngles.js +82 -0
  169. package/src/compiler/detector/kernels/webgl/computeExtremaFreak.js +105 -0
  170. package/src/compiler/detector/kernels/webgl/computeFreakDescriptors.js +56 -0
  171. package/src/compiler/detector/kernels/webgl/computeLocalization.js +70 -0
  172. package/src/compiler/detector/kernels/webgl/computeOrientationHistograms.js +129 -0
  173. package/src/compiler/detector/kernels/webgl/downsampleBilinear.js +50 -0
  174. package/src/compiler/detector/kernels/webgl/extremaReduction.js +50 -0
  175. package/src/compiler/detector/kernels/webgl/index.js +26 -0
  176. package/src/compiler/detector/kernels/webgl/smoothHistograms.js +53 -0
  177. package/src/compiler/detector/kernels/webgl/upsampleBilinear.js +62 -0
  178. package/src/compiler/estimation/esimate-experiment.js +316 -0
  179. package/src/compiler/estimation/estimate.js +67 -0
  180. package/src/compiler/estimation/estimator.js +34 -0
  181. package/src/compiler/estimation/refine-estimate-experiment.js +512 -0
  182. package/src/compiler/estimation/refine-estimate.js +365 -0
  183. package/src/compiler/estimation/utils.js +97 -0
  184. package/src/compiler/image-list.js +62 -0
  185. package/src/compiler/index.js +13 -0
  186. package/src/compiler/input-loader.js +107 -0
  187. package/src/compiler/matching/hamming-distance.js +23 -0
  188. package/src/compiler/matching/hierarchical-clustering.js +131 -0
  189. package/src/compiler/matching/hough.js +206 -0
  190. package/src/compiler/matching/matcher.js +59 -0
  191. package/src/compiler/matching/matching.js +237 -0
  192. package/src/compiler/matching/ransacHomography.js +192 -0
  193. package/src/compiler/offline-compiler.js +553 -0
  194. package/src/compiler/tensorflow-setup.js +88 -0
  195. package/src/compiler/three.js +368 -0
  196. package/src/compiler/tracker/extract-utils.js +34 -0
  197. package/src/compiler/tracker/extract.js +419 -0
  198. package/src/compiler/tracker/tracker.js +397 -0
  199. package/src/compiler/utils/cumsum.js +40 -0
  200. package/src/compiler/utils/geometry.js +114 -0
  201. package/src/compiler/utils/homography.js +150 -0
  202. package/src/compiler/utils/images.js +111 -0
  203. package/src/compiler/utils/randomizer.js +29 -0
  204. package/src/index.ts +8 -0
  205. package/src/react/AREditor.tsx +394 -0
  206. package/src/react/ProgressDialog.tsx +185 -0
  207. package/src/react/types.ts +35 -0
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # @srsergio/taptapp-ar
2
+
3
+ AR Visualizer and Image Target Compiler for Astro and React.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Astro-ready**: Built-in components for Astro projects.
8
+ - ⚛️ **React Support**: Advanced AREditor and Progress UI.
9
+ - 🖼️ **Offline Compiler**: Powerful image target compilation using TensorFlow.js.
10
+ - 📱 **Mobile Optimized**: Smooth performance on mobile devices.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @srsergio/taptapp-ar
16
+ ```
17
+
18
+ Note: You should also have `three`, `aframe`, `react`, and `react-dom` installed in your project as peer dependencies.
19
+
20
+ ## Usage
21
+
22
+ ### Using the AR Visualizer in Astro
23
+
24
+ ```astro
25
+ ---
26
+ import ARVideoTrigger from '@srsergio/taptapp-ar/astro/ARVideoTrigger.astro';
27
+
28
+ const config = {
29
+ targetImageSrc: '/path/to/image.jpg',
30
+ targetMindSrc: '/path/to/targets.mind',
31
+ videoSrc: '/path/to/video.mp4',
32
+ videoWidth: 1280,
33
+ videoHeight: 720,
34
+ scale: 1,
35
+ };
36
+ ---
37
+
38
+ <ARVideoTrigger config={config} />
39
+ ```
40
+
41
+ ### Using the AR Editor in React
42
+
43
+ ```tsx
44
+ import { AREditor } from '@srsergio/taptapp-ar';
45
+
46
+ function MyEditor() {
47
+ return <AREditor adminId="some-id" />;
48
+ }
49
+ ```
50
+
51
+ ### Using the Offline Compiler (Backend/Serverless)
52
+
53
+ ```typescript
54
+ import { OfflineCompiler } from '@srsergio/taptapp-ar';
55
+
56
+ const compiler = new OfflineCompiler();
57
+ // ... logic to compile image targets
58
+ ```
59
+
60
+ ## License
61
+
62
+ MIT
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,275 @@
1
+ import { Controller, UI } from "./index.js";
2
+ const needsDOMRefresh = document.readyState === "complete" || document.readyState == "interactive";
3
+ AFRAME.registerSystem("mindar-image-system", {
4
+ container: null,
5
+ video: null,
6
+ processingImage: false,
7
+ init: function () {
8
+ this.anchorEntities = [];
9
+ },
10
+ tick: function () { },
11
+ setup: function ({ imageTargetSrc, maxTrack, showStats, uiLoading, uiScanning, uiError, missTolerance, warmupTolerance, filterMinCF, filterBeta, }) {
12
+ this.imageTargetSrc = imageTargetSrc;
13
+ this.maxTrack = maxTrack;
14
+ this.filterMinCF = filterMinCF;
15
+ this.filterBeta = filterBeta;
16
+ this.missTolerance = missTolerance;
17
+ this.warmupTolerance = warmupTolerance;
18
+ this.showStats = showStats;
19
+ this.ui = new UI({ uiLoading, uiScanning, uiError });
20
+ },
21
+ registerAnchor: function (el, targetIndex) {
22
+ this.anchorEntities.push({ el: el, targetIndex: targetIndex });
23
+ },
24
+ start: function () {
25
+ this.container = this.el.sceneEl.parentNode;
26
+ if (this.showStats) {
27
+ this.mainStats = new Stats();
28
+ this.mainStats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
29
+ this.mainStats.domElement.style.cssText = "position:absolute;top:0px;left:0px;z-index:999";
30
+ this.container.appendChild(this.mainStats.domElement);
31
+ }
32
+ this.ui.showLoading();
33
+ this._startVideo();
34
+ },
35
+ switchTarget: function (targetIndex) {
36
+ this.controller.interestedTargetIndex = targetIndex;
37
+ },
38
+ stop: function () {
39
+ this.pause();
40
+ const tracks = this.video.srcObject.getTracks();
41
+ tracks.forEach(function (track) {
42
+ track.stop();
43
+ });
44
+ this.video.remove();
45
+ this.controller.dispose();
46
+ },
47
+ pause: function (keepVideo = false) {
48
+ if (!keepVideo) {
49
+ this.video.pause();
50
+ }
51
+ this.controller.stopProcessVideo();
52
+ },
53
+ unpause: function () {
54
+ this.video.play();
55
+ this.controller.processVideo(this.video);
56
+ },
57
+ _startVideo: function () {
58
+ this.video = document.createElement("video");
59
+ this.video.setAttribute("autoplay", "");
60
+ this.video.setAttribute("muted", "");
61
+ this.video.setAttribute("playsinline", "");
62
+ this.video.style.position = "absolute";
63
+ this.video.style.top = "0px";
64
+ this.video.style.left = "0px";
65
+ this.video.style.zIndex = "-2";
66
+ this.container.appendChild(this.video);
67
+ if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
68
+ // TODO: show unsupported error
69
+ this.el.emit("arError", { error: "VIDEO_FAIL" });
70
+ this.ui.showCompatibility();
71
+ return;
72
+ }
73
+ navigator.mediaDevices
74
+ .getUserMedia({
75
+ audio: false,
76
+ video: {
77
+ facingMode: "environment",
78
+ },
79
+ })
80
+ .then((stream) => {
81
+ this.video.addEventListener("loadedmetadata", () => {
82
+ //console.log("video ready...", this.video);
83
+ this.video.setAttribute("width", this.video.videoWidth);
84
+ this.video.setAttribute("height", this.video.videoHeight);
85
+ this._startAR();
86
+ });
87
+ this.video.srcObject = stream;
88
+ })
89
+ .catch((err) => {
90
+ console.log("getUserMedia error", err);
91
+ this.el.emit("arError", { error: "VIDEO_FAIL" });
92
+ });
93
+ },
94
+ _startAR: async function () {
95
+ const video = this.video;
96
+ const container = this.container;
97
+ this.controller = new Controller({
98
+ inputWidth: video.videoWidth,
99
+ inputHeight: video.videoHeight,
100
+ maxTrack: this.maxTrack,
101
+ filterMinCF: this.filterMinCF,
102
+ filterBeta: this.filterBeta,
103
+ missTolerance: this.missTolerance,
104
+ warmupTolerance: this.warmupTolerance,
105
+ onUpdate: (data) => {
106
+ if (data.type === "processDone") {
107
+ if (this.mainStats)
108
+ this.mainStats.update();
109
+ }
110
+ else if (data.type === "updateMatrix") {
111
+ const { targetIndex, worldMatrix } = data;
112
+ for (let i = 0; i < this.anchorEntities.length; i++) {
113
+ if (this.anchorEntities[i].targetIndex === targetIndex) {
114
+ this.anchorEntities[i].el.updateWorldMatrix(worldMatrix);
115
+ }
116
+ }
117
+ let isAnyVisible = this.anchorEntities.reduce((acc, entity) => {
118
+ return acc || entity.el.el.object3D.visible;
119
+ }, false);
120
+ if (isAnyVisible) {
121
+ this.ui.hideScanning();
122
+ }
123
+ else {
124
+ this.ui.showScanning();
125
+ }
126
+ }
127
+ },
128
+ });
129
+ this._resize();
130
+ window.addEventListener("resize", this._resize.bind(this));
131
+ const { dimensions: imageTargetDimensions } = await this.controller.addImageTargets(this.imageTargetSrc);
132
+ for (let i = 0; i < this.anchorEntities.length; i++) {
133
+ const { el, targetIndex } = this.anchorEntities[i];
134
+ if (targetIndex < imageTargetDimensions.length) {
135
+ el.setupMarker(imageTargetDimensions[targetIndex]);
136
+ }
137
+ }
138
+ await this.controller.dummyRun(this.video);
139
+ this.el.emit("arReady");
140
+ this.ui.hideLoading();
141
+ this.ui.showScanning();
142
+ this.controller.processVideo(this.video);
143
+ },
144
+ _resize: function () {
145
+ const video = this.video;
146
+ const container = this.container;
147
+ let vw, vh; // display css width, height
148
+ const videoRatio = video.videoWidth / video.videoHeight;
149
+ const containerRatio = container.clientWidth / container.clientHeight;
150
+ if (videoRatio > containerRatio) {
151
+ vh = container.clientHeight;
152
+ vw = vh * videoRatio;
153
+ }
154
+ else {
155
+ vw = container.clientWidth;
156
+ vh = vw / videoRatio;
157
+ }
158
+ const proj = this.controller.getProjectionMatrix();
159
+ const fov = (2 * Math.atan((1 / proj[5] / vh) * container.clientHeight) * 180) / Math.PI; // vertical fov
160
+ const near = proj[14] / (proj[10] - 1.0);
161
+ const far = proj[14] / (proj[10] + 1.0);
162
+ const ratio = proj[5] / proj[0]; // (r-l) / (t-b)
163
+ //console.log("loaded proj: ", proj, ". fov: ", fov, ". near: ", near, ". far: ", far, ". ratio: ", ratio);
164
+ const newAspect = container.clientWidth / container.clientHeight;
165
+ const cameraEle = container.getElementsByTagName("a-camera")[0];
166
+ const camera = cameraEle.getObject3D("camera");
167
+ camera.fov = fov;
168
+ camera.aspect = newAspect;
169
+ camera.near = near;
170
+ camera.far = far;
171
+ camera.updateProjectionMatrix();
172
+ //const newCam = new AFRAME.THREE.PerspectiveCamera(fov, newRatio, near, far);
173
+ //camera.getObject3D('camera').projectionMatrix = newCam.projectionMatrix;
174
+ this.video.style.top = -(vh - container.clientHeight) / 2 + "px";
175
+ this.video.style.left = -(vw - container.clientWidth) / 2 + "px";
176
+ this.video.style.width = vw + "px";
177
+ this.video.style.height = vh + "px";
178
+ },
179
+ });
180
+ AFRAME.registerComponent("mindar-image", {
181
+ dependencies: ["mindar-image-system"],
182
+ schema: {
183
+ imageTargetSrc: { type: "string" },
184
+ maxTrack: { type: "int", default: 1 },
185
+ filterMinCF: { type: "number", default: -1 },
186
+ filterBeta: { type: "number", default: -1 },
187
+ missTolerance: { type: "int", default: -1 },
188
+ warmupTolerance: { type: "int", default: -1 },
189
+ showStats: { type: "boolean", default: false },
190
+ autoStart: { type: "boolean", default: true },
191
+ uiLoading: { type: "string", default: "yes" },
192
+ uiScanning: { type: "string", default: "yes" },
193
+ uiError: { type: "string", default: "yes" },
194
+ },
195
+ init: function () {
196
+ const arSystem = this.el.sceneEl.systems["mindar-image-system"];
197
+ arSystem.setup({
198
+ imageTargetSrc: this.data.imageTargetSrc,
199
+ maxTrack: this.data.maxTrack,
200
+ filterMinCF: this.data.filterMinCF === -1 ? null : this.data.filterMinCF,
201
+ filterBeta: this.data.filterBeta === -1 ? null : this.data.filterBeta,
202
+ missTolerance: this.data.missTolerance === -1 ? null : this.data.missTolerance,
203
+ warmupTolerance: this.data.warmupTolerance === -1 ? null : this.data.warmupTolerance,
204
+ showStats: this.data.showStats,
205
+ uiLoading: this.data.uiLoading,
206
+ uiScanning: this.data.uiScanning,
207
+ uiError: this.data.uiError,
208
+ });
209
+ if (this.data.autoStart) {
210
+ this.el.sceneEl.addEventListener("renderstart", () => {
211
+ arSystem.start();
212
+ });
213
+ }
214
+ },
215
+ remove: function () {
216
+ const arSystem = this.el.sceneEl.systems["mindar-image-system"];
217
+ arSystem.stop();
218
+ },
219
+ });
220
+ AFRAME.registerComponent("mindar-image-target", {
221
+ dependencies: ["mindar-image-system"],
222
+ schema: {
223
+ targetIndex: { type: "number" },
224
+ },
225
+ postMatrix: null, // rescale the anchor to make width of 1 unit = physical width of card
226
+ init: function () {
227
+ const arSystem = this.el.sceneEl.systems["mindar-image-system"];
228
+ arSystem.registerAnchor(this, this.data.targetIndex);
229
+ this.invisibleMatrix = new AFRAME.THREE.Matrix4().set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
230
+ const root = this.el.object3D;
231
+ root.visible = false;
232
+ root.matrixAutoUpdate = false;
233
+ root.matrix = this.invisibleMatrix;
234
+ },
235
+ setupMarker([markerWidth, markerHeight]) {
236
+ const position = new AFRAME.THREE.Vector3();
237
+ const quaternion = new AFRAME.THREE.Quaternion();
238
+ const scale = new AFRAME.THREE.Vector3();
239
+ position.x = markerWidth / 2;
240
+ position.y = markerWidth / 2 + (markerHeight - markerWidth) / 2;
241
+ scale.x = markerWidth;
242
+ scale.y = markerWidth;
243
+ scale.z = markerWidth;
244
+ this.postMatrix = new AFRAME.THREE.Matrix4();
245
+ this.postMatrix.compose(position, quaternion, scale);
246
+ },
247
+ updateWorldMatrix(worldMatrix) {
248
+ this.el.emit("targetUpdate");
249
+ if (!this.el.object3D.visible && worldMatrix !== null) {
250
+ this.el.emit("targetFound");
251
+ }
252
+ else if (this.el.object3D.visible && worldMatrix === null) {
253
+ this.el.emit("targetLost");
254
+ }
255
+ this.el.object3D.visible = worldMatrix !== null;
256
+ if (worldMatrix === null) {
257
+ this.el.object3D.matrix = this.invisibleMatrix;
258
+ return;
259
+ }
260
+ var m = new AFRAME.THREE.Matrix4();
261
+ m.elements = worldMatrix;
262
+ m.multiply(this.postMatrix);
263
+ this.el.object3D.matrix = m;
264
+ },
265
+ });
266
+ /*
267
+ This is a hack.
268
+ If the user's browser has cached A-Frame,
269
+ then A-Frame will process the webpage *before* the system and components get registered.
270
+ Resulting in a blank page. This happens because module loading is deferred.
271
+ */
272
+ /* if(needsDOMRefresh){
273
+ console.log("mindar-face-aframe::Refreshing DOM...")
274
+ document.body.innerHTML=document.body.innerHTML;
275
+ } */
@@ -0,0 +1,12 @@
1
+ export class CompilerBase {
2
+ data: any[] | null;
3
+ compileImageTargets(images: any, progressCallback: any): Promise<any>;
4
+ exportData(): Uint8Array<ArrayBufferLike>;
5
+ importData(buffer: any): any[];
6
+ createProcessCanvas(img: any): void;
7
+ compileTrack({ progressCallback, targetImages, basePercent }: {
8
+ progressCallback: any;
9
+ targetImages: any;
10
+ basePercent: any;
11
+ }): void;
12
+ }
@@ -0,0 +1,165 @@
1
+ import { Detector } from "./detector/detector.js";
2
+ import { buildImageList, buildTrackingImageList } from "./image-list.js";
3
+ import { build as hierarchicalClusteringBuild } from "./matching/hierarchical-clustering.js";
4
+ import * as msgpack from "@msgpack/msgpack";
5
+ import { tf } from "./tensorflow-setup.js";
6
+ // TODO: better compression method. now grey image saved in pixels, which could be larger than original image
7
+ const CURRENT_VERSION = 2;
8
+ class CompilerBase {
9
+ constructor() {
10
+ this.data = null;
11
+ }
12
+ // input images con formato {width, height, data}
13
+ compileImageTargets(images, progressCallback) {
14
+ return new Promise(async (resolve, reject) => {
15
+ try {
16
+ const targetImages = [];
17
+ for (let i = 0; i < images.length; i++) {
18
+ const img = images[i];
19
+ if (!img || !img.width || !img.height || !img.data) {
20
+ reject(new Error(`Imagen inválida en posición ${i}. Debe tener propiedades width, height y data.`));
21
+ return;
22
+ }
23
+ // Convertir a escala de grises si aún no lo está
24
+ // Buffer alineado para optimización SIMD
25
+ const greyImageData = new Uint8Array(new SharedArrayBuffer(Math.ceil((img.width * img.height) / 16) * 16));
26
+ // Si los datos ya están en escala de grises (1 byte por píxel)
27
+ if (img.data.length === img.width * img.height) {
28
+ greyImageData.set(img.data);
29
+ }
30
+ // Si los datos están en formato RGBA (4 bytes por píxel)
31
+ else if (img.data.length === img.width * img.height * 4) {
32
+ for (let j = 0; j < greyImageData.length; j++) {
33
+ const offset = j * 4;
34
+ greyImageData[j] = Math.floor((img.data[offset] + img.data[offset + 1] + img.data[offset + 2]) / 3);
35
+ }
36
+ }
37
+ // Si los datos están en otro formato, rechazar
38
+ else {
39
+ reject(new Error(`Formato de datos de imagen no soportado en posición ${i}`));
40
+ return;
41
+ }
42
+ const targetImage = {
43
+ data: greyImageData,
44
+ height: img.height,
45
+ width: img.width,
46
+ };
47
+ targetImages.push(targetImage);
48
+ }
49
+ // compute matching data: 50% progress
50
+ const percentPerImage = 50.0 / targetImages.length;
51
+ let percent = 0.0;
52
+ this.data = [];
53
+ for (let i = 0; i < targetImages.length; i++) {
54
+ const targetImage = targetImages[i];
55
+ const imageList = buildImageList(targetImage);
56
+ const percentPerAction = percentPerImage / imageList.length;
57
+ const matchingData = await _extractMatchingFeatures(imageList, () => {
58
+ percent += percentPerAction;
59
+ progressCallback(percent);
60
+ });
61
+ this.data.push({
62
+ targetImage: targetImage,
63
+ imageList: imageList,
64
+ matchingData: matchingData,
65
+ });
66
+ }
67
+ for (let i = 0; i < targetImages.length; i++) {
68
+ const trackingImageList = buildTrackingImageList(targetImages[i]);
69
+ this.data[i].trackingImageList = trackingImageList;
70
+ }
71
+ const trackingDataList = await this.compileTrack({
72
+ progressCallback,
73
+ targetImages,
74
+ basePercent: 50,
75
+ });
76
+ for (let i = 0; i < targetImages.length; i++) {
77
+ this.data[i].trackingData = trackingDataList[i];
78
+ }
79
+ resolve(this.data);
80
+ }
81
+ catch (error) {
82
+ reject(error);
83
+ }
84
+ });
85
+ }
86
+ // not exporting imageList because too large. rebuild this using targetImage
87
+ exportData() {
88
+ const dataList = [];
89
+ for (let i = 0; i < this.data.length; i++) {
90
+ dataList.push({
91
+ //targetImage: this.data[i].targetImage,
92
+ targetImage: {
93
+ width: this.data[i].targetImage.width,
94
+ height: this.data[i].targetImage.height,
95
+ },
96
+ trackingData: this.data[i].trackingData,
97
+ matchingData: this.data[i].matchingData,
98
+ });
99
+ }
100
+ const buffer = msgpack.encode({
101
+ v: CURRENT_VERSION,
102
+ dataList,
103
+ });
104
+ return buffer;
105
+ }
106
+ importData(buffer) {
107
+ const content = msgpack.decode(new Uint8Array(buffer));
108
+ //console.log("import", content);
109
+ if (!content.v || content.v !== CURRENT_VERSION) {
110
+ console.error("Your compiled .mind might be outdated. Please recompile");
111
+ return [];
112
+ }
113
+ const { dataList } = content;
114
+ this.data = [];
115
+ for (let i = 0; i < dataList.length; i++) {
116
+ this.data.push({
117
+ targetImage: dataList[i].targetImage,
118
+ trackingData: dataList[i].trackingData,
119
+ matchingData: dataList[i].matchingData,
120
+ });
121
+ }
122
+ return this.data;
123
+ }
124
+ createProcessCanvas(img) {
125
+ // sub-class implements
126
+ console.warn("missing createProcessCanvas implementation");
127
+ }
128
+ compileTrack({ progressCallback, targetImages, basePercent }) {
129
+ // sub-class implements
130
+ console.warn("missing compileTrack implementation");
131
+ }
132
+ }
133
+ const _extractMatchingFeatures = async (imageList, doneCallback) => {
134
+ const keyframes = [];
135
+ for (let i = 0; i < imageList.length; i++) {
136
+ const image = imageList[i];
137
+ // TODO: can improve performance greatly if reuse the same detector. just need to handle resizing the kernel outputs
138
+ const detector = new Detector(image.width, image.height);
139
+ await tf.nextFrame();
140
+ tf.tidy(() => {
141
+ //const inputT = tf.tensor(image.data, [image.data.length]).reshape([image.height, image.width]);
142
+ const inputT = tf
143
+ .tensor(image.data, [image.data.length], "float32")
144
+ .reshape([image.height, image.width]);
145
+ //const ps = detector.detectImageData(image.data);
146
+ const { featurePoints: ps } = detector.detect(inputT);
147
+ const maximaPoints = ps.filter((p) => p.maxima);
148
+ const minimaPoints = ps.filter((p) => !p.maxima);
149
+ const maximaPointsCluster = hierarchicalClusteringBuild({ points: maximaPoints });
150
+ const minimaPointsCluster = hierarchicalClusteringBuild({ points: minimaPoints });
151
+ keyframes.push({
152
+ maximaPoints,
153
+ minimaPoints,
154
+ maximaPointsCluster,
155
+ minimaPointsCluster,
156
+ width: image.width,
157
+ height: image.height,
158
+ scale: image.scale,
159
+ });
160
+ doneCallback(i);
161
+ });
162
+ }
163
+ return keyframes;
164
+ };
165
+ export { CompilerBase };
@@ -0,0 +1,9 @@
1
+ export class Compiler extends CompilerBase {
2
+ createProcessCanvas(img: any): HTMLCanvasElement;
3
+ compileTrack({ progressCallback, targetImages, basePercent }: {
4
+ progressCallback: any;
5
+ targetImages: any;
6
+ basePercent: any;
7
+ }): Promise<any>;
8
+ }
9
+ import { CompilerBase } from "./compiler-base.js";
@@ -0,0 +1,24 @@
1
+ import { CompilerBase } from "./compiler-base.js";
2
+ import CompilerWorker from "./compiler.worker.js?worker&inline";
3
+ export class Compiler extends CompilerBase {
4
+ createProcessCanvas(img) {
5
+ const processCanvas = document.createElement("canvas");
6
+ processCanvas.width = img.width;
7
+ processCanvas.height = img.height;
8
+ return processCanvas;
9
+ }
10
+ compileTrack({ progressCallback, targetImages, basePercent }) {
11
+ return new Promise((resolve, reject) => {
12
+ const worker = new CompilerWorker();
13
+ worker.onmessage = (e) => {
14
+ if (e.data.type === "progress") {
15
+ progressCallback(basePercent + (e.data.percent * basePercent) / 100);
16
+ }
17
+ else if (e.data.type === "compileDone") {
18
+ resolve(e.data.list);
19
+ }
20
+ };
21
+ worker.postMessage({ type: "compile", targetImages });
22
+ });
23
+ }
24
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ import { extractTrackingFeatures } from "./tracker/extract-utils.js";
2
+ import { buildTrackingImageList } from "./image-list.js";
3
+ onmessage = (msg) => {
4
+ const { data } = msg;
5
+ if (data.type === "compile") {
6
+ //console.log("worker compile...");
7
+ const { targetImages } = data;
8
+ const percentPerImage = 100.0 / targetImages.length;
9
+ let percent = 0.0;
10
+ const list = [];
11
+ for (let i = 0; i < targetImages.length; i++) {
12
+ const targetImage = targetImages[i];
13
+ const imageList = buildTrackingImageList(targetImage);
14
+ const percentPerAction = percentPerImage / imageList.length;
15
+ //console.log("compiling tracking...", i);
16
+ const trackingData = extractTrackingFeatures(imageList, (index) => {
17
+ //console.log("done tracking", i, index);
18
+ percent += percentPerAction;
19
+ postMessage({ type: "progress", percent });
20
+ });
21
+ list.push(trackingData);
22
+ }
23
+ postMessage({
24
+ type: "compileDone",
25
+ list,
26
+ });
27
+ }
28
+ };
@@ -0,0 +1,101 @@
1
+ export class Controller {
2
+ constructor({ inputWidth, inputHeight, onUpdate, debugMode, maxTrack, warmupTolerance, missTolerance, filterMinCF, filterBeta, }: {
3
+ inputWidth: any;
4
+ inputHeight: any;
5
+ onUpdate?: null | undefined;
6
+ debugMode?: boolean | undefined;
7
+ maxTrack?: number | undefined;
8
+ warmupTolerance?: null | undefined;
9
+ missTolerance?: null | undefined;
10
+ filterMinCF?: null | undefined;
11
+ filterBeta?: null | undefined;
12
+ });
13
+ inputWidth: any;
14
+ inputHeight: any;
15
+ maxTrack: number;
16
+ filterMinCF: number;
17
+ filterBeta: number;
18
+ warmupTolerance: number;
19
+ missTolerance: number;
20
+ cropDetector: CropDetector;
21
+ inputLoader: InputLoader;
22
+ markerDimensions: any[][] | null;
23
+ onUpdate: any;
24
+ debugMode: boolean;
25
+ processingVideo: boolean;
26
+ interestedTargetIndex: number;
27
+ trackingStates: any[];
28
+ projectionTransform: number[][];
29
+ projectionMatrix: number[];
30
+ worker: any;
31
+ workerMatchDone: ((data: any) => void) | null;
32
+ workerTrackDone: ((data: any) => void) | null;
33
+ showTFStats(): void;
34
+ addImageTargets(fileURL: any): Promise<any>;
35
+ addImageTargetsFromBuffer(buffer: any): {
36
+ dimensions: any[][];
37
+ matchingDataList: any[];
38
+ trackingDataList: any[];
39
+ };
40
+ tracker: Tracker | undefined;
41
+ dispose(): void;
42
+ dummyRun(input: any): void;
43
+ getProjectionMatrix(): number[];
44
+ getRotatedZ90Matrix(m: any): any[];
45
+ getWorldMatrix(modelViewTransform: any, targetIndex: any): any[];
46
+ _detectAndMatch(inputT: any, targetIndexes: any): Promise<{
47
+ targetIndex: any;
48
+ modelViewTransform: any;
49
+ }>;
50
+ _trackAndUpdate(inputT: any, lastModelViewTransform: any, targetIndex: any): Promise<any>;
51
+ processVideo(input: any): void;
52
+ stopProcessVideo(): void;
53
+ detect(input: any): Promise<{
54
+ featurePoints: {
55
+ maxima: boolean;
56
+ x: number;
57
+ y: number;
58
+ scale: number;
59
+ angle: any;
60
+ descriptors: any[];
61
+ }[];
62
+ debugExtra: {
63
+ pyramidImages: (number | number[] | number[][] | number[][][] | number[][][][] | number[][][][][] | number[][][][][][])[][];
64
+ dogPyramidImages: (number | number[] | number[][] | number[][][] | number[][][][] | number[][][][][] | number[][][][][][] | null)[];
65
+ extremasResults: (number | number[] | number[][] | number[][][] | number[][][][] | number[][][][][] | number[][][][][][])[];
66
+ extremaAngles: any;
67
+ prunedExtremas: number[][];
68
+ localizedExtremas: number | number[] | number[][] | number[][][] | number[][][][] | number[][][][][] | number[][][][][][];
69
+ } | null;
70
+ }>;
71
+ match(featurePoints: any, targetIndex: any): Promise<{
72
+ modelViewTransform: any;
73
+ debugExtra: any;
74
+ }>;
75
+ track(input: any, modelViewTransform: any, targetIndex: any): Promise<{
76
+ worldCoords: {
77
+ x: number;
78
+ y: number;
79
+ z: number;
80
+ }[];
81
+ screenCoords: {
82
+ x: number;
83
+ y: number;
84
+ }[];
85
+ debugExtra: {};
86
+ }>;
87
+ trackUpdate(modelViewTransform: any, trackFeatures: any): Promise<any>;
88
+ _workerMatch(featurePoints: any, targetIndexes: any): Promise<any>;
89
+ _workerTrackUpdate(modelViewTransform: any, trackingFeatures: any): Promise<any>;
90
+ _glModelViewMatrix(modelViewTransform: any, targetIndex: any): any[];
91
+ _glProjectionMatrix({ projectionTransform, width, height, near, far }: {
92
+ projectionTransform: any;
93
+ width: any;
94
+ height: any;
95
+ near: any;
96
+ far: any;
97
+ }): number[];
98
+ }
99
+ import { CropDetector } from "./detector/crop-detector.js";
100
+ import { InputLoader } from "./input-loader.js";
101
+ import { Tracker } from "./tracker/tracker.js";