@srsergio/taptapp-ar 1.0.9 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compiler/controller.d.ts +15 -22
- package/dist/compiler/controller.js +73 -92
- package/dist/compiler/detector/crop-detector.d.ts +20 -51
- package/dist/compiler/detector/crop-detector.js +21 -15
- package/dist/compiler/input-loader.d.ts +15 -17
- package/dist/compiler/input-loader.js +58 -76
- package/dist/compiler/matching/hamming-distance.js +4 -4
- package/dist/compiler/matching/matcher.js +2 -2
- package/dist/compiler/matching/matching.d.ts +2 -16
- package/dist/compiler/matching/matching.js +72 -60
- package/dist/compiler/offline-compiler.d.ts +9 -29
- package/dist/compiler/offline-compiler.js +38 -72
- package/dist/compiler/three.js +0 -4
- package/dist/compiler/tracker/tracker.d.ts +26 -12
- package/dist/compiler/tracker/tracker.js +158 -259
- package/package.json +1 -1
- package/src/compiler/controller.js +71 -93
- package/src/compiler/detector/crop-detector.js +26 -15
- package/src/compiler/input-loader.js +62 -88
- package/src/compiler/matching/hamming-distance.js +4 -4
- package/src/compiler/matching/hough.js +1 -1
- package/src/compiler/matching/matcher.js +2 -2
- package/src/compiler/matching/matching.js +80 -72
- package/src/compiler/offline-compiler.js +38 -75
- package/src/compiler/three.js +0 -4
- package/src/compiler/tracker/tracker.js +183 -283
- package/dist/compiler/compiler-base.d.ts +0 -8
- package/dist/compiler/compiler-base.js +0 -179
- package/dist/compiler/compiler.d.ts +0 -9
- package/dist/compiler/compiler.js +0 -24
- package/dist/compiler/compiler.worker.d.ts +0 -1
- package/dist/compiler/compiler.worker.js +0 -28
- package/dist/compiler/detector/detector.d.ts +0 -97
- package/dist/compiler/detector/detector.js +0 -1042
- package/dist/compiler/detector/kernels/cpu/binomialFilter.d.ts +0 -6
- package/dist/compiler/detector/kernels/cpu/binomialFilter.js +0 -50
- package/dist/compiler/detector/kernels/cpu/buildExtremas.d.ts +0 -6
- package/dist/compiler/detector/kernels/cpu/buildExtremas.js +0 -89
- package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.d.ts +0 -7
- package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.js +0 -79
- package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.d.ts +0 -6
- package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.js +0 -68
- package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.d.ts +0 -6
- package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.js +0 -57
- package/dist/compiler/detector/kernels/cpu/computeLocalization.d.ts +0 -6
- package/dist/compiler/detector/kernels/cpu/computeLocalization.js +0 -50
- package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.d.ts +0 -6
- package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.js +0 -100
- package/dist/compiler/detector/kernels/cpu/downsampleBilinear.d.ts +0 -6
- package/dist/compiler/detector/kernels/cpu/downsampleBilinear.js +0 -29
- package/dist/compiler/detector/kernels/cpu/extremaReduction.d.ts +0 -6
- package/dist/compiler/detector/kernels/cpu/extremaReduction.js +0 -50
- package/dist/compiler/detector/kernels/cpu/fakeShader.d.ts +0 -20
- package/dist/compiler/detector/kernels/cpu/fakeShader.js +0 -80
- package/dist/compiler/detector/kernels/cpu/index.d.ts +0 -1
- package/dist/compiler/detector/kernels/cpu/index.js +0 -25
- package/dist/compiler/detector/kernels/cpu/prune.d.ts +0 -7
- package/dist/compiler/detector/kernels/cpu/prune.js +0 -62
- package/dist/compiler/detector/kernels/cpu/smoothHistograms.d.ts +0 -6
- package/dist/compiler/detector/kernels/cpu/smoothHistograms.js +0 -47
- package/dist/compiler/detector/kernels/cpu/upsampleBilinear.d.ts +0 -6
- package/dist/compiler/detector/kernels/cpu/upsampleBilinear.js +0 -43
- package/dist/compiler/detector/kernels/index.d.ts +0 -1
- package/dist/compiler/detector/kernels/index.js +0 -2
- package/dist/compiler/detector/kernels/webgl/binomialFilter.d.ts +0 -6
- package/dist/compiler/detector/kernels/webgl/binomialFilter.js +0 -67
- package/dist/compiler/detector/kernels/webgl/buildExtremas.d.ts +0 -6
- package/dist/compiler/detector/kernels/webgl/buildExtremas.js +0 -101
- package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.d.ts +0 -6
- package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.js +0 -78
- package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.d.ts +0 -6
- package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.js +0 -86
- package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.d.ts +0 -6
- package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.js +0 -52
- package/dist/compiler/detector/kernels/webgl/computeLocalization.d.ts +0 -6
- package/dist/compiler/detector/kernels/webgl/computeLocalization.js +0 -58
- package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.d.ts +0 -6
- package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.js +0 -116
- package/dist/compiler/detector/kernels/webgl/downsampleBilinear.d.ts +0 -6
- package/dist/compiler/detector/kernels/webgl/downsampleBilinear.js +0 -46
- package/dist/compiler/detector/kernels/webgl/extremaReduction.d.ts +0 -6
- package/dist/compiler/detector/kernels/webgl/extremaReduction.js +0 -48
- package/dist/compiler/detector/kernels/webgl/index.d.ts +0 -1
- package/dist/compiler/detector/kernels/webgl/index.js +0 -25
- package/dist/compiler/detector/kernels/webgl/smoothHistograms.d.ts +0 -6
- package/dist/compiler/detector/kernels/webgl/smoothHistograms.js +0 -49
- package/dist/compiler/detector/kernels/webgl/upsampleBilinear.d.ts +0 -6
- package/dist/compiler/detector/kernels/webgl/upsampleBilinear.js +0 -56
- package/dist/compiler/tensorflow-setup.d.ts +0 -6
- package/dist/compiler/tensorflow-setup.js +0 -99
- package/src/compiler/compiler-base.js +0 -210
- package/src/compiler/compiler.js +0 -25
- package/src/compiler/compiler.worker.js +0 -30
- package/src/compiler/detector/detector.js +0 -1119
- package/src/compiler/detector/kernels/cpu/binomialFilter.js +0 -58
- package/src/compiler/detector/kernels/cpu/buildExtremas.js +0 -108
- package/src/compiler/detector/kernels/cpu/computeExtremaAngles.js +0 -91
- package/src/compiler/detector/kernels/cpu/computeExtremaFreak.js +0 -92
- package/src/compiler/detector/kernels/cpu/computeFreakDescriptors.js +0 -68
- package/src/compiler/detector/kernels/cpu/computeLocalization.js +0 -67
- package/src/compiler/detector/kernels/cpu/computeOrientationHistograms.js +0 -124
- package/src/compiler/detector/kernels/cpu/downsampleBilinear.js +0 -33
- package/src/compiler/detector/kernels/cpu/extremaReduction.js +0 -53
- package/src/compiler/detector/kernels/cpu/fakeShader.js +0 -88
- package/src/compiler/detector/kernels/cpu/index.js +0 -26
- package/src/compiler/detector/kernels/cpu/prune.js +0 -78
- package/src/compiler/detector/kernels/cpu/smoothHistograms.js +0 -57
- package/src/compiler/detector/kernels/cpu/upsampleBilinear.js +0 -51
- package/src/compiler/detector/kernels/index.js +0 -2
- package/src/compiler/detector/kernels/webgl/binomialFilter.js +0 -72
- package/src/compiler/detector/kernels/webgl/buildExtremas.js +0 -109
- package/src/compiler/detector/kernels/webgl/computeExtremaAngles.js +0 -82
- package/src/compiler/detector/kernels/webgl/computeExtremaFreak.js +0 -105
- package/src/compiler/detector/kernels/webgl/computeFreakDescriptors.js +0 -56
- package/src/compiler/detector/kernels/webgl/computeLocalization.js +0 -70
- package/src/compiler/detector/kernels/webgl/computeOrientationHistograms.js +0 -129
- package/src/compiler/detector/kernels/webgl/downsampleBilinear.js +0 -50
- package/src/compiler/detector/kernels/webgl/extremaReduction.js +0 -50
- package/src/compiler/detector/kernels/webgl/index.js +0 -26
- package/src/compiler/detector/kernels/webgl/smoothHistograms.js +0 -53
- package/src/compiler/detector/kernels/webgl/upsampleBilinear.js +0 -62
- package/src/compiler/tensorflow-setup.js +0 -116
|
@@ -1,88 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
//
|
|
5
|
-
// This implementation return grey scale instead of RGBA in the orignal implementation
|
|
1
|
+
/**
|
|
2
|
+
* InputLoader - Maneja la carga de imágenes y video sin TensorFlow
|
|
3
|
+
*/
|
|
6
4
|
class InputLoader {
|
|
7
5
|
constructor(width, height) {
|
|
8
6
|
this.width = width;
|
|
9
7
|
this.height = height;
|
|
10
|
-
this.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
//this.tempPixelHandle = backend.makeTensorInfo(this.texShape, 'int32');
|
|
18
|
-
this.tempPixelHandle = backend.makeTensorInfo(this.texShape, "float32");
|
|
19
|
-
// warning!!!
|
|
20
|
-
// usage type should be TextureUsage.PIXELS, but tfjs didn't export this enum type, so we hard-coded 2 here
|
|
21
|
-
// i.e. backend.texData.get(tempPixelHandle.dataId).usage = TextureUsage.PIXELS;
|
|
22
|
-
backend.texData.get(this.tempPixelHandle.dataId).usage = 2;
|
|
23
|
-
}
|
|
24
|
-
// old method
|
|
25
|
-
_loadInput(input) {
|
|
26
|
-
return tf.tidy(() => {
|
|
27
|
-
let inputImage = tf.browser.fromPixels(input);
|
|
28
|
-
inputImage = inputImage.mean(2);
|
|
29
|
-
return inputImage;
|
|
30
|
-
});
|
|
8
|
+
this.grayscaleBuffer = new Uint8Array(width * height);
|
|
9
|
+
if (typeof document !== "undefined") {
|
|
10
|
+
const canvas = document.createElement("canvas");
|
|
11
|
+
canvas.width = width;
|
|
12
|
+
canvas.height = height;
|
|
13
|
+
this.context = canvas.getContext("2d", { willReadFrequently: true, alpha: false });
|
|
14
|
+
}
|
|
31
15
|
}
|
|
32
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Carga una imagen o video y devuelve los datos en escala de grises
|
|
18
|
+
* @param {HTMLVideoElement|HTMLImageElement|ImageData|Uint8Array} input - La fuente de entrada
|
|
19
|
+
* @returns {Uint8Array} Datos de imagen en escala de grises (width * height)
|
|
20
|
+
*/
|
|
33
21
|
loadInput(input) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (isInputRotated) {
|
|
38
|
-
// rotate 90 degree and draw
|
|
39
|
-
let x = this.context.canvas.width / 2;
|
|
40
|
-
let y = this.context.canvas.height / 2;
|
|
41
|
-
let angleInDegrees = 90;
|
|
42
|
-
context.save(); // save the current context state
|
|
43
|
-
context.translate(x, y); // move the context origin to the center of the image
|
|
44
|
-
context.rotate((angleInDegrees * Math.PI) / 180); // rotate the context
|
|
45
|
-
// draw the image with its center at the origin
|
|
46
|
-
context.drawImage(input, -input.width / 2, -input.height / 2);
|
|
47
|
-
context.restore(); // restore the context to its original state
|
|
22
|
+
// Si ya es un Uint8Array de escala de grises, lo devolvemos
|
|
23
|
+
if (input instanceof Uint8Array && input.length === this.width * this.height) {
|
|
24
|
+
return input;
|
|
48
25
|
}
|
|
49
|
-
|
|
50
|
-
|
|
26
|
+
// Si es ImageData, convertimos a escala de grises directamente
|
|
27
|
+
if (typeof ImageData !== "undefined" && input instanceof ImageData) {
|
|
28
|
+
this._convertToGrayscale(input.data, input.width, input.height);
|
|
29
|
+
return this.grayscaleBuffer;
|
|
51
30
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
};
|
|
77
|
-
return program;
|
|
78
|
-
}
|
|
79
|
-
_compileAndRun(program, inputs) {
|
|
80
|
-
const outInfo = tf.backend().compileAndRun(program, inputs);
|
|
81
|
-
return tf.engine().makeTensor(outInfo.dataId, outInfo.shape, outInfo.dtype);
|
|
31
|
+
// En el navegador, usamos canvas para procesar video/imágenes
|
|
32
|
+
if (this.context) {
|
|
33
|
+
this.context.clearRect(0, 0, this.width, this.height);
|
|
34
|
+
const isInputRotated = input.width === this.height && input.height === this.width;
|
|
35
|
+
if (isInputRotated) {
|
|
36
|
+
this.context.save();
|
|
37
|
+
this.context.translate(this.width / 2, this.height / 2);
|
|
38
|
+
this.context.rotate(Math.PI / 2);
|
|
39
|
+
this.context.drawImage(input, -input.width / 2, -input.height / 2);
|
|
40
|
+
this.context.restore();
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
this.context.drawImage(input, 0, 0, this.width, this.height);
|
|
44
|
+
}
|
|
45
|
+
const imageData = this.context.getImageData(0, 0, this.width, this.height);
|
|
46
|
+
this._convertToGrayscale(imageData.data, this.width, this.height);
|
|
47
|
+
return this.grayscaleBuffer;
|
|
48
|
+
}
|
|
49
|
+
// Fallback para Node.js o entornos sin DOM
|
|
50
|
+
if (input.data && input.data instanceof Uint8Array) {
|
|
51
|
+
this._convertToGrayscale(input.data, input.width || this.width, input.height || this.height);
|
|
52
|
+
return this.grayscaleBuffer;
|
|
53
|
+
}
|
|
54
|
+
throw new Error("Input no soportado o entorno sin Canvas");
|
|
82
55
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Convierte datos RGBA a escala de grises optimizada (reutilizando buffer)
|
|
58
|
+
*/
|
|
59
|
+
_convertToGrayscale(rgbaData, width, height) {
|
|
60
|
+
const grayscale = this.grayscaleBuffer;
|
|
61
|
+
const len = (width * height);
|
|
62
|
+
// Optimized loop with bitwise ops
|
|
63
|
+
for (let i = 0; i < len; i++) {
|
|
64
|
+
const offset = i << 2;
|
|
65
|
+
// Formula de luminosidad estándar: 0.299R + 0.587G + 0.114B (scaled by 256)
|
|
66
|
+
grayscale[i] = (rgbaData[offset] * 77 + rgbaData[offset + 1] * 150 + rgbaData[offset + 2] * 29) >> 8;
|
|
67
|
+
}
|
|
86
68
|
}
|
|
87
69
|
}
|
|
88
70
|
export { InputLoader };
|
|
@@ -9,11 +9,11 @@ for (let i = 0; i < 256; i++) {
|
|
|
9
9
|
BIT_COUNT_8[i] = c;
|
|
10
10
|
}
|
|
11
11
|
const compute = (options) => {
|
|
12
|
-
const { v1, v2 } = options;
|
|
12
|
+
const { v1, v2, v1Offset = 0, v2Offset = 0 } = options;
|
|
13
13
|
let d = 0;
|
|
14
|
-
|
|
15
|
-
for (let i = 0; i <
|
|
16
|
-
d += BIT_COUNT_8[v1[i] ^ v2[i]];
|
|
14
|
+
// FREAK descriptors are 84 bytes
|
|
15
|
+
for (let i = 0; i < 84; i++) {
|
|
16
|
+
d += BIT_COUNT_8[v1[v1Offset + i] ^ v2[v2Offset + i]];
|
|
17
17
|
}
|
|
18
18
|
return d;
|
|
19
19
|
};
|
|
@@ -37,8 +37,8 @@ class Matcher {
|
|
|
37
37
|
y: querypoint.y,
|
|
38
38
|
});
|
|
39
39
|
worldCoords.push({
|
|
40
|
-
x: (keypoint.x + 0.5) / keyframe.scale,
|
|
41
|
-
y: (keypoint.y + 0.5) / keyframe.scale,
|
|
40
|
+
x: (keypoint.x + 0.5) / (keyframe.s || keyframe.scale || 1.0),
|
|
41
|
+
y: (keypoint.y + 0.5) / (keyframe.s || keyframe.scale || 1.0),
|
|
42
42
|
z: 0,
|
|
43
43
|
});
|
|
44
44
|
}
|
|
@@ -6,14 +6,6 @@ export function match({ keyframe, querypoints, querywidth, queryheight, debugMod
|
|
|
6
6
|
debugMode: any;
|
|
7
7
|
}): {
|
|
8
8
|
debugExtra: {
|
|
9
|
-
matches: {
|
|
10
|
-
querypoint: any;
|
|
11
|
-
keypoint: {
|
|
12
|
-
x: any;
|
|
13
|
-
y: any;
|
|
14
|
-
angle: any;
|
|
15
|
-
};
|
|
16
|
-
}[];
|
|
17
9
|
houghMatches: any[];
|
|
18
10
|
inlierMatches: any[];
|
|
19
11
|
matches2: {
|
|
@@ -22,6 +14,7 @@ export function match({ keyframe, querypoints, querywidth, queryheight, debugMod
|
|
|
22
14
|
x: any;
|
|
23
15
|
y: any;
|
|
24
16
|
angle: any;
|
|
17
|
+
scale: any;
|
|
25
18
|
};
|
|
26
19
|
}[];
|
|
27
20
|
houghMatches2: any[];
|
|
@@ -33,14 +26,6 @@ export function match({ keyframe, querypoints, querywidth, queryheight, debugMod
|
|
|
33
26
|
H: number[];
|
|
34
27
|
matches: any[];
|
|
35
28
|
debugExtra: {
|
|
36
|
-
matches: {
|
|
37
|
-
querypoint: any;
|
|
38
|
-
keypoint: {
|
|
39
|
-
x: any;
|
|
40
|
-
y: any;
|
|
41
|
-
angle: any;
|
|
42
|
-
};
|
|
43
|
-
}[];
|
|
44
29
|
houghMatches: any[];
|
|
45
30
|
inlierMatches: any[];
|
|
46
31
|
matches2: {
|
|
@@ -49,6 +34,7 @@ export function match({ keyframe, querypoints, querywidth, queryheight, debugMod
|
|
|
49
34
|
x: any;
|
|
50
35
|
y: any;
|
|
51
36
|
angle: any;
|
|
37
|
+
scale: any;
|
|
52
38
|
};
|
|
53
39
|
}[];
|
|
54
40
|
houghMatches2: any[];
|
|
@@ -12,16 +12,17 @@ const HAMMING_THRESHOLD = 0.7;
|
|
|
12
12
|
const match = ({ keyframe, querypoints, querywidth, queryheight, debugMode }) => {
|
|
13
13
|
let debugExtra = {};
|
|
14
14
|
const matches = [];
|
|
15
|
-
|
|
15
|
+
const qlen = querypoints.length;
|
|
16
|
+
const kmax = keyframe.max;
|
|
17
|
+
const kmin = keyframe.min;
|
|
18
|
+
for (let j = 0; j < qlen; j++) {
|
|
16
19
|
const querypoint = querypoints[j];
|
|
17
|
-
const col = querypoint.maxima ?
|
|
20
|
+
const col = querypoint.maxima ? kmax : kmin;
|
|
18
21
|
if (!col || col.x.length === 0)
|
|
19
22
|
continue;
|
|
20
23
|
const rootNode = col.t;
|
|
21
24
|
const keypointIndexes = [];
|
|
22
|
-
const queue = new TinyQueue([], (a1, a2) =>
|
|
23
|
-
return a1.d - a2.d;
|
|
24
|
-
});
|
|
25
|
+
const queue = new TinyQueue([], (a1, a2) => a1.d - a2.d);
|
|
25
26
|
// query potential candidates from the columnar tree
|
|
26
27
|
_query({
|
|
27
28
|
node: rootNode,
|
|
@@ -34,11 +35,12 @@ const match = ({ keyframe, querypoints, querywidth, queryheight, debugMode }) =>
|
|
|
34
35
|
let bestIndex = -1;
|
|
35
36
|
let bestD1 = Number.MAX_SAFE_INTEGER;
|
|
36
37
|
let bestD2 = Number.MAX_SAFE_INTEGER;
|
|
38
|
+
const qDesc = querypoint.descriptors;
|
|
39
|
+
const cDesc = col.d;
|
|
37
40
|
for (let k = 0; k < keypointIndexes.length; k++) {
|
|
38
41
|
const idx = keypointIndexes[k];
|
|
39
|
-
//
|
|
40
|
-
const
|
|
41
|
-
const d = hammingCompute({ v1: keypointDescriptor, v2: querypoint.descriptors });
|
|
42
|
+
// Use offsets to avoid subarray allocation
|
|
43
|
+
const d = hammingCompute({ v1: cDesc, v1Offset: idx * 84, v2: qDesc });
|
|
42
44
|
if (d < bestD1) {
|
|
43
45
|
bestD2 = bestD1;
|
|
44
46
|
bestD1 = d;
|
|
@@ -49,32 +51,29 @@ const match = ({ keyframe, querypoints, querywidth, queryheight, debugMode }) =>
|
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
if (bestIndex !== -1 &&
|
|
52
|
-
(bestD2 === Number.MAX_SAFE_INTEGER || (
|
|
54
|
+
(bestD2 === Number.MAX_SAFE_INTEGER || (bestD1 / bestD2) < HAMMING_THRESHOLD)) {
|
|
53
55
|
matches.push({
|
|
54
56
|
querypoint,
|
|
55
57
|
keypoint: {
|
|
56
58
|
x: col.x[bestIndex],
|
|
57
59
|
y: col.y[bestIndex],
|
|
58
|
-
angle: col.a[bestIndex]
|
|
60
|
+
angle: col.a[bestIndex],
|
|
61
|
+
scale: col.s ? col.s[bestIndex] : keyframe.s
|
|
59
62
|
}
|
|
60
63
|
});
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
|
-
if (debugMode) {
|
|
64
|
-
debugExtra.matches = matches;
|
|
65
|
-
}
|
|
66
66
|
if (matches.length < MIN_NUM_INLIERS)
|
|
67
67
|
return { debugExtra };
|
|
68
68
|
const houghMatches = computeHoughMatches({
|
|
69
|
-
keywidth: keyframe.w,
|
|
69
|
+
keywidth: keyframe.w,
|
|
70
70
|
keyheight: keyframe.h,
|
|
71
71
|
querywidth,
|
|
72
72
|
queryheight,
|
|
73
73
|
matches,
|
|
74
74
|
});
|
|
75
|
-
if (debugMode)
|
|
75
|
+
if (debugMode)
|
|
76
76
|
debugExtra.houghMatches = houghMatches;
|
|
77
|
-
}
|
|
78
77
|
const H = computeHomography({
|
|
79
78
|
srcPoints: houghMatches.map((m) => [m.keypoint.x, m.keypoint.y]),
|
|
80
79
|
dstPoints: houghMatches.map((m) => [m.querypoint.x, m.querypoint.y]),
|
|
@@ -87,32 +86,40 @@ const match = ({ keyframe, querypoints, querywidth, queryheight, debugMode }) =>
|
|
|
87
86
|
matches: houghMatches,
|
|
88
87
|
threshold: INLIER_THRESHOLD,
|
|
89
88
|
});
|
|
90
|
-
if (debugMode)
|
|
89
|
+
if (debugMode)
|
|
91
90
|
debugExtra.inlierMatches = inlierMatches;
|
|
92
|
-
}
|
|
93
91
|
if (inlierMatches.length < MIN_NUM_INLIERS)
|
|
94
92
|
return { debugExtra };
|
|
95
93
|
// Second pass with homography guided matching
|
|
96
94
|
const HInv = matrixInverse33(H, 0.00001);
|
|
97
|
-
const dThreshold2 = 10 * 10
|
|
95
|
+
const dThreshold2 = 100; // 10 * 10
|
|
98
96
|
const matches2 = [];
|
|
99
|
-
|
|
97
|
+
const hi00 = HInv[0], hi01 = HInv[1], hi02 = HInv[2];
|
|
98
|
+
const hi10 = HInv[3], hi11 = HInv[4], hi12 = HInv[5];
|
|
99
|
+
const hi20 = HInv[6], hi21 = HInv[7], hi22 = HInv[8];
|
|
100
|
+
for (let j = 0; j < qlen; j++) {
|
|
100
101
|
const querypoint = querypoints[j];
|
|
101
|
-
const
|
|
102
|
+
const qx = querypoint.x, qy = querypoint.y;
|
|
103
|
+
// Inline multiplyPointHomographyInhomogenous
|
|
104
|
+
const uz = (qx * hi20) + (qy * hi21) + hi22;
|
|
105
|
+
const invZ = 1.0 / uz;
|
|
106
|
+
const mapX = ((qx * hi00) + (qy * hi01) + hi02) * invZ;
|
|
107
|
+
const mapY = ((qx * hi10) + (qy * hi11) + hi12) * invZ;
|
|
102
108
|
let bestIndex = -1;
|
|
103
109
|
let bestD1 = Number.MAX_SAFE_INTEGER;
|
|
104
110
|
let bestD2 = Number.MAX_SAFE_INTEGER;
|
|
105
|
-
const col = querypoint.maxima ?
|
|
111
|
+
const col = querypoint.maxima ? kmax : kmin;
|
|
106
112
|
if (!col)
|
|
107
113
|
continue;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
const cx = col.x, cy = col.y, cd = col.d;
|
|
115
|
+
const qDesc = querypoint.descriptors;
|
|
116
|
+
for (let k = 0, clen = cx.length; k < clen; k++) {
|
|
117
|
+
const dx = cx[k] - mapX;
|
|
118
|
+
const dy = cy[k] - mapY;
|
|
111
119
|
const d2 = dx * dx + dy * dy;
|
|
112
120
|
if (d2 > dThreshold2)
|
|
113
121
|
continue;
|
|
114
|
-
const
|
|
115
|
-
const d = hammingCompute({ v1: keypointDescriptor, v2: querypoint.descriptors });
|
|
122
|
+
const d = hammingCompute({ v1: cd, v1Offset: k * 84, v2: qDesc });
|
|
116
123
|
if (d < bestD1) {
|
|
117
124
|
bestD2 = bestD1;
|
|
118
125
|
bestD1 = d;
|
|
@@ -123,20 +130,20 @@ const match = ({ keyframe, querypoints, querywidth, queryheight, debugMode }) =>
|
|
|
123
130
|
}
|
|
124
131
|
}
|
|
125
132
|
if (bestIndex !== -1 &&
|
|
126
|
-
(bestD2 === Number.MAX_SAFE_INTEGER || (
|
|
133
|
+
(bestD2 === Number.MAX_SAFE_INTEGER || (bestD1 / bestD2) < HAMMING_THRESHOLD)) {
|
|
127
134
|
matches2.push({
|
|
128
135
|
querypoint,
|
|
129
136
|
keypoint: {
|
|
130
137
|
x: col.x[bestIndex],
|
|
131
138
|
y: col.y[bestIndex],
|
|
132
|
-
angle: col.a[bestIndex]
|
|
139
|
+
angle: col.a[bestIndex],
|
|
140
|
+
scale: col.s ? col.s[bestIndex] : keyframe.s
|
|
133
141
|
}
|
|
134
142
|
});
|
|
135
143
|
}
|
|
136
144
|
}
|
|
137
|
-
if (debugMode)
|
|
145
|
+
if (debugMode)
|
|
138
146
|
debugExtra.matches2 = matches2;
|
|
139
|
-
}
|
|
140
147
|
const houghMatches2 = computeHoughMatches({
|
|
141
148
|
keywidth: keyframe.w,
|
|
142
149
|
keyheight: keyframe.h,
|
|
@@ -144,9 +151,8 @@ const match = ({ keyframe, querypoints, querywidth, queryheight, debugMode }) =>
|
|
|
144
151
|
queryheight,
|
|
145
152
|
matches: matches2,
|
|
146
153
|
});
|
|
147
|
-
if (debugMode)
|
|
154
|
+
if (debugMode)
|
|
148
155
|
debugExtra.houghMatches2 = houghMatches2;
|
|
149
|
-
}
|
|
150
156
|
const H2 = computeHomography({
|
|
151
157
|
srcPoints: houghMatches2.map((m) => [m.keypoint.x, m.keypoint.y]),
|
|
152
158
|
dstPoints: houghMatches2.map((m) => [m.querypoint.x, m.querypoint.y]),
|
|
@@ -159,14 +165,12 @@ const match = ({ keyframe, querypoints, querywidth, queryheight, debugMode }) =>
|
|
|
159
165
|
matches: houghMatches2,
|
|
160
166
|
threshold: INLIER_THRESHOLD,
|
|
161
167
|
});
|
|
162
|
-
if (debugMode)
|
|
168
|
+
if (debugMode)
|
|
163
169
|
debugExtra.inlierMatches2 = inlierMatches2;
|
|
164
|
-
}
|
|
165
170
|
return { H: H2, matches: inlierMatches2, debugExtra };
|
|
166
171
|
};
|
|
167
172
|
const _query = ({ node, descriptors, querypoint, queue, keypointIndexes, numPop }) => {
|
|
168
173
|
const isLeaf = node[0] === 1;
|
|
169
|
-
const centerIdx = node[1];
|
|
170
174
|
const childrenOrIndices = node[2];
|
|
171
175
|
if (isLeaf) {
|
|
172
176
|
for (let i = 0; i < childrenOrIndices.length; i++) {
|
|
@@ -174,48 +178,56 @@ const _query = ({ node, descriptors, querypoint, queue, keypointIndexes, numPop
|
|
|
174
178
|
}
|
|
175
179
|
return;
|
|
176
180
|
}
|
|
177
|
-
const
|
|
178
|
-
|
|
181
|
+
const qDesc = querypoint.descriptors;
|
|
182
|
+
let minD = Number.MAX_SAFE_INTEGER;
|
|
183
|
+
const clen = childrenOrIndices.length;
|
|
184
|
+
const distances = new Int32Array(clen);
|
|
185
|
+
for (let i = 0; i < clen; i++) {
|
|
179
186
|
const childNode = childrenOrIndices[i];
|
|
180
187
|
const cIdx = childNode[1];
|
|
181
188
|
const d = hammingCompute({
|
|
182
|
-
v1: descriptors
|
|
183
|
-
|
|
189
|
+
v1: descriptors,
|
|
190
|
+
v1Offset: cIdx * 84,
|
|
191
|
+
v2: qDesc,
|
|
184
192
|
});
|
|
185
|
-
distances
|
|
193
|
+
distances[i] = d;
|
|
194
|
+
if (d < minD)
|
|
195
|
+
minD = d;
|
|
186
196
|
}
|
|
187
|
-
let
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
for (let i = 0; i < childrenOrIndices.length; i++) {
|
|
192
|
-
if (distances[i] !== minD) {
|
|
193
|
-
queue.push({ node: childrenOrIndices[i], d: distances[i] });
|
|
197
|
+
for (let i = 0; i < clen; i++) {
|
|
198
|
+
const dist = distances[i];
|
|
199
|
+
if (dist !== minD) {
|
|
200
|
+
queue.push({ node: childrenOrIndices[i], d: dist });
|
|
194
201
|
}
|
|
195
|
-
|
|
196
|
-
for (let i = 0; i < childrenOrIndices.length; i++) {
|
|
197
|
-
if (distances[i] === minD) {
|
|
202
|
+
else {
|
|
198
203
|
_query({ node: childrenOrIndices[i], descriptors, querypoint, queue, keypointIndexes, numPop });
|
|
199
204
|
}
|
|
200
205
|
}
|
|
201
206
|
if (numPop < CLUSTER_MAX_POP && queue.length > 0) {
|
|
202
207
|
const { node } = queue.pop();
|
|
203
|
-
numPop
|
|
204
|
-
_query({ node, descriptors, querypoint, queue, keypointIndexes, numPop });
|
|
208
|
+
_query({ node, descriptors, querypoint, queue, keypointIndexes, numPop: numPop + 1 });
|
|
205
209
|
}
|
|
206
210
|
};
|
|
207
211
|
const _findInlierMatches = (options) => {
|
|
208
212
|
const { H, matches, threshold } = options;
|
|
209
213
|
const threshold2 = threshold * threshold;
|
|
214
|
+
const h00 = H[0], h01 = H[1], h02 = H[2];
|
|
215
|
+
const h10 = H[3], h11 = H[4], h12 = H[5];
|
|
216
|
+
const h20 = H[6], h21 = H[7], h22 = H[8];
|
|
210
217
|
const goodMatches = [];
|
|
211
218
|
for (let i = 0; i < matches.length; i++) {
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
+
const m = matches[i];
|
|
220
|
+
const qp = m.querypoint;
|
|
221
|
+
const kp = m.keypoint;
|
|
222
|
+
// Inline multiplyPointHomographyInhomogenous
|
|
223
|
+
const uz = (kp.x * h20) + (kp.y * h21) + h22;
|
|
224
|
+
const invZ = 1.0 / uz;
|
|
225
|
+
const mx = ((kp.x * h00) + (kp.y * h01) + h02) * invZ;
|
|
226
|
+
const my = ((kp.x * h10) + (kp.y * h11) + h12) * invZ;
|
|
227
|
+
const dx = mx - qp.x;
|
|
228
|
+
const dy = my - qp.y;
|
|
229
|
+
if (dx * dx + dy * dy <= threshold2) {
|
|
230
|
+
goodMatches.push(m);
|
|
219
231
|
}
|
|
220
232
|
}
|
|
221
233
|
return goodMatches;
|
|
@@ -12,38 +12,18 @@ export class OfflineCompiler {
|
|
|
12
12
|
* @returns {Promise<Array>} Datos compilados
|
|
13
13
|
*/
|
|
14
14
|
compileImageTargets(images: any[], progressCallback: Function): Promise<any[]>;
|
|
15
|
-
/**
|
|
16
|
-
* Compila datos de matching usando DetectorLite (JS puro)
|
|
17
|
-
*/
|
|
18
15
|
_compileMatch(targetImages: any, progressCallback: any): Promise<any[]>;
|
|
19
|
-
/**
|
|
20
|
-
* Compila datos de tracking usando extractTrackingFeatures (JS puro)
|
|
21
|
-
*/
|
|
22
16
|
_compileTrack(targetImages: any, progressCallback: any): Promise<any[]>;
|
|
23
|
-
/**
|
|
24
|
-
* Método público para compilar tracking (compatibilidad con API anterior)
|
|
25
|
-
* @param {Object} options - Opciones de compilación
|
|
26
|
-
* @param {Function} options.progressCallback - Callback de progreso
|
|
27
|
-
* @param {Array} options.targetImages - Lista de imágenes objetivo
|
|
28
|
-
* @param {number} options.basePercent - Porcentaje base
|
|
29
|
-
* @returns {Promise<Array>} Datos de tracking
|
|
30
|
-
*/
|
|
31
17
|
compileTrack({ progressCallback, targetImages, basePercent }: {
|
|
32
|
-
progressCallback:
|
|
33
|
-
targetImages: any
|
|
34
|
-
basePercent
|
|
18
|
+
progressCallback: any;
|
|
19
|
+
targetImages: any;
|
|
20
|
+
basePercent?: number | undefined;
|
|
35
21
|
}): Promise<any[]>;
|
|
36
|
-
/**
|
|
37
|
-
* Método público para compilar matching (compatibilidad con API anterior)
|
|
38
|
-
*/
|
|
39
22
|
compileMatch({ progressCallback, targetImages, basePercent }: {
|
|
40
23
|
progressCallback: any;
|
|
41
24
|
targetImages: any;
|
|
42
25
|
basePercent?: number | undefined;
|
|
43
26
|
}): Promise<any[]>;
|
|
44
|
-
/**
|
|
45
|
-
* Exporta datos compilados en formato binario columnar optimizado
|
|
46
|
-
*/
|
|
47
27
|
exportData(): any;
|
|
48
28
|
_packKeyframe(kf: any): {
|
|
49
29
|
w: any;
|
|
@@ -53,6 +33,7 @@ export class OfflineCompiler {
|
|
|
53
33
|
x: Float32Array<any>;
|
|
54
34
|
y: Float32Array<any>;
|
|
55
35
|
a: Float32Array<any>;
|
|
36
|
+
s: Float32Array<any>;
|
|
56
37
|
d: Uint8Array<ArrayBuffer>;
|
|
57
38
|
t: any[];
|
|
58
39
|
};
|
|
@@ -60,6 +41,7 @@ export class OfflineCompiler {
|
|
|
60
41
|
x: Float32Array<any>;
|
|
61
42
|
y: Float32Array<any>;
|
|
62
43
|
a: Float32Array<any>;
|
|
44
|
+
s: Float32Array<any>;
|
|
63
45
|
d: Uint8Array<ArrayBuffer>;
|
|
64
46
|
t: any[];
|
|
65
47
|
};
|
|
@@ -68,13 +50,11 @@ export class OfflineCompiler {
|
|
|
68
50
|
x: Float32Array<any>;
|
|
69
51
|
y: Float32Array<any>;
|
|
70
52
|
a: Float32Array<any>;
|
|
53
|
+
s: Float32Array<any>;
|
|
71
54
|
d: Uint8Array<ArrayBuffer>;
|
|
72
55
|
t: any[];
|
|
73
56
|
};
|
|
74
57
|
_compactTree(node: any): any[];
|
|
75
|
-
/**
|
|
76
|
-
* Importa datos - Mantiene el formato columnar para máximo rendimiento (Zero-copy)
|
|
77
|
-
*/
|
|
78
58
|
importData(buffer: any): any;
|
|
79
59
|
_unpackKeyframe(kf: any): {
|
|
80
60
|
width: any;
|
|
@@ -84,12 +64,14 @@ export class OfflineCompiler {
|
|
|
84
64
|
x: any;
|
|
85
65
|
y: any;
|
|
86
66
|
angle: any;
|
|
67
|
+
scale: any;
|
|
87
68
|
descriptors: any;
|
|
88
69
|
}[];
|
|
89
70
|
minimaPoints: {
|
|
90
71
|
x: any;
|
|
91
72
|
y: any;
|
|
92
73
|
angle: any;
|
|
74
|
+
scale: any;
|
|
93
75
|
descriptors: any;
|
|
94
76
|
}[];
|
|
95
77
|
maximaPointsCluster: {
|
|
@@ -123,6 +105,7 @@ export class OfflineCompiler {
|
|
|
123
105
|
x: any;
|
|
124
106
|
y: any;
|
|
125
107
|
angle: any;
|
|
108
|
+
scale: any;
|
|
126
109
|
descriptors: any;
|
|
127
110
|
}[];
|
|
128
111
|
_expandTree(node: any): {
|
|
@@ -136,9 +119,6 @@ export class OfflineCompiler {
|
|
|
136
119
|
children: any;
|
|
137
120
|
pointIndexes?: undefined;
|
|
138
121
|
};
|
|
139
|
-
/**
|
|
140
|
-
* Destruye el pool de workers
|
|
141
|
-
*/
|
|
142
122
|
destroy(): Promise<void>;
|
|
143
123
|
}
|
|
144
124
|
import { WorkerPool } from "./utils/worker-pool.js";
|