@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.
- 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 +9 -29
- package/dist/compiler/offline-compiler.js +38 -72
- 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/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 +38 -75
- package/src/compiler/three.js +0 -4
- package/src/compiler/tracker/tracker.js +183 -283
- 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
|
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
|
-
//
|
|
25
|
-
|
|
20
|
+
// Prebuild TypedArrays for features and pixels
|
|
21
|
+
this.prebuiltData = [];
|
|
26
22
|
for (let i = 0; i < this.trackingKeyframeList.length; i++) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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(
|
|
40
|
+
dummyRun(inputData) {
|
|
41
41
|
let transform = [
|
|
42
|
-
[1,
|
|
43
|
-
[
|
|
44
|
-
[
|
|
42
|
+
[1, 0, 0, 0],
|
|
43
|
+
[0, 1, 0, 0],
|
|
44
|
+
[0, 0, 1, 0],
|
|
45
45
|
];
|
|
46
|
-
for (let targetIndex = 0; targetIndex < this.
|
|
47
|
-
this.track(
|
|
46
|
+
for (let targetIndex = 0; targetIndex < this.trackingKeyframeList.length; targetIndex++) {
|
|
47
|
+
this.track(inputData, transform, targetIndex);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
track(
|
|
50
|
+
track(inputData, lastModelViewTransform, targetIndex) {
|
|
51
51
|
let debugExtra = {};
|
|
52
52
|
const modelViewProjectionTransform = buildModelViewProjectionTransform(this.projectionTransform, lastModelViewTransform);
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
const {
|
|
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:
|
|
81
|
-
matchingPoints
|
|
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
|
-
|
|
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
|
|
97
|
-
const
|
|
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
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
292
|
-
|
|
293
|
-
}
|
|
161
|
+
sims[f] = bestSim;
|
|
162
|
+
matchingPoints.push([bestX, bestY]);
|
|
163
|
+
}
|
|
164
|
+
return { matchingPoints, sim: sims };
|
|
294
165
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
-
|
|
215
|
+
projectedImage[jOffset + i] = 0;
|
|
305
216
|
}
|
|
306
217
|
}
|
|
307
|
-
|
|
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 };
|