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