@srsergio/taptapp-ar 1.0.0

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 (207) hide show
  1. package/README.md +62 -0
  2. package/dist/compiler/aframe.d.ts +1 -0
  3. package/dist/compiler/aframe.js +275 -0
  4. package/dist/compiler/compiler-base.d.ts +12 -0
  5. package/dist/compiler/compiler-base.js +165 -0
  6. package/dist/compiler/compiler.d.ts +9 -0
  7. package/dist/compiler/compiler.js +24 -0
  8. package/dist/compiler/compiler.worker.d.ts +1 -0
  9. package/dist/compiler/compiler.worker.js +28 -0
  10. package/dist/compiler/controller.d.ts +101 -0
  11. package/dist/compiler/controller.js +400 -0
  12. package/dist/compiler/controller.worker.d.ts +1 -0
  13. package/dist/compiler/controller.worker.js +61 -0
  14. package/dist/compiler/detector/crop-detector.d.ts +65 -0
  15. package/dist/compiler/detector/crop-detector.js +59 -0
  16. package/dist/compiler/detector/detector.d.ts +98 -0
  17. package/dist/compiler/detector/detector.js +1049 -0
  18. package/dist/compiler/detector/freak.d.ts +1 -0
  19. package/dist/compiler/detector/freak.js +89 -0
  20. package/dist/compiler/detector/kernels/cpu/binomialFilter.d.ts +6 -0
  21. package/dist/compiler/detector/kernels/cpu/binomialFilter.js +51 -0
  22. package/dist/compiler/detector/kernels/cpu/buildExtremas.d.ts +6 -0
  23. package/dist/compiler/detector/kernels/cpu/buildExtremas.js +89 -0
  24. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.d.ts +7 -0
  25. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.js +79 -0
  26. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.d.ts +6 -0
  27. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.js +68 -0
  28. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.d.ts +6 -0
  29. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.js +57 -0
  30. package/dist/compiler/detector/kernels/cpu/computeLocalization.d.ts +6 -0
  31. package/dist/compiler/detector/kernels/cpu/computeLocalization.js +54 -0
  32. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.d.ts +6 -0
  33. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.js +118 -0
  34. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.d.ts +6 -0
  35. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.js +29 -0
  36. package/dist/compiler/detector/kernels/cpu/extremaReduction.d.ts +6 -0
  37. package/dist/compiler/detector/kernels/cpu/extremaReduction.js +50 -0
  38. package/dist/compiler/detector/kernels/cpu/fakeShader.d.ts +20 -0
  39. package/dist/compiler/detector/kernels/cpu/fakeShader.js +80 -0
  40. package/dist/compiler/detector/kernels/cpu/index.d.ts +1 -0
  41. package/dist/compiler/detector/kernels/cpu/index.js +25 -0
  42. package/dist/compiler/detector/kernels/cpu/prune.d.ts +1 -0
  43. package/dist/compiler/detector/kernels/cpu/prune.js +103 -0
  44. package/dist/compiler/detector/kernels/cpu/smoothHistograms.d.ts +6 -0
  45. package/dist/compiler/detector/kernels/cpu/smoothHistograms.js +47 -0
  46. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.d.ts +6 -0
  47. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.js +43 -0
  48. package/dist/compiler/detector/kernels/index.d.ts +1 -0
  49. package/dist/compiler/detector/kernels/index.js +2 -0
  50. package/dist/compiler/detector/kernels/webgl/binomialFilter.d.ts +6 -0
  51. package/dist/compiler/detector/kernels/webgl/binomialFilter.js +67 -0
  52. package/dist/compiler/detector/kernels/webgl/buildExtremas.d.ts +6 -0
  53. package/dist/compiler/detector/kernels/webgl/buildExtremas.js +101 -0
  54. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.d.ts +6 -0
  55. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.js +78 -0
  56. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.d.ts +6 -0
  57. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.js +86 -0
  58. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.d.ts +6 -0
  59. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.js +52 -0
  60. package/dist/compiler/detector/kernels/webgl/computeLocalization.d.ts +6 -0
  61. package/dist/compiler/detector/kernels/webgl/computeLocalization.js +58 -0
  62. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.d.ts +6 -0
  63. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.js +116 -0
  64. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.d.ts +6 -0
  65. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.js +46 -0
  66. package/dist/compiler/detector/kernels/webgl/extremaReduction.d.ts +6 -0
  67. package/dist/compiler/detector/kernels/webgl/extremaReduction.js +48 -0
  68. package/dist/compiler/detector/kernels/webgl/index.d.ts +1 -0
  69. package/dist/compiler/detector/kernels/webgl/index.js +25 -0
  70. package/dist/compiler/detector/kernels/webgl/smoothHistograms.d.ts +6 -0
  71. package/dist/compiler/detector/kernels/webgl/smoothHistograms.js +49 -0
  72. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.d.ts +6 -0
  73. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.js +56 -0
  74. package/dist/compiler/estimation/esimate-experiment.d.ts +5 -0
  75. package/dist/compiler/estimation/esimate-experiment.js +267 -0
  76. package/dist/compiler/estimation/estimate.d.ts +5 -0
  77. package/dist/compiler/estimation/estimate.js +51 -0
  78. package/dist/compiler/estimation/estimator.d.ts +13 -0
  79. package/dist/compiler/estimation/estimator.js +30 -0
  80. package/dist/compiler/estimation/refine-estimate-experiment.d.ts +6 -0
  81. package/dist/compiler/estimation/refine-estimate-experiment.js +429 -0
  82. package/dist/compiler/estimation/refine-estimate.d.ts +6 -0
  83. package/dist/compiler/estimation/refine-estimate.js +299 -0
  84. package/dist/compiler/estimation/utils.d.ts +10 -0
  85. package/dist/compiler/estimation/utils.js +80 -0
  86. package/dist/compiler/image-list.d.ts +13 -0
  87. package/dist/compiler/image-list.js +52 -0
  88. package/dist/compiler/index.d.ts +3 -0
  89. package/dist/compiler/index.js +10 -0
  90. package/dist/compiler/input-loader.d.ts +23 -0
  91. package/dist/compiler/input-loader.js +88 -0
  92. package/dist/compiler/matching/hamming-distance.d.ts +1 -0
  93. package/dist/compiler/matching/hamming-distance.js +20 -0
  94. package/dist/compiler/matching/hierarchical-clustering.d.ts +7 -0
  95. package/dist/compiler/matching/hierarchical-clustering.js +109 -0
  96. package/dist/compiler/matching/hough.d.ts +1 -0
  97. package/dist/compiler/matching/hough.js +169 -0
  98. package/dist/compiler/matching/matcher.d.ts +28 -0
  99. package/dist/compiler/matching/matcher.js +48 -0
  100. package/dist/compiler/matching/matching.d.ts +41 -0
  101. package/dist/compiler/matching/matching.js +197 -0
  102. package/dist/compiler/matching/ransacHomography.d.ts +1 -0
  103. package/dist/compiler/matching/ransacHomography.js +136 -0
  104. package/dist/compiler/offline-compiler.d.ts +10 -0
  105. package/dist/compiler/offline-compiler.js +450 -0
  106. package/dist/compiler/tensorflow-setup.d.ts +7 -0
  107. package/dist/compiler/tensorflow-setup.js +73 -0
  108. package/dist/compiler/three.d.ts +66 -0
  109. package/dist/compiler/three.js +310 -0
  110. package/dist/compiler/tracker/extract-utils.d.ts +1 -0
  111. package/dist/compiler/tracker/extract-utils.js +29 -0
  112. package/dist/compiler/tracker/extract.d.ts +4 -0
  113. package/dist/compiler/tracker/extract.js +349 -0
  114. package/dist/compiler/tracker/tracker.d.ts +38 -0
  115. package/dist/compiler/tracker/tracker.js +327 -0
  116. package/dist/compiler/utils/cumsum.d.ts +5 -0
  117. package/dist/compiler/utils/cumsum.js +39 -0
  118. package/dist/compiler/utils/geometry.d.ts +8 -0
  119. package/dist/compiler/utils/geometry.js +101 -0
  120. package/dist/compiler/utils/homography.d.ts +1 -0
  121. package/dist/compiler/utils/homography.js +138 -0
  122. package/dist/compiler/utils/images.d.ts +24 -0
  123. package/dist/compiler/utils/images.js +99 -0
  124. package/dist/compiler/utils/randomizer.d.ts +5 -0
  125. package/dist/compiler/utils/randomizer.js +25 -0
  126. package/dist/index.d.ts +6 -0
  127. package/dist/index.js +7 -0
  128. package/dist/react/AREditor.d.ts +5 -0
  129. package/dist/react/AREditor.js +159 -0
  130. package/dist/react/ProgressDialog.d.ts +13 -0
  131. package/dist/react/ProgressDialog.js +57 -0
  132. package/dist/react/types.d.ts +22 -0
  133. package/dist/react/types.js +14 -0
  134. package/package.json +53 -0
  135. package/src/astro/ARScene.astro +59 -0
  136. package/src/astro/ARVideoTrigger.astro +73 -0
  137. package/src/astro/overlays/ErrorOverlay.astro +40 -0
  138. package/src/astro/overlays/LoadingOverlay.astro +28 -0
  139. package/src/astro/overlays/ScanningOverlay.astro +119 -0
  140. package/src/astro/scripts/ARScripts.astro +118 -0
  141. package/src/astro/styles/ARStyles.astro +147 -0
  142. package/src/compiler/aframe.js +343 -0
  143. package/src/compiler/compiler-base.js +195 -0
  144. package/src/compiler/compiler.js +25 -0
  145. package/src/compiler/compiler.worker.js +30 -0
  146. package/src/compiler/controller.js +473 -0
  147. package/src/compiler/controller.worker.js +77 -0
  148. package/src/compiler/detector/crop-detector.js +68 -0
  149. package/src/compiler/detector/detector.js +1130 -0
  150. package/src/compiler/detector/freak.js +91 -0
  151. package/src/compiler/detector/kernels/cpu/binomialFilter.js +59 -0
  152. package/src/compiler/detector/kernels/cpu/buildExtremas.js +108 -0
  153. package/src/compiler/detector/kernels/cpu/computeExtremaAngles.js +91 -0
  154. package/src/compiler/detector/kernels/cpu/computeExtremaFreak.js +92 -0
  155. package/src/compiler/detector/kernels/cpu/computeFreakDescriptors.js +68 -0
  156. package/src/compiler/detector/kernels/cpu/computeLocalization.js +71 -0
  157. package/src/compiler/detector/kernels/cpu/computeOrientationHistograms.js +141 -0
  158. package/src/compiler/detector/kernels/cpu/downsampleBilinear.js +33 -0
  159. package/src/compiler/detector/kernels/cpu/extremaReduction.js +53 -0
  160. package/src/compiler/detector/kernels/cpu/fakeShader.js +88 -0
  161. package/src/compiler/detector/kernels/cpu/index.js +26 -0
  162. package/src/compiler/detector/kernels/cpu/prune.js +114 -0
  163. package/src/compiler/detector/kernels/cpu/smoothHistograms.js +57 -0
  164. package/src/compiler/detector/kernels/cpu/upsampleBilinear.js +51 -0
  165. package/src/compiler/detector/kernels/index.js +2 -0
  166. package/src/compiler/detector/kernels/webgl/binomialFilter.js +72 -0
  167. package/src/compiler/detector/kernels/webgl/buildExtremas.js +109 -0
  168. package/src/compiler/detector/kernels/webgl/computeExtremaAngles.js +82 -0
  169. package/src/compiler/detector/kernels/webgl/computeExtremaFreak.js +105 -0
  170. package/src/compiler/detector/kernels/webgl/computeFreakDescriptors.js +56 -0
  171. package/src/compiler/detector/kernels/webgl/computeLocalization.js +70 -0
  172. package/src/compiler/detector/kernels/webgl/computeOrientationHistograms.js +129 -0
  173. package/src/compiler/detector/kernels/webgl/downsampleBilinear.js +50 -0
  174. package/src/compiler/detector/kernels/webgl/extremaReduction.js +50 -0
  175. package/src/compiler/detector/kernels/webgl/index.js +26 -0
  176. package/src/compiler/detector/kernels/webgl/smoothHistograms.js +53 -0
  177. package/src/compiler/detector/kernels/webgl/upsampleBilinear.js +62 -0
  178. package/src/compiler/estimation/esimate-experiment.js +316 -0
  179. package/src/compiler/estimation/estimate.js +67 -0
  180. package/src/compiler/estimation/estimator.js +34 -0
  181. package/src/compiler/estimation/refine-estimate-experiment.js +512 -0
  182. package/src/compiler/estimation/refine-estimate.js +365 -0
  183. package/src/compiler/estimation/utils.js +97 -0
  184. package/src/compiler/image-list.js +62 -0
  185. package/src/compiler/index.js +13 -0
  186. package/src/compiler/input-loader.js +107 -0
  187. package/src/compiler/matching/hamming-distance.js +23 -0
  188. package/src/compiler/matching/hierarchical-clustering.js +131 -0
  189. package/src/compiler/matching/hough.js +206 -0
  190. package/src/compiler/matching/matcher.js +59 -0
  191. package/src/compiler/matching/matching.js +237 -0
  192. package/src/compiler/matching/ransacHomography.js +192 -0
  193. package/src/compiler/offline-compiler.js +553 -0
  194. package/src/compiler/tensorflow-setup.js +88 -0
  195. package/src/compiler/three.js +368 -0
  196. package/src/compiler/tracker/extract-utils.js +34 -0
  197. package/src/compiler/tracker/extract.js +419 -0
  198. package/src/compiler/tracker/tracker.js +397 -0
  199. package/src/compiler/utils/cumsum.js +40 -0
  200. package/src/compiler/utils/geometry.js +114 -0
  201. package/src/compiler/utils/homography.js +150 -0
  202. package/src/compiler/utils/images.js +111 -0
  203. package/src/compiler/utils/randomizer.js +29 -0
  204. package/src/index.ts +8 -0
  205. package/src/react/AREditor.tsx +394 -0
  206. package/src/react/ProgressDialog.tsx +185 -0
  207. package/src/react/types.ts +35 -0
@@ -0,0 +1,136 @@
1
+ import { Matrix, inverse } from "ml-matrix";
2
+ import { createRandomizer } from "../utils/randomizer.js";
3
+ import { quadrilateralConvex, matrixInverse33, smallestTriangleArea, multiplyPointHomographyInhomogenous, checkThreePointsConsistent, checkFourPointsConsistent, determinant, } from "../utils/geometry.js";
4
+ import { solveHomography } from "../utils/homography.js";
5
+ const CAUCHY_SCALE = 0.01;
6
+ const CHUNK_SIZE = 10;
7
+ const NUM_HYPOTHESES = 20;
8
+ const NUM_HYPOTHESES_QUICK = 10;
9
+ // Using RANSAC to estimate homography
10
+ const computeHomography = (options) => {
11
+ const { srcPoints, dstPoints, keyframe, quickMode } = options;
12
+ // testPoints is four corners of keyframe
13
+ const testPoints = [
14
+ [0, 0],
15
+ [keyframe.width, 0],
16
+ [keyframe.width, keyframe.height],
17
+ [0, keyframe.height],
18
+ ];
19
+ const sampleSize = 4; // use four points to compute homography
20
+ if (srcPoints.length < sampleSize)
21
+ return null;
22
+ const scale = CAUCHY_SCALE;
23
+ const oneOverScale2 = 1.0 / (scale * scale);
24
+ const chuckSize = Math.min(CHUNK_SIZE, srcPoints.length);
25
+ const randomizer = createRandomizer();
26
+ const perm = [];
27
+ for (let i = 0; i < srcPoints.length; i++) {
28
+ perm[i] = i;
29
+ }
30
+ randomizer.arrayShuffle({ arr: perm, sampleSize: perm.length });
31
+ const numHypothesis = quickMode ? NUM_HYPOTHESES_QUICK : NUM_HYPOTHESES;
32
+ const maxTrials = numHypothesis * 2;
33
+ // build numerous hypotheses by randoming draw four points
34
+ // TODO: optimize: if number of points is less than certain number, can brute force all combinations
35
+ let trial = 0;
36
+ const Hs = [];
37
+ while (trial < maxTrials && Hs.length < numHypothesis) {
38
+ trial += 1;
39
+ randomizer.arrayShuffle({ arr: perm, sampleSize: sampleSize });
40
+ // their relative positions match each other
41
+ if (!checkFourPointsConsistent(srcPoints[perm[0]], srcPoints[perm[1]], srcPoints[perm[2]], srcPoints[perm[3]], dstPoints[perm[0]], dstPoints[perm[1]], dstPoints[perm[2]], dstPoints[perm[3]])) {
42
+ continue;
43
+ }
44
+ const H = solveHomography([srcPoints[perm[0]], srcPoints[perm[1]], srcPoints[perm[2]], srcPoints[perm[3]]], [dstPoints[perm[0]], dstPoints[perm[1]], dstPoints[perm[2]], dstPoints[perm[3]]]);
45
+ if (H === null)
46
+ continue;
47
+ if (!_checkHomographyPointsGeometricallyConsistent({ H, testPoints })) {
48
+ continue;
49
+ }
50
+ Hs.push(H);
51
+ }
52
+ if (Hs.length === 0)
53
+ return null;
54
+ // pick the best hypothesis
55
+ const hypotheses = [];
56
+ for (let i = 0; i < Hs.length; i++) {
57
+ hypotheses.push({
58
+ H: Hs[i],
59
+ cost: 0,
60
+ });
61
+ }
62
+ let curChuckSize = chuckSize;
63
+ for (let i = 0; i < srcPoints.length && hypotheses.length > 2; i += curChuckSize) {
64
+ curChuckSize = Math.min(chuckSize, srcPoints.length - i);
65
+ let chuckEnd = i + curChuckSize;
66
+ for (let j = 0; j < hypotheses.length; j++) {
67
+ for (let k = i; k < chuckEnd; k++) {
68
+ const cost = _cauchyProjectiveReprojectionCost({
69
+ H: hypotheses[j].H,
70
+ srcPoint: srcPoints[k],
71
+ dstPoint: dstPoints[k],
72
+ oneOverScale2,
73
+ });
74
+ hypotheses[j].cost += cost;
75
+ }
76
+ }
77
+ hypotheses.sort((h1, h2) => {
78
+ return h1.cost - h2.cost;
79
+ });
80
+ hypotheses.splice(-Math.floor((hypotheses.length + 1) / 2)); // keep the best half
81
+ }
82
+ let finalH = null;
83
+ for (let i = 0; i < hypotheses.length; i++) {
84
+ const H = _normalizeHomography({ inH: hypotheses[i].H });
85
+ if (_checkHeuristics({ H: H, testPoints, keyframe })) {
86
+ finalH = H;
87
+ break;
88
+ }
89
+ }
90
+ return finalH;
91
+ };
92
+ const _checkHeuristics = ({ H, testPoints, keyframe }) => {
93
+ const HInv = matrixInverse33(H, 0.00001);
94
+ if (HInv === null)
95
+ return false;
96
+ const mp = [];
97
+ for (let i = 0; i < testPoints.length; i++) {
98
+ // 4 test points, corner of keyframe
99
+ mp.push(multiplyPointHomographyInhomogenous(testPoints[i], HInv));
100
+ }
101
+ const smallArea = smallestTriangleArea(mp[0], mp[1], mp[2], mp[3]);
102
+ if (smallArea < keyframe.width * keyframe.height * 0.0001)
103
+ return false;
104
+ if (!quadrilateralConvex(mp[0], mp[1], mp[2], mp[3]))
105
+ return false;
106
+ return true;
107
+ };
108
+ const _normalizeHomography = ({ inH }) => {
109
+ const oneOver = 1.0 / inH[8];
110
+ const H = [];
111
+ for (let i = 0; i < 8; i++) {
112
+ H[i] = inH[i] * oneOver;
113
+ }
114
+ H[8] = 1.0;
115
+ return H;
116
+ };
117
+ const _cauchyProjectiveReprojectionCost = ({ H, srcPoint, dstPoint, oneOverScale2 }) => {
118
+ const x = multiplyPointHomographyInhomogenous(srcPoint, H);
119
+ const f = [x[0] - dstPoint[0], x[1] - dstPoint[1]];
120
+ return Math.log(1 + (f[0] * f[0] + f[1] * f[1]) * oneOverScale2);
121
+ };
122
+ const _checkHomographyPointsGeometricallyConsistent = ({ H, testPoints }) => {
123
+ const mappedPoints = [];
124
+ for (let i = 0; i < testPoints.length; i++) {
125
+ mappedPoints[i] = multiplyPointHomographyInhomogenous(testPoints[i], H);
126
+ }
127
+ for (let i = 0; i < testPoints.length; i++) {
128
+ const i1 = i;
129
+ const i2 = (i + 1) % testPoints.length;
130
+ const i3 = (i + 2) % testPoints.length;
131
+ if (!checkThreePointsConsistent(testPoints[i1], testPoints[i2], testPoints[i3], mappedPoints[i1], mappedPoints[i2], mappedPoints[i3]))
132
+ return false;
133
+ }
134
+ return true;
135
+ };
136
+ export { computeHomography };
@@ -0,0 +1,10 @@
1
+ export class OfflineCompiler extends CompilerBase {
2
+ isServerless: string | undefined;
3
+ _ensureTensorflowReady(): Promise<any>;
4
+ compileTrack({ progressCallback, targetImages, basePercent }: {
5
+ progressCallback: any;
6
+ targetImages: any;
7
+ basePercent: any;
8
+ }): Promise<any>;
9
+ }
10
+ import { CompilerBase } from "./compiler-base.js";
@@ -0,0 +1,450 @@
1
+ /**
2
+ * @fileoverview Compilador Offline para Procesamiento de Imágenes con TensorFlow.js
3
+ *
4
+ * Este módulo implementa un sistema avanzado de compilación de imágenes para tracking
5
+ * utilizando TensorFlow.js, optimizado especialmente para entornos backend con alto rendimiento.
6
+ *
7
+ * Arquitectura y Componentes Principales:
8
+ *
9
+ * 1. Sistema de Inicialización:
10
+ * - Implementa un patrón Singleton para TensorFlow con inicialización temprana
11
+ * - Carga asíncrona y paralela de backends (CPU/WebGL/Node)
12
+ * - Detección automática de entorno (serverless/navegador/backend dedicado)
13
+ * - Precalentamiento agresivo para reducir cold starts
14
+ *
15
+ * 2. Gestión de Memoria:
16
+ * - Sistema de liberación ultra-agresiva de memoria con umbrales dinámicos
17
+ * - Monitoreo continuo del uso de tensores con cleanup automático
18
+ * - Estrategias de scope anidados para control preciso de recursos
19
+ * - Liberación proactiva entre operaciones intensivas
20
+ *
21
+ * 3. Optimizaciones de Rendimiento:
22
+ * - Precalentamiento estratégico del backend para eliminar latencia inicial
23
+ * - Ajustes específicos por backend con configuraciones óptimas por plataforma
24
+ * - Configuraciones especializadas para entornos backend de alto rendimiento
25
+ * - Reducción de precisión selectiva para operaciones no críticas
26
+ *
27
+ * 4. Procesamiento por Lotes:
28
+ * - Sistema adaptativo de tamaño de lotes basado en capacidad de hardware
29
+ * - Paralelización multinivel con control de concurrencia
30
+ * - Control de progreso granular con retroalimentación en tiempo real
31
+ * - Estrategias de división de trabajo para CPUs multi-núcleo
32
+ *
33
+ * 5. Gestión de Recursos:
34
+ * - Timeouts inteligentes con recuperación automática
35
+ * - Liberación proactiva de recursos con GC forzado estratégico
36
+ * - Manejo de errores robusto con recuperación de fallos
37
+ * - Monitoreo de rendimiento en tiempo real
38
+ *
39
+ * @requires tensorflow/tfjs
40
+ * @requires ./compiler-base.js
41
+ * @requires ./image-list.js
42
+ * @requires ./tracker/extract-utils.js
43
+ * @requires ./tensorflow-setup.js
44
+ */
45
+ import { CompilerBase } from "./compiler-base.js";
46
+ import { buildTrackingImageList } from "./image-list.js";
47
+ import { extractTrackingFeatures } from "./tracker/extract-utils.js";
48
+ import { setupTensorFlow } from "./tensorflow-setup.js";
49
+ import { tf } from "./tensorflow-setup.js";
50
+ import os from "os";
51
+ // OPTIMIZACIÓN CORE DEL PROCESO DE COMPILACIÓN
52
+ // 1. Inicialización temprana y paralela de TensorFlow
53
+ // 2. Optimizaciones de memoria y procesamiento agresivas
54
+ // 3. Estrategias de paralelización avanzadas
55
+ // 4. Ajustes para entornos serverless (Vercel, AWS Lambda, etc)
56
+ // Detector de entorno serverless
57
+ const isServerlessEnvironment = () => {
58
+ return process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME || process.env.NETLIFY;
59
+ };
60
+ // Configurar TensorFlow lo antes posible con un Singleton
61
+ let tensorflowBackend = null;
62
+ let setupPromise = null;
63
+ const setupTensorFlowAsync = async () => {
64
+ // Si ya hay una configuración en curso, reutilizarla
65
+ if (setupPromise)
66
+ return setupPromise;
67
+ // Iniciar configuración y guardar la promesa
68
+ setupPromise = (async () => {
69
+ try {
70
+ console.time("⏱️ Configuración de TensorFlow");
71
+ const backend = await setupTensorFlow();
72
+ tensorflowBackend = backend;
73
+ console.timeEnd("⏱️ Configuración de TensorFlow");
74
+ return backend;
75
+ }
76
+ catch (error) {
77
+ console.error("Error crítico al configurar TensorFlow:", error);
78
+ return null;
79
+ }
80
+ })();
81
+ return setupPromise;
82
+ };
83
+ // Iniciar la configuración inmediatamente al importar el módulo
84
+ const tensorflowSetupPromise = setupTensorFlowAsync();
85
+ // Registrar los kernels necesarios para CPU (carga temprana)
86
+ import "./detector/kernels/cpu/index.js";
87
+ // Registrar los backends básicos
88
+ import "@tensorflow/tfjs-backend-cpu";
89
+ // Configuraciones avanzadas para maximizar rendimiento en backend
90
+ const enablePerformanceOptimizations = async () => {
91
+ try {
92
+ // Esperar a que TensorFlow esté configurado
93
+ await tensorflowSetupPromise;
94
+ // Optimizaciones específicas según el backend
95
+ const backend = tf.getBackend();
96
+ console.log(`⚙️ Optimizando agresivamente para backend: ${backend}`);
97
+ // Entorno serverless necesita configuraciones especiales
98
+ const isServerless = isServerlessEnvironment();
99
+ const isBackendDedicated = !isServerless && process.env.NODE_ENV === "production";
100
+ if (isBackendDedicated) {
101
+ console.log("🚀🚀 Entorno backend dedicado detectado, aplicando configuraciones de alto rendimiento");
102
+ // Configuraciones agresivas para backend dedicado
103
+ tf.ENV.set("CPU_HANDOFF_SIZE_THRESHOLD", 1024 * 1024 * 16); // 16MB - más memoria disponible
104
+ tf.ENV.set("WEBGL_SIZE_UPLOAD_UNIFORM", 16); // Mayor capacidad de transferencia
105
+ tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD", 64); // Más texturas en memoria
106
+ // Configuraciones para maximizar throughput
107
+ tf.ENV.set("WEBGL_FLUSH_THRESHOLD", 10); // Menos flushes para mejor rendimiento
108
+ tf.ENV.set("KEEP_INTERMEDIATE_TENSORS", false); // Liberar intermedios agresivamente
109
+ tf.ENV.set("WEBGL_PACK_BINARY_OPERATIONS", true); // Empaquetar operaciones binarias
110
+ }
111
+ else if (isServerless) {
112
+ console.log("🚀 Entorno serverless detectado, aplicando configuraciones de memoria restrictivas");
113
+ // En serverless aplicamos configuraciones más conservadoras para memoria
114
+ tf.ENV.set("CPU_HANDOFF_SIZE_THRESHOLD", 1024 * 1024 * 4); // 4MB
115
+ tf.ENV.set("WEBGL_SIZE_UPLOAD_UNIFORM", 4);
116
+ tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD", 10);
117
+ // Menor precisión para mejor rendimiento
118
+ tf.ENV.set("WEBGL_RENDER_FLOAT32_ENABLED", false);
119
+ }
120
+ // Optimizaciones generales para todos los backends
121
+ tf.ENV.set("WEBGL_CPU_FORWARD", false);
122
+ tf.ENV.set("DEBUG", false);
123
+ tf.ENV.set("CHECK_COMPUTATION_FOR_ERRORS", false); // Deshabilitar verificaciones para mayor velocidad
124
+ // Optimizar el uso de memoria con límites más altos
125
+ if (backend === "node") {
126
+ console.log("🔧 Aplicando optimizaciones avanzadas para Node.js backend");
127
+ }
128
+ else if (backend === "webgl") {
129
+ // Optimizaciones específicas para WebGL
130
+ console.log("🔧 Aplicando optimizaciones avanzadas para WebGL backend");
131
+ tf.ENV.set("WEBGL_FORCE_F16_TEXTURES", true);
132
+ tf.ENV.set("WEBGL_PACK", true);
133
+ tf.ENV.set("WEBGL_PACK_DEPTHWISECONV", true);
134
+ tf.ENV.set("WEBGL_PACK_BINARY_OPERATIONS", true);
135
+ tf.ENV.set("WEBGL_PACK_ARRAY_OPERATIONS", true);
136
+ tf.ENV.set("WEBGL_PACK_IMAGE_OPERATIONS", true);
137
+ tf.ENV.set("WEBGL_PACK_REDUCE", true);
138
+ // Configuraciones de textura según entorno
139
+ if (isBackendDedicated) {
140
+ // En backend dedicado, usar valores más agresivos
141
+ tf.ENV.set("WEBGL_MAX_TEXTURE_SIZE", 8192); // Texturas más grandes
142
+ tf.ENV.set("WEBGL_MAX_TEXTURES_IN_SHADER", 16); // Más texturas por shader
143
+ }
144
+ else if (isServerless) {
145
+ // En serverless, usamos valores más conservadores
146
+ tf.ENV.set("WEBGL_MAX_TEXTURE_SIZE", 2048);
147
+ tf.ENV.set("WEBGL_MAX_TEXTURES_IN_SHADER", 8);
148
+ }
149
+ else {
150
+ // Entorno normal
151
+ tf.ENV.set("WEBGL_MAX_TEXTURE_SIZE", 4096);
152
+ tf.ENV.set("WEBGL_MAX_TEXTURES_IN_SHADER", 12);
153
+ }
154
+ }
155
+ else if (backend === "cpu") {
156
+ // Optimizaciones específicas para CPU
157
+ console.log("🔧 Aplicando optimizaciones para CPU backend");
158
+ // Intentar usar SIMD si está disponible
159
+ try {
160
+ if (typeof WebAssembly.validate === "function" &&
161
+ WebAssembly.validate(new Uint8Array([
162
+ 0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 123, 3, 2, 1, 0, 10, 10, 1, 8, 0, 65,
163
+ 0, 253, 15, 253, 98, 11,
164
+ ]))) {
165
+ console.log("🚀 SIMD disponible, habilitando aceleración vectorial");
166
+ tf.ENV.set("WASM_HAS_SIMD_SUPPORT", true);
167
+ tf.ENV.set("WASM_HAS_MULTITHREAD_SUPPORT", true);
168
+ }
169
+ }
170
+ catch (e) {
171
+ console.warn("⚠️ No se pudo detectar soporte SIMD", e);
172
+ }
173
+ }
174
+ // Precalentamiento estratégico del backend para eliminar retrasos en la primera ejecución
175
+ // Implementamos un precalentamiento adaptativo según el entorno
176
+ console.time("🔥 Precalentamiento estratégico");
177
+ console.log("🔥 Precalentando TensorFlow con operaciones específicas...");
178
+ await tf.ready();
179
+ // Detectar si estamos en un entorno de backend dedicado
180
+ // Estrategia de precalentamiento adaptativa según entorno
181
+ const warmupStrategy = isBackendDedicated
182
+ ? "aggressive"
183
+ : isServerless
184
+ ? "minimal"
185
+ : "balanced";
186
+ console.log(`🔥 Aplicando estrategia de precalentamiento: ${warmupStrategy}`);
187
+ // Función para ejecutar y esperar operaciones tensores
188
+ const executeAndWait = async (tensors) => {
189
+ // Esperar a que todas las operaciones se completen
190
+ await Promise.all(tensors.map((t) => t.data()));
191
+ // Liberar memoria inmediatamente
192
+ tf.dispose(tensors);
193
+ };
194
+ // Precalentamiento básico para todos los entornos
195
+ await tf.tidy(async () => {
196
+ // Operaciones básicas de álgebra tensorial
197
+ const a = tf.tensor([1, 2, 3, 4]);
198
+ const b = tf.tensor([2, 2, 2, 2]);
199
+ const result = a.add(b);
200
+ const mult = a.mul(b);
201
+ const div = a.div(b);
202
+ await executeAndWait([result, mult, div]);
203
+ });
204
+ // Tamaño de imagen adaptativo según entorno
205
+ const size = isBackendDedicated ? 224 : isServerless ? 64 : 128;
206
+ console.log(`🖼️ Precalentando con imagen de tamaño ${size}x${size}`);
207
+ // Precalentamiento de operaciones de procesamiento de imágenes
208
+ await tf.tidy(async () => {
209
+ // Crear imagen sintética para precalentamiento
210
+ const image = tf.ones([size, size, 3]);
211
+ // Precalentar operaciones de preprocesamiento comunes
212
+ const normalized = image.div(tf.scalar(255));
213
+ const grayscale = image.mean(2, true); // Reducción de canal para escala de grises
214
+ await executeAndWait([normalized, grayscale]);
215
+ // Precalentar operaciones de convolución con diferentes configuraciones
216
+ // Estas operaciones son críticas para la extracción de características
217
+ const kernelSizes = warmupStrategy === "aggressive" ? [3, 5, 7] : [3];
218
+ const filterCounts = warmupStrategy === "aggressive" ? [8, 16] : [4];
219
+ for (const kernelSize of kernelSizes) {
220
+ for (const filters of filterCounts) {
221
+ // Crear kernel aleatorio para convolución
222
+ const kernel = tf.randomNormal([kernelSize, kernelSize, 3, filters]);
223
+ // Aplicar convolución - operación clave en detección de características
224
+ const convResult = tf.conv2d(image, kernel, 1, "same");
225
+ // Operaciones de pooling - también críticas en redes de detección
226
+ const maxPooled = tf.maxPool(convResult, [2, 2], 2, "same");
227
+ const avgPooled = tf.avgPool(convResult, [2, 2], 2, "same");
228
+ // Activaciones comunes
229
+ const activated = tf.relu(convResult);
230
+ await executeAndWait([convResult, maxPooled, avgPooled, activated]);
231
+ }
232
+ }
233
+ // En modo agresivo, precalentar operaciones más avanzadas
234
+ if (warmupStrategy === "aggressive") {
235
+ // Operaciones de transformación espacial comunes en tracking
236
+ const resized = tf.image.resizeBilinear(image, [size / 2, size / 2]);
237
+ const cropped = tf.slice(image, [0, 0, 0], [size / 2, size / 2, 3]);
238
+ await executeAndWait([resized, cropped]);
239
+ // Operaciones de detección de bordes (aproximación)
240
+ const sobelX = tf.conv2d(grayscale, tf.tensor4d([
241
+ [-1, 0, 1],
242
+ [-2, 0, 2],
243
+ [-1, 0, 1],
244
+ ], [3, 3, 1, 1]), 1, "same");
245
+ const sobelY = tf.conv2d(grayscale, tf.tensor4d([
246
+ [-1, -2, -1],
247
+ [0, 0, 0],
248
+ [1, 2, 1],
249
+ ], [3, 3, 1, 1]), 1, "same");
250
+ const edges = tf.sqrt(tf.add(tf.square(sobelX), tf.square(sobelY)));
251
+ await executeAndWait([sobelX, sobelY, edges]);
252
+ }
253
+ });
254
+ // Forzar recolección de basura para limpiar completamente
255
+ if (global.gc) {
256
+ try {
257
+ global.gc();
258
+ console.log("♻️ Recolección de basura manual ejecutada");
259
+ }
260
+ catch (e) {
261
+ // Ignorar errores si no está disponible
262
+ }
263
+ }
264
+ // Verificar estado de memoria después del precalentamiento
265
+ const memInfo = tf.memory();
266
+ console.log(`📊 Estado de memoria post-precalentamiento: ${memInfo.numTensors} tensores, ${(memInfo.numBytes / (1024 * 1024)).toFixed(2)}MB`);
267
+ console.timeEnd("🔥 Precalentamiento estratégico");
268
+ }
269
+ catch (error) {
270
+ console.warn("⚠️ No se pudieron aplicar todas las optimizaciones:", error);
271
+ }
272
+ };
273
+ // Aplicar optimizaciones de manera asíncrona para no bloquear
274
+ enablePerformanceOptimizations();
275
+ // Versión optimizada del compilador
276
+ export class OfflineCompiler extends CompilerBase {
277
+ constructor() {
278
+ super();
279
+ // Detección de entorno
280
+ this.isServerless = isServerlessEnvironment();
281
+ if (this.isServerless) {
282
+ console.log("🚀 Compilador optimizado para entorno serverless");
283
+ }
284
+ // Inicializar inmediatamente para evitar arranque frío
285
+ this._ensureTensorflowReady();
286
+ }
287
+ // Método privado para asegurar que TensorFlow esté listo
288
+ async _ensureTensorflowReady() {
289
+ if (!tensorflowBackend) {
290
+ await tensorflowSetupPromise;
291
+ }
292
+ return tensorflowBackend;
293
+ }
294
+ // Versión optimizada del método principal de compilación
295
+ compileTrack({ progressCallback, targetImages, basePercent }) {
296
+ return new Promise(async (resolve, reject) => {
297
+ // Prevenir errores de timeout en entornos serverless
298
+ let compilationTimeout;
299
+ // En serverless, establecer un límite estricto de tiempo para evitar timeouts
300
+ if (this.isServerless) {
301
+ const timeoutSeconds = 25; // Tiempo límite para compilación en serverless
302
+ compilationTimeout = setTimeout(() => {
303
+ reject(new Error(`Tiempo límite de compilación excedido (${timeoutSeconds}s). La imagen puede ser demasiado compleja para procesamiento serverless.`));
304
+ }, timeoutSeconds * 1000);
305
+ }
306
+ try {
307
+ // Asegurar que TensorFlow esté configurado
308
+ await this._ensureTensorflowReady();
309
+ console.time("⏱️ Tiempo de compilación de tracking");
310
+ const backend = tf.getBackend();
311
+ const percentPerImage = (100 - basePercent) / targetImages.length;
312
+ let percent = 0;
313
+ const list = [];
314
+ console.log(`🧮 Compilando con backend: ${backend}`);
315
+ // Optimizar el tamaño de lote según el backend disponible
316
+ // En serverless, siempre usar lotes más pequeños
317
+ // Estrategia adaptativa para tamaño de lote (CPU/GPU)
318
+ let batchSize = 1;
319
+ if (backend === "node") {
320
+ // Calcular tamaño óptimo basado en recursos
321
+ try {
322
+ const cpus = os.cpus().length;
323
+ const freeMem = os.freemem() / 1024 / 1024 / 1024; // GB libres
324
+ // Lógica de batch dinámico:
325
+ // - 1 núcleo: batch 1 (evitar sobrecarga)
326
+ // - 2-4 núcleos: batch 2-4 (balance carga/paralelismo)
327
+ // - >4 núcleos: batch escalable con memoria
328
+ batchSize =
329
+ cpus > 4
330
+ ? Math.min(Math.floor(freeMem * 0.5), 8) // 0.5GB por batch
331
+ : Math.min(cpus, 4);
332
+ console.log(`🧠 Batch size calculado: ${batchSize} (${cpus} cores, ${freeMem.toFixed(1)}GB libres)`);
333
+ }
334
+ catch (e) {
335
+ console.warn("⚠️ Error cálculo batch size:", e);
336
+ batchSize = 2; // Fallback: equilibrio seguridad/performance
337
+ }
338
+ }
339
+ else if (this.isServerless) {
340
+ batchSize = 1; // Priorizar seguridad sobre performance
341
+ }
342
+ // Garantizar límites operativos seguros:
343
+ // - Mínimo: Evitar underflow en procesamiento
344
+ // - Máximo: Prevenir OOM (Out Of Memory)
345
+ batchSize = Math.max(1, Math.min(batchSize, 8));
346
+ console.log(`📊 Procesando imágenes en lotes de ${batchSize}`);
347
+ // Solicitar memoria mínima antes de empezar procesamiento intensivo
348
+ if (global.gc) {
349
+ try {
350
+ global.gc();
351
+ }
352
+ catch (e) {
353
+ // Ignorar errores
354
+ }
355
+ }
356
+ // Paralelismo para el procesamiento en lotes
357
+ for (let i = 0; i < targetImages.length; i += batchSize) {
358
+ // Procesar un lote de imágenes
359
+ const batch = targetImages.slice(i, Math.min(i + batchSize, targetImages.length));
360
+ // Imprimir información sobre el procesamiento por lotes
361
+ if (batch.length > 1) {
362
+ console.log(`🔄 Procesando lote ${Math.floor(i / batchSize) + 1}: ${batch.length} imágenes`);
363
+ }
364
+ // Usar tf.engine().startScope() para mejor control de memoria por lote
365
+ tf.engine().startScope();
366
+ try {
367
+ // Procesamiento paralelo de imágenes en el lote
368
+ const batchResults = await Promise.all(batch.map(async (targetImage) => {
369
+ const imageList = buildTrackingImageList(targetImage);
370
+ const percentPerAction = percentPerImage / imageList.length;
371
+ // Usar tf.tidy para liberar memoria automáticamente en cada imagen
372
+ return await tf.tidy(() => {
373
+ // Extraer características con monitoreo de progreso
374
+ const trackingData = extractTrackingFeatures(imageList, (index) => {
375
+ percent += percentPerAction;
376
+ progressCallback(basePercent + percent);
377
+ });
378
+ return trackingData;
379
+ });
380
+ }));
381
+ // Agregar resultados a la lista final
382
+ list.push(...batchResults);
383
+ }
384
+ finally {
385
+ // Asegurar que siempre se cierre el scope para evitar fugas de memoria
386
+ tf.engine().endScope();
387
+ }
388
+ // Liberar memoria entre lotes grandes o al final
389
+ // En serverless, liberar más agresivamente
390
+ if (i % (this.isServerless ? 2 : 5) === 0 || i === targetImages.length - 1) {
391
+ await tf.nextFrame(); // Permitir que el recolector de basura libere memoria
392
+ // Cálculo de presión de memoria adaptativa
393
+ const memoryInfo = tf.memory();
394
+ const totalMem = os.totalmem();
395
+ const freeMem = os.freemem();
396
+ const memPressure = 1 - freeMem / totalMem;
397
+ // Umbrales dinámicos basados en:
398
+ // 1. Tipo de backend (mayor tolerancia en GPU)
399
+ // 2. Presión de memoria actual
400
+ // 3. Entorno de ejecución (serverless vs dedicado)
401
+ const baseThreshold = backend === "webgl" ? 50 : 30;
402
+ const adaptiveThreshold = Math.floor(baseThreshold *
403
+ (1 - Math.min(memPressure, 0.5)) *
404
+ (this.isServerless ? 0.6 : 1) *
405
+ (this.isBackendDedicated ? 1.2 : 1));
406
+ console.log(`🧠 Memoria: ${(freeMem / 1024 / 1024).toFixed(1)}MB libres | ` +
407
+ `Presión: ${(memPressure * 100).toFixed(1)}% | ` +
408
+ `Umbral: ${adaptiveThreshold} tensores`);
409
+ if (memoryInfo.numTensors > adaptiveThreshold) {
410
+ // Estrategia de limpieza diferenciada
411
+ console.log(`🧹 Limpieza ${this.isServerless ? "conservadora" : "agresiva"}: ` +
412
+ `${memoryInfo.numTensors} tensores, ${(memoryInfo.numBytes / 1024 / 1024).toFixed(2)}MB`);
413
+ // Estrategia de limpieza diferenciada:
414
+ // - Serverless: Liberación temprana preventiva
415
+ // - Dedicado: Postergar GC para mejor throughput
416
+ tf.disposeVariables();
417
+ tf.dispose();
418
+ // Forzar recolección de basura en Node.js si está disponible
419
+ if (global.gc) {
420
+ try {
421
+ global.gc();
422
+ }
423
+ catch (e) {
424
+ // Ignorar errores si no está disponible
425
+ }
426
+ }
427
+ }
428
+ }
429
+ }
430
+ // Terminar medición de tiempo
431
+ console.timeEnd("⏱️ Tiempo de compilación de tracking");
432
+ // Liberar toda la memoria restante antes de finalizar
433
+ tf.dispose();
434
+ // Limpiar timeout si existía
435
+ if (compilationTimeout) {
436
+ clearTimeout(compilationTimeout);
437
+ }
438
+ resolve(list);
439
+ }
440
+ catch (error) {
441
+ // Limpiar timeout si existía
442
+ if (compilationTimeout) {
443
+ clearTimeout(compilationTimeout);
444
+ }
445
+ console.error("❌ Error en compilación:", error);
446
+ reject(error);
447
+ }
448
+ });
449
+ }
450
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Configuración optimizada de TensorFlow para diferentes entornos
3
+ * @returns {Promise<string>} El backend activo ('webgl', 'cpu')
4
+ */
5
+ export function setupTensorFlow(): Promise<string>;
6
+ export { tf };
7
+ import * as tf from "@tensorflow/tfjs";