@srsergio/taptapp-ar 1.0.9 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/compiler/controller.d.ts +15 -22
  2. package/dist/compiler/controller.js +73 -92
  3. package/dist/compiler/detector/crop-detector.d.ts +20 -51
  4. package/dist/compiler/detector/crop-detector.js +21 -15
  5. package/dist/compiler/input-loader.d.ts +15 -17
  6. package/dist/compiler/input-loader.js +58 -76
  7. package/dist/compiler/matching/hamming-distance.js +4 -4
  8. package/dist/compiler/matching/matcher.js +2 -2
  9. package/dist/compiler/matching/matching.d.ts +2 -16
  10. package/dist/compiler/matching/matching.js +72 -60
  11. package/dist/compiler/offline-compiler.d.ts +9 -29
  12. package/dist/compiler/offline-compiler.js +38 -72
  13. package/dist/compiler/three.js +0 -4
  14. package/dist/compiler/tracker/tracker.d.ts +26 -12
  15. package/dist/compiler/tracker/tracker.js +158 -259
  16. package/package.json +1 -1
  17. package/src/compiler/controller.js +71 -93
  18. package/src/compiler/detector/crop-detector.js +26 -15
  19. package/src/compiler/input-loader.js +62 -88
  20. package/src/compiler/matching/hamming-distance.js +4 -4
  21. package/src/compiler/matching/hough.js +1 -1
  22. package/src/compiler/matching/matcher.js +2 -2
  23. package/src/compiler/matching/matching.js +80 -72
  24. package/src/compiler/offline-compiler.js +38 -75
  25. package/src/compiler/three.js +0 -4
  26. package/src/compiler/tracker/tracker.js +183 -283
  27. package/dist/compiler/compiler-base.d.ts +0 -8
  28. package/dist/compiler/compiler-base.js +0 -179
  29. package/dist/compiler/compiler.d.ts +0 -9
  30. package/dist/compiler/compiler.js +0 -24
  31. package/dist/compiler/compiler.worker.d.ts +0 -1
  32. package/dist/compiler/compiler.worker.js +0 -28
  33. package/dist/compiler/detector/detector.d.ts +0 -97
  34. package/dist/compiler/detector/detector.js +0 -1042
  35. package/dist/compiler/detector/kernels/cpu/binomialFilter.d.ts +0 -6
  36. package/dist/compiler/detector/kernels/cpu/binomialFilter.js +0 -50
  37. package/dist/compiler/detector/kernels/cpu/buildExtremas.d.ts +0 -6
  38. package/dist/compiler/detector/kernels/cpu/buildExtremas.js +0 -89
  39. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.d.ts +0 -7
  40. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.js +0 -79
  41. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.d.ts +0 -6
  42. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.js +0 -68
  43. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.d.ts +0 -6
  44. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.js +0 -57
  45. package/dist/compiler/detector/kernels/cpu/computeLocalization.d.ts +0 -6
  46. package/dist/compiler/detector/kernels/cpu/computeLocalization.js +0 -50
  47. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.d.ts +0 -6
  48. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.js +0 -100
  49. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.d.ts +0 -6
  50. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.js +0 -29
  51. package/dist/compiler/detector/kernels/cpu/extremaReduction.d.ts +0 -6
  52. package/dist/compiler/detector/kernels/cpu/extremaReduction.js +0 -50
  53. package/dist/compiler/detector/kernels/cpu/fakeShader.d.ts +0 -20
  54. package/dist/compiler/detector/kernels/cpu/fakeShader.js +0 -80
  55. package/dist/compiler/detector/kernels/cpu/index.d.ts +0 -1
  56. package/dist/compiler/detector/kernels/cpu/index.js +0 -25
  57. package/dist/compiler/detector/kernels/cpu/prune.d.ts +0 -7
  58. package/dist/compiler/detector/kernels/cpu/prune.js +0 -62
  59. package/dist/compiler/detector/kernels/cpu/smoothHistograms.d.ts +0 -6
  60. package/dist/compiler/detector/kernels/cpu/smoothHistograms.js +0 -47
  61. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.d.ts +0 -6
  62. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.js +0 -43
  63. package/dist/compiler/detector/kernels/index.d.ts +0 -1
  64. package/dist/compiler/detector/kernels/index.js +0 -2
  65. package/dist/compiler/detector/kernels/webgl/binomialFilter.d.ts +0 -6
  66. package/dist/compiler/detector/kernels/webgl/binomialFilter.js +0 -67
  67. package/dist/compiler/detector/kernels/webgl/buildExtremas.d.ts +0 -6
  68. package/dist/compiler/detector/kernels/webgl/buildExtremas.js +0 -101
  69. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.d.ts +0 -6
  70. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.js +0 -78
  71. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.d.ts +0 -6
  72. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.js +0 -86
  73. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.d.ts +0 -6
  74. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.js +0 -52
  75. package/dist/compiler/detector/kernels/webgl/computeLocalization.d.ts +0 -6
  76. package/dist/compiler/detector/kernels/webgl/computeLocalization.js +0 -58
  77. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.d.ts +0 -6
  78. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.js +0 -116
  79. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.d.ts +0 -6
  80. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.js +0 -46
  81. package/dist/compiler/detector/kernels/webgl/extremaReduction.d.ts +0 -6
  82. package/dist/compiler/detector/kernels/webgl/extremaReduction.js +0 -48
  83. package/dist/compiler/detector/kernels/webgl/index.d.ts +0 -1
  84. package/dist/compiler/detector/kernels/webgl/index.js +0 -25
  85. package/dist/compiler/detector/kernels/webgl/smoothHistograms.d.ts +0 -6
  86. package/dist/compiler/detector/kernels/webgl/smoothHistograms.js +0 -49
  87. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.d.ts +0 -6
  88. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.js +0 -56
  89. package/dist/compiler/tensorflow-setup.d.ts +0 -6
  90. package/dist/compiler/tensorflow-setup.js +0 -99
  91. package/src/compiler/compiler-base.js +0 -210
  92. package/src/compiler/compiler.js +0 -25
  93. package/src/compiler/compiler.worker.js +0 -30
  94. package/src/compiler/detector/detector.js +0 -1119
  95. package/src/compiler/detector/kernels/cpu/binomialFilter.js +0 -58
  96. package/src/compiler/detector/kernels/cpu/buildExtremas.js +0 -108
  97. package/src/compiler/detector/kernels/cpu/computeExtremaAngles.js +0 -91
  98. package/src/compiler/detector/kernels/cpu/computeExtremaFreak.js +0 -92
  99. package/src/compiler/detector/kernels/cpu/computeFreakDescriptors.js +0 -68
  100. package/src/compiler/detector/kernels/cpu/computeLocalization.js +0 -67
  101. package/src/compiler/detector/kernels/cpu/computeOrientationHistograms.js +0 -124
  102. package/src/compiler/detector/kernels/cpu/downsampleBilinear.js +0 -33
  103. package/src/compiler/detector/kernels/cpu/extremaReduction.js +0 -53
  104. package/src/compiler/detector/kernels/cpu/fakeShader.js +0 -88
  105. package/src/compiler/detector/kernels/cpu/index.js +0 -26
  106. package/src/compiler/detector/kernels/cpu/prune.js +0 -78
  107. package/src/compiler/detector/kernels/cpu/smoothHistograms.js +0 -57
  108. package/src/compiler/detector/kernels/cpu/upsampleBilinear.js +0 -51
  109. package/src/compiler/detector/kernels/index.js +0 -2
  110. package/src/compiler/detector/kernels/webgl/binomialFilter.js +0 -72
  111. package/src/compiler/detector/kernels/webgl/buildExtremas.js +0 -109
  112. package/src/compiler/detector/kernels/webgl/computeExtremaAngles.js +0 -82
  113. package/src/compiler/detector/kernels/webgl/computeExtremaFreak.js +0 -105
  114. package/src/compiler/detector/kernels/webgl/computeFreakDescriptors.js +0 -56
  115. package/src/compiler/detector/kernels/webgl/computeLocalization.js +0 -70
  116. package/src/compiler/detector/kernels/webgl/computeOrientationHistograms.js +0 -129
  117. package/src/compiler/detector/kernels/webgl/downsampleBilinear.js +0 -50
  118. package/src/compiler/detector/kernels/webgl/extremaReduction.js +0 -50
  119. package/src/compiler/detector/kernels/webgl/index.js +0 -26
  120. package/src/compiler/detector/kernels/webgl/smoothHistograms.js +0 -53
  121. package/src/compiler/detector/kernels/webgl/upsampleBilinear.js +0 -62
  122. package/src/compiler/tensorflow-setup.js +0 -116
@@ -1,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; // 45 in radian. field of view vertical
56
+ const fovy = (45.0 * Math.PI) / 180;
47
57
  const f = this.inputHeight / 2 / Math.tan(fovy / 2);
48
- // [fx s cx]
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
- this.worker = new ControllerWorker(); //new Worker(new URL('./controller.worker.js', import.meta.url));
66
- this.workerMatchDone = null;
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
- showTFStats() {
79
- console.log(tf.memory().numTensors);
80
- console.table(tf.memory());
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
- matchingDataList.push(dataList[i].matchingData);
101
- trackingDataList.push(dataList[i].trackingData);
102
- dimensions.push([dataList[i].targetImage.width, dataList[i].targetImage.height]);
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.worker.postMessage({
115
- type: "setup",
116
- inputWidth: this.inputWidth,
117
- inputHeight: this.inputHeight,
118
- projectionTransform: this.projectionTransform,
119
- debugMode: this.debugMode,
120
- matchingDataList,
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.postMessage({
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 inputT = this.inputLoader.loadInput(input);
138
- this.cropDetector.detect(inputT);
139
- this.tracker.dummyRun(inputT);
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(inputT, targetIndexes) {
180
- const { featurePoints } = this.cropDetector.detectMoving(inputT);
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(inputT, lastModelViewTransform, targetIndex) {
200
+ async _trackAndUpdate(inputData, lastModelViewTransform, targetIndex) {
188
201
  const { worldCoords, screenCoords } = this.tracker.track(
189
- inputT,
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 inputT = this.inputLoader.loadInput(input);
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(inputT, matchingIndexes);
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
- inputT,
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
- await tf.nextFrame();
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 inputT = this.inputLoader.loadInput(input);
331
- const { featurePoints, debugExtra } = this.cropDetector.detect(inputT);
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 inputT = this.inputLoader.loadInput(input);
345
- const result = this.tracker.track(inputT, modelViewTransform, targetIndex);
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 { Detector } from "./detector.js";
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 Detector(cropSize, cropSize, debugMode);
14
+ this.detector = new DetectorLite(cropSize, cropSize);
15
15
 
16
- this.kernelCaches = {};
17
16
  this.lastRandomIndex = 4;
18
17
  }
19
18
 
20
- detect(inputImageT) {
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(inputImageT, startX, startY);
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(inputImageT) {
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(inputImageT, startX, startY);
50
+ const result = this._detect(imageData, startX, startY);
48
51
  return result;
49
52
  }
50
53
 
51
- _detect(inputImageT, startX, startY) {
52
- const cropInputImageT = inputImageT.slice([startY, startX], [this.cropSize, this.cropSize]);
53
- const { featurePoints, debugExtra } = this.detector.detect(cropInputImageT);
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
- if (this.debugMode) {
59
- debugExtra.projectedImage = cropInputImageT.arraySync();
60
- }
61
- cropInputImageT.dispose();
62
- return { featurePoints: featurePoints, debugExtra };
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
- import * as tf from "@tensorflow/tfjs";
2
-
3
- // More efficient implementation for tf.browser.fromPixels
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.texShape = [height, width];
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
- this.program = this.buildProgram(width, height);
20
-
21
- const backend = tf.backend();
22
- //this.tempPixelHandle = backend.makeTensorInfo(this.texShape, 'int32');
23
- this.tempPixelHandle = backend.makeTensorInfo(this.texShape, "float32");
24
- // warning!!!
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
- // input is instance of HTMLVideoElement or HTMLImageElement
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
- const context = this.context;
42
- context.clearRect(0, 0, this.context.canvas.width, this.context.canvas.height);
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
- const backend = tf.backend();
63
- backend.gpgpu.uploadPixelDataToTexture(
64
- backend.getTexture(this.tempPixelHandle.dataId),
65
- this.context.canvas,
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
- const program = {
79
- variableNames: ["A"],
80
- outputShape: this.texShape,
81
- userCode: `
82
- void main() {
83
- ivec2 coords = getOutputCoords();
84
- int texR = coords[0];
85
- int texC = coords[1];
86
- vec2 uv = (vec2(texC, texR) + halfCR) / vec2(${width}.0, ${height}.0);
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
- vec4 values = ${textureMethod}(A, uv);
89
- setOutput((0.299 * values.r + 0.587 * values.g + 0.114 * values.b) * 255.0);
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
- _compileAndRun(program, inputs) {
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
- _runWebGLProgram(program, inputs, outputType) {
102
- const outInfo = tf.backend().runWebGLProgram(program, inputs, outputType);
103
- return tf.engine().makeTensor(outInfo.dataId, outInfo.shape, outInfo.dtype);
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
- const len = v1.length;
13
- for (let i = 0; i < len; 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
- Math.floor(projectedDims.length / 2) - (projectedDims.length % 2 == 0 ? 1 : 0) - 1
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
  }