@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
@@ -0,0 +1,473 @@
1
+ import { memory, nextFrame } from "@tensorflow/tfjs";
2
+
3
+ const tf = { memory, nextFrame };
4
+ import ControllerWorker from "./controller.worker.js?worker&inline";
5
+ import { Tracker } from "./tracker/tracker.js";
6
+ import { CropDetector } from "./detector/crop-detector.js";
7
+ import { Compiler } from "./compiler.js";
8
+ import { InputLoader } from "./input-loader.js";
9
+ import { OneEuroFilter } from "../libs/one-euro-filter.js";
10
+
11
+ const DEFAULT_FILTER_CUTOFF = 0.001; // 1Hz. time period in milliseconds
12
+ const DEFAULT_FILTER_BETA = 1000;
13
+ const DEFAULT_WARMUP_TOLERANCE = 5;
14
+ const DEFAULT_MISS_TOLERANCE = 5;
15
+
16
+ class Controller {
17
+ constructor({
18
+ inputWidth,
19
+ inputHeight,
20
+ onUpdate = null,
21
+ debugMode = false,
22
+ maxTrack = 1,
23
+ warmupTolerance = null,
24
+ missTolerance = null,
25
+ filterMinCF = null,
26
+ filterBeta = null,
27
+ }) {
28
+ this.inputWidth = inputWidth;
29
+ this.inputHeight = inputHeight;
30
+ this.maxTrack = maxTrack;
31
+ this.filterMinCF = filterMinCF === null ? DEFAULT_FILTER_CUTOFF : filterMinCF;
32
+ this.filterBeta = filterBeta === null ? DEFAULT_FILTER_BETA : filterBeta;
33
+ this.warmupTolerance = warmupTolerance === null ? DEFAULT_WARMUP_TOLERANCE : warmupTolerance;
34
+ this.missTolerance = missTolerance === null ? DEFAULT_MISS_TOLERANCE : missTolerance;
35
+ this.cropDetector = new CropDetector(this.inputWidth, this.inputHeight, debugMode);
36
+ this.inputLoader = new InputLoader(this.inputWidth, this.inputHeight);
37
+ this.markerDimensions = null;
38
+ this.onUpdate = onUpdate;
39
+ this.debugMode = debugMode;
40
+ this.processingVideo = false;
41
+ this.interestedTargetIndex = -1;
42
+ this.trackingStates = [];
43
+
44
+ const near = 10;
45
+ const far = 100000;
46
+ const fovy = (45.0 * Math.PI) / 180; // 45 in radian. field of view vertical
47
+ const f = this.inputHeight / 2 / Math.tan(fovy / 2);
48
+ // [fx s cx]
49
+ // K = [ 0 fx cy]
50
+ // [ 0 0 1]
51
+ this.projectionTransform = [
52
+ [f, 0, this.inputWidth / 2],
53
+ [0, f, this.inputHeight / 2],
54
+ [0, 0, 1],
55
+ ];
56
+
57
+ this.projectionMatrix = this._glProjectionMatrix({
58
+ projectionTransform: this.projectionTransform,
59
+ width: this.inputWidth,
60
+ height: this.inputHeight,
61
+ near: near,
62
+ far: far,
63
+ });
64
+
65
+ this.worker = new ControllerWorker(); //new Worker(new URL('./controller.worker.js', import.meta.url));
66
+ this.workerMatchDone = null;
67
+ this.workerTrackDone = null;
68
+ this.worker.onmessage = (e) => {
69
+ if (e.data.type === "matchDone" && this.workerMatchDone !== null) {
70
+ this.workerMatchDone(e.data);
71
+ }
72
+ if (e.data.type === "trackUpdateDone" && this.workerTrackDone !== null) {
73
+ this.workerTrackDone(e.data);
74
+ }
75
+ };
76
+ }
77
+
78
+ showTFStats() {
79
+ console.log(tf.memory().numTensors);
80
+ console.table(tf.memory());
81
+ }
82
+
83
+ addImageTargets(fileURL) {
84
+ return new Promise(async (resolve, reject) => {
85
+ const content = await fetch(fileURL);
86
+ const buffer = await content.arrayBuffer();
87
+ const result = this.addImageTargetsFromBuffer(buffer);
88
+ resolve(result);
89
+ });
90
+ }
91
+
92
+ addImageTargetsFromBuffer(buffer) {
93
+ const compiler = new Compiler();
94
+ const dataList = compiler.importData(buffer);
95
+
96
+ const trackingDataList = [];
97
+ const matchingDataList = [];
98
+ const imageListList = [];
99
+ const dimensions = [];
100
+ for (let i = 0; i < dataList.length; i++) {
101
+ matchingDataList.push(dataList[i].matchingData);
102
+ trackingDataList.push(dataList[i].trackingData);
103
+ dimensions.push([dataList[i].targetImage.width, dataList[i].targetImage.height]);
104
+ }
105
+
106
+ this.tracker = new Tracker(
107
+ dimensions,
108
+ trackingDataList,
109
+ this.projectionTransform,
110
+ this.inputWidth,
111
+ this.inputHeight,
112
+ this.debugMode,
113
+ );
114
+
115
+ this.worker.postMessage({
116
+ type: "setup",
117
+ inputWidth: this.inputWidth,
118
+ inputHeight: this.inputHeight,
119
+ projectionTransform: this.projectionTransform,
120
+ debugMode: this.debugMode,
121
+ matchingDataList,
122
+ });
123
+
124
+ this.markerDimensions = dimensions;
125
+
126
+ return { dimensions: dimensions, matchingDataList, trackingDataList };
127
+ }
128
+
129
+ dispose() {
130
+ this.stopProcessVideo();
131
+ this.worker.postMessage({
132
+ type: "dispose",
133
+ });
134
+ }
135
+
136
+ // warm up gpu - build kernels is slow
137
+ dummyRun(input) {
138
+ const inputT = this.inputLoader.loadInput(input);
139
+ this.cropDetector.detect(inputT);
140
+ this.tracker.dummyRun(inputT);
141
+ inputT.dispose();
142
+ }
143
+
144
+ getProjectionMatrix() {
145
+ return this.projectionMatrix;
146
+ }
147
+
148
+ getRotatedZ90Matrix(m) {
149
+ // rotate 90 degree along z-axis
150
+ // rotation matrix
151
+ // | 0 -1 0 0 |
152
+ // | 1 0 0 0 |
153
+ // | 0 0 1 0 |
154
+ // | 0 0 0 1 |
155
+ const rotatedMatrix = [
156
+ -m[1],
157
+ m[0],
158
+ m[2],
159
+ m[3],
160
+ -m[5],
161
+ m[4],
162
+ m[6],
163
+ m[7],
164
+ -m[9],
165
+ m[8],
166
+ m[10],
167
+ m[11],
168
+ -m[13],
169
+ m[12],
170
+ m[14],
171
+ m[15],
172
+ ];
173
+ return rotatedMatrix;
174
+ }
175
+
176
+ getWorldMatrix(modelViewTransform, targetIndex) {
177
+ return this._glModelViewMatrix(modelViewTransform, targetIndex);
178
+ }
179
+
180
+ async _detectAndMatch(inputT, targetIndexes) {
181
+ const { featurePoints } = this.cropDetector.detectMoving(inputT);
182
+ const { targetIndex: matchedTargetIndex, modelViewTransform } = await this._workerMatch(
183
+ featurePoints,
184
+ targetIndexes,
185
+ );
186
+ return { targetIndex: matchedTargetIndex, modelViewTransform };
187
+ }
188
+ async _trackAndUpdate(inputT, lastModelViewTransform, targetIndex) {
189
+ const { worldCoords, screenCoords } = this.tracker.track(
190
+ inputT,
191
+ lastModelViewTransform,
192
+ targetIndex,
193
+ );
194
+ if (worldCoords.length < 4) return null;
195
+ const modelViewTransform = await this._workerTrackUpdate(lastModelViewTransform, {
196
+ worldCoords,
197
+ screenCoords,
198
+ });
199
+ return modelViewTransform;
200
+ }
201
+
202
+ processVideo(input) {
203
+ if (this.processingVideo) return;
204
+
205
+ this.processingVideo = true;
206
+
207
+ this.trackingStates = [];
208
+ for (let i = 0; i < this.markerDimensions.length; i++) {
209
+ this.trackingStates.push({
210
+ showing: false,
211
+ isTracking: false,
212
+ currentModelViewTransform: null,
213
+ trackCount: 0,
214
+ trackMiss: 0,
215
+ filter: new OneEuroFilter({ minCutOff: this.filterMinCF, beta: this.filterBeta }),
216
+ });
217
+ //console.log("filterMinCF", this.filterMinCF, this.filterBeta);
218
+ }
219
+
220
+ const startProcessing = async () => {
221
+ while (true) {
222
+ if (!this.processingVideo) break;
223
+
224
+ const inputT = this.inputLoader.loadInput(input);
225
+
226
+ const nTracking = this.trackingStates.reduce((acc, s) => {
227
+ return acc + (!!s.isTracking ? 1 : 0);
228
+ }, 0);
229
+
230
+ // detect and match only if less then maxTrack
231
+ if (nTracking < this.maxTrack) {
232
+ const matchingIndexes = [];
233
+ for (let i = 0; i < this.trackingStates.length; i++) {
234
+ const trackingState = this.trackingStates[i];
235
+ if (trackingState.isTracking === true) continue;
236
+ if (this.interestedTargetIndex !== -1 && this.interestedTargetIndex !== i) continue;
237
+
238
+ matchingIndexes.push(i);
239
+ }
240
+
241
+ const { targetIndex: matchedTargetIndex, modelViewTransform } =
242
+ await this._detectAndMatch(inputT, matchingIndexes);
243
+
244
+ if (matchedTargetIndex !== -1) {
245
+ this.trackingStates[matchedTargetIndex].isTracking = true;
246
+ this.trackingStates[matchedTargetIndex].currentModelViewTransform = modelViewTransform;
247
+ }
248
+ }
249
+
250
+ // tracking update
251
+ for (let i = 0; i < this.trackingStates.length; i++) {
252
+ const trackingState = this.trackingStates[i];
253
+
254
+ if (trackingState.isTracking) {
255
+ let modelViewTransform = await this._trackAndUpdate(
256
+ inputT,
257
+ trackingState.currentModelViewTransform,
258
+ i,
259
+ );
260
+ if (modelViewTransform === null) {
261
+ trackingState.isTracking = false;
262
+ } else {
263
+ trackingState.currentModelViewTransform = modelViewTransform;
264
+ }
265
+ }
266
+
267
+ // if not showing, then show it once it reaches warmup number of frames
268
+ if (!trackingState.showing) {
269
+ if (trackingState.isTracking) {
270
+ trackingState.trackMiss = 0;
271
+ trackingState.trackCount += 1;
272
+ if (trackingState.trackCount > this.warmupTolerance) {
273
+ trackingState.showing = true;
274
+ trackingState.trackingMatrix = null;
275
+ trackingState.filter.reset();
276
+ }
277
+ }
278
+ }
279
+
280
+ // if showing, then count miss, and hide it when reaches tolerance
281
+ if (trackingState.showing) {
282
+ if (!trackingState.isTracking) {
283
+ trackingState.trackCount = 0;
284
+ trackingState.trackMiss += 1;
285
+
286
+ if (trackingState.trackMiss > this.missTolerance) {
287
+ trackingState.showing = false;
288
+ trackingState.trackingMatrix = null;
289
+ this.onUpdate &&
290
+ this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: null });
291
+ }
292
+ } else {
293
+ trackingState.trackMiss = 0;
294
+ }
295
+ }
296
+
297
+ // if showing, then call onUpdate, with world matrix
298
+ if (trackingState.showing) {
299
+ const worldMatrix = this._glModelViewMatrix(trackingState.currentModelViewTransform, i);
300
+ trackingState.trackingMatrix = trackingState.filter.filter(Date.now(), worldMatrix);
301
+
302
+ let clone = [];
303
+ for (let j = 0; j < trackingState.trackingMatrix.length; j++) {
304
+ clone[j] = trackingState.trackingMatrix[j];
305
+ }
306
+
307
+ const isInputRotated =
308
+ input.width === this.inputHeight && input.height === this.inputWidth;
309
+ if (isInputRotated) {
310
+ clone = this.getRotatedZ90Matrix(clone);
311
+ }
312
+
313
+ this.onUpdate &&
314
+ this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone });
315
+ }
316
+ }
317
+
318
+ inputT.dispose();
319
+ this.onUpdate && this.onUpdate({ type: "processDone" });
320
+ await tf.nextFrame();
321
+ }
322
+ };
323
+ startProcessing();
324
+ }
325
+
326
+ stopProcessVideo() {
327
+ this.processingVideo = false;
328
+ }
329
+
330
+ async detect(input) {
331
+ const inputT = this.inputLoader.loadInput(input);
332
+ const { featurePoints, debugExtra } = await this.cropDetector.detect(inputT);
333
+ inputT.dispose();
334
+ return { featurePoints, debugExtra };
335
+ }
336
+
337
+ async match(featurePoints, targetIndex) {
338
+ const { modelViewTransform, debugExtra } = await this._workerMatch(featurePoints, [
339
+ targetIndex,
340
+ ]);
341
+ return { modelViewTransform, debugExtra };
342
+ }
343
+
344
+ async track(input, modelViewTransform, targetIndex) {
345
+ const inputT = this.inputLoader.loadInput(input);
346
+ const result = this.tracker.track(inputT, modelViewTransform, targetIndex);
347
+ inputT.dispose();
348
+ return result;
349
+ }
350
+
351
+ async trackUpdate(modelViewTransform, trackFeatures) {
352
+ if (trackFeatures.worldCoords.length < 4) return null;
353
+ const modelViewTransform2 = await this._workerTrackUpdate(modelViewTransform, trackFeatures);
354
+ return modelViewTransform2;
355
+ }
356
+
357
+ _workerMatch(featurePoints, targetIndexes) {
358
+ return new Promise(async (resolve, reject) => {
359
+ this.workerMatchDone = (data) => {
360
+ resolve({
361
+ targetIndex: data.targetIndex,
362
+ modelViewTransform: data.modelViewTransform,
363
+ debugExtra: data.debugExtra,
364
+ });
365
+ };
366
+ this.worker.postMessage({ type: "match", featurePoints: featurePoints, targetIndexes });
367
+ });
368
+ }
369
+
370
+ _workerTrackUpdate(modelViewTransform, trackingFeatures) {
371
+ return new Promise(async (resolve, reject) => {
372
+ this.workerTrackDone = (data) => {
373
+ resolve(data.modelViewTransform);
374
+ };
375
+ const { worldCoords, screenCoords } = trackingFeatures;
376
+ this.worker.postMessage({
377
+ type: "trackUpdate",
378
+ modelViewTransform,
379
+ worldCoords,
380
+ screenCoords,
381
+ });
382
+ });
383
+ }
384
+
385
+ _glModelViewMatrix(modelViewTransform, targetIndex) {
386
+ const height = this.markerDimensions[targetIndex][1];
387
+
388
+ // Question: can someone verify this interpreation is correct?
389
+ // I'm not very convinced, but more like trial and error and works......
390
+ //
391
+ // First, opengl has y coordinate system go from bottom to top, while the marker corrdinate goes from top to bottom,
392
+ // since the modelViewTransform is estimated in marker coordinate, we need to apply this transform before modelViewTransform
393
+ // I can see why y = h - y*, but why z = z* ? should we intepret it as rotate 90 deg along x-axis and then translate y by h?
394
+ //
395
+ // [1 0 0 0]
396
+ // [0 -1 0 h]
397
+ // [0 0 -1 0]
398
+ // [0 0 0 1]
399
+ //
400
+ // This is tested that if we reverse marker coordinate from bottom to top and estimate the modelViewTransform,
401
+ // then the above matrix is not necessary.
402
+ //
403
+ // Second, in opengl, positive z is away from camera, so we rotate 90 deg along x-axis after transform to fix the axis mismatch
404
+ // [1 1 0 0]
405
+ // [0 -1 0 0]
406
+ // [0 0 -1 0]
407
+ // [0 0 0 1]
408
+ //
409
+ // all together, the combined matrix is
410
+ //
411
+ // [1 1 0 0] [m00, m01, m02, m03] [1 0 0 0]
412
+ // [0 -1 0 0] [m10, m11, m12, m13] [0 -1 0 h]
413
+ // [0 0 -1 0] [m20, m21, m22, m23] [0 0 -1 0]
414
+ // [0 0 0 1] [ 0 0 0 1] [0 0 0 1]
415
+ //
416
+ // [ m00, -m01, -m02, (m01 * h + m03) ]
417
+ // [-m10, m11, m12, -(m11 * h + m13) ]
418
+ // = [-m20, m21, m22, -(m21 * h + m23) ]
419
+ // [ 0, 0, 0, 1 ]
420
+ //
421
+ //
422
+ // Finally, in threejs, matrix is represented in col by row, so we transpose it, and get below:
423
+ const openGLWorldMatrix = [
424
+ modelViewTransform[0][0],
425
+ -modelViewTransform[1][0],
426
+ -modelViewTransform[2][0],
427
+ 0,
428
+ -modelViewTransform[0][1],
429
+ modelViewTransform[1][1],
430
+ modelViewTransform[2][1],
431
+ 0,
432
+ -modelViewTransform[0][2],
433
+ modelViewTransform[1][2],
434
+ modelViewTransform[2][2],
435
+ 0,
436
+ modelViewTransform[0][1] * height + modelViewTransform[0][3],
437
+ -(modelViewTransform[1][1] * height + modelViewTransform[1][3]),
438
+ -(modelViewTransform[2][1] * height + modelViewTransform[2][3]),
439
+ 1,
440
+ ];
441
+ return openGLWorldMatrix;
442
+ }
443
+
444
+ // build openGL projection matrix
445
+ // ref: https://strawlab.org/2011/11/05/augmented-reality-with-OpenGL/
446
+ _glProjectionMatrix({ projectionTransform, width, height, near, far }) {
447
+ const proj = [
448
+ [
449
+ (2 * projectionTransform[0][0]) / width,
450
+ 0,
451
+ -((2 * projectionTransform[0][2]) / width - 1),
452
+ 0,
453
+ ],
454
+ [
455
+ 0,
456
+ (2 * projectionTransform[1][1]) / height,
457
+ -((2 * projectionTransform[1][2]) / height - 1),
458
+ 0,
459
+ ],
460
+ [0, 0, -(far + near) / (far - near), (-2 * far * near) / (far - near)],
461
+ [0, 0, -1, 0],
462
+ ];
463
+ const projMatrix = [];
464
+ for (let i = 0; i < 4; i++) {
465
+ for (let j = 0; j < 4; j++) {
466
+ projMatrix.push(proj[j][i]);
467
+ }
468
+ }
469
+ return projMatrix;
470
+ }
471
+ }
472
+
473
+ export { Controller };
@@ -0,0 +1,77 @@
1
+ import { Matcher } from "./matching/matcher.js";
2
+ import { Estimator } from "./estimation/estimator.js";
3
+
4
+ let projectionTransform = null;
5
+ let matchingDataList = null;
6
+ let debugMode = false;
7
+ let matcher = null;
8
+ let estimator = null;
9
+
10
+ onmessage = (msg) => {
11
+ const { data } = msg;
12
+
13
+ switch (data.type) {
14
+ case "setup":
15
+ projectionTransform = data.projectionTransform;
16
+ matchingDataList = data.matchingDataList;
17
+ debugMode = data.debugMode;
18
+ matcher = new Matcher(data.inputWidth, data.inputHeight, debugMode);
19
+ estimator = new Estimator(data.projectionTransform);
20
+ break;
21
+
22
+ case "match":
23
+ const interestedTargetIndexes = data.targetIndexes;
24
+
25
+ let matchedTargetIndex = -1;
26
+ let matchedModelViewTransform = null;
27
+ let matchedDebugExtra = null;
28
+
29
+ for (let i = 0; i < interestedTargetIndexes.length; i++) {
30
+ const matchingIndex = interestedTargetIndexes[i];
31
+
32
+ const { keyframeIndex, screenCoords, worldCoords, debugExtra } = matcher.matchDetection(
33
+ matchingDataList[matchingIndex],
34
+ data.featurePoints,
35
+ );
36
+ matchedDebugExtra = debugExtra;
37
+
38
+ if (keyframeIndex !== -1) {
39
+ const modelViewTransform = estimator.estimate({ screenCoords, worldCoords });
40
+
41
+ if (modelViewTransform) {
42
+ matchedTargetIndex = matchingIndex;
43
+ matchedModelViewTransform = modelViewTransform;
44
+ }
45
+ break;
46
+ }
47
+ }
48
+
49
+ postMessage({
50
+ type: "matchDone",
51
+ targetIndex: matchedTargetIndex,
52
+ modelViewTransform: matchedModelViewTransform,
53
+ debugExtra: matchedDebugExtra,
54
+ });
55
+ break;
56
+
57
+ case "trackUpdate":
58
+ const { modelViewTransform, worldCoords, screenCoords } = data;
59
+ const finalModelViewTransform = estimator.refineEstimate({
60
+ initialModelViewTransform: modelViewTransform,
61
+ worldCoords,
62
+ screenCoords,
63
+ });
64
+ postMessage({
65
+ type: "trackUpdateDone",
66
+ modelViewTransform: finalModelViewTransform,
67
+ });
68
+ break;
69
+
70
+ case "dispose":
71
+ close();
72
+ break;
73
+
74
+ default:
75
+ throw new Error(`Invalid message type '${data.type}'`);
76
+ }
77
+ };
@@ -0,0 +1,68 @@
1
+ import * as tf from "@tensorflow/tfjs";
2
+ import { Detector } from "./detector.js";
3
+ import { buildModelViewProjectionTransform, computeScreenCoordiate } from "../estimation/utils.js";
4
+
5
+ class CropDetector {
6
+ constructor(width, height, debugMode = false) {
7
+ this.debugMode = debugMode;
8
+ this.width = width;
9
+ this.height = height;
10
+
11
+ // nearest power of 2, min dimensions
12
+ let minDimension = Math.min(width, height) / 2;
13
+ let cropSize = Math.pow(2, Math.round(Math.log(minDimension) / Math.log(2)));
14
+ this.cropSize = cropSize;
15
+
16
+ this.detector = new Detector(cropSize, cropSize, debugMode);
17
+
18
+ this.kernelCaches = {};
19
+ this.lastRandomIndex = 4;
20
+ }
21
+
22
+ detect(inputImageT) {
23
+ // crop center
24
+ const startY = Math.floor(this.height / 2 - this.cropSize / 2);
25
+ const startX = Math.floor(this.width / 2 - this.cropSize / 2);
26
+ const result = this._detect(inputImageT, startX, startY);
27
+
28
+ if (this.debugMode) {
29
+ result.debugExtra.crop = { startX, startY, cropSize: this.cropSize };
30
+ }
31
+ return result;
32
+ }
33
+
34
+ detectMoving(inputImageT) {
35
+ // loop a few locations around center
36
+ const dx = this.lastRandomIndex % 3;
37
+ const dy = Math.floor(this.lastRandomIndex / 3);
38
+
39
+ let startY = Math.floor(this.height / 2 - this.cropSize + (dy * this.cropSize) / 2);
40
+ let startX = Math.floor(this.width / 2 - this.cropSize + (dx * this.cropSize) / 2);
41
+
42
+ if (startX < 0) startX = 0;
43
+ if (startY < 0) startY = 0;
44
+ if (startX >= this.width - this.cropSize) startX = this.width - this.cropSize - 1;
45
+ if (startY >= this.height - this.cropSize) startY = this.height - this.cropSize - 1;
46
+
47
+ this.lastRandomIndex = (this.lastRandomIndex + 1) % 9;
48
+
49
+ const result = this._detect(inputImageT, startX, startY);
50
+ return result;
51
+ }
52
+
53
+ _detect(inputImageT, startX, startY) {
54
+ const cropInputImageT = inputImageT.slice([startY, startX], [this.cropSize, this.cropSize]);
55
+ const { featurePoints, debugExtra } = this.detector.detect(cropInputImageT);
56
+ featurePoints.forEach((p) => {
57
+ p.x += startX;
58
+ p.y += startY;
59
+ });
60
+ if (this.debugMode) {
61
+ debugExtra.projectedImage = cropInputImageT.arraySync();
62
+ }
63
+ cropInputImageT.dispose();
64
+ return { featurePoints: featurePoints, debugExtra };
65
+ }
66
+ }
67
+
68
+ export { CropDetector };