@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,13 +1,20 @@
|
|
|
1
|
-
import { memory, nextFrame } from "@tensorflow/tfjs";
|
|
2
|
-
|
|
3
|
-
const tf = { memory, nextFrame };
|
|
4
|
-
import ControllerWorker from "./controller.worker.js?worker&inline";
|
|
5
1
|
import { Tracker } from "./tracker/tracker.js";
|
|
6
2
|
import { CropDetector } from "./detector/crop-detector.js";
|
|
7
|
-
import { Compiler } from "./compiler.js";
|
|
3
|
+
import { OfflineCompiler as Compiler } from "./offline-compiler.js";
|
|
8
4
|
import { InputLoader } from "./input-loader.js";
|
|
9
5
|
import { OneEuroFilter } from "../libs/one-euro-filter.js";
|
|
10
6
|
|
|
7
|
+
let ControllerWorker;
|
|
8
|
+
|
|
9
|
+
// Conditional import for worker to avoid crash in non-vite environments
|
|
10
|
+
try {
|
|
11
|
+
const workerModule = await import("./controller.worker.js?worker&inline");
|
|
12
|
+
ControllerWorker = workerModule.default;
|
|
13
|
+
} catch (e) {
|
|
14
|
+
// Fallback for tests or other environments
|
|
15
|
+
ControllerWorker = null;
|
|
16
|
+
}
|
|
17
|
+
|
|
11
18
|
const DEFAULT_FILTER_CUTOFF = 0.001; // 1Hz. time period in milliseconds
|
|
12
19
|
const DEFAULT_FILTER_BETA = 1000;
|
|
13
20
|
const DEFAULT_WARMUP_TOLERANCE = 5;
|
|
@@ -24,6 +31,7 @@ class Controller {
|
|
|
24
31
|
missTolerance = null,
|
|
25
32
|
filterMinCF = null,
|
|
26
33
|
filterBeta = null,
|
|
34
|
+
worker = null, // Allow custom worker injection
|
|
27
35
|
}) {
|
|
28
36
|
this.inputWidth = inputWidth;
|
|
29
37
|
this.inputHeight = inputHeight;
|
|
@@ -40,14 +48,14 @@ class Controller {
|
|
|
40
48
|
this.processingVideo = false;
|
|
41
49
|
this.interestedTargetIndex = -1;
|
|
42
50
|
this.trackingStates = [];
|
|
51
|
+
this.worker = worker;
|
|
52
|
+
if (this.worker) this._setupWorkerListener();
|
|
43
53
|
|
|
44
54
|
const near = 10;
|
|
45
55
|
const far = 100000;
|
|
46
|
-
const fovy = (45.0 * Math.PI) / 180;
|
|
56
|
+
const fovy = (45.0 * Math.PI) / 180;
|
|
47
57
|
const f = this.inputHeight / 2 / Math.tan(fovy / 2);
|
|
48
|
-
|
|
49
|
-
// K = [ 0 fx cy]
|
|
50
|
-
// [ 0 0 1]
|
|
58
|
+
|
|
51
59
|
this.projectionTransform = [
|
|
52
60
|
[f, 0, this.inputWidth / 2],
|
|
53
61
|
[0, f, this.inputHeight / 2],
|
|
@@ -61,10 +69,10 @@ class Controller {
|
|
|
61
69
|
near: near,
|
|
62
70
|
far: far,
|
|
63
71
|
});
|
|
72
|
+
}
|
|
64
73
|
|
|
65
|
-
|
|
66
|
-
this.
|
|
67
|
-
this.workerTrackDone = null;
|
|
74
|
+
_setupWorkerListener() {
|
|
75
|
+
if (!this.worker) return;
|
|
68
76
|
this.worker.onmessage = (e) => {
|
|
69
77
|
if (e.data.type === "matchDone" && this.workerMatchDone !== null) {
|
|
70
78
|
this.workerMatchDone(e.data);
|
|
@@ -75,9 +83,12 @@ class Controller {
|
|
|
75
83
|
};
|
|
76
84
|
}
|
|
77
85
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
_ensureWorker() {
|
|
87
|
+
if (this.worker) return;
|
|
88
|
+
if (ControllerWorker) {
|
|
89
|
+
this.worker = new ControllerWorker();
|
|
90
|
+
this._setupWorkerListener();
|
|
91
|
+
}
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
addImageTargets(fileURL) {
|
|
@@ -97,9 +108,10 @@ class Controller {
|
|
|
97
108
|
const matchingDataList = [];
|
|
98
109
|
const dimensions = [];
|
|
99
110
|
for (let i = 0; i < dataList.length; i++) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
const item = dataList[i];
|
|
112
|
+
matchingDataList.push(item.matchingData);
|
|
113
|
+
trackingDataList.push(item.trackingData);
|
|
114
|
+
dimensions.push([item.targetImage.width, item.targetImage.height]);
|
|
103
115
|
}
|
|
104
116
|
|
|
105
117
|
this.tracker = new Tracker(
|
|
@@ -111,33 +123,34 @@ class Controller {
|
|
|
111
123
|
this.debugMode,
|
|
112
124
|
);
|
|
113
125
|
|
|
114
|
-
this.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
126
|
+
this._ensureWorker();
|
|
127
|
+
if (this.worker) {
|
|
128
|
+
this.worker.postMessage({
|
|
129
|
+
type: "setup",
|
|
130
|
+
inputWidth: this.inputWidth,
|
|
131
|
+
inputHeight: this.inputHeight,
|
|
132
|
+
projectionTransform: this.projectionTransform,
|
|
133
|
+
debugMode: this.debugMode,
|
|
134
|
+
matchingDataList,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
122
137
|
|
|
123
138
|
this.markerDimensions = dimensions;
|
|
124
|
-
|
|
125
|
-
return { dimensions: dimensions, matchingDataList, trackingDataList };
|
|
139
|
+
return { dimensions, matchingDataList, trackingDataList };
|
|
126
140
|
}
|
|
127
141
|
|
|
128
142
|
dispose() {
|
|
129
143
|
this.stopProcessVideo();
|
|
130
|
-
this.worker
|
|
131
|
-
type: "dispose"
|
|
132
|
-
|
|
144
|
+
if (this.worker) {
|
|
145
|
+
this.worker.postMessage({ type: "dispose" });
|
|
146
|
+
this.worker = null;
|
|
147
|
+
}
|
|
133
148
|
}
|
|
134
149
|
|
|
135
|
-
// warm up gpu - build kernels is slow
|
|
136
150
|
dummyRun(input) {
|
|
137
|
-
const
|
|
138
|
-
this.cropDetector.detect(
|
|
139
|
-
this.tracker.dummyRun(
|
|
140
|
-
inputT.dispose();
|
|
151
|
+
const inputData = this.inputLoader.loadInput(input);
|
|
152
|
+
this.cropDetector.detect(inputData);
|
|
153
|
+
this.tracker.dummyRun(inputData);
|
|
141
154
|
}
|
|
142
155
|
|
|
143
156
|
getProjectionMatrix() {
|
|
@@ -176,17 +189,17 @@ class Controller {
|
|
|
176
189
|
return this._glModelViewMatrix(modelViewTransform, targetIndex);
|
|
177
190
|
}
|
|
178
191
|
|
|
179
|
-
async _detectAndMatch(
|
|
180
|
-
const { featurePoints } = this.cropDetector.detectMoving(
|
|
192
|
+
async _detectAndMatch(inputData, targetIndexes) {
|
|
193
|
+
const { featurePoints } = this.cropDetector.detectMoving(inputData);
|
|
181
194
|
const { targetIndex: matchedTargetIndex, modelViewTransform } = await this._workerMatch(
|
|
182
195
|
featurePoints,
|
|
183
196
|
targetIndexes,
|
|
184
197
|
);
|
|
185
198
|
return { targetIndex: matchedTargetIndex, modelViewTransform };
|
|
186
199
|
}
|
|
187
|
-
async _trackAndUpdate(
|
|
200
|
+
async _trackAndUpdate(inputData, lastModelViewTransform, targetIndex) {
|
|
188
201
|
const { worldCoords, screenCoords } = this.tracker.track(
|
|
189
|
-
|
|
202
|
+
inputData,
|
|
190
203
|
lastModelViewTransform,
|
|
191
204
|
targetIndex,
|
|
192
205
|
);
|
|
@@ -213,14 +226,13 @@ class Controller {
|
|
|
213
226
|
trackMiss: 0,
|
|
214
227
|
filter: new OneEuroFilter({ minCutOff: this.filterMinCF, beta: this.filterBeta }),
|
|
215
228
|
});
|
|
216
|
-
//console.log("filterMinCF", this.filterMinCF, this.filterBeta);
|
|
217
229
|
}
|
|
218
230
|
|
|
219
231
|
const startProcessing = async () => {
|
|
220
232
|
while (true) {
|
|
221
233
|
if (!this.processingVideo) break;
|
|
222
234
|
|
|
223
|
-
const
|
|
235
|
+
const inputData = this.inputLoader.loadInput(input);
|
|
224
236
|
|
|
225
237
|
const nTracking = this.trackingStates.reduce((acc, s) => {
|
|
226
238
|
return acc + (!!s.isTracking ? 1 : 0);
|
|
@@ -238,7 +250,7 @@ class Controller {
|
|
|
238
250
|
}
|
|
239
251
|
|
|
240
252
|
const { targetIndex: matchedTargetIndex, modelViewTransform } =
|
|
241
|
-
await this._detectAndMatch(
|
|
253
|
+
await this._detectAndMatch(inputData, matchingIndexes);
|
|
242
254
|
|
|
243
255
|
if (matchedTargetIndex !== -1) {
|
|
244
256
|
this.trackingStates[matchedTargetIndex].isTracking = true;
|
|
@@ -252,7 +264,7 @@ class Controller {
|
|
|
252
264
|
|
|
253
265
|
if (trackingState.isTracking) {
|
|
254
266
|
let modelViewTransform = await this._trackAndUpdate(
|
|
255
|
-
|
|
267
|
+
inputData,
|
|
256
268
|
trackingState.currentModelViewTransform,
|
|
257
269
|
i,
|
|
258
270
|
);
|
|
@@ -314,9 +326,14 @@ class Controller {
|
|
|
314
326
|
}
|
|
315
327
|
}
|
|
316
328
|
|
|
317
|
-
inputT.dispose();
|
|
318
329
|
this.onUpdate && this.onUpdate({ type: "processDone" });
|
|
319
|
-
|
|
330
|
+
|
|
331
|
+
// Use requestAnimationFrame if available, otherwise just wait briefly
|
|
332
|
+
if (typeof requestAnimationFrame !== "undefined") {
|
|
333
|
+
await new Promise(requestAnimationFrame);
|
|
334
|
+
} else {
|
|
335
|
+
await new Promise(resolve => setTimeout(resolve, 16));
|
|
336
|
+
}
|
|
320
337
|
}
|
|
321
338
|
};
|
|
322
339
|
startProcessing();
|
|
@@ -327,23 +344,21 @@ class Controller {
|
|
|
327
344
|
}
|
|
328
345
|
|
|
329
346
|
async detect(input) {
|
|
330
|
-
const
|
|
331
|
-
const { featurePoints, debugExtra } = this.cropDetector.detect(
|
|
332
|
-
inputT.dispose();
|
|
347
|
+
const inputData = this.inputLoader.loadInput(input);
|
|
348
|
+
const { featurePoints, debugExtra } = this.cropDetector.detect(inputData);
|
|
333
349
|
return { featurePoints, debugExtra };
|
|
334
350
|
}
|
|
335
351
|
|
|
336
352
|
async match(featurePoints, targetIndex) {
|
|
337
|
-
const { modelViewTransform, debugExtra } = await this._workerMatch(featurePoints, [
|
|
353
|
+
const { targetIndex: matchedTargetIndex, modelViewTransform, debugExtra } = await this._workerMatch(featurePoints, [
|
|
338
354
|
targetIndex,
|
|
339
355
|
]);
|
|
340
|
-
return { modelViewTransform, debugExtra };
|
|
356
|
+
return { targetIndex: matchedTargetIndex, modelViewTransform, debugExtra };
|
|
341
357
|
}
|
|
342
358
|
|
|
343
359
|
async track(input, modelViewTransform, targetIndex) {
|
|
344
|
-
const
|
|
345
|
-
const result = this.tracker.track(
|
|
346
|
-
inputT.dispose();
|
|
360
|
+
const inputData = this.inputLoader.loadInput(input);
|
|
361
|
+
const result = this.tracker.track(inputData, modelViewTransform, targetIndex);
|
|
347
362
|
return result;
|
|
348
363
|
}
|
|
349
364
|
|
|
@@ -362,7 +377,7 @@ class Controller {
|
|
|
362
377
|
debugExtra: data.debugExtra,
|
|
363
378
|
});
|
|
364
379
|
};
|
|
365
|
-
this.worker.postMessage({ type: "match", featurePoints: featurePoints, targetIndexes });
|
|
380
|
+
this.worker && this.worker.postMessage({ type: "match", featurePoints: featurePoints, targetIndexes });
|
|
366
381
|
});
|
|
367
382
|
}
|
|
368
383
|
|
|
@@ -372,7 +387,7 @@ class Controller {
|
|
|
372
387
|
resolve(data.modelViewTransform);
|
|
373
388
|
};
|
|
374
389
|
const { worldCoords, screenCoords } = trackingFeatures;
|
|
375
|
-
this.worker.postMessage({
|
|
390
|
+
this.worker && this.worker.postMessage({
|
|
376
391
|
type: "trackUpdate",
|
|
377
392
|
modelViewTransform,
|
|
378
393
|
worldCoords,
|
|
@@ -384,41 +399,6 @@ class Controller {
|
|
|
384
399
|
_glModelViewMatrix(modelViewTransform, targetIndex) {
|
|
385
400
|
const height = this.markerDimensions[targetIndex][1];
|
|
386
401
|
|
|
387
|
-
// Question: can someone verify this interpreation is correct?
|
|
388
|
-
// I'm not very convinced, but more like trial and error and works......
|
|
389
|
-
//
|
|
390
|
-
// First, opengl has y coordinate system go from bottom to top, while the marker corrdinate goes from top to bottom,
|
|
391
|
-
// since the modelViewTransform is estimated in marker coordinate, we need to apply this transform before modelViewTransform
|
|
392
|
-
// 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?
|
|
393
|
-
//
|
|
394
|
-
// [1 0 0 0]
|
|
395
|
-
// [0 -1 0 h]
|
|
396
|
-
// [0 0 -1 0]
|
|
397
|
-
// [0 0 0 1]
|
|
398
|
-
//
|
|
399
|
-
// This is tested that if we reverse marker coordinate from bottom to top and estimate the modelViewTransform,
|
|
400
|
-
// then the above matrix is not necessary.
|
|
401
|
-
//
|
|
402
|
-
// Second, in opengl, positive z is away from camera, so we rotate 90 deg along x-axis after transform to fix the axis mismatch
|
|
403
|
-
// [1 1 0 0]
|
|
404
|
-
// [0 -1 0 0]
|
|
405
|
-
// [0 0 -1 0]
|
|
406
|
-
// [0 0 0 1]
|
|
407
|
-
//
|
|
408
|
-
// all together, the combined matrix is
|
|
409
|
-
//
|
|
410
|
-
// [1 1 0 0] [m00, m01, m02, m03] [1 0 0 0]
|
|
411
|
-
// [0 -1 0 0] [m10, m11, m12, m13] [0 -1 0 h]
|
|
412
|
-
// [0 0 -1 0] [m20, m21, m22, m23] [0 0 -1 0]
|
|
413
|
-
// [0 0 0 1] [ 0 0 0 1] [0 0 0 1]
|
|
414
|
-
//
|
|
415
|
-
// [ m00, -m01, -m02, (m01 * h + m03) ]
|
|
416
|
-
// [-m10, m11, m12, -(m11 * h + m13) ]
|
|
417
|
-
// = [-m20, m21, m22, -(m21 * h + m23) ]
|
|
418
|
-
// [ 0, 0, 0, 1 ]
|
|
419
|
-
//
|
|
420
|
-
//
|
|
421
|
-
// Finally, in threejs, matrix is represented in col by row, so we transpose it, and get below:
|
|
422
402
|
const openGLWorldMatrix = [
|
|
423
403
|
modelViewTransform[0][0],
|
|
424
404
|
-modelViewTransform[1][0],
|
|
@@ -440,8 +420,6 @@ class Controller {
|
|
|
440
420
|
return openGLWorldMatrix;
|
|
441
421
|
}
|
|
442
422
|
|
|
443
|
-
// build openGL projection matrix
|
|
444
|
-
// ref: https://strawlab.org/2011/11/05/augmented-reality-with-OpenGL/
|
|
445
423
|
_glProjectionMatrix({ projectionTransform, width, height, near, far }) {
|
|
446
424
|
const proj = [
|
|
447
425
|
[
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DetectorLite } from "./detector-lite.js";
|
|
2
2
|
|
|
3
3
|
class CropDetector {
|
|
4
4
|
constructor(width, height, debugMode = false) {
|
|
@@ -11,17 +11,18 @@ class CropDetector {
|
|
|
11
11
|
let cropSize = Math.pow(2, Math.round(Math.log(minDimension) / Math.log(2)));
|
|
12
12
|
this.cropSize = cropSize;
|
|
13
13
|
|
|
14
|
-
this.detector = new
|
|
14
|
+
this.detector = new DetectorLite(cropSize, cropSize);
|
|
15
15
|
|
|
16
|
-
this.kernelCaches = {};
|
|
17
16
|
this.lastRandomIndex = 4;
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
detect(
|
|
19
|
+
detect(input) {
|
|
20
|
+
const imageData = input;
|
|
21
|
+
|
|
21
22
|
// crop center
|
|
22
23
|
const startY = Math.floor(this.height / 2 - this.cropSize / 2);
|
|
23
24
|
const startX = Math.floor(this.width / 2 - this.cropSize / 2);
|
|
24
|
-
const result = this._detect(
|
|
25
|
+
const result = this._detect(imageData, startX, startY);
|
|
25
26
|
|
|
26
27
|
if (this.debugMode) {
|
|
27
28
|
result.debugExtra.crop = { startX, startY, cropSize: this.cropSize };
|
|
@@ -29,7 +30,9 @@ class CropDetector {
|
|
|
29
30
|
return result;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
detectMoving(
|
|
33
|
+
detectMoving(input) {
|
|
34
|
+
const imageData = input;
|
|
35
|
+
|
|
33
36
|
// loop a few locations around center
|
|
34
37
|
const dx = this.lastRandomIndex % 3;
|
|
35
38
|
const dy = Math.floor(this.lastRandomIndex / 3);
|
|
@@ -44,22 +47,30 @@ class CropDetector {
|
|
|
44
47
|
|
|
45
48
|
this.lastRandomIndex = (this.lastRandomIndex + 1) % 9;
|
|
46
49
|
|
|
47
|
-
const result = this._detect(
|
|
50
|
+
const result = this._detect(imageData, startX, startY);
|
|
48
51
|
return result;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
|
-
_detect(
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
+
_detect(imageData, startX, startY) {
|
|
55
|
+
// Crop manually since imageData is now a flat array (width * height)
|
|
56
|
+
const croppedData = new Float32Array(this.cropSize * this.cropSize);
|
|
57
|
+
for (let y = 0; y < this.cropSize; y++) {
|
|
58
|
+
for (let x = 0; x < this.cropSize; x++) {
|
|
59
|
+
croppedData[y * this.cropSize + x] = imageData[(startY + y) * this.width + (startX + x)];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const { featurePoints } = this.detector.detect(croppedData);
|
|
64
|
+
|
|
54
65
|
featurePoints.forEach((p) => {
|
|
55
66
|
p.x += startX;
|
|
56
67
|
p.y += startY;
|
|
57
68
|
});
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
featurePoints,
|
|
72
|
+
debugExtra: this.debugMode ? { projectedImage: Array.from(croppedData) } : {}
|
|
73
|
+
};
|
|
63
74
|
}
|
|
64
75
|
}
|
|
65
76
|
|
|
@@ -1,106 +1,80 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// original implementation: /node_modules/@tensorflow/tfjs-backend-webgl/src/kernels/FromPixels.ts
|
|
5
|
-
//
|
|
6
|
-
// This implementation return grey scale instead of RGBA in the orignal implementation
|
|
7
|
-
|
|
1
|
+
/**
|
|
2
|
+
* InputLoader - Maneja la carga de imágenes y video sin TensorFlow
|
|
3
|
+
*/
|
|
8
4
|
class InputLoader {
|
|
9
5
|
constructor(width, height) {
|
|
10
6
|
this.width = width;
|
|
11
7
|
this.height = height;
|
|
12
|
-
this.
|
|
13
|
-
|
|
14
|
-
const context = document.createElement("canvas").getContext("2d");
|
|
15
|
-
context.canvas.width = width;
|
|
16
|
-
context.canvas.height = height;
|
|
17
|
-
this.context = context;
|
|
8
|
+
this.grayscaleBuffer = new Uint8Array(width * height);
|
|
18
9
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// usage type should be TextureUsage.PIXELS, but tfjs didn't export this enum type, so we hard-coded 2 here
|
|
26
|
-
// i.e. backend.texData.get(tempPixelHandle.dataId).usage = TextureUsage.PIXELS;
|
|
27
|
-
backend.texData.get(this.tempPixelHandle.dataId).usage = 2;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// old method
|
|
31
|
-
_loadInput(input) {
|
|
32
|
-
return tf.tidy(() => {
|
|
33
|
-
let inputImage = tf.browser.fromPixels(input);
|
|
34
|
-
inputImage = inputImage.mean(2);
|
|
35
|
-
return inputImage;
|
|
36
|
-
});
|
|
10
|
+
if (typeof document !== "undefined") {
|
|
11
|
+
const canvas = document.createElement("canvas");
|
|
12
|
+
canvas.width = width;
|
|
13
|
+
canvas.height = height;
|
|
14
|
+
this.context = canvas.getContext("2d", { willReadFrequently: true, alpha: false });
|
|
15
|
+
}
|
|
37
16
|
}
|
|
38
17
|
|
|
39
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Carga una imagen o video y devuelve los datos en escala de grises
|
|
20
|
+
* @param {HTMLVideoElement|HTMLImageElement|ImageData|Uint8Array} input - La fuente de entrada
|
|
21
|
+
* @returns {Uint8Array} Datos de imagen en escala de grises (width * height)
|
|
22
|
+
*/
|
|
40
23
|
loadInput(input) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const isInputRotated = input.width === this.height && input.height === this.width;
|
|
45
|
-
if (isInputRotated) {
|
|
46
|
-
// rotate 90 degree and draw
|
|
47
|
-
let x = this.context.canvas.width / 2;
|
|
48
|
-
let y = this.context.canvas.height / 2;
|
|
49
|
-
let angleInDegrees = 90;
|
|
50
|
-
|
|
51
|
-
context.save(); // save the current context state
|
|
52
|
-
context.translate(x, y); // move the context origin to the center of the image
|
|
53
|
-
context.rotate((angleInDegrees * Math.PI) / 180); // rotate the context
|
|
54
|
-
|
|
55
|
-
// draw the image with its center at the origin
|
|
56
|
-
context.drawImage(input, -input.width / 2, -input.height / 2);
|
|
57
|
-
context.restore(); // restore the context to its original state
|
|
58
|
-
} else {
|
|
59
|
-
this.context.drawImage(input, 0, 0, input.width, input.height);
|
|
24
|
+
// Si ya es un Uint8Array de escala de grises, lo devolvemos
|
|
25
|
+
if (input instanceof Uint8Array && input.length === this.width * this.height) {
|
|
26
|
+
return input;
|
|
60
27
|
}
|
|
61
28
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
this.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
//const res = backend.compileAndRun(this.program, [this.tempPixelHandle]);
|
|
69
|
-
const res = this._compileAndRun(this.program, [this.tempPixelHandle]);
|
|
70
|
-
//const res = this._runWebGLProgram(this.program, [this.tempPixelHandle], 'float32');
|
|
71
|
-
//backend.disposeData(tempPixelHandle.dataId);
|
|
72
|
-
return res;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
buildProgram(width, height) {
|
|
76
|
-
const textureMethod = tf.env().getNumber("WEBGL_VERSION") === 2 ? "texture" : "texture2D";
|
|
29
|
+
// Si es ImageData, convertimos a escala de grises directamente
|
|
30
|
+
if (typeof ImageData !== "undefined" && input instanceof ImageData) {
|
|
31
|
+
this._convertToGrayscale(input.data, input.width, input.height);
|
|
32
|
+
return this.grayscaleBuffer;
|
|
33
|
+
}
|
|
77
34
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
35
|
+
// En el navegador, usamos canvas para procesar video/imágenes
|
|
36
|
+
if (this.context) {
|
|
37
|
+
this.context.clearRect(0, 0, this.width, this.height);
|
|
38
|
+
|
|
39
|
+
const isInputRotated = input.width === this.height && input.height === this.width;
|
|
40
|
+
|
|
41
|
+
if (isInputRotated) {
|
|
42
|
+
this.context.save();
|
|
43
|
+
this.context.translate(this.width / 2, this.height / 2);
|
|
44
|
+
this.context.rotate(Math.PI / 2);
|
|
45
|
+
this.context.drawImage(input, -input.width / 2, -input.height / 2);
|
|
46
|
+
this.context.restore();
|
|
47
|
+
} else {
|
|
48
|
+
this.context.drawImage(input, 0, 0, this.width, this.height);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const imageData = this.context.getImageData(0, 0, this.width, this.height);
|
|
52
|
+
this._convertToGrayscale(imageData.data, this.width, this.height);
|
|
53
|
+
return this.grayscaleBuffer;
|
|
54
|
+
}
|
|
87
55
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
return program;
|
|
94
|
-
}
|
|
56
|
+
// Fallback para Node.js o entornos sin DOM
|
|
57
|
+
if (input.data && input.data instanceof Uint8Array) {
|
|
58
|
+
this._convertToGrayscale(input.data, input.width || this.width, input.height || this.height);
|
|
59
|
+
return this.grayscaleBuffer;
|
|
60
|
+
}
|
|
95
61
|
|
|
96
|
-
|
|
97
|
-
const outInfo = tf.backend().compileAndRun(program, inputs);
|
|
98
|
-
return tf.engine().makeTensor(outInfo.dataId, outInfo.shape, outInfo.dtype);
|
|
62
|
+
throw new Error("Input no soportado o entorno sin Canvas");
|
|
99
63
|
}
|
|
100
64
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Convierte datos RGBA a escala de grises optimizada (reutilizando buffer)
|
|
67
|
+
*/
|
|
68
|
+
_convertToGrayscale(rgbaData, width, height) {
|
|
69
|
+
const grayscale = this.grayscaleBuffer;
|
|
70
|
+
const len = (width * height);
|
|
71
|
+
|
|
72
|
+
// Optimized loop with bitwise ops
|
|
73
|
+
for (let i = 0; i < len; i++) {
|
|
74
|
+
const offset = i << 2;
|
|
75
|
+
// Formula de luminosidad estándar: 0.299R + 0.587G + 0.114B (scaled by 256)
|
|
76
|
+
grayscale[i] = (rgbaData[offset] * 77 + rgbaData[offset + 1] * 150 + rgbaData[offset + 2] * 29) >> 8;
|
|
77
|
+
}
|
|
104
78
|
}
|
|
105
79
|
}
|
|
106
80
|
|
|
@@ -7,11 +7,11 @@ for (let i = 0; i < 256; i++) {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
const compute = (options) => {
|
|
10
|
-
const { v1, v2 } = options;
|
|
10
|
+
const { v1, v2, v1Offset = 0, v2Offset = 0 } = options;
|
|
11
11
|
let d = 0;
|
|
12
|
-
|
|
13
|
-
for (let i = 0; i <
|
|
14
|
-
d += BIT_COUNT_8[v1[i] ^ v2[i]];
|
|
12
|
+
// FREAK descriptors are 84 bytes
|
|
13
|
+
for (let i = 0; i < 84; i++) {
|
|
14
|
+
d += BIT_COUNT_8[v1[v1Offset + i] ^ v2[v2Offset + i]];
|
|
15
15
|
}
|
|
16
16
|
return d;
|
|
17
17
|
};
|
|
@@ -35,7 +35,7 @@ const computeHoughMatches = (options) => {
|
|
|
35
35
|
});
|
|
36
36
|
const medianProjectedDim =
|
|
37
37
|
projectedDims[
|
|
38
|
-
|
|
38
|
+
Math.floor(projectedDims.length / 2) - (projectedDims.length % 2 == 0 ? 1 : 0) - 1
|
|
39
39
|
];
|
|
40
40
|
|
|
41
41
|
const binSize = 0.25 * medianProjectedDim;
|
|
@@ -47,8 +47,8 @@ class Matcher {
|
|
|
47
47
|
y: querypoint.y,
|
|
48
48
|
});
|
|
49
49
|
worldCoords.push({
|
|
50
|
-
x: (keypoint.x + 0.5) / keyframe.scale,
|
|
51
|
-
y: (keypoint.y + 0.5) / keyframe.scale,
|
|
50
|
+
x: (keypoint.x + 0.5) / (keyframe.s || keyframe.scale || 1.0),
|
|
51
|
+
y: (keypoint.y + 0.5) / (keyframe.s || keyframe.scale || 1.0),
|
|
52
52
|
z: 0,
|
|
53
53
|
});
|
|
54
54
|
}
|