@srsergio/taptapp-ar 1.0.37 → 1.0.40
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 +4 -3
- package/dist/compiler/controller.js +75 -60
- package/dist/compiler/tracker/tracker.d.ts +1 -0
- package/dist/compiler/tracker/tracker.js +14 -13
- package/package.json +1 -1
- package/src/compiler/controller.js +77 -67
- package/src/compiler/tracker/tracker.js +11 -14
|
@@ -65,7 +65,7 @@ export class Controller {
|
|
|
65
65
|
dummyRun(input: any): void;
|
|
66
66
|
getProjectionMatrix(): number[];
|
|
67
67
|
getRotatedZ90Matrix(m: any): any[];
|
|
68
|
-
getWorldMatrix(modelViewTransform: any, targetIndex: any): any[];
|
|
68
|
+
getWorldMatrix(modelViewTransform: any, targetIndex: any): any[] | null;
|
|
69
69
|
_detectAndMatch(inputData: any, targetIndexes: any): Promise<{
|
|
70
70
|
targetIndex: any;
|
|
71
71
|
modelViewTransform: any;
|
|
@@ -73,7 +73,7 @@ export class Controller {
|
|
|
73
73
|
_trackAndUpdate(inputData: any, lastModelViewTransform: any, targetIndex: any): Promise<{
|
|
74
74
|
modelViewTransform: any;
|
|
75
75
|
inliers: number;
|
|
76
|
-
octaveIndex:
|
|
76
|
+
octaveIndex: number;
|
|
77
77
|
} | null>;
|
|
78
78
|
processVideo(input: any): void;
|
|
79
79
|
stopProcessVideo(): void;
|
|
@@ -102,6 +102,7 @@ export class Controller {
|
|
|
102
102
|
x: number;
|
|
103
103
|
y: number;
|
|
104
104
|
}[];
|
|
105
|
+
octaveIndex: number;
|
|
105
106
|
debugExtra: {};
|
|
106
107
|
}>;
|
|
107
108
|
trackUpdate(modelViewTransform: any, trackFeatures: any): Promise<any>;
|
|
@@ -128,7 +129,7 @@ export class Controller {
|
|
|
128
129
|
_workerTrackUpdate(modelViewTransform: any, trackingFeatures: any): Promise<any>;
|
|
129
130
|
workerTrackDone: ((data: any) => void) | undefined;
|
|
130
131
|
_trackUpdateOnMainThread(modelViewTransform: any, trackingFeatures: any): Promise<never[][] | null>;
|
|
131
|
-
_glModelViewMatrix(modelViewTransform: any, targetIndex: any): any[];
|
|
132
|
+
_glModelViewMatrix(modelViewTransform: any, targetIndex: any): any[] | null;
|
|
132
133
|
_glProjectionMatrix({ projectionTransform, width, height, near, far }: {
|
|
133
134
|
projectionTransform: any;
|
|
134
135
|
width: any;
|
|
@@ -181,17 +181,19 @@ class Controller {
|
|
|
181
181
|
return { targetIndex: matchedTargetIndex, modelViewTransform };
|
|
182
182
|
}
|
|
183
183
|
async _trackAndUpdate(inputData, lastModelViewTransform, targetIndex) {
|
|
184
|
-
|
|
185
|
-
|
|
184
|
+
if (!lastModelViewTransform)
|
|
185
|
+
return null;
|
|
186
|
+
const result = this.tracker.track(inputData, lastModelViewTransform, targetIndex);
|
|
187
|
+
if (result.worldCoords.length < 6)
|
|
186
188
|
return null; // Umbral de puntos mínimos para mantener el seguimiento
|
|
187
189
|
const modelViewTransform = await this._workerTrackUpdate(lastModelViewTransform, {
|
|
188
|
-
worldCoords,
|
|
189
|
-
screenCoords,
|
|
190
|
+
worldCoords: result.worldCoords,
|
|
191
|
+
screenCoords: result.screenCoords,
|
|
190
192
|
});
|
|
191
193
|
return {
|
|
192
194
|
modelViewTransform,
|
|
193
|
-
inliers: worldCoords.length,
|
|
194
|
-
octaveIndex:
|
|
195
|
+
inliers: result.worldCoords.length,
|
|
196
|
+
octaveIndex: result.octaveIndex
|
|
195
197
|
};
|
|
196
198
|
}
|
|
197
199
|
processVideo(input) {
|
|
@@ -219,18 +221,22 @@ class Controller {
|
|
|
219
221
|
return acc + (!!s.isTracking ? 1 : 0);
|
|
220
222
|
}, 0);
|
|
221
223
|
// detect and match only if less then maxTrack
|
|
224
|
+
// BUG FIX: Only match if we are NOT in a "ghosting" period for a target
|
|
225
|
+
// to prevent the "found but immediately lost" loop that keeps opacity at 1.
|
|
222
226
|
if (nTracking < this.maxTrack) {
|
|
223
227
|
const matchingIndexes = [];
|
|
224
228
|
for (let i = 0; i < this.trackingStates.length; i++) {
|
|
225
229
|
const trackingState = this.trackingStates[i];
|
|
226
230
|
if (trackingState.isTracking === true)
|
|
227
231
|
continue;
|
|
232
|
+
if (trackingState.showing === true)
|
|
233
|
+
continue; // Don't try to re-detect if we are still buffers-showing the last position
|
|
228
234
|
if (this.interestedTargetIndex !== -1 && this.interestedTargetIndex !== i)
|
|
229
235
|
continue;
|
|
230
236
|
matchingIndexes.push(i);
|
|
231
237
|
}
|
|
232
238
|
const { targetIndex: matchedTargetIndex, modelViewTransform } = await this._detectAndMatch(inputData, matchingIndexes);
|
|
233
|
-
if (matchedTargetIndex !== -1) {
|
|
239
|
+
if (matchedTargetIndex !== -1 && modelViewTransform) {
|
|
234
240
|
this.trackingStates[matchedTargetIndex].isTracking = true;
|
|
235
241
|
this.trackingStates[matchedTargetIndex].currentModelViewTransform = modelViewTransform;
|
|
236
242
|
}
|
|
@@ -239,72 +245,79 @@ class Controller {
|
|
|
239
245
|
for (let i = 0; i < this.trackingStates.length; i++) {
|
|
240
246
|
const trackingState = this.trackingStates[i];
|
|
241
247
|
if (trackingState.isTracking) {
|
|
242
|
-
|
|
243
|
-
if (result === null) {
|
|
248
|
+
if (!trackingState.currentModelViewTransform) {
|
|
244
249
|
trackingState.isTracking = false;
|
|
245
250
|
trackingState.stabilityCount = 0;
|
|
246
251
|
}
|
|
247
252
|
else {
|
|
248
|
-
trackingState.currentModelViewTransform
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
trackingState.stabilityCount++;
|
|
253
|
-
if (trackingState.stabilityCount > 20) { // 20 frames de estabilidad absoluta
|
|
254
|
-
this.tracker.applyLiveFeedback(i, result.octaveIndex, 0.1); // 10% de mezcla real
|
|
255
|
-
if (this.debugMode)
|
|
256
|
-
console.log(`✨ Live Reification: Target ${i} (Octave ${result.octaveIndex}) updated with real-world textures.`);
|
|
257
|
-
trackingState.stabilityCount = 0; // Reset para la siguiente actualización
|
|
258
|
-
}
|
|
253
|
+
let result = await this._trackAndUpdate(inputData, trackingState.currentModelViewTransform, i);
|
|
254
|
+
if (result === null) {
|
|
255
|
+
trackingState.isTracking = false;
|
|
256
|
+
trackingState.stabilityCount = 0;
|
|
259
257
|
}
|
|
260
258
|
else {
|
|
261
|
-
trackingState.
|
|
259
|
+
trackingState.currentModelViewTransform = result.modelViewTransform;
|
|
260
|
+
// --- LIVE MODEL ADAPTATION LOGIC ---
|
|
261
|
+
// Si el tracking es muy sólido (muchos inliers) y estable, refinamos el modelo
|
|
262
|
+
// Requisito: > 35 inliers (muy exigente) para evitar polución por ruido
|
|
263
|
+
if (result.inliers > 35) {
|
|
264
|
+
trackingState.stabilityCount++;
|
|
265
|
+
if (trackingState.stabilityCount > 30) { // 30 frames (~1s) de estabilidad absoluta
|
|
266
|
+
this.tracker.applyLiveFeedback(i, result.octaveIndex, 0.05); // Menor alpha (5%) para ser más conservador
|
|
267
|
+
if (this.debugMode)
|
|
268
|
+
console.log(`✨ Live Reification: Target ${i} (Octave ${result.octaveIndex}) updated.`);
|
|
269
|
+
trackingState.stabilityCount = 0;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
trackingState.stabilityCount = Math.max(0, trackingState.stabilityCount - 1);
|
|
274
|
+
}
|
|
275
|
+
// -----------------------------------
|
|
262
276
|
}
|
|
263
|
-
// -----------------------------------
|
|
264
277
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
278
|
+
// if not showing, then show it once it reaches warmup number of frames
|
|
279
|
+
if (!trackingState.showing) {
|
|
280
|
+
if (trackingState.isTracking) {
|
|
281
|
+
trackingState.trackMiss = 0;
|
|
282
|
+
trackingState.trackCount += 1;
|
|
283
|
+
if (trackingState.trackCount > this.warmupTolerance) {
|
|
284
|
+
trackingState.showing = true;
|
|
285
|
+
trackingState.trackingMatrix = null;
|
|
286
|
+
trackingState.filter.reset();
|
|
287
|
+
}
|
|
275
288
|
}
|
|
276
289
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
290
|
+
// if showing, then count miss, and hide it when reaches tolerance
|
|
291
|
+
if (trackingState.showing) {
|
|
292
|
+
if (!trackingState.isTracking) {
|
|
293
|
+
trackingState.trackCount = 0;
|
|
294
|
+
trackingState.trackMiss += 1;
|
|
295
|
+
if (trackingState.trackMiss > this.missTolerance) {
|
|
296
|
+
trackingState.showing = false;
|
|
297
|
+
trackingState.trackingMatrix = null;
|
|
298
|
+
this.onUpdate &&
|
|
299
|
+
this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: null });
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
trackingState.trackMiss = 0;
|
|
288
304
|
}
|
|
289
305
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
clone = this.getRotatedZ90Matrix(clone);
|
|
306
|
+
// if showing, then call onUpdate, with world matrix
|
|
307
|
+
if (trackingState.showing && trackingState.currentModelViewTransform) {
|
|
308
|
+
const worldMatrix = this._glModelViewMatrix(trackingState.currentModelViewTransform, i);
|
|
309
|
+
trackingState.trackingMatrix = trackingState.filter.filter(Date.now(), worldMatrix);
|
|
310
|
+
let clone = [];
|
|
311
|
+
for (let j = 0; j < trackingState.trackingMatrix.length; j++) {
|
|
312
|
+
clone[j] = trackingState.trackingMatrix[j];
|
|
313
|
+
}
|
|
314
|
+
const isInputRotated = input.width === this.inputHeight && input.height === this.inputWidth;
|
|
315
|
+
if (isInputRotated) {
|
|
316
|
+
clone = this.getRotatedZ90Matrix(clone);
|
|
317
|
+
}
|
|
318
|
+
this.onUpdate &&
|
|
319
|
+
this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone, modelViewTransform: trackingState.currentModelViewTransform });
|
|
305
320
|
}
|
|
306
|
-
this.onUpdate &&
|
|
307
|
-
this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone, modelViewTransform: trackingState.currentModelViewTransform });
|
|
308
321
|
}
|
|
309
322
|
}
|
|
310
323
|
this.onUpdate && this.onUpdate({ type: "processDone" });
|
|
@@ -433,6 +446,8 @@ class Controller {
|
|
|
433
446
|
return finalModelViewTransform;
|
|
434
447
|
}
|
|
435
448
|
_glModelViewMatrix(modelViewTransform, targetIndex) {
|
|
449
|
+
if (!modelViewTransform)
|
|
450
|
+
return null;
|
|
436
451
|
const height = this.markerDimensions[targetIndex][1];
|
|
437
452
|
const openGLWorldMatrix = [
|
|
438
453
|
modelViewTransform[0][0],
|
|
@@ -46,6 +46,8 @@ class Tracker {
|
|
|
46
46
|
}
|
|
47
47
|
track(inputData, lastModelViewTransform, targetIndex) {
|
|
48
48
|
let debugExtra = {};
|
|
49
|
+
if (!lastModelViewTransform)
|
|
50
|
+
return { worldCoords: [], screenCoords: [], octaveIndex: 0, debugExtra };
|
|
49
51
|
// Select the best octave based on current estimated distance/scale
|
|
50
52
|
// We want the octave where the marker size is closest to its projected size on screen
|
|
51
53
|
const modelViewProjectionTransform = buildModelViewProjectionTransform(this.projectionTransform, lastModelViewTransform);
|
|
@@ -87,16 +89,7 @@ class Tracker {
|
|
|
87
89
|
});
|
|
88
90
|
}
|
|
89
91
|
}
|
|
90
|
-
|
|
91
|
-
debugExtra = {
|
|
92
|
-
octaveIndex,
|
|
93
|
-
projectedImage: Array.from(projectedImage),
|
|
94
|
-
matchingPoints,
|
|
95
|
-
goodTrack,
|
|
96
|
-
trackedPoints: screenCoords,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
return { worldCoords, screenCoords, debugExtra };
|
|
92
|
+
return { worldCoords, screenCoords, octaveIndex, debugExtra };
|
|
100
93
|
}
|
|
101
94
|
/**
|
|
102
95
|
* Pure JS implementation of NCC matching
|
|
@@ -239,8 +232,13 @@ class Tracker {
|
|
|
239
232
|
* @param {number} alpha - Blending factor (e.g. 0.1 for 10% new data)
|
|
240
233
|
*/
|
|
241
234
|
applyLiveFeedback(targetIndex, octaveIndex, alpha) {
|
|
242
|
-
|
|
243
|
-
|
|
235
|
+
if (targetIndex === undefined || octaveIndex === undefined)
|
|
236
|
+
return;
|
|
237
|
+
const targetPrebuilts = this.prebuiltData[targetIndex];
|
|
238
|
+
if (!targetPrebuilts)
|
|
239
|
+
return;
|
|
240
|
+
const prebuilt = targetPrebuilts[octaveIndex];
|
|
241
|
+
if (!prebuilt || !prebuilt.projectedImage || !prebuilt.data)
|
|
244
242
|
return;
|
|
245
243
|
const markerPixels = prebuilt.data;
|
|
246
244
|
const projectedPixels = prebuilt.projectedImage;
|
|
@@ -248,8 +246,11 @@ class Tracker {
|
|
|
248
246
|
// Blend the projected (camera-sourced) pixels into the marker reference data
|
|
249
247
|
// This allows the NCC matching to adapt to real-world lighting and print quality
|
|
250
248
|
for (let i = 0; i < count; i++) {
|
|
249
|
+
const val = projectedPixels[i];
|
|
250
|
+
if (isNaN(val))
|
|
251
|
+
continue; // Don't pollute with NaN
|
|
251
252
|
// Simple linear blend
|
|
252
|
-
markerPixels[i] = (1 - alpha) * markerPixels[i] + alpha *
|
|
253
|
+
markerPixels[i] = (1 - alpha) * markerPixels[i] + alpha * val;
|
|
253
254
|
}
|
|
254
255
|
}
|
|
255
256
|
}
|
package/package.json
CHANGED
|
@@ -226,20 +226,21 @@ class Controller {
|
|
|
226
226
|
return { targetIndex: matchedTargetIndex, modelViewTransform };
|
|
227
227
|
}
|
|
228
228
|
async _trackAndUpdate(inputData, lastModelViewTransform, targetIndex) {
|
|
229
|
-
|
|
229
|
+
if (!lastModelViewTransform) return null;
|
|
230
|
+
const result = this.tracker.track(
|
|
230
231
|
inputData,
|
|
231
232
|
lastModelViewTransform,
|
|
232
233
|
targetIndex,
|
|
233
234
|
);
|
|
234
|
-
if (worldCoords.length < 6) return null; // Umbral de puntos mínimos para mantener el seguimiento
|
|
235
|
+
if (result.worldCoords.length < 6) return null; // Umbral de puntos mínimos para mantener el seguimiento
|
|
235
236
|
const modelViewTransform = await this._workerTrackUpdate(lastModelViewTransform, {
|
|
236
|
-
worldCoords,
|
|
237
|
-
screenCoords,
|
|
237
|
+
worldCoords: result.worldCoords,
|
|
238
|
+
screenCoords: result.screenCoords,
|
|
238
239
|
});
|
|
239
240
|
return {
|
|
240
241
|
modelViewTransform,
|
|
241
|
-
inliers: worldCoords.length,
|
|
242
|
-
octaveIndex:
|
|
242
|
+
inliers: result.worldCoords.length,
|
|
243
|
+
octaveIndex: result.octaveIndex
|
|
243
244
|
};
|
|
244
245
|
}
|
|
245
246
|
|
|
@@ -272,11 +273,14 @@ class Controller {
|
|
|
272
273
|
}, 0);
|
|
273
274
|
|
|
274
275
|
// detect and match only if less then maxTrack
|
|
276
|
+
// BUG FIX: Only match if we are NOT in a "ghosting" period for a target
|
|
277
|
+
// to prevent the "found but immediately lost" loop that keeps opacity at 1.
|
|
275
278
|
if (nTracking < this.maxTrack) {
|
|
276
279
|
const matchingIndexes = [];
|
|
277
280
|
for (let i = 0; i < this.trackingStates.length; i++) {
|
|
278
281
|
const trackingState = this.trackingStates[i];
|
|
279
282
|
if (trackingState.isTracking === true) continue;
|
|
283
|
+
if (trackingState.showing === true) continue; // Don't try to re-detect if we are still buffers-showing the last position
|
|
280
284
|
if (this.interestedTargetIndex !== -1 && this.interestedTargetIndex !== i) continue;
|
|
281
285
|
|
|
282
286
|
matchingIndexes.push(i);
|
|
@@ -285,7 +289,7 @@ class Controller {
|
|
|
285
289
|
const { targetIndex: matchedTargetIndex, modelViewTransform } =
|
|
286
290
|
await this._detectAndMatch(inputData, matchingIndexes);
|
|
287
291
|
|
|
288
|
-
if (matchedTargetIndex !== -1) {
|
|
292
|
+
if (matchedTargetIndex !== -1 && modelViewTransform) {
|
|
289
293
|
this.trackingStates[matchedTargetIndex].isTracking = true;
|
|
290
294
|
this.trackingStates[matchedTargetIndex].currentModelViewTransform = modelViewTransform;
|
|
291
295
|
}
|
|
@@ -296,84 +300,89 @@ class Controller {
|
|
|
296
300
|
const trackingState = this.trackingStates[i];
|
|
297
301
|
|
|
298
302
|
if (trackingState.isTracking) {
|
|
299
|
-
|
|
300
|
-
inputData,
|
|
301
|
-
trackingState.currentModelViewTransform,
|
|
302
|
-
i,
|
|
303
|
-
);
|
|
304
|
-
if (result === null) {
|
|
303
|
+
if (!trackingState.currentModelViewTransform) {
|
|
305
304
|
trackingState.isTracking = false;
|
|
306
305
|
trackingState.stabilityCount = 0;
|
|
307
306
|
} else {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if (this.debugMode) console.log(`✨ Live Reification: Target ${i} (Octave ${result.octaveIndex}) updated with real-world textures.`);
|
|
317
|
-
trackingState.stabilityCount = 0; // Reset para la siguiente actualización
|
|
318
|
-
}
|
|
307
|
+
let result = await this._trackAndUpdate(
|
|
308
|
+
inputData,
|
|
309
|
+
trackingState.currentModelViewTransform,
|
|
310
|
+
i,
|
|
311
|
+
);
|
|
312
|
+
if (result === null) {
|
|
313
|
+
trackingState.isTracking = false;
|
|
314
|
+
trackingState.stabilityCount = 0;
|
|
319
315
|
} else {
|
|
320
|
-
trackingState.
|
|
316
|
+
trackingState.currentModelViewTransform = result.modelViewTransform;
|
|
317
|
+
|
|
318
|
+
// --- LIVE MODEL ADAPTATION LOGIC ---
|
|
319
|
+
// Si el tracking es muy sólido (muchos inliers) y estable, refinamos el modelo
|
|
320
|
+
// Requisito: > 35 inliers (muy exigente) para evitar polución por ruido
|
|
321
|
+
if (result.inliers > 35) {
|
|
322
|
+
trackingState.stabilityCount++;
|
|
323
|
+
if (trackingState.stabilityCount > 30) { // 30 frames (~1s) de estabilidad absoluta
|
|
324
|
+
this.tracker.applyLiveFeedback(i, result.octaveIndex, 0.05); // Menor alpha (5%) para ser más conservador
|
|
325
|
+
if (this.debugMode) console.log(`✨ Live Reification: Target ${i} (Octave ${result.octaveIndex}) updated.`);
|
|
326
|
+
trackingState.stabilityCount = 0;
|
|
327
|
+
}
|
|
328
|
+
} else {
|
|
329
|
+
trackingState.stabilityCount = Math.max(0, trackingState.stabilityCount - 1);
|
|
330
|
+
}
|
|
331
|
+
// -----------------------------------
|
|
321
332
|
}
|
|
322
|
-
// -----------------------------------
|
|
323
333
|
}
|
|
324
|
-
}
|
|
325
334
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
+
// if not showing, then show it once it reaches warmup number of frames
|
|
336
|
+
if (!trackingState.showing) {
|
|
337
|
+
if (trackingState.isTracking) {
|
|
338
|
+
trackingState.trackMiss = 0;
|
|
339
|
+
trackingState.trackCount += 1;
|
|
340
|
+
if (trackingState.trackCount > this.warmupTolerance) {
|
|
341
|
+
trackingState.showing = true;
|
|
342
|
+
trackingState.trackingMatrix = null;
|
|
343
|
+
trackingState.filter.reset();
|
|
344
|
+
}
|
|
335
345
|
}
|
|
336
346
|
}
|
|
337
|
-
}
|
|
338
347
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
348
|
+
// if showing, then count miss, and hide it when reaches tolerance
|
|
349
|
+
if (trackingState.showing) {
|
|
350
|
+
if (!trackingState.isTracking) {
|
|
351
|
+
trackingState.trackCount = 0;
|
|
352
|
+
trackingState.trackMiss += 1;
|
|
353
|
+
|
|
354
|
+
if (trackingState.trackMiss > this.missTolerance) {
|
|
355
|
+
trackingState.showing = false;
|
|
356
|
+
trackingState.trackingMatrix = null;
|
|
357
|
+
this.onUpdate &&
|
|
358
|
+
this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: null });
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
trackingState.trackMiss = 0;
|
|
350
362
|
}
|
|
351
|
-
} else {
|
|
352
|
-
trackingState.trackMiss = 0;
|
|
353
363
|
}
|
|
354
|
-
}
|
|
355
364
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
365
|
+
// if showing, then call onUpdate, with world matrix
|
|
366
|
+
if (trackingState.showing && trackingState.currentModelViewTransform) {
|
|
367
|
+
const worldMatrix = this._glModelViewMatrix(trackingState.currentModelViewTransform, i);
|
|
368
|
+
trackingState.trackingMatrix = trackingState.filter.filter(Date.now(), worldMatrix);
|
|
360
369
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
370
|
+
let clone = [];
|
|
371
|
+
for (let j = 0; j < trackingState.trackingMatrix.length; j++) {
|
|
372
|
+
clone[j] = trackingState.trackingMatrix[j];
|
|
373
|
+
}
|
|
365
374
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
375
|
+
const isInputRotated =
|
|
376
|
+
input.width === this.inputHeight && input.height === this.inputWidth;
|
|
377
|
+
if (isInputRotated) {
|
|
378
|
+
clone = this.getRotatedZ90Matrix(clone);
|
|
379
|
+
}
|
|
371
380
|
|
|
372
|
-
|
|
373
|
-
|
|
381
|
+
this.onUpdate &&
|
|
382
|
+
this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone, modelViewTransform: trackingState.currentModelViewTransform });
|
|
383
|
+
}
|
|
374
384
|
}
|
|
375
385
|
}
|
|
376
|
-
|
|
377
386
|
this.onUpdate && this.onUpdate({ type: "processDone" });
|
|
378
387
|
|
|
379
388
|
// Use requestAnimationFrame if available, otherwise just wait briefly
|
|
@@ -521,6 +530,7 @@ class Controller {
|
|
|
521
530
|
}
|
|
522
531
|
|
|
523
532
|
_glModelViewMatrix(modelViewTransform, targetIndex) {
|
|
533
|
+
if (!modelViewTransform) return null;
|
|
524
534
|
const height = this.markerDimensions[targetIndex][1];
|
|
525
535
|
|
|
526
536
|
const openGLWorldMatrix = [
|
|
@@ -61,6 +61,7 @@ class Tracker {
|
|
|
61
61
|
|
|
62
62
|
track(inputData, lastModelViewTransform, targetIndex) {
|
|
63
63
|
let debugExtra = {};
|
|
64
|
+
if (!lastModelViewTransform) return { worldCoords: [], screenCoords: [], octaveIndex: 0, debugExtra };
|
|
64
65
|
|
|
65
66
|
// Select the best octave based on current estimated distance/scale
|
|
66
67
|
// We want the octave where the marker size is closest to its projected size on screen
|
|
@@ -127,17 +128,7 @@ class Tracker {
|
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
|
|
131
|
-
debugExtra = {
|
|
132
|
-
octaveIndex,
|
|
133
|
-
projectedImage: Array.from(projectedImage),
|
|
134
|
-
matchingPoints,
|
|
135
|
-
goodTrack,
|
|
136
|
-
trackedPoints: screenCoords,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return { worldCoords, screenCoords, debugExtra };
|
|
131
|
+
return { worldCoords, screenCoords, octaveIndex, debugExtra };
|
|
141
132
|
}
|
|
142
133
|
|
|
143
134
|
/**
|
|
@@ -308,8 +299,12 @@ class Tracker {
|
|
|
308
299
|
* @param {number} alpha - Blending factor (e.g. 0.1 for 10% new data)
|
|
309
300
|
*/
|
|
310
301
|
applyLiveFeedback(targetIndex, octaveIndex, alpha) {
|
|
311
|
-
|
|
312
|
-
|
|
302
|
+
if (targetIndex === undefined || octaveIndex === undefined) return;
|
|
303
|
+
const targetPrebuilts = this.prebuiltData[targetIndex];
|
|
304
|
+
if (!targetPrebuilts) return;
|
|
305
|
+
|
|
306
|
+
const prebuilt = targetPrebuilts[octaveIndex];
|
|
307
|
+
if (!prebuilt || !prebuilt.projectedImage || !prebuilt.data) return;
|
|
313
308
|
|
|
314
309
|
const markerPixels = prebuilt.data;
|
|
315
310
|
const projectedPixels = prebuilt.projectedImage;
|
|
@@ -318,8 +313,10 @@ class Tracker {
|
|
|
318
313
|
// Blend the projected (camera-sourced) pixels into the marker reference data
|
|
319
314
|
// This allows the NCC matching to adapt to real-world lighting and print quality
|
|
320
315
|
for (let i = 0; i < count; i++) {
|
|
316
|
+
const val = projectedPixels[i];
|
|
317
|
+
if (isNaN(val)) continue; // Don't pollute with NaN
|
|
321
318
|
// Simple linear blend
|
|
322
|
-
markerPixels[i] = (1 - alpha) * markerPixels[i] + alpha *
|
|
319
|
+
markerPixels[i] = (1 - alpha) * markerPixels[i] + alpha * val;
|
|
323
320
|
}
|
|
324
321
|
}
|
|
325
322
|
}
|