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