@srsergio/taptapp-ar 1.0.18 → 1.0.20

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.
@@ -13,9 +13,9 @@ catch (e) {
13
13
  // Fallback for tests or other environments
14
14
  ControllerWorker = null;
15
15
  }
16
- const DEFAULT_FILTER_CUTOFF = 0.001; // 1Hz. time period in milliseconds
17
- const DEFAULT_FILTER_BETA = 1000;
18
- const DEFAULT_WARMUP_TOLERANCE = 5;
16
+ const DEFAULT_FILTER_CUTOFF = 0.1; // Menor cutoff para filtrar más ruidos cuando está quieto
17
+ const DEFAULT_FILTER_BETA = 0.01; // Beta bajo para suavizar movimientos rápidos
18
+ const DEFAULT_WARMUP_TOLERANCE = 8; // Más frames de calentamiento para asegurar estabilidad inicial
19
19
  const DEFAULT_MISS_TOLERANCE = 5;
20
20
  class Controller {
21
21
  constructor({ inputWidth, inputHeight, onUpdate = null, debugMode = false, maxTrack = 1, warmupTolerance = null, missTolerance = null, filterMinCF = null, filterBeta = null, worker = null, // Allow custom worker injection
@@ -11,10 +11,10 @@
11
11
  */
12
12
  import { FREAKPOINTS } from "./freak.js";
13
13
  import { gpuCompute } from "../utils/gpu-compute.js";
14
- const PYRAMID_MIN_SIZE = 8;
15
- const PYRAMID_MAX_OCTAVE = 5;
14
+ const PYRAMID_MIN_SIZE = 4; // Reducido de 8 a 4 para exprimir al máximo la resolución
15
+ // PYRAMID_MAX_OCTAVE ya no es necesario, el límite lo da PYRAMID_MIN_SIZE
16
16
  const NUM_BUCKETS_PER_DIMENSION = 8;
17
- const MAX_FEATURES_PER_BUCKET = 10; // Aumentado de 3 a 10 para mayor densidad de puntos tracking
17
+ const MAX_FEATURES_PER_BUCKET = 12; // Ajustado para un equilibrio óptimo entre densidad y estabilidad
18
18
  const ORIENTATION_NUM_BINS = 36;
19
19
  const FREAK_EXPANSION_FACTOR = 7.0;
20
20
  // Global GPU mode flag
@@ -40,7 +40,8 @@ export class DetectorLite {
40
40
  w = Math.floor(w / 2);
41
41
  h = Math.floor(h / 2);
42
42
  numOctaves++;
43
- if (numOctaves === PYRAMID_MAX_OCTAVE)
43
+ // Límite de seguridad razonable para evitar bucles infinitos en imágenes gigantes
44
+ if (numOctaves === 10)
44
45
  break;
45
46
  }
46
47
  this.numOctaves = numOctaves;
@@ -4,7 +4,7 @@ import { resize } from "./utils/images.js";
4
4
  * Un valor más bajo permite detectar imágenes más pequeñas pero aumenta el tiempo de procesamiento
5
5
  * @constant {number}
6
6
  */
7
- const MIN_IMAGE_PIXEL_SIZE = 100;
7
+ const MIN_IMAGE_PIXEL_SIZE = 32;
8
8
  /**
9
9
  * Construye una lista de imágenes con diferentes escalas para detección de características
10
10
  * @param {Object} inputImage - Imagen de entrada con propiedades width, height y data
@@ -42,7 +42,8 @@ const buildTrackingImageList = (inputImage) => {
42
42
  const minDimension = Math.min(inputImage.width, inputImage.height);
43
43
  const scaleList = [];
44
44
  const imageList = [];
45
- // Solo generamos la versión de 128px para ahorrar espacio (antes generaba 256px y 128px)
45
+ // Generamos versiones de 256px y 128px para tracking robusto a diferentes distancias
46
+ scaleList.push(256.0 / minDimension);
46
47
  scaleList.push(128.0 / minDimension);
47
48
  for (let i = 0; i < scaleList.length; i++) {
48
49
  imageList.push(Object.assign(resize({ image: inputImage, ratio: scaleList[i] }), { scale: scaleList[i] }));
@@ -157,20 +157,23 @@ class SimpleAR {
157
157
  // focal length (roughly 45 degrees FOV match Controller.js)
158
158
  const f = videoH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
159
159
  // Perspective projection to screen space
160
- const screenX = offsetX + (videoW / 2 + (tx * f / -tz)) * scaleX;
161
- const screenY = offsetY + (videoH / 2 - (ty * f / -tz)) * scaleY;
160
+ // The estimator returns positive Z for depth, so we divide by tz directly.
161
+ const screenX = offsetX + (videoW / 2 + (tx * f / tz)) * scaleX;
162
+ const screenY = offsetY + (videoH / 2 - (ty * f / tz)) * scaleY;
162
163
  // Use the first row of mVT to determine rotation and base scale component
163
- // Since marker coordinates are in pixels, mVT[0][0] and mVT[0][1] are unitless scale factors
164
164
  const rotation = Math.atan2(mVT[1][0], mVT[0][0]);
165
165
  const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
166
- // Perspective scale: how much larger/smaller the object is based on distance (tz)
167
- // Correct scale should make a marker-width sized element cover the marker.
168
- const perspectiveScale = (f / -tz) * scaleX;
169
- // The overlay element has its own width in CSS pixels (e.g. 200px)
170
- const overlayCSSWidth = parseFloat(this.overlay.style.width) || 200;
171
- // Final scale = (Target Width in Pixels on screen) / (Overlay CSS Width)
172
- // matrixScale is usually ~1.0 if tracking is rigid
173
- const finalScale = (matrixScale * markerW * perspectiveScale) / overlayCSSWidth;
166
+ // Perspective scale: 1 world pixel = (f/tz) screen pixels
167
+ const perspectiveScale = (f / tz) * scaleX;
168
+ // Detect overlay intrinsic size (videoWidth for video, naturalWidth for images)
169
+ const intrinsicWidth = (this.overlay instanceof HTMLVideoElement)
170
+ ? this.overlay.videoWidth
171
+ : (this.overlay instanceof HTMLImageElement ? this.overlay.naturalWidth : 0);
172
+ // Final scale = (Target Width in Pixels on screen) / (Overlay Intrinsic Width)
173
+ // If intrinsicWidth is 0 (not loaded), we fallback to a safe 1.0 scale to avoid Infinity
174
+ const finalScale = intrinsicWidth > 0
175
+ ? (matrixScale * markerW * perspectiveScale) / intrinsicWidth
176
+ : 1.0;
174
177
  // Apply transform
175
178
  this.overlay.style.position = 'absolute';
176
179
  this.overlay.style.transformOrigin = 'center center';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@srsergio/taptapp-ar",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "AR Compiler for Node.js and Browser",
5
5
  "repository": {
6
6
  "type": "git",
@@ -15,9 +15,11 @@ try {
15
15
  ControllerWorker = null;
16
16
  }
17
17
 
18
- const DEFAULT_FILTER_CUTOFF = 0.001; // 1Hz. time period in milliseconds
19
- const DEFAULT_FILTER_BETA = 1000;
20
- const DEFAULT_WARMUP_TOLERANCE = 5;
18
+ const DEFAULT_FILTER_CUTOFF = 0.1; // Menor cutoff para filtrar más ruidos cuando está quieto
19
+ const DEFAULT_FILTER_BETA = 0.01; // Beta bajo para suavizar movimientos rápidos
20
+
21
+ const DEFAULT_WARMUP_TOLERANCE = 8; // Más frames de calentamiento para asegurar estabilidad inicial
22
+
21
23
  const DEFAULT_MISS_TOLERANCE = 5;
22
24
 
23
25
  class Controller {
@@ -13,10 +13,14 @@
13
13
  import { FREAKPOINTS } from "./freak.js";
14
14
  import { gpuCompute } from "../utils/gpu-compute.js";
15
15
 
16
- const PYRAMID_MIN_SIZE = 8;
17
- const PYRAMID_MAX_OCTAVE = 5;
16
+ const PYRAMID_MIN_SIZE = 4; // Reducido de 8 a 4 para exprimir al máximo la resolución
17
+ // PYRAMID_MAX_OCTAVE ya no es necesario, el límite lo da PYRAMID_MIN_SIZE
18
+
19
+
18
20
  const NUM_BUCKETS_PER_DIMENSION = 8;
19
- const MAX_FEATURES_PER_BUCKET = 10; // Aumentado de 3 a 10 para mayor densidad de puntos tracking
21
+ const MAX_FEATURES_PER_BUCKET = 12; // Ajustado para un equilibrio óptimo entre densidad y estabilidad
22
+
23
+
20
24
  const ORIENTATION_NUM_BINS = 36;
21
25
  const FREAK_EXPANSION_FACTOR = 7.0;
22
26
 
@@ -46,8 +50,10 @@ export class DetectorLite {
46
50
  w = Math.floor(w / 2);
47
51
  h = Math.floor(h / 2);
48
52
  numOctaves++;
49
- if (numOctaves === PYRAMID_MAX_OCTAVE) break;
53
+ // Límite de seguridad razonable para evitar bucles infinitos en imágenes gigantes
54
+ if (numOctaves === 10) break;
50
55
  }
56
+
51
57
  this.numOctaves = numOctaves;
52
58
  }
53
59
 
@@ -5,7 +5,9 @@ import { resize } from "./utils/images.js";
5
5
  * Un valor más bajo permite detectar imágenes más pequeñas pero aumenta el tiempo de procesamiento
6
6
  * @constant {number}
7
7
  */
8
- const MIN_IMAGE_PIXEL_SIZE = 100;
8
+ const MIN_IMAGE_PIXEL_SIZE = 32;
9
+
10
+
9
11
 
10
12
  /**
11
13
  * Construye una lista de imágenes con diferentes escalas para detección de características
@@ -49,7 +51,8 @@ const buildTrackingImageList = (inputImage) => {
49
51
  const minDimension = Math.min(inputImage.width, inputImage.height);
50
52
  const scaleList = [];
51
53
  const imageList = [];
52
- // Solo generamos la versión de 128px para ahorrar espacio (antes generaba 256px y 128px)
54
+ // Generamos versiones de 256px y 128px para tracking robusto a diferentes distancias
55
+ scaleList.push(256.0 / minDimension);
53
56
  scaleList.push(128.0 / minDimension);
54
57
  for (let i = 0; i < scaleList.length; i++) {
55
58
  imageList.push(
@@ -59,4 +62,5 @@ const buildTrackingImageList = (inputImage) => {
59
62
  return imageList;
60
63
  };
61
64
 
65
+
62
66
  export { buildImageList, buildTrackingImageList };
@@ -187,24 +187,27 @@ class SimpleAR {
187
187
  const f = videoH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
188
188
 
189
189
  // Perspective projection to screen space
190
- const screenX = offsetX + (videoW / 2 + (tx * f / -tz)) * scaleX;
191
- const screenY = offsetY + (videoH / 2 - (ty * f / -tz)) * scaleY;
190
+ // The estimator returns positive Z for depth, so we divide by tz directly.
191
+ const screenX = offsetX + (videoW / 2 + (tx * f / tz)) * scaleX;
192
+ const screenY = offsetY + (videoH / 2 - (ty * f / tz)) * scaleY;
192
193
 
193
194
  // Use the first row of mVT to determine rotation and base scale component
194
- // Since marker coordinates are in pixels, mVT[0][0] and mVT[0][1] are unitless scale factors
195
195
  const rotation = Math.atan2(mVT[1][0], mVT[0][0]);
196
196
  const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
197
197
 
198
- // Perspective scale: how much larger/smaller the object is based on distance (tz)
199
- // Correct scale should make a marker-width sized element cover the marker.
200
- const perspectiveScale = (f / -tz) * scaleX;
198
+ // Perspective scale: 1 world pixel = (f/tz) screen pixels
199
+ const perspectiveScale = (f / tz) * scaleX;
201
200
 
202
- // The overlay element has its own width in CSS pixels (e.g. 200px)
203
- const overlayCSSWidth = parseFloat(this.overlay.style.width) || 200;
201
+ // Detect overlay intrinsic size (videoWidth for video, naturalWidth for images)
202
+ const intrinsicWidth = (this.overlay instanceof HTMLVideoElement)
203
+ ? this.overlay.videoWidth
204
+ : (this.overlay instanceof HTMLImageElement ? this.overlay.naturalWidth : 0);
204
205
 
205
- // Final scale = (Target Width in Pixels on screen) / (Overlay CSS Width)
206
- // matrixScale is usually ~1.0 if tracking is rigid
207
- const finalScale = (matrixScale * markerW * perspectiveScale) / overlayCSSWidth;
206
+ // Final scale = (Target Width in Pixels on screen) / (Overlay Intrinsic Width)
207
+ // If intrinsicWidth is 0 (not loaded), we fallback to a safe 1.0 scale to avoid Infinity
208
+ const finalScale = intrinsicWidth > 0
209
+ ? (matrixScale * markerW * perspectiveScale) / intrinsicWidth
210
+ : 1.0;
208
211
 
209
212
  // Apply transform
210
213
  this.overlay.style.position = 'absolute';
@@ -218,6 +221,7 @@ class SimpleAR {
218
221
  rotate(${-rotation}rad)
219
222
  `;
220
223
  }
224
+
221
225
  }
222
226
 
223
227
  export { SimpleAR };