@srsergio/taptapp-ar 1.0.9 → 1.0.10

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 (122) hide show
  1. package/dist/compiler/controller.d.ts +15 -22
  2. package/dist/compiler/controller.js +73 -92
  3. package/dist/compiler/detector/crop-detector.d.ts +20 -51
  4. package/dist/compiler/detector/crop-detector.js +21 -15
  5. package/dist/compiler/input-loader.d.ts +15 -17
  6. package/dist/compiler/input-loader.js +58 -76
  7. package/dist/compiler/matching/hamming-distance.js +4 -4
  8. package/dist/compiler/matching/matcher.js +2 -2
  9. package/dist/compiler/matching/matching.d.ts +2 -16
  10. package/dist/compiler/matching/matching.js +72 -60
  11. package/dist/compiler/offline-compiler.d.ts +9 -29
  12. package/dist/compiler/offline-compiler.js +38 -72
  13. package/dist/compiler/three.js +0 -4
  14. package/dist/compiler/tracker/tracker.d.ts +26 -12
  15. package/dist/compiler/tracker/tracker.js +158 -259
  16. package/package.json +1 -1
  17. package/src/compiler/controller.js +71 -93
  18. package/src/compiler/detector/crop-detector.js +26 -15
  19. package/src/compiler/input-loader.js +62 -88
  20. package/src/compiler/matching/hamming-distance.js +4 -4
  21. package/src/compiler/matching/hough.js +1 -1
  22. package/src/compiler/matching/matcher.js +2 -2
  23. package/src/compiler/matching/matching.js +80 -72
  24. package/src/compiler/offline-compiler.js +38 -75
  25. package/src/compiler/three.js +0 -4
  26. package/src/compiler/tracker/tracker.js +183 -283
  27. package/dist/compiler/compiler-base.d.ts +0 -8
  28. package/dist/compiler/compiler-base.js +0 -179
  29. package/dist/compiler/compiler.d.ts +0 -9
  30. package/dist/compiler/compiler.js +0 -24
  31. package/dist/compiler/compiler.worker.d.ts +0 -1
  32. package/dist/compiler/compiler.worker.js +0 -28
  33. package/dist/compiler/detector/detector.d.ts +0 -97
  34. package/dist/compiler/detector/detector.js +0 -1042
  35. package/dist/compiler/detector/kernels/cpu/binomialFilter.d.ts +0 -6
  36. package/dist/compiler/detector/kernels/cpu/binomialFilter.js +0 -50
  37. package/dist/compiler/detector/kernels/cpu/buildExtremas.d.ts +0 -6
  38. package/dist/compiler/detector/kernels/cpu/buildExtremas.js +0 -89
  39. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.d.ts +0 -7
  40. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.js +0 -79
  41. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.d.ts +0 -6
  42. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.js +0 -68
  43. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.d.ts +0 -6
  44. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.js +0 -57
  45. package/dist/compiler/detector/kernels/cpu/computeLocalization.d.ts +0 -6
  46. package/dist/compiler/detector/kernels/cpu/computeLocalization.js +0 -50
  47. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.d.ts +0 -6
  48. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.js +0 -100
  49. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.d.ts +0 -6
  50. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.js +0 -29
  51. package/dist/compiler/detector/kernels/cpu/extremaReduction.d.ts +0 -6
  52. package/dist/compiler/detector/kernels/cpu/extremaReduction.js +0 -50
  53. package/dist/compiler/detector/kernels/cpu/fakeShader.d.ts +0 -20
  54. package/dist/compiler/detector/kernels/cpu/fakeShader.js +0 -80
  55. package/dist/compiler/detector/kernels/cpu/index.d.ts +0 -1
  56. package/dist/compiler/detector/kernels/cpu/index.js +0 -25
  57. package/dist/compiler/detector/kernels/cpu/prune.d.ts +0 -7
  58. package/dist/compiler/detector/kernels/cpu/prune.js +0 -62
  59. package/dist/compiler/detector/kernels/cpu/smoothHistograms.d.ts +0 -6
  60. package/dist/compiler/detector/kernels/cpu/smoothHistograms.js +0 -47
  61. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.d.ts +0 -6
  62. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.js +0 -43
  63. package/dist/compiler/detector/kernels/index.d.ts +0 -1
  64. package/dist/compiler/detector/kernels/index.js +0 -2
  65. package/dist/compiler/detector/kernels/webgl/binomialFilter.d.ts +0 -6
  66. package/dist/compiler/detector/kernels/webgl/binomialFilter.js +0 -67
  67. package/dist/compiler/detector/kernels/webgl/buildExtremas.d.ts +0 -6
  68. package/dist/compiler/detector/kernels/webgl/buildExtremas.js +0 -101
  69. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.d.ts +0 -6
  70. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.js +0 -78
  71. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.d.ts +0 -6
  72. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.js +0 -86
  73. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.d.ts +0 -6
  74. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.js +0 -52
  75. package/dist/compiler/detector/kernels/webgl/computeLocalization.d.ts +0 -6
  76. package/dist/compiler/detector/kernels/webgl/computeLocalization.js +0 -58
  77. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.d.ts +0 -6
  78. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.js +0 -116
  79. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.d.ts +0 -6
  80. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.js +0 -46
  81. package/dist/compiler/detector/kernels/webgl/extremaReduction.d.ts +0 -6
  82. package/dist/compiler/detector/kernels/webgl/extremaReduction.js +0 -48
  83. package/dist/compiler/detector/kernels/webgl/index.d.ts +0 -1
  84. package/dist/compiler/detector/kernels/webgl/index.js +0 -25
  85. package/dist/compiler/detector/kernels/webgl/smoothHistograms.d.ts +0 -6
  86. package/dist/compiler/detector/kernels/webgl/smoothHistograms.js +0 -49
  87. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.d.ts +0 -6
  88. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.js +0 -56
  89. package/dist/compiler/tensorflow-setup.d.ts +0 -6
  90. package/dist/compiler/tensorflow-setup.js +0 -99
  91. package/src/compiler/compiler-base.js +0 -210
  92. package/src/compiler/compiler.js +0 -25
  93. package/src/compiler/compiler.worker.js +0 -30
  94. package/src/compiler/detector/detector.js +0 -1119
  95. package/src/compiler/detector/kernels/cpu/binomialFilter.js +0 -58
  96. package/src/compiler/detector/kernels/cpu/buildExtremas.js +0 -108
  97. package/src/compiler/detector/kernels/cpu/computeExtremaAngles.js +0 -91
  98. package/src/compiler/detector/kernels/cpu/computeExtremaFreak.js +0 -92
  99. package/src/compiler/detector/kernels/cpu/computeFreakDescriptors.js +0 -68
  100. package/src/compiler/detector/kernels/cpu/computeLocalization.js +0 -67
  101. package/src/compiler/detector/kernels/cpu/computeOrientationHistograms.js +0 -124
  102. package/src/compiler/detector/kernels/cpu/downsampleBilinear.js +0 -33
  103. package/src/compiler/detector/kernels/cpu/extremaReduction.js +0 -53
  104. package/src/compiler/detector/kernels/cpu/fakeShader.js +0 -88
  105. package/src/compiler/detector/kernels/cpu/index.js +0 -26
  106. package/src/compiler/detector/kernels/cpu/prune.js +0 -78
  107. package/src/compiler/detector/kernels/cpu/smoothHistograms.js +0 -57
  108. package/src/compiler/detector/kernels/cpu/upsampleBilinear.js +0 -51
  109. package/src/compiler/detector/kernels/index.js +0 -2
  110. package/src/compiler/detector/kernels/webgl/binomialFilter.js +0 -72
  111. package/src/compiler/detector/kernels/webgl/buildExtremas.js +0 -109
  112. package/src/compiler/detector/kernels/webgl/computeExtremaAngles.js +0 -82
  113. package/src/compiler/detector/kernels/webgl/computeExtremaFreak.js +0 -105
  114. package/src/compiler/detector/kernels/webgl/computeFreakDescriptors.js +0 -56
  115. package/src/compiler/detector/kernels/webgl/computeLocalization.js +0 -70
  116. package/src/compiler/detector/kernels/webgl/computeOrientationHistograms.js +0 -129
  117. package/src/compiler/detector/kernels/webgl/downsampleBilinear.js +0 -50
  118. package/src/compiler/detector/kernels/webgl/extremaReduction.js +0 -50
  119. package/src/compiler/detector/kernels/webgl/index.js +0 -26
  120. package/src/compiler/detector/kernels/webgl/smoothHistograms.js +0 -53
  121. package/src/compiler/detector/kernels/webgl/upsampleBilinear.js +0 -62
  122. package/src/compiler/tensorflow-setup.js +0 -116
@@ -1,4 +1,3 @@
1
- import * as tf from "@tensorflow/tfjs";
2
1
  import { buildModelViewProjectionTransform, computeScreenCoordiate } from "../estimation/utils.js";
3
2
  const AR2_DEFAULT_TS = 6;
4
3
  const AR2_DEFAULT_TS_GAP = 1;
@@ -6,58 +5,57 @@ const AR2_SEARCH_SIZE = 10;
6
5
  const AR2_SEARCH_GAP = 1;
7
6
  const AR2_SIM_THRESH = 0.8;
8
7
  const TRACKING_KEYFRAME = 0; // 0: 128px (optimized)
9
- // For some mobile device, only 16bit floating point texture is supported
10
- // ref: https://www.tensorflow.org/js/guide/platform_environment#precision
11
- // Empirical results shows that modelViewProjectTransform can go up beyond that, resulting in error
12
- // We get around this by dividing the transform matrix by 1000, and then multiply back inside webgl program
13
- const PRECISION_ADJUST = 1000;
14
8
  class Tracker {
15
- constructor(markerDimensions, trackingDataList, projectionTransform, debugMode = false) {
9
+ constructor(markerDimensions, trackingDataList, projectionTransform, inputWidth, inputHeight, debugMode = false) {
16
10
  this.markerDimensions = markerDimensions;
17
11
  this.trackingDataList = trackingDataList;
18
12
  this.projectionTransform = projectionTransform;
13
+ this.inputWidth = inputWidth;
14
+ this.inputHeight = inputHeight;
19
15
  this.debugMode = debugMode;
20
16
  this.trackingKeyframeList = [];
21
17
  for (let i = 0; i < trackingDataList.length; i++) {
22
18
  this.trackingKeyframeList.push(trackingDataList[i][TRACKING_KEYFRAME]);
23
19
  }
24
- // prebuild feature and marker pixel tensors
25
- let maxCount = 0;
20
+ // Prebuild TypedArrays for features and pixels
21
+ this.prebuiltData = [];
26
22
  for (let i = 0; i < this.trackingKeyframeList.length; i++) {
27
- maxCount = Math.max(maxCount, this.trackingKeyframeList[i].px.length);
28
- }
29
- this.featurePointsListT = [];
30
- this.imagePixelsListT = [];
31
- this.imagePropertiesListT = [];
32
- for (let i = 0; i < this.trackingKeyframeList.length; i++) {
33
- const { featurePoints, imagePixels, imageProperties } = this._prebuild(this.trackingKeyframeList[i], maxCount);
34
- this.featurePointsListT[i] = featurePoints;
35
- this.imagePixelsListT[i] = imagePixels;
36
- this.imagePropertiesListT[i] = imageProperties;
23
+ const keyframe = this.trackingKeyframeList[i];
24
+ this.prebuiltData[i] = {
25
+ px: new Float32Array(keyframe.px),
26
+ py: new Float32Array(keyframe.py),
27
+ data: new Uint8Array(keyframe.d),
28
+ width: keyframe.w,
29
+ height: keyframe.h,
30
+ scale: keyframe.s,
31
+ // Recyclable projected image buffer
32
+ projectedImage: new Float32Array(keyframe.w * keyframe.h)
33
+ };
37
34
  }
38
- this.kernelCaches = {};
35
+ // Pre-allocate template data buffer to avoid garbage collection
36
+ const templateOneSize = AR2_DEFAULT_TS;
37
+ const templateSize = templateOneSize * 2 + 1;
38
+ this.templateBuffer = new Float32Array(templateSize * templateSize);
39
39
  }
40
- dummyRun(inputT) {
40
+ dummyRun(inputData) {
41
41
  let transform = [
42
- [1, 1, 1, 1],
43
- [1, 1, 1, 1],
44
- [1, 1, 1, 1],
42
+ [1, 0, 0, 0],
43
+ [0, 1, 0, 0],
44
+ [0, 0, 1, 0],
45
45
  ];
46
- for (let targetIndex = 0; targetIndex < this.featurePointsListT.length; targetIndex++) {
47
- this.track(inputT, transform, targetIndex);
46
+ for (let targetIndex = 0; targetIndex < this.trackingKeyframeList.length; targetIndex++) {
47
+ this.track(inputData, transform, targetIndex);
48
48
  }
49
49
  }
50
- track(inputImageT, lastModelViewTransform, targetIndex) {
50
+ track(inputData, lastModelViewTransform, targetIndex) {
51
51
  let debugExtra = {};
52
52
  const modelViewProjectionTransform = buildModelViewProjectionTransform(this.projectionTransform, lastModelViewTransform);
53
- const modelViewProjectionTransformT = this._buildAdjustedModelViewTransform(modelViewProjectionTransform);
54
- const featurePointsT = this.featurePointsListT[targetIndex];
55
- const imagePixelsT = this.imagePixelsListT[targetIndex];
56
- const imagePropertiesT = this.imagePropertiesListT[targetIndex];
57
- const projectedImageT = this._computeProjection(modelViewProjectionTransformT, inputImageT, targetIndex);
58
- const { matchingPointsT, simT } = this._computeMatching(featurePointsT, imagePixelsT, imagePropertiesT, projectedImageT);
59
- const matchingPoints = matchingPointsT.arraySync();
60
- const sim = simT.arraySync();
53
+ const prebuilt = this.prebuiltData[targetIndex];
54
+ // 1. Compute Projection (Warping)
55
+ this._computeProjection(modelViewProjectionTransform, inputData, prebuilt);
56
+ const projectedImage = prebuilt.projectedImage;
57
+ // 2. Compute Matching (NCC)
58
+ const { matchingPoints, sim } = this._computeMatching(prebuilt, projectedImage);
61
59
  const trackingFrame = this.trackingKeyframeList[targetIndex];
62
60
  const worldCoords = [];
63
61
  const screenCoords = [];
@@ -77,246 +75,147 @@ class Tracker {
77
75
  }
78
76
  if (this.debugMode) {
79
77
  debugExtra = {
80
- projectedImage: projectedImageT.arraySync(),
81
- matchingPoints: matchingPointsT.arraySync(),
78
+ projectedImage: Array.from(projectedImage),
79
+ matchingPoints,
82
80
  goodTrack,
83
81
  trackedPoints: screenCoords,
84
82
  };
85
83
  }
86
- // tensors cleanup
87
- modelViewProjectionTransformT.dispose();
88
- projectedImageT.dispose();
89
- matchingPointsT.dispose();
90
- simT.dispose();
91
84
  return { worldCoords, screenCoords, debugExtra };
92
85
  }
93
- _computeMatching(featurePointsT, imagePixelsT, imagePropertiesT, projectedImageT) {
86
+ /**
87
+ * Pure JS implementation of NCC matching
88
+ */
89
+ _computeMatching(prebuilt, projectedImage) {
90
+ const { px, py, scale, data: markerPixels, width: markerWidth, height: markerHeight } = prebuilt;
91
+ const featureCount = px.length;
94
92
  const templateOneSize = AR2_DEFAULT_TS;
95
93
  const templateSize = templateOneSize * 2 + 1;
96
- const templateGap = AR2_DEFAULT_TS_GAP;
97
- const searchOneSize = AR2_SEARCH_SIZE * templateGap;
94
+ const nPixels = templateSize * templateSize;
95
+ const oneOverNPixels = 1.0 / nPixels;
96
+ const searchOneSize = AR2_SEARCH_SIZE;
98
97
  const searchGap = AR2_SEARCH_GAP;
99
- const searchSize = searchOneSize * 2 + 1;
100
- const targetHeight = projectedImageT.shape[0];
101
- const targetWidth = projectedImageT.shape[1];
102
- const featureCount = featurePointsT.shape[0];
103
- if (!this.kernelCaches.computeMatching) {
104
- const kernel1 = {
105
- variableNames: ["features", "markerPixels", "markerProperties", "targetPixels"],
106
- outputShape: [featureCount, searchSize * searchSize],
107
- userCode: `
108
- void main() {
109
- ivec2 coords = getOutputCoords();
110
-
111
- int featureIndex = coords[0];
112
- int searchOffsetIndex = coords[1];
113
-
114
- int markerWidth = int(getMarkerProperties(0));
115
- int markerHeight = int(getMarkerProperties(1));
116
- float markerScale = getMarkerProperties(2);
117
-
118
- int searchOffsetX = imod(searchOffsetIndex, ${searchSize}) * ${searchGap};
119
- int searchOffsetY = searchOffsetIndex / ${searchSize} * ${searchGap};
120
-
121
- int sCenterX = int(getFeatures(featureIndex, 0) * markerScale);
122
- int sCenterY = int(getFeatures(featureIndex, 1) * markerScale);
123
-
124
- int sx = sCenterX + searchOffsetX - ${searchOneSize};
125
- int sy = sCenterY + searchOffsetY - ${searchOneSize};
126
-
127
- if (sx < ${templateOneSize} || sx >= (${targetWidth} - ${templateOneSize}) || sy < ${templateOneSize} || sy >= (${targetHeight} - ${templateOneSize})) {
128
- setOutput(-2.);
129
- }
130
- else {
131
- float sumPoint = 0.;
132
- float sumPointSquare = 0.;
133
- float sumTemplate = 0.;
134
- float sumTemplateSquare = 0.;
135
- float sumPointTemplate = 0.;
136
-
137
- for (int templateOffsetY = 0; templateOffsetY < ${templateSize}; templateOffsetY++) {
138
- for (int templateOffsetX = 0; templateOffsetX < ${templateSize}; templateOffsetX++) {
139
- int fx2 = sCenterX + templateOffsetX - ${templateOneSize};
140
- int fy2 = sCenterY + templateOffsetY - ${templateOneSize};
141
-
142
- int sx2 = sx + templateOffsetX - ${templateOneSize};
143
- int sy2 = sy + templateOffsetY - ${templateOneSize};
144
-
145
- int markerPixelIndex = fy2 * markerWidth + fx2;
146
- float markerPixel = getMarkerPixels(markerPixelIndex);
147
- float targetPixel = getTargetPixels(sy2, sx2);
148
-
149
- sumTemplate += markerPixel;
150
- sumTemplateSquare += markerPixel * markerPixel;
151
- sumPoint += targetPixel;
152
- sumPointSquare += targetPixel * targetPixel;
153
- sumPointTemplate += targetPixel * markerPixel;
154
- }
155
- }
156
-
157
- // Normalized cross-correlation
158
- // !important divide first avoid overflow (e.g. sumPoint / count * sumPoint)
159
- float count = float(${templateSize} * ${templateSize});
160
- float pointVariance = sqrt(sumPointSquare - sumPoint / count * sumPoint);
161
- float templateVariance = sqrt(sumTemplateSquare - sumTemplate / count * sumTemplate);
162
-
163
- if (pointVariance < 0.0000001) {
164
- setOutput(-3.);
165
- } else if (templateVariance < 0.0000001) {
166
- //setOutput(sumTemplate);
167
- setOutput(-4.);
168
- } else {
169
- sumPointTemplate -= sumPoint / count * sumTemplate;
170
- float sim = sumPointTemplate / pointVariance / templateVariance;
171
- setOutput(sim);
172
- }
173
- }
174
- }
175
- `,
176
- };
177
- const kernel2 = {
178
- variableNames: ["featurePoints", "markerProperties", "maxIndex"],
179
- outputShape: [featureCount, 2], // [x, y]
180
- userCode: `
181
- void main() {
182
- ivec2 coords = getOutputCoords();
183
-
184
- float markerScale = getMarkerProperties(2);
185
-
186
- int featureIndex = coords[0];
187
-
188
- int maxIndex = int(getMaxIndex(featureIndex));
189
- int searchLocationIndex = maxIndex / ${searchSize * searchSize};
190
- int searchOffsetIndex = imod(maxIndex, ${searchSize * searchSize});
191
-
192
- if (coords[1] == 0) {
193
- int searchOffsetX = imod(searchOffsetIndex, ${searchSize}) * ${searchGap};
194
- setOutput(getFeaturePoints(featureIndex, 0) + float(searchOffsetX - ${searchOneSize}) / markerScale);
195
- }
196
- else if (coords[1] == 1) {
197
- int searchOffsetY = searchOffsetIndex / ${searchSize} * ${searchGap};
198
- setOutput(getFeaturePoints(featureIndex, 1) + float(searchOffsetY - ${searchOneSize}) / markerScale);
199
- }
200
- }
201
- `,
202
- };
203
- const kernel3 = {
204
- variableNames: ["sims", "maxIndex"],
205
- outputShape: [featureCount],
206
- userCode: `
207
- void main() {
208
- int featureIndex = getOutputCoords();
209
- int maxIndex = int(getMaxIndex(featureIndex));
210
- setOutput(getSims(featureIndex, maxIndex));
211
- }
212
- `,
213
- };
214
- this.kernelCaches.computeMatching = [kernel1, kernel2, kernel3];
215
- }
216
- return tf.tidy(() => {
217
- const programs = this.kernelCaches.computeMatching;
218
- const allSims = this._compileAndRun(programs[0], [
219
- featurePointsT,
220
- imagePixelsT,
221
- imagePropertiesT,
222
- projectedImageT,
223
- ]);
224
- const maxIndex = allSims.argMax(1);
225
- const matchingPointsT = this._compileAndRun(programs[1], [
226
- featurePointsT,
227
- imagePropertiesT,
228
- maxIndex,
229
- ]);
230
- const simT = this._compileAndRun(programs[2], [allSims, maxIndex]);
231
- return { matchingPointsT, simT };
232
- });
233
- }
234
- _computeProjection(modelViewProjectionTransformT, inputImageT, targetIndex) {
235
- const markerWidth = this.trackingKeyframeList[targetIndex].width;
236
- const markerHeight = this.trackingKeyframeList[targetIndex].height;
237
- const markerScale = this.trackingKeyframeList[targetIndex].scale;
238
- const kernelKey = markerWidth + "-" + markerHeight + "-" + markerScale;
239
- if (!this.kernelCaches.computeProjection) {
240
- this.kernelCaches.computeProjection = {};
241
- }
242
- if (!this.kernelCaches.computeProjection[kernelKey]) {
243
- const kernel = {
244
- variableNames: ["M", "pixel"],
245
- outputShape: [markerHeight, markerWidth],
246
- userCode: `
247
- void main() {
248
- ivec2 coords = getOutputCoords();
249
-
250
- float m00 = getM(0, 0) * ${PRECISION_ADJUST}.;
251
- float m01 = getM(0, 1) * ${PRECISION_ADJUST}.;
252
- float m03 = getM(0, 3) * ${PRECISION_ADJUST}.;
253
- float m10 = getM(1, 0) * ${PRECISION_ADJUST}.;
254
- float m11 = getM(1, 1) * ${PRECISION_ADJUST}.;
255
- float m13 = getM(1, 3) * ${PRECISION_ADJUST}.;
256
- float m20 = getM(2, 0) * ${PRECISION_ADJUST}.;
257
- float m21 = getM(2, 1) * ${PRECISION_ADJUST}.;
258
- float m23 = getM(2, 3) * ${PRECISION_ADJUST}.;
259
-
260
- float y = float(coords[0]) / float(${markerScale});
261
- float x = float(coords[1]) / float(${markerScale});
262
- float uz = (x * m20) + (y * m21) + m23;
263
- float oneOverUz = 1. / uz;
264
-
265
- float ux = (x * m00) + (y * m01) + m03;
266
- float uy = (x * m10) + (y * m11) + m13;
267
-
268
- ux = floor(ux * oneOverUz + 0.5);
269
- uy = floor(uy * oneOverUz + 0.5);
270
- setOutput(getPixel(int(uy), int(ux)));
271
- }
272
- `,
273
- };
274
- this.kernelCaches.computeProjection[kernelKey] = kernel;
275
- }
276
- return tf.tidy(() => {
277
- const program = this.kernelCaches.computeProjection[kernelKey];
278
- const result = this._compileAndRun(program, [modelViewProjectionTransformT, inputImageT]);
279
- return result;
280
- });
281
- }
282
- _buildAdjustedModelViewTransform(modelViewProjectionTransform) {
283
- return tf.tidy(() => {
284
- let modelViewProjectionTransformAdjusted = [];
285
- for (let i = 0; i < modelViewProjectionTransform.length; i++) {
286
- modelViewProjectionTransformAdjusted.push([]);
287
- for (let j = 0; j < modelViewProjectionTransform[i].length; j++) {
288
- modelViewProjectionTransformAdjusted[i].push(modelViewProjectionTransform[i][j] / PRECISION_ADJUST);
98
+ const matchingPoints = [];
99
+ const sims = new Float32Array(featureCount);
100
+ // Reuse shared template buffer
101
+ const templateData = this.templateBuffer;
102
+ for (let f = 0; f < featureCount; f++) {
103
+ const sCenterX = (px[f] + 0.5) | 0; // Faster Math.round
104
+ const sCenterY = (py[f] + 0.5) | 0;
105
+ let bestSim = -1.0;
106
+ let bestX = px[f] / scale;
107
+ let bestY = py[f] / scale;
108
+ // Pre-calculate template stats for this feature
109
+ let sumT = 0;
110
+ let sumT2 = 0;
111
+ let tidx = 0;
112
+ for (let ty = -templateOneSize; ty <= templateOneSize; ty++) {
113
+ const fyOffset = (sCenterY + ty) * markerWidth;
114
+ for (let tx = -templateOneSize; tx <= templateOneSize; tx++) {
115
+ const val = markerPixels[fyOffset + sCenterX + tx];
116
+ templateData[tidx++] = val;
117
+ sumT += val;
118
+ sumT2 += val * val;
119
+ }
120
+ }
121
+ const varT = Math.sqrt(Math.max(0, sumT2 - (sumT * sumT) * oneOverNPixels));
122
+ if (varT < 0.0001) {
123
+ sims[f] = -1.0;
124
+ matchingPoints.push([bestX, bestY]);
125
+ continue;
126
+ }
127
+ // Search in projected image
128
+ for (let sy = -searchOneSize; sy <= searchOneSize; sy += searchGap) {
129
+ const cy = sCenterY + sy;
130
+ if (cy < templateOneSize || cy >= markerHeight - templateOneSize)
131
+ continue;
132
+ for (let sx = -searchOneSize; sx <= searchOneSize; sx += searchGap) {
133
+ const cx = sCenterX + sx;
134
+ if (cx < templateOneSize || cx >= markerWidth - templateOneSize)
135
+ continue;
136
+ let sumI = 0;
137
+ let sumI2 = 0;
138
+ let sumIT = 0;
139
+ for (let ty = -templateOneSize; ty <= templateOneSize; ty++) {
140
+ const rowOffset = (cy + ty) * markerWidth;
141
+ const tRowOffset = (ty + templateOneSize) * templateSize;
142
+ for (let tx = -templateOneSize; tx <= templateOneSize; tx++) {
143
+ const valI = projectedImage[rowOffset + (cx + tx)];
144
+ const valT = templateData[tRowOffset + (tx + templateOneSize)];
145
+ sumI += valI;
146
+ sumI2 += valI * valI;
147
+ sumIT += valI * valT;
148
+ }
149
+ }
150
+ const varI = Math.sqrt(Math.max(0, sumI2 - (sumI * sumI) * oneOverNPixels));
151
+ if (varI < 0.0001)
152
+ continue;
153
+ const sim = (sumIT - (sumI * sumT) * oneOverNPixels) / (varI * varT);
154
+ if (sim > bestSim) {
155
+ bestSim = sim;
156
+ bestX = cx / scale;
157
+ bestY = cy / scale;
158
+ }
289
159
  }
290
160
  }
291
- const t = tf.tensor(modelViewProjectionTransformAdjusted, [3, 4]);
292
- return t;
293
- });
161
+ sims[f] = bestSim;
162
+ matchingPoints.push([bestX, bestY]);
163
+ }
164
+ return { matchingPoints, sim: sims };
294
165
  }
295
- _prebuild(trackingFrame, maxCount) {
296
- return tf.tidy(() => {
297
- const { px, py, s: scale, d: data, w: width, h: height } = trackingFrame;
298
- const p = [];
299
- for (let k = 0; k < maxCount; k++) {
300
- if (k < px.length) {
301
- p.push([px[k] / scale, py[k] / scale]);
166
+ /**
167
+ * Pure JS implementation of Bilinear Warping
168
+ */
169
+ _computeProjection(M, inputData, prebuilt) {
170
+ const { width: markerWidth, height: markerHeight, scale: markerScale, projectedImage } = prebuilt;
171
+ const invScale = 1.0 / markerScale;
172
+ const inputW = this.inputWidth;
173
+ const inputH = this.inputHeight;
174
+ const m00 = M[0][0];
175
+ const m01 = M[0][1];
176
+ const m03 = M[0][3];
177
+ const m10 = M[1][0];
178
+ const m11 = M[1][1];
179
+ const m13 = M[1][3];
180
+ const m20 = M[2][0];
181
+ const m21 = M[2][1];
182
+ const m23 = M[2][3];
183
+ for (let j = 0; j < markerHeight; j++) {
184
+ const y = j * invScale;
185
+ const jOffset = j * markerWidth;
186
+ for (let i = 0; i < markerWidth; i++) {
187
+ const x = i * invScale;
188
+ const uz = (x * m20) + (y * m21) + m23;
189
+ const invZ = 1.0 / uz;
190
+ const ux = ((x * m00) + (y * m01) + m03) * invZ;
191
+ const uy = ((x * m10) + (y * m11) + m13) * invZ;
192
+ // Bilinear interpolation
193
+ const x0 = ux | 0; // Faster Math.floor
194
+ const y0 = uy | 0;
195
+ const x1 = x0 + 1;
196
+ const y1 = y0 + 1;
197
+ if (x0 >= 0 && x1 < inputW && y0 >= 0 && y1 < inputH) {
198
+ const dx = ux - x0;
199
+ const dy = uy - y0;
200
+ const omDx = 1.0 - dx;
201
+ const omDy = 1.0 - dy;
202
+ const y0Offset = y0 * inputW;
203
+ const y1Offset = y1 * inputW;
204
+ const v00 = inputData[y0Offset + x0];
205
+ const v10 = inputData[y0Offset + x1];
206
+ const v01 = inputData[y1Offset + x0];
207
+ const v11 = inputData[y1Offset + x1];
208
+ projectedImage[jOffset + i] =
209
+ v00 * omDx * omDy +
210
+ v10 * dx * omDy +
211
+ v01 * omDx * dy +
212
+ v11 * dx * dy;
302
213
  }
303
214
  else {
304
- p.push([-1, -1]);
215
+ projectedImage[jOffset + i] = 0;
305
216
  }
306
217
  }
307
- const imagePixels = tf.tensor(data, [width * height]);
308
- const imageProperties = tf.tensor([width, height, scale], [3]);
309
- const featurePoints = tf.tensor(p, [p.length, 2], "float32");
310
- return {
311
- featurePoints,
312
- imagePixels,
313
- imageProperties,
314
- };
315
- });
316
- }
317
- _compileAndRun(program, inputs) {
318
- const outInfo = tf.backend().compileAndRun(program, inputs);
319
- return tf.engine().makeTensor(outInfo.dataId, outInfo.shape, outInfo.dtype);
218
+ }
320
219
  }
321
220
  }
322
221
  export { Tracker };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@srsergio/taptapp-ar",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "AR Compiler for Node.js and Browser",
5
5
  "repository": {
6
6
  "type": "git",