@srsergio/taptapp-ar 1.1.1 → 1.1.3

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 (63) hide show
  1. package/dist/compiler/node-worker.js +1 -197
  2. package/dist/compiler/offline-compiler.js +1 -207
  3. package/dist/core/constants.js +1 -38
  4. package/dist/core/detector/crop-detector.js +1 -88
  5. package/dist/core/detector/detector-lite.js +1 -455
  6. package/dist/core/detector/freak.js +1 -89
  7. package/dist/core/estimation/estimate.js +1 -16
  8. package/dist/core/estimation/estimator.js +1 -30
  9. package/dist/core/estimation/morph-refinement.js +1 -116
  10. package/dist/core/estimation/non-rigid-refine.js +1 -70
  11. package/dist/core/estimation/pnp-solver.js +1 -109
  12. package/dist/core/estimation/refine-estimate.js +1 -311
  13. package/dist/core/estimation/utils.js +1 -67
  14. package/dist/core/features/auto-rotation-feature.js +1 -30
  15. package/dist/core/features/crop-detection-feature.js +1 -26
  16. package/dist/core/features/feature-base.js +1 -1
  17. package/dist/core/features/feature-manager.js +1 -55
  18. package/dist/core/features/one-euro-filter-feature.js +1 -44
  19. package/dist/core/features/temporal-filter-feature.js +1 -57
  20. package/dist/core/image-list.js +1 -54
  21. package/dist/core/input-loader.js +1 -87
  22. package/dist/core/matching/hamming-distance.js +1 -66
  23. package/dist/core/matching/hdc.js +1 -102
  24. package/dist/core/matching/hierarchical-clustering.js +1 -130
  25. package/dist/core/matching/hough.js +1 -170
  26. package/dist/core/matching/matcher.js +1 -66
  27. package/dist/core/matching/matching.js +1 -401
  28. package/dist/core/matching/ransacHomography.js +1 -132
  29. package/dist/core/perception/bio-inspired-engine.js +1 -232
  30. package/dist/core/perception/foveal-attention.js +1 -280
  31. package/dist/core/perception/index.js +1 -17
  32. package/dist/core/perception/predictive-coding.js +1 -278
  33. package/dist/core/perception/saccadic-controller.js +1 -269
  34. package/dist/core/perception/saliency-map.js +1 -254
  35. package/dist/core/perception/scale-orchestrator.js +1 -68
  36. package/dist/core/protocol.js +1 -254
  37. package/dist/core/tracker/extract-utils.js +1 -29
  38. package/dist/core/tracker/extract.js +1 -306
  39. package/dist/core/tracker/tracker.js +1 -352
  40. package/dist/core/utils/cumsum.js +1 -37
  41. package/dist/core/utils/delaunay.js +1 -125
  42. package/dist/core/utils/geometry.js +1 -101
  43. package/dist/core/utils/gpu-compute.js +1 -231
  44. package/dist/core/utils/homography.js +1 -138
  45. package/dist/core/utils/images.js +1 -108
  46. package/dist/core/utils/lsh-binarizer.js +1 -37
  47. package/dist/core/utils/lsh-direct.js +1 -76
  48. package/dist/core/utils/projection.js +1 -51
  49. package/dist/core/utils/randomizer.js +1 -25
  50. package/dist/core/utils/worker-pool.js +1 -89
  51. package/dist/index.js +1 -7
  52. package/dist/libs/one-euro-filter.js +1 -70
  53. package/dist/react/TaptappAR.js +1 -151
  54. package/dist/react/types.js +1 -16
  55. package/dist/react/use-ar.js +1 -118
  56. package/dist/runtime/aframe.js +1 -272
  57. package/dist/runtime/bio-inspired-controller.js +1 -358
  58. package/dist/runtime/controller.js +1 -592
  59. package/dist/runtime/controller.worker.js +1 -93
  60. package/dist/runtime/index.js +1 -5
  61. package/dist/runtime/three.js +1 -304
  62. package/dist/runtime/track.js +1 -381
  63. package/package.json +10 -4
@@ -1,130 +1 @@
1
- import { compute64 as hammingCompute64 } from "./hamming-distance.js";
2
- import { createRandomizer } from "../utils/randomizer.js";
3
- const MIN_FEATURE_PER_NODE = 32;
4
- const NUM_ASSIGNMENT_HYPOTHESES = 12;
5
- const NUM_CENTERS = 8;
6
- export function popcount32(n) {
7
- n = n - ((n >> 1) & 0x55555555);
8
- n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
9
- return (((n + (n >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
10
- }
11
- const _computeKMedoids = (options) => {
12
- const { descriptors, pointIndexes, randomizer, useHDC } = options;
13
- const numPointIndexes = pointIndexes.length;
14
- const randomPointIndexes = new Int32Array(numPointIndexes);
15
- for (let i = 0; i < numPointIndexes; i++) {
16
- randomPointIndexes[i] = i;
17
- }
18
- let bestSumD = Number.MAX_SAFE_INTEGER;
19
- let bestAssignment = null;
20
- const centerPointIndices = new Int32Array(NUM_CENTERS);
21
- for (let i = 0; i < NUM_ASSIGNMENT_HYPOTHESES; i++) {
22
- randomizer.arrayShuffle({ arr: randomPointIndexes, sampleSize: NUM_CENTERS });
23
- for (let k = 0; k < NUM_CENTERS; k++) {
24
- centerPointIndices[k] = pointIndexes[randomPointIndexes[k]];
25
- }
26
- let sumD = 0;
27
- const currentAssignment = new Int32Array(numPointIndexes);
28
- for (let j = 0; j < numPointIndexes; j++) {
29
- const pIdx = pointIndexes[j];
30
- let bestD = 255;
31
- let bestCenterIdx = -1;
32
- for (let k = 0; k < NUM_CENTERS; k++) {
33
- const cIdx = centerPointIndices[k];
34
- let d;
35
- if (useHDC) {
36
- d = popcount32(descriptors[pIdx] ^ descriptors[cIdx]);
37
- }
38
- else {
39
- d = hammingCompute64(descriptors, pIdx * 2, descriptors, cIdx * 2);
40
- }
41
- if (d < bestD) {
42
- bestCenterIdx = randomPointIndexes[k];
43
- bestD = d;
44
- }
45
- }
46
- currentAssignment[j] = bestCenterIdx;
47
- sumD += bestD;
48
- }
49
- if (sumD < bestSumD) {
50
- bestSumD = sumD;
51
- bestAssignment = currentAssignment;
52
- }
53
- }
54
- return bestAssignment;
55
- };
56
- const build = ({ points }) => {
57
- const numPoints = points.length;
58
- if (numPoints === 0)
59
- return { rootNode: { leaf: true, pointIndexes: [], centerPointIndex: null } };
60
- const useHDC = points[0] && points[0].hdcSignature !== undefined;
61
- const descriptors = new Uint32Array(useHDC ? numPoints : numPoints * 2);
62
- for (let i = 0; i < numPoints; i++) {
63
- if (useHDC) {
64
- descriptors[i] = points[i].hdcSignature;
65
- }
66
- else {
67
- const d = points[i].descriptors;
68
- descriptors[i * 2] = d[0];
69
- descriptors[i * 2 + 1] = d[1];
70
- }
71
- }
72
- const pointIndexes = new Int32Array(numPoints);
73
- for (let i = 0; i < numPoints; i++) {
74
- pointIndexes[i] = i;
75
- }
76
- const randomizer = createRandomizer();
77
- const rootNode = _build({
78
- descriptors,
79
- pointIndexes,
80
- centerPointIndex: null,
81
- randomizer,
82
- useHDC
83
- });
84
- return { rootNode };
85
- };
86
- const _build = (options) => {
87
- const { descriptors, pointIndexes, centerPointIndex, randomizer, useHDC } = options;
88
- const numPoints = pointIndexes.length;
89
- let isLeaf = false;
90
- if (numPoints <= NUM_CENTERS || numPoints <= MIN_FEATURE_PER_NODE) {
91
- isLeaf = true;
92
- }
93
- const clusters = new Map();
94
- if (!isLeaf) {
95
- const assignment = _computeKMedoids({ descriptors, pointIndexes, randomizer, useHDC });
96
- for (let i = 0; i < assignment.length; i++) {
97
- const centerIdx = pointIndexes[assignment[i]];
98
- let cluster = clusters.get(centerIdx);
99
- if (cluster === undefined) {
100
- cluster = [];
101
- clusters.set(centerIdx, cluster);
102
- }
103
- cluster.push(pointIndexes[i]);
104
- }
105
- if (clusters.size === 1) {
106
- isLeaf = true;
107
- }
108
- }
109
- const node = {
110
- centerPointIndex: centerPointIndex,
111
- };
112
- if (isLeaf) {
113
- node.leaf = true;
114
- node.pointIndexes = new Int32Array(pointIndexes);
115
- return node;
116
- }
117
- node.leaf = false;
118
- node.children = [];
119
- for (const [cIdx, clusterPoints] of clusters) {
120
- node.children.push(_build({
121
- descriptors,
122
- pointIndexes: new Int32Array(clusterPoints),
123
- centerPointIndex: cIdx,
124
- randomizer,
125
- useHDC
126
- }));
127
- }
128
- return node;
129
- };
130
- export { build };
1
+ import{compute64 as e}from"./hamming-distance.js";import{createRandomizer as n}from"../utils/randomizer.js";export function popcount32(e){return 16843009*((e=(858993459&(e-=e>>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135)>>24}const t=({points:e})=>{const t=e.length;if(0===t)return{rootNode:{leaf:!0,pointIndexes:[],centerPointIndex:null}};const o=e[0]&&void 0!==e[0].hdcSignature,s=new Uint32Array(o?t:2*t);for(let n=0;n<t;n++)if(o)s[n]=e[n].hdcSignature;else{const t=e[n].descriptors;s[2*n]=t[0],s[2*n+1]=t[1]}const i=new Int32Array(t);for(let e=0;e<t;e++)i[e]=e;const c=n();return{rootNode:r({descriptors:s,pointIndexes:i,centerPointIndex:null,randomizer:c,useHDC:o})}},r=n=>{const{descriptors:t,pointIndexes:o,centerPointIndex:s,randomizer:i,useHDC:c}=n,d=o.length;let l=!1;(d<=8||d<=32)&&(l=!0);const p=new Map;if(!l){const n=(n=>{const{descriptors:t,pointIndexes:r,randomizer:o,useHDC:s}=n,i=r.length,c=new Int32Array(i);for(let e=0;e<i;e++)c[e]=e;let d=Number.MAX_SAFE_INTEGER,l=null;const p=new Int32Array(8);for(let n=0;n<12;n++){o.arrayShuffle({arr:c,sampleSize:8});for(let e=0;e<8;e++)p[e]=r[c[e]];let n=0;const a=new Int32Array(i);for(let o=0;o<i;o++){const i=r[o];let d=255,l=-1;for(let n=0;n<8;n++){const r=p[n];let o;o=s?popcount32(t[i]^t[r]):e(t,2*i,t,2*r),o<d&&(l=c[n],d=o)}a[o]=l,n+=d}n<d&&(d=n,l=a)}return l})({descriptors:t,pointIndexes:o,randomizer:i,useHDC:c});for(let e=0;e<n.length;e++){const t=o[n[e]];let r=p.get(t);void 0===r&&(r=[],p.set(t,r)),r.push(o[e])}1===p.size&&(l=!0)}const a={centerPointIndex:s};if(l)return a.leaf=!0,a.pointIndexes=new Int32Array(o),a;a.leaf=!1,a.children=[];for(const[e,n]of p)a.children.push(r({descriptors:t,pointIndexes:new Int32Array(n),centerPointIndex:e,randomizer:i,useHDC:c}));return a};export{t as build};
@@ -1,170 +1 @@
1
- const kHoughBinDelta = 1;
2
- // mathces [querypointIndex:x, keypointIndex: x]
3
- const computeHoughMatches = (options) => {
4
- const { keywidth, keyheight, querywidth, queryheight, matches } = options;
5
- const maxX = querywidth * 1.2;
6
- const minX = -maxX;
7
- const maxY = queryheight * 1.2;
8
- const minY = -maxY;
9
- const numAngleBins = 12;
10
- const numScaleBins = 12; // 🚀 Increased bins
11
- const minScale = -2; // 📐 Support 1% scale (10^-2)
12
- const maxScale = 1; // 📐 Support 1000% scale (10^1)
13
- const scaleK = 10.0;
14
- const scaleOneOverLogK = 1.0 / Math.log(scaleK);
15
- const maxDim = Math.max(keywidth, keyheight);
16
- const keycenterX = Math.floor(keywidth / 2);
17
- const keycenterY = Math.floor(keyheight / 2);
18
- // compute numXBins and numYBins based on matches
19
- const projectedDims = [];
20
- for (let i = 0; i < matches.length; i++) {
21
- const queryscale = matches[i].querypoint.scale;
22
- const keyscale = matches[i].keypoint.scale;
23
- if (keyscale == 0)
24
- console.log("ERROR divide zero");
25
- const scale = queryscale / keyscale;
26
- projectedDims.push(scale * maxDim);
27
- }
28
- // TODO optimize median
29
- // weird. median should be [Math.floor(projectedDims.length/2) - 1] ?
30
- projectedDims.sort((a1, a2) => {
31
- return a1 - a2;
32
- });
33
- const medianProjectedDim = projectedDims[Math.floor(projectedDims.length / 2) - (projectedDims.length % 2 == 0 ? 1 : 0) - 1];
34
- const binSize = Math.max(20, 0.25 * medianProjectedDim); // 🚀 Ensure bins aren't too small for noise
35
- const numXBins = Math.max(5, Math.min(40, Math.ceil((maxX - minX) / binSize))); // 🎯 Cap bins to keep voting dense
36
- const numYBins = Math.max(5, Math.min(40, Math.ceil((maxY - minY) / binSize)));
37
- const numXYBins = numXBins * numYBins;
38
- const numXYAngleBins = numXYBins * numAngleBins;
39
- // do voting
40
- const querypointValids = [];
41
- const querypointBinLocations = [];
42
- const votes = {};
43
- for (let i = 0; i < matches.length; i++) {
44
- const querypoint = matches[i].querypoint;
45
- const keypoint = matches[i].keypoint;
46
- const { x, y, scale, angle } = _mapCorrespondence({
47
- querypoint,
48
- keypoint,
49
- keycenterX,
50
- keycenterY,
51
- scaleOneOverLogK,
52
- });
53
- // Check that the vote is within range
54
- if (x < minX ||
55
- x >= maxX ||
56
- y < minY ||
57
- y >= maxY ||
58
- angle <= -Math.PI ||
59
- angle > Math.PI ||
60
- scale < minScale ||
61
- scale >= maxScale) {
62
- querypointValids[i] = false;
63
- continue;
64
- }
65
- // map properties to bins
66
- let fbinX = (numXBins * (x - minX)) / (maxX - minX);
67
- let fbinY = (numYBins * (y - minY)) / (maxY - minY);
68
- let fbinAngle = (numAngleBins * (angle + Math.PI)) / (2.0 * Math.PI);
69
- let fbinScale = (numScaleBins * (scale - minScale)) / (maxScale - minScale);
70
- querypointBinLocations[i] = {
71
- binX: fbinX,
72
- binY: fbinY,
73
- binAngle: fbinAngle,
74
- binScale: fbinScale,
75
- };
76
- let binX = Math.floor(fbinX - 0.5);
77
- let binY = Math.floor(fbinY - 0.5);
78
- let binScale = Math.floor(fbinScale - 0.5);
79
- let binAngle = (Math.floor(fbinAngle - 0.5) + numAngleBins) % numAngleBins;
80
- // check can vote all 16 bins
81
- if (binX < 0 ||
82
- binX + 1 >= numXBins ||
83
- binY < 0 ||
84
- binY + 1 >= numYBins ||
85
- binScale < 0 ||
86
- binScale + 1 >= numScaleBins) {
87
- querypointValids[i] = false;
88
- continue;
89
- }
90
- for (let dx = 0; dx < 2; dx++) {
91
- let binX2 = binX + dx;
92
- for (let dy = 0; dy < 2; dy++) {
93
- let binY2 = binY + dy;
94
- for (let dangle = 0; dangle < 2; dangle++) {
95
- let binAngle2 = (binAngle + dangle) % numAngleBins;
96
- for (let dscale = 0; dscale < 2; dscale++) {
97
- let binScale2 = binScale + dscale;
98
- const binIndex = binX2 + binY2 * numXBins + binAngle2 * numXYBins + binScale2 * numXYAngleBins;
99
- if (votes[binIndex] === undefined)
100
- votes[binIndex] = 0;
101
- votes[binIndex] += 1;
102
- }
103
- }
104
- }
105
- }
106
- querypointValids[i] = true;
107
- }
108
- let maxVotes = 0;
109
- let maxVoteIndex = -1;
110
- Object.keys(votes).forEach((index) => {
111
- if (votes[index] > maxVotes) {
112
- maxVotes = votes[index];
113
- maxVoteIndex = index;
114
- }
115
- });
116
- if (maxVotes < 3)
117
- return [];
118
- // get back bins from vote index
119
- const binX = Math.floor(((maxVoteIndex % numXYAngleBins) % numXYBins) % numXBins);
120
- const binY = Math.floor((((maxVoteIndex - binX) % numXYAngleBins) % numXYBins) / numXBins);
121
- const binAngle = Math.floor(((maxVoteIndex - binX - binY * numXBins) % numXYAngleBins) / numXYBins);
122
- const binScale = Math.floor((maxVoteIndex - binX - binY * numXBins - binAngle * numXYBins) / numXYAngleBins);
123
- // console.log(`[Hough] Peak votes: ${maxVotes} out of ${matches.length} matches.`);
124
- const houghMatches = [];
125
- const relaxedDelta = 2.0; // 🚀 Increased for better cluster robustness
126
- for (let i = 0; i < matches.length; i++) {
127
- if (!querypointValids[i])
128
- continue;
129
- const queryBins = querypointBinLocations[i];
130
- // compute bin difference
131
- const distBinX = Math.abs(queryBins.binX - (binX + 0.5));
132
- if (distBinX >= relaxedDelta)
133
- continue;
134
- const distBinY = Math.abs(queryBins.binY - (binY + 0.5));
135
- if (distBinY >= relaxedDelta)
136
- continue;
137
- const distBinScale = Math.abs(queryBins.binScale - (binScale + 0.5));
138
- if (distBinScale >= relaxedDelta)
139
- continue;
140
- const temp = Math.abs(queryBins.binAngle - (binAngle + 0.5));
141
- const distBinAngle = Math.min(temp, numAngleBins - temp);
142
- if (distBinAngle >= relaxedDelta)
143
- continue;
144
- houghMatches.push(matches[i]);
145
- }
146
- return houghMatches;
147
- };
148
- const _mapCorrespondence = ({ querypoint, keypoint, keycenterX, keycenterY, scaleOneOverLogK }) => {
149
- // map angle to (-pi, pi]
150
- let angle = querypoint.angle - keypoint.angle;
151
- if (angle <= -Math.PI)
152
- angle += 2 * Math.PI;
153
- else if (angle > Math.PI)
154
- angle -= 2 * Math.PI;
155
- const scale = querypoint.scale / keypoint.scale;
156
- // 2x2 similarity
157
- const cos = scale * Math.cos(angle);
158
- const sin = scale * Math.sin(angle);
159
- const S = [cos, -sin, sin, cos];
160
- const tp = [S[0] * keypoint.x + S[1] * keypoint.y, S[2] * keypoint.x + S[3] * keypoint.y];
161
- const tx = querypoint.x - tp[0];
162
- const ty = querypoint.y - tp[1];
163
- return {
164
- x: S[0] * keycenterX + S[1] * keycenterY + tx,
165
- y: S[2] * keycenterX + S[3] * keycenterY + ty,
166
- angle: angle,
167
- scale: Math.log(scale) * scaleOneOverLogK,
168
- };
169
- };
170
- export { computeHoughMatches };
1
+ const t=t=>{const{keywidth:o,keyheight:n,querywidth:a,queryheight:l,matches:h}=t,i=1.2*a,r=-i,c=1.2*l,M=-c,s=12,f=1/Math.log(10),y=Math.max(o,n),g=Math.floor(o/2),u=Math.floor(n/2),b=[];for(let t=0;t<h.length;t++){const e=h[t].querypoint.scale,o=h[t].keypoint.scale;0==o&&console.log("ERROR divide zero");const n=e/o;b.push(n*y)}b.sort((t,e)=>t-e);const k=b[Math.floor(b.length/2)-(b.length%2==0?1:0)-1],p=Math.max(20,.25*k),x=Math.max(5,Math.min(40,Math.ceil((i-r)/p))),m=Math.max(5,Math.min(40,Math.ceil((c-M)/p))),I=x*m,P=I*s,q=[],O=[],d={};for(let t=0;t<h.length;t++){const o=h[t].querypoint,n=h[t].keypoint,{x:a,y:l,scale:y,angle:b}=e({querypoint:o,keypoint:n,keycenterX:g,keycenterY:u,scaleOneOverLogK:f});if(a<r||a>=i||l<M||l>=c||b<=-Math.PI||b>Math.PI||y<-2||y>=1){q[t]=!1;continue}let k=x*(a-r)/(i-r),p=m*(l-M)/(c-M),v=s*(b+Math.PI)/(2*Math.PI),X=12*(y- -2)/3;O[t]={binX:k,binY:p,binAngle:v,binScale:X};let Y=Math.floor(k-.5),R=Math.floor(p-.5),w=Math.floor(X-.5),A=(Math.floor(v-.5)+s)%s;if(Y<0||Y+1>=x||R<0||R+1>=m||w<0||w+1>=12)q[t]=!1;else{for(let t=0;t<2;t++){let e=Y+t;for(let t=0;t<2;t++){let o=R+t;for(let t=0;t<2;t++){let n=(A+t)%s;for(let t=0;t<2;t++){const a=e+o*x+n*I+(w+t)*P;void 0===d[a]&&(d[a]=0),d[a]+=1}}}}q[t]=!0}}let v=0,X=-1;if(Object.keys(d).forEach(t=>{d[t]>v&&(v=d[t],X=t)}),v<3)return[];const Y=Math.floor(X%P%I%x),R=Math.floor((X-Y)%P%I/x),w=Math.floor((X-Y-R*x)%P/I),A=Math.floor((X-Y-R*x-w*I)/P),E=[];for(let t=0;t<h.length;t++){if(!q[t])continue;const e=O[t];if(Math.abs(e.binX-(Y+.5))>=2)continue;if(Math.abs(e.binY-(R+.5))>=2)continue;if(Math.abs(e.binScale-(A+.5))>=2)continue;const o=Math.abs(e.binAngle-(w+.5));Math.min(o,s-o)>=2||E.push(h[t])}return E},e=({querypoint:t,keypoint:e,keycenterX:o,keycenterY:n,scaleOneOverLogK:a})=>{let l=t.angle-e.angle;l<=-Math.PI?l+=2*Math.PI:l>Math.PI&&(l-=2*Math.PI);const h=t.scale/e.scale,i=h*Math.cos(l),r=h*Math.sin(l),c=[i,-r,r,i],M=[c[0]*e.x+c[1]*e.y,c[2]*e.x+c[3]*e.y],s=t.x-M[0],f=t.y-M[1];return{x:c[0]*o+c[1]*n+s,y:c[2]*o+c[3]*n+f,angle:l,scale:Math.log(h)*a}};export{t as computeHoughMatches};
@@ -1,66 +1 @@
1
- import { match } from "./matching.js";
2
- class Matcher {
3
- constructor(queryWidth, queryHeight, debugMode = false) {
4
- this.queryWidth = queryWidth;
5
- this.queryHeight = queryHeight;
6
- this.debugMode = debugMode;
7
- }
8
- matchDetection(keyframes, featurePoints, expectedScale) {
9
- let debugExtra = { frames: [] };
10
- let bestResult = null;
11
- // keyframes is actually the matchingData array for a single target
12
- if (!keyframes || !Array.isArray(keyframes)) {
13
- return { targetIndex: -1, keyframeIndex: -1, debugExtra };
14
- }
15
- for (let j = 0; j < keyframes.length; j++) {
16
- const { H, matches, debugExtra: frameDebugExtra, } = match({
17
- keyframe: keyframes[j],
18
- querypoints: featurePoints,
19
- querywidth: this.queryWidth,
20
- queryheight: this.queryHeight,
21
- debugMode: this.debugMode,
22
- expectedScale,
23
- });
24
- if (frameDebugExtra) {
25
- frameDebugExtra.keyframeIndex = j;
26
- debugExtra.frames.push(frameDebugExtra);
27
- }
28
- if (H) {
29
- if (bestResult === null || bestResult.matches.length < matches.length) {
30
- bestResult = { keyframeIndex: j, H, matches };
31
- }
32
- }
33
- }
34
- if (bestResult === null) {
35
- return { targetIndex: -1, keyframeIndex: -1, debugExtra };
36
- }
37
- const screenCoords = [];
38
- const worldCoords = [];
39
- const keyframe = keyframes[bestResult.keyframeIndex];
40
- const kfScale = keyframe.s || keyframe.scale || 1.0;
41
- for (let i = 0; i < bestResult.matches.length; i++) {
42
- const querypoint = bestResult.matches[i].querypoint;
43
- const keypoint = bestResult.matches[i].keypoint;
44
- // 🚀 NANITE-STYLE: Use per-keypoint scale (octave) for accurate world mapping
45
- const pointScale = keypoint.scale || kfScale;
46
- screenCoords.push({
47
- x: querypoint.x,
48
- y: querypoint.y,
49
- });
50
- worldCoords.push({
51
- x: (keypoint.x + 0.5) / kfScale,
52
- y: (keypoint.y + 0.5) / kfScale,
53
- z: 0,
54
- });
55
- }
56
- return {
57
- screenCoords,
58
- worldCoords,
59
- targetIndex: -1, // Caller knows the targetIndex
60
- keyframeIndex: bestResult.keyframeIndex,
61
- H: bestResult.H,
62
- debugExtra
63
- };
64
- }
65
- }
66
- export { Matcher };
1
+ import{match as e}from"./matching.js";class t{constructor(e,t,r=!1){this.queryWidth=e,this.queryHeight=t,this.debugMode=r}matchDetection(t,r,s){let a={frames:[]},n=null;if(!t||!Array.isArray(t))return{targetIndex:-1,keyframeIndex:-1,debugExtra:a};for(let h=0;h<t.length;h++){const{H:d,matches:u,debugExtra:y}=e({keyframe:t[h],querypoints:r,querywidth:this.queryWidth,queryheight:this.queryHeight,debugMode:this.debugMode,expectedScale:s});y&&(y.keyframeIndex=h,a.frames.push(y)),d&&(null===n||n.matches.length<u.length)&&(n={keyframeIndex:h,H:d,matches:u})}if(null===n)return{targetIndex:-1,keyframeIndex:-1,debugExtra:a};const h=[],d=[],u=t[n.keyframeIndex],y=u.s||u.scale||1;for(let e=0;e<n.matches.length;e++){const t=n.matches[e].querypoint,r=n.matches[e].keypoint;r.scale,h.push({x:t.x,y:t.y}),d.push({x:(r.x+.5)/y,y:(r.y+.5)/y,z:0})}return{screenCoords:h,worldCoords:d,targetIndex:-1,keyframeIndex:n.keyframeIndex,H:n.H,debugExtra:a}}}export{t as Matcher};