@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,37 +1 @@
1
- // fast 2D submatrix sum using cumulative sum algorithm
2
- class Cumsum {
3
- constructor(data, width, height) {
4
- this.width = width;
5
- this.height = height;
6
- this.cumsum = new Int32Array(width * height);
7
- this.cumsum[0] = data[0];
8
- for (let i = 1; i < width; i++) {
9
- this.cumsum[i] = this.cumsum[i - 1] + data[i];
10
- }
11
- for (let j = 1; j < height; j++) {
12
- this.cumsum[j * width] = this.cumsum[(j - 1) * width] + data[j * width];
13
- }
14
- for (let j = 1; j < height; j++) {
15
- for (let i = 1; i < width; i++) {
16
- const pos = j * width + i;
17
- this.cumsum[pos] =
18
- data[pos] +
19
- this.cumsum[(j - 1) * width + i] +
20
- this.cumsum[j * width + i - 1] -
21
- this.cumsum[(j - 1) * width + i - 1];
22
- }
23
- }
24
- }
25
- query(x1, y1, x2, y2) {
26
- const { width } = this;
27
- let ret = this.cumsum[y2 * width + x2];
28
- if (y1 > 0)
29
- ret -= this.cumsum[(y1 - 1) * width + x2];
30
- if (x1 > 0)
31
- ret -= this.cumsum[y2 * width + x1 - 1];
32
- if (x1 > 0 && y1 > 0)
33
- ret += this.cumsum[(y1 - 1) * width + x1 - 1];
34
- return ret;
35
- }
36
- }
37
- export { Cumsum };
1
+ class s{constructor(s,t,u){this.width=t,this.height=u,this.cumsum=new Int32Array(t*u),this.cumsum[0]=s[0];for(let u=1;u<t;u++)this.cumsum[u]=this.cumsum[u-1]+s[u];for(let m=1;m<u;m++)this.cumsum[m*t]=this.cumsum[(m-1)*t]+s[m*t];for(let m=1;m<u;m++)for(let u=1;u<t;u++){const h=m*t+u;this.cumsum[h]=s[h]+this.cumsum[(m-1)*t+u]+this.cumsum[m*t+u-1]-this.cumsum[(m-1)*t+u-1]}}query(s,t,u,m){const{width:h}=this;let i=this.cumsum[m*h+u];return t>0&&(i-=this.cumsum[(t-1)*h+u]),s>0&&(i-=this.cumsum[m*h+s-1]),s>0&&t>0&&(i+=this.cumsum[(t-1)*h+s-1]),i}}export{s as Cumsum};
@@ -1,125 +1 @@
1
- /**
2
- * 🚀 Moonshot: Simple incremental Delaunay Triangulation (Bowyer-Watson)
3
- *
4
- * Used to create a topological mesh covering the image target features.
5
- */
6
- export function triangulate(points) {
7
- if (points.length < 3)
8
- return [];
9
- // 1. Create a super-triangle that contains all points
10
- // Find min/max bounds
11
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
12
- for (const p of points) {
13
- if (p.x < minX)
14
- minX = p.x;
15
- if (p.x > maxX)
16
- maxX = p.x;
17
- if (p.y < minY)
18
- minY = p.y;
19
- if (p.y > maxY)
20
- maxY = p.y;
21
- }
22
- const dx = maxX - minX;
23
- const dy = maxY - minY;
24
- const deltaMax = Math.max(dx, dy);
25
- const midX = (minX + maxX) / 2;
26
- const midY = (minY + maxY) / 2;
27
- // A triangle large enough to cover all points
28
- const p1 = { x: midX - 20 * deltaMax, y: midY - deltaMax };
29
- const p2 = { x: midX, y: midY + 20 * deltaMax };
30
- const p3 = { x: midX + 20 * deltaMax, y: midY - deltaMax };
31
- let triangles = [
32
- { p1, p2, p3, indices: [-1, -2, -3] }
33
- ];
34
- // 2. Add points one by one
35
- for (let i = 0; i < points.length; i++) {
36
- const p = points[i];
37
- const badTriangles = [];
38
- for (const t of triangles) {
39
- if (isInCircumcircle(p, t)) {
40
- badTriangles.push(t);
41
- }
42
- }
43
- const polygon = [];
44
- for (const t of badTriangles) {
45
- const edges = [
46
- { a: t.p1, b: t.p2, i1: t.indices[0], i2: t.indices[1] },
47
- { a: t.p2, b: t.p3, i1: t.indices[1], i2: t.indices[2] },
48
- { a: t.p3, b: t.p1, i1: t.indices[2], i2: t.indices[0] }
49
- ];
50
- for (const edge of edges) {
51
- let isShared = false;
52
- for (const t2 of badTriangles) {
53
- if (t === t2)
54
- continue;
55
- if (isSameEdge(edge, t2)) {
56
- isShared = true;
57
- break;
58
- }
59
- }
60
- if (!isShared) {
61
- polygon.push(edge);
62
- }
63
- }
64
- }
65
- // Remove bad triangles
66
- triangles = triangles.filter(t => !badTriangles.includes(t));
67
- // Add new triangles from polygon edges to point p
68
- for (const edge of polygon) {
69
- triangles.push({
70
- p1: edge.a,
71
- p2: edge.b,
72
- p3: p,
73
- indices: [edge.i1, edge.i2, i]
74
- });
75
- }
76
- }
77
- // 3. Remove triangles that share vertices with the super-triangle
78
- return triangles.filter(t => {
79
- return t.indices[0] >= 0 && t.indices[1] >= 0 && t.indices[2] >= 0;
80
- }).map(t => t.indices);
81
- }
82
- function isInCircumcircle(p, t) {
83
- const x1 = t.p1.x, y1 = t.p1.y;
84
- const x2 = t.p2.x, y2 = t.p2.y;
85
- const x3 = t.p3.x, y3 = t.p3.y;
86
- const D = 2 * (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
87
- const centerX = ((x1 * x1 + y1 * y1) * (y2 - y3) + (x2 * x2 + y2 * y2) * (y3 - y1) + (x3 * x3 + y3 * y3) * (y1 - y2)) / D;
88
- const centerY = ((x1 * x1 + y1 * y1) * (x3 - x2) + (x2 * x2 + y2 * y2) * (x1 - x3) + (x3 * x3 + y3 * y3) * (x2 - x1)) / D;
89
- const radiusSq = (x1 - centerX) * (x1 - centerX) + (y1 - centerY) * (y1 - centerY);
90
- const distSq = (p.x - centerX) * (p.x - centerX) + (p.y - centerY) * (p.y - centerY);
91
- return distSq <= radiusSq;
92
- }
93
- function isSameEdge(edge, triangle) {
94
- const tEdges = [
95
- [triangle.indices[0], triangle.indices[1]],
96
- [triangle.indices[1], triangle.indices[2]],
97
- [triangle.indices[2], triangle.indices[0]]
98
- ];
99
- for (const te of tEdges) {
100
- if ((edge.i1 === te[0] && edge.i2 === te[1]) || (edge.i1 === te[1] && edge.i2 === te[0])) {
101
- return true;
102
- }
103
- }
104
- return false;
105
- }
106
- /**
107
- * Extract edges from triangles for Mass-Spring logic
108
- */
109
- export function getEdges(triangles) {
110
- const edgeSet = new Set();
111
- const edges = [];
112
- for (const t of triangles) {
113
- const pairs = [[t[0], t[1]], [t[1], t[2]], [t[2], t[0]]];
114
- for (const pair of pairs) {
115
- const low = Math.min(pair[0], pair[1]);
116
- const high = Math.max(pair[0], pair[1]);
117
- const key = `${low}-${high}`;
118
- if (!edgeSet.has(key)) {
119
- edgeSet.add(key);
120
- edges.push([low, high]);
121
- }
122
- }
123
- }
124
- return edges;
125
- }
1
+ export function triangulate(t){if(t.length<3)return[];let o=1/0,s=1/0,c=-1/0,e=-1/0;for(const i of t)i.x<o&&(o=i.x),i.x>c&&(c=i.x),i.y<s&&(s=i.y),i.y>e&&(e=i.y);const f=c-o,r=e-s,p=Math.max(f,r),d=(o+c)/2,u=(s+e)/2;let x=[{p1:{x:d-20*p,y:u-p},p2:{x:d,y:u+20*p},p3:{x:d+20*p,y:u-p},indices:[-1,-2,-3]}];for(let o=0;o<t.length;o++){const s=t[o],c=[];for(const n of x)i(s,n)&&c.push(n);const e=[];for(const i of c){const t=[{a:i.p1,b:i.p2,i1:i.indices[0],i2:i.indices[1]},{a:i.p2,b:i.p3,i1:i.indices[1],i2:i.indices[2]},{a:i.p3,b:i.p1,i1:i.indices[2],i2:i.indices[0]}];for(const o of t){let t=!1;for(const s of c)if(i!==s&&n(o,s)){t=!0;break}t||e.push(o)}}x=x.filter(i=>!c.includes(i));for(const i of e)x.push({p1:i.a,p2:i.b,p3:s,indices:[i.i1,i.i2,o]})}return x.filter(i=>i.indices[0]>=0&&i.indices[1]>=0&&i.indices[2]>=0).map(i=>i.indices)}function i(i,n){const t=n.p1.x,o=n.p1.y,s=n.p2.x,c=n.p2.y,e=n.p3.x,f=n.p3.y,r=2*(t*(c-f)+s*(f-o)+e*(o-c)),p=((t*t+o*o)*(c-f)+(s*s+c*c)*(f-o)+(e*e+f*f)*(o-c))/r,d=((t*t+o*o)*(e-s)+(s*s+c*c)*(t-e)+(e*e+f*f)*(s-t))/r,u=(t-p)*(t-p)+(o-d)*(o-d);return(i.x-p)*(i.x-p)+(i.y-d)*(i.y-d)<=u}function n(i,n){const t=[[n.indices[0],n.indices[1]],[n.indices[1],n.indices[2]],[n.indices[2],n.indices[0]]];for(const n of t)if(i.i1===n[0]&&i.i2===n[1]||i.i1===n[1]&&i.i2===n[0])return!0;return!1}export function getEdges(i){const n=new Set,t=[];for(const o of i){const i=[[o[0],o[1]],[o[1],o[2]],[o[2],o[0]]];for(const o of i){const i=Math.min(o[0],o[1]),s=Math.max(o[0],o[1]),c=`${i}-${s}`;n.has(c)||(n.add(c),t.push([i,s]))}}return t}
@@ -1,101 +1 @@
1
- // check which side point C on the line from A to B
2
- const linePointSide = (A, B, C) => {
3
- return (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1]) * (C[0] - A[0]);
4
- };
5
- // srcPoints, dstPoints: array of four elements [x, y]
6
- const checkFourPointsConsistent = (x1, x2, x3, x4, x1p, x2p, x3p, x4p) => {
7
- if (linePointSide(x1, x2, x3) > 0 !== linePointSide(x1p, x2p, x3p) > 0)
8
- return false;
9
- if (linePointSide(x2, x3, x4) > 0 !== linePointSide(x2p, x3p, x4p) > 0)
10
- return false;
11
- if (linePointSide(x3, x4, x1) > 0 !== linePointSide(x3p, x4p, x1p) > 0)
12
- return false;
13
- if (linePointSide(x4, x1, x2) > 0 !== linePointSide(x4p, x1p, x2p) > 0)
14
- return false;
15
- return true;
16
- };
17
- const checkThreePointsConsistent = (x1, x2, x3, x1p, x2p, x3p) => {
18
- if (linePointSide(x1, x2, x3) > 0 !== linePointSide(x1p, x2p, x3p) > 0)
19
- return false;
20
- return true;
21
- };
22
- const determinant = (A) => {
23
- const C1 = A[4] * A[8] - A[5] * A[7];
24
- const C2 = A[3] * A[8] - A[5] * A[6];
25
- const C3 = A[3] * A[7] - A[4] * A[6];
26
- return A[0] * C1 - A[1] * C2 + A[2] * C3;
27
- };
28
- const matrixInverse33 = (A, threshold) => {
29
- const det = determinant(A);
30
- if (Math.abs(det) <= threshold)
31
- return null;
32
- const oneOver = 1.0 / det;
33
- const B = [
34
- (A[4] * A[8] - A[5] * A[7]) * oneOver,
35
- (A[2] * A[7] - A[1] * A[8]) * oneOver,
36
- (A[1] * A[5] - A[2] * A[4]) * oneOver,
37
- (A[5] * A[6] - A[3] * A[8]) * oneOver,
38
- (A[0] * A[8] - A[2] * A[6]) * oneOver,
39
- (A[2] * A[3] - A[0] * A[5]) * oneOver,
40
- (A[3] * A[7] - A[4] * A[6]) * oneOver,
41
- (A[1] * A[6] - A[0] * A[7]) * oneOver,
42
- (A[0] * A[4] - A[1] * A[3]) * oneOver,
43
- ];
44
- return B;
45
- };
46
- const matrixMul33 = (A, B) => {
47
- const C = [];
48
- C[0] = A[0] * B[0] + A[1] * B[3] + A[2] * B[6];
49
- C[1] = A[0] * B[1] + A[1] * B[4] + A[2] * B[7];
50
- C[2] = A[0] * B[2] + A[1] * B[5] + A[2] * B[8];
51
- C[3] = A[3] * B[0] + A[4] * B[3] + A[5] * B[6];
52
- C[4] = A[3] * B[1] + A[4] * B[4] + A[5] * B[7];
53
- C[5] = A[3] * B[2] + A[4] * B[5] + A[5] * B[8];
54
- C[6] = A[6] * B[0] + A[7] * B[3] + A[8] * B[6];
55
- C[7] = A[6] * B[1] + A[7] * B[4] + A[8] * B[7];
56
- C[8] = A[6] * B[2] + A[7] * B[5] + A[8] * B[8];
57
- return C;
58
- };
59
- const multiplyPointHomographyInhomogenous = (x, H) => {
60
- const w = H[6] * x[0] + H[7] * x[1] + H[8];
61
- const xp = [];
62
- xp[0] = (H[0] * x[0] + H[1] * x[1] + H[2]) / w;
63
- xp[1] = (H[3] * x[0] + H[4] * x[1] + H[5]) / w;
64
- return xp;
65
- };
66
- const smallestTriangleArea = (x1, x2, x3, x4) => {
67
- const v12 = _vector(x2, x1);
68
- const v13 = _vector(x3, x1);
69
- const v14 = _vector(x4, x1);
70
- const v32 = _vector(x2, x3);
71
- const v34 = _vector(x4, x3);
72
- const a1 = _areaOfTriangle(v12, v13);
73
- const a2 = _areaOfTriangle(v13, v14);
74
- const a3 = _areaOfTriangle(v12, v14);
75
- const a4 = _areaOfTriangle(v32, v34);
76
- return Math.min(Math.min(Math.min(a1, a2), a3), a4);
77
- };
78
- // check if four points form a convex quadrilaternal.
79
- // all four combinations should have same sign
80
- const quadrilateralConvex = (x1, x2, x3, x4) => {
81
- const first = linePointSide(x1, x2, x3) <= 0;
82
- if (linePointSide(x2, x3, x4) <= 0 !== first)
83
- return false;
84
- if (linePointSide(x3, x4, x1) <= 0 !== first)
85
- return false;
86
- if (linePointSide(x4, x1, x2) <= 0 !== first)
87
- return false;
88
- //if (linePointSide(x1, x2, x3) <= 0) return false;
89
- //if (linePointSide(x2, x3, x4) <= 0) return false;
90
- //if (linePointSide(x3, x4, x1) <= 0) return false;
91
- //if (linePointSide(x4, x1, x2) <= 0) return false;
92
- return true;
93
- };
94
- const _vector = (a, b) => {
95
- return [a[0] - b[0], a[1] - b[1]];
96
- };
97
- const _areaOfTriangle = (u, v) => {
98
- const a = u[0] * v[1] - u[1] * v[0];
99
- return Math.abs(a) * 0.5;
100
- };
101
- export { matrixInverse33, matrixMul33, quadrilateralConvex, smallestTriangleArea, multiplyPointHomographyInhomogenous, checkThreePointsConsistent, checkFourPointsConsistent, determinant, };
1
+ const t=(t,n,r)=>(n[0]-t[0])*(r[1]-t[1])-(n[1]-t[1])*(r[0]-t[0]),n=(n,r,s,o,c,e,u,a)=>t(n,r,s)>0==t(c,e,u)>0&&t(r,s,o)>0==t(e,u,a)>0&&t(s,o,n)>0==t(u,a,c)>0&&t(o,n,r)>0==t(a,c,e)>0,r=(n,r,s,o,c,e)=>t(n,r,s)>0==t(o,c,e)>0,s=t=>{const n=t[4]*t[8]-t[5]*t[7],r=t[3]*t[8]-t[5]*t[6],s=t[3]*t[7]-t[4]*t[6];return t[0]*n-t[1]*r+t[2]*s},o=(t,n)=>{const r=s(t);if(Math.abs(r)<=n)return null;const o=1/r;return[(t[4]*t[8]-t[5]*t[7])*o,(t[2]*t[7]-t[1]*t[8])*o,(t[1]*t[5]-t[2]*t[4])*o,(t[5]*t[6]-t[3]*t[8])*o,(t[0]*t[8]-t[2]*t[6])*o,(t[2]*t[3]-t[0]*t[5])*o,(t[3]*t[7]-t[4]*t[6])*o,(t[1]*t[6]-t[0]*t[7])*o,(t[0]*t[4]-t[1]*t[3])*o]},c=(t,n)=>{const r=[];return r[0]=t[0]*n[0]+t[1]*n[3]+t[2]*n[6],r[1]=t[0]*n[1]+t[1]*n[4]+t[2]*n[7],r[2]=t[0]*n[2]+t[1]*n[5]+t[2]*n[8],r[3]=t[3]*n[0]+t[4]*n[3]+t[5]*n[6],r[4]=t[3]*n[1]+t[4]*n[4]+t[5]*n[7],r[5]=t[3]*n[2]+t[4]*n[5]+t[5]*n[8],r[6]=t[6]*n[0]+t[7]*n[3]+t[8]*n[6],r[7]=t[6]*n[1]+t[7]*n[4]+t[8]*n[7],r[8]=t[6]*n[2]+t[7]*n[5]+t[8]*n[8],r},e=(t,n)=>{const r=n[6]*t[0]+n[7]*t[1]+n[8],s=[];return s[0]=(n[0]*t[0]+n[1]*t[1]+n[2])/r,s[1]=(n[3]*t[0]+n[4]*t[1]+n[5])/r,s},u=(t,n,r,s)=>{const o=h(n,t),c=h(r,t),e=h(s,t),u=h(n,r),a=h(s,r),i=M(o,c),m=M(c,e),b=M(o,e),l=M(u,a);return Math.min(Math.min(Math.min(i,m),b),l)},a=(n,r,s,o)=>{const c=t(n,r,s)<=0;return t(r,s,o)<=0===c&&t(s,o,n)<=0===c&&t(o,n,r)<=0===c},h=(t,n)=>[t[0]-n[0],t[1]-n[1]],M=(t,n)=>{const r=t[0]*n[1]-t[1]*n[0];return.5*Math.abs(r)};export{o as matrixInverse33,c as matrixMul33,a as quadrilateralConvex,u as smallestTriangleArea,e as multiplyPointHomographyInhomogenous,r as checkThreePointsConsistent,n as checkFourPointsConsistent,s as determinant};
@@ -1,231 +1 @@
1
- /**
2
- * @fileoverview GPU Compute Layer for AR Compiler
3
- *
4
- * Provides optimized image processing with GPU acceleration when available.
5
- * - In browser: Uses GPU.js with WebGL
6
- * - In Node.js: Uses pure JavaScript (GPU.js requires headless-gl which may not compile)
7
- *
8
- * All methods have pure JS fallbacks that work universally.
9
- */
10
- // This module now uses pure JavaScript for all operations to ensure
11
- // zero-dependency builds and universal compatibility (Node.js & Browser).
12
- // The pure JS implementations are highly optimized for performance.
13
- /**
14
- * No-op initialization for compatibility
15
- */
16
- const tryInitGPU = () => {
17
- return null;
18
- };
19
- // ============================================================================
20
- // PURE JAVASCRIPT IMPLEMENTATIONS (Always work)
21
- // ============================================================================
22
- /**
23
- * Pure JS: Compute edge gradients
24
- */
25
- const computeGradientsJS = (imageData, width, height) => {
26
- const dValue = new Float32Array(width * height);
27
- for (let j = 1; j < height - 1; j++) {
28
- const rowOffset = j * width;
29
- const prevRowOffset = (j - 1) * width;
30
- const nextRowOffset = (j + 1) * width;
31
- for (let i = 1; i < width - 1; i++) {
32
- const pos = rowOffset + i;
33
- const dx = (imageData[prevRowOffset + i + 1] - imageData[prevRowOffset + i - 1] +
34
- imageData[rowOffset + i + 1] - imageData[rowOffset + i - 1] +
35
- imageData[nextRowOffset + i + 1] - imageData[nextRowOffset + i - 1]) / 768;
36
- const dy = (imageData[nextRowOffset + i - 1] - imageData[prevRowOffset + i - 1] +
37
- imageData[nextRowOffset + i] - imageData[prevRowOffset + i] +
38
- imageData[nextRowOffset + i + 1] - imageData[prevRowOffset + i + 1]) / 768;
39
- dValue[pos] = Math.sqrt((dx * dx + dy * dy) / 2);
40
- }
41
- }
42
- return dValue;
43
- };
44
- /**
45
- * Pure JS: Find local maxima
46
- */
47
- const findLocalMaximaJS = (gradients, width, height) => {
48
- const isCandidate = new Uint8Array(width * height);
49
- for (let j = 1; j < height - 1; j++) {
50
- const rowOffset = j * width;
51
- for (let i = 1; i < width - 1; i++) {
52
- const pos = rowOffset + i;
53
- const val = gradients[pos];
54
- if (val > 0 &&
55
- val >= gradients[pos - 1] && val >= gradients[pos + 1] &&
56
- val >= gradients[pos - width] && val >= gradients[pos + width]) {
57
- isCandidate[pos] = 1;
58
- }
59
- }
60
- }
61
- return isCandidate;
62
- };
63
- /**
64
- * Pure JS: Gaussian blur (5x5 binomial)
65
- */
66
- const gaussianBlurJS = (data, width, height) => {
67
- const output = new Float32Array(width * height);
68
- const temp = new Float32Array(width * height);
69
- const k0 = 1 / 16, k1 = 4 / 16, k2 = 6 / 16;
70
- const w1 = width - 1;
71
- const h1 = height - 1;
72
- // Horizontal pass
73
- for (let y = 0; y < height; y++) {
74
- const rowOffset = y * width;
75
- for (let x = 0; x < width; x++) {
76
- const x0 = x < 2 ? 0 : x - 2;
77
- const x1 = x < 1 ? 0 : x - 1;
78
- const x3 = x > w1 - 1 ? w1 : x + 1;
79
- const x4 = x > w1 - 2 ? w1 : x + 2;
80
- temp[rowOffset + x] =
81
- data[rowOffset + x0] * k0 +
82
- data[rowOffset + x1] * k1 +
83
- data[rowOffset + x] * k2 +
84
- data[rowOffset + x3] * k1 +
85
- data[rowOffset + x4] * k0;
86
- }
87
- }
88
- // Vertical pass
89
- for (let y = 0; y < height; y++) {
90
- const y0 = (y < 2 ? 0 : y - 2) * width;
91
- const y1 = (y < 1 ? 0 : y - 1) * width;
92
- const y2 = y * width;
93
- const y3 = (y > h1 - 1 ? h1 : y + 1) * width;
94
- const y4 = (y > h1 - 2 ? h1 : y + 2) * width;
95
- for (let x = 0; x < width; x++) {
96
- output[y2 + x] =
97
- temp[y0 + x] * k0 +
98
- temp[y1 + x] * k1 +
99
- temp[y2 + x] * k2 +
100
- temp[y3 + x] * k1 +
101
- temp[y4 + x] * k0;
102
- }
103
- }
104
- return output;
105
- };
106
- /**
107
- * Pure JS: Downsample by factor of 2
108
- */
109
- const downsampleJS = (data, width, height) => {
110
- const newWidth = Math.floor(width / 2);
111
- const newHeight = Math.floor(height / 2);
112
- const output = new Float32Array(newWidth * newHeight);
113
- for (let y = 0; y < newHeight; y++) {
114
- const sy = y * 2;
115
- for (let x = 0; x < newWidth; x++) {
116
- const sx = x * 2;
117
- const pos = sy * width + sx;
118
- output[y * newWidth + x] =
119
- (data[pos] + data[pos + 1] + data[pos + width] + data[pos + width + 1]) / 4;
120
- }
121
- }
122
- return { data: output, width: newWidth, height: newHeight };
123
- };
124
- // ============================================================================
125
- // GPU COMPUTE CLASS
126
- // ============================================================================
127
- /**
128
- * GPU Compute class - provides optimized image processing
129
- */
130
- export class GPUCompute {
131
- constructor() {
132
- this.gpu = null;
133
- this.kernelCache = new Map();
134
- this.initialized = false;
135
- }
136
- /**
137
- * Initialize (tries GPU in browser, uses JS in Node)
138
- */
139
- init() {
140
- if (this.initialized)
141
- return;
142
- this.gpu = tryInitGPU();
143
- this.initialized = true;
144
- }
145
- /**
146
- * Compute edge gradients
147
- */
148
- computeGradients(imageData, width, height) {
149
- this.init();
150
- // Always use JS implementation for reliability
151
- return computeGradientsJS(imageData, width, height);
152
- }
153
- /**
154
- * Find local maxima
155
- */
156
- findLocalMaxima(gradients, width, height) {
157
- this.init();
158
- return findLocalMaximaJS(gradients, width, height);
159
- }
160
- /**
161
- * Combined edge detection
162
- */
163
- edgeDetection(imageData, width, height) {
164
- const dValue = this.computeGradients(imageData, width, height);
165
- const isCandidate = this.findLocalMaxima(dValue, width, height);
166
- return { dValue, isCandidate };
167
- }
168
- /**
169
- * Gaussian blur
170
- */
171
- gaussianBlur(imageData, width, height) {
172
- this.init();
173
- return gaussianBlurJS(imageData, width, height);
174
- }
175
- /**
176
- * Downsample by factor of 2
177
- */
178
- downsample(imageData, width, height) {
179
- this.init();
180
- return downsampleJS(imageData, width, height);
181
- }
182
- /**
183
- * Build Gaussian pyramid
184
- */
185
- buildPyramid(imageData, width, height, numLevels = 5) {
186
- this.init();
187
- const pyramid = [];
188
- let currentData = imageData instanceof Float32Array ? imageData : Float32Array.from(imageData);
189
- let currentWidth = width;
190
- let currentHeight = height;
191
- for (let level = 0; level < numLevels; level++) {
192
- const blurred = this.gaussianBlur(currentData, currentWidth, currentHeight);
193
- pyramid.push({
194
- data: blurred,
195
- width: currentWidth,
196
- height: currentHeight,
197
- scale: Math.pow(2, level),
198
- });
199
- if (currentWidth > 8 && currentHeight > 8) {
200
- const downsampled = this.downsample(blurred, currentWidth, currentHeight);
201
- currentData = downsampled.data;
202
- currentWidth = downsampled.width;
203
- currentHeight = downsampled.height;
204
- }
205
- else {
206
- break;
207
- }
208
- }
209
- return pyramid;
210
- }
211
- /**
212
- * Check if GPU is available
213
- */
214
- isGPUAvailable() {
215
- this.init();
216
- return this.gpu !== null;
217
- }
218
- /**
219
- * Cleanup resources
220
- */
221
- destroy() {
222
- this.kernelCache.clear();
223
- if (this.gpu && this.gpu.destroy) {
224
- this.gpu.destroy();
225
- }
226
- this.gpu = null;
227
- this.initialized = false;
228
- }
229
- }
230
- // Singleton instance
231
- export const gpuCompute = new GPUCompute();
1
+ export class GPUCompute{constructor(){this.gpu=null,this.kernelCache=new Map,this.initialized=!1}init(){this.initialized||(this.gpu=null,this.initialized=!0)}computeGradients(t,i,e){return this.init(),((t,i,e)=>{const n=new Float32Array(i*e);for(let r=1;r<e-1;r++){const e=r*i,s=(r-1)*i,o=(r+1)*i;for(let r=1;r<i-1;r++){const i=e+r,a=(t[s+r+1]-t[s+r-1]+t[e+r+1]-t[e+r-1]+t[o+r+1]-t[o+r-1])/768,l=(t[o+r-1]-t[s+r-1]+t[o+r]-t[s+r]+t[o+r+1]-t[s+r+1])/768;n[i]=Math.sqrt((a*a+l*l)/2)}}return n})(t,i,e)}findLocalMaxima(t,i,e){return this.init(),((t,i,e)=>{const n=new Uint8Array(i*e);for(let r=1;r<e-1;r++){const e=r*i;for(let r=1;r<i-1;r++){const s=e+r,o=t[s];o>0&&o>=t[s-1]&&o>=t[s+1]&&o>=t[s-i]&&o>=t[s+i]&&(n[s]=1)}}return n})(t,i,e)}edgeDetection(t,i,e){const n=this.computeGradients(t,i,e);return{dValue:n,isCandidate:this.findLocalMaxima(n,i,e)}}gaussianBlur(t,i,e){return this.init(),((t,i,e)=>{const n=new Float32Array(i*e),r=new Float32Array(i*e),s=1/16,o=.25,a=6/16,l=i-1,h=e-1;for(let n=0;n<e;n++){const e=n*i;for(let n=0;n<i;n++){const i=n<2?0:n-2,h=n<1?0:n-1,u=n>l-1?l:n+1,c=n>l-2?l:n+2;r[e+n]=t[e+i]*s+t[e+h]*o+t[e+n]*a+t[e+u]*o+t[e+c]*s}}for(let t=0;t<e;t++){const e=(t<2?0:t-2)*i,l=(t<1?0:t-1)*i,u=t*i,c=(t>h-1?h:t+1)*i,d=(t>h-2?h:t+2)*i;for(let t=0;t<i;t++)n[u+t]=r[e+t]*s+r[l+t]*o+r[u+t]*a+r[c+t]*o+r[d+t]*s}return n})(t,i,e)}downsample(t,i,e){return this.init(),((t,i,e)=>{const n=Math.floor(i/2),r=Math.floor(e/2),s=new Float32Array(n*r);for(let e=0;e<r;e++){const r=2*e;for(let o=0;o<n;o++){const a=r*i+2*o;s[e*n+o]=(t[a]+t[a+1]+t[a+i]+t[a+i+1])/4}}return{data:s,width:n,height:r}})(t,i,e)}buildPyramid(t,i,e,n=5){this.init();const r=[];let s=t instanceof Float32Array?t:Float32Array.from(t),o=i,a=e;for(let t=0;t<n;t++){const i=this.gaussianBlur(s,o,a);if(r.push({data:i,width:o,height:a,scale:Math.pow(2,t)}),!(o>8&&a>8))break;{const t=this.downsample(i,o,a);s=t.data,o=t.width,a=t.height}}return r}isGPUAvailable(){return this.init(),null!==this.gpu}destroy(){this.kernelCache.clear(),this.gpu&&this.gpu.destroy&&this.gpu.destroy(),this.gpu=null,this.initialized=!1}}export const gpuCompute=new GPUCompute;
@@ -1,138 +1 @@
1
- import { Matrix, inverse } from "ml-matrix";
2
- const solveHomography = (srcPoints, dstPoints) => {
3
- const { normPoints: normSrcPoints, param: srcParam } = _normalizePoints(srcPoints);
4
- const { normPoints: normDstPoints, param: dstParam } = _normalizePoints(dstPoints);
5
- const num = normDstPoints.length;
6
- const AData = [];
7
- const BData = [];
8
- for (let j = 0; j < num; j++) {
9
- const row1 = [
10
- normSrcPoints[j][0],
11
- normSrcPoints[j][1],
12
- 1,
13
- 0,
14
- 0,
15
- 0,
16
- -(normSrcPoints[j][0] * normDstPoints[j][0]),
17
- -(normSrcPoints[j][1] * normDstPoints[j][0]),
18
- ];
19
- const row2 = [
20
- 0,
21
- 0,
22
- 0,
23
- normSrcPoints[j][0],
24
- normSrcPoints[j][1],
25
- 1,
26
- -(normSrcPoints[j][0] * normDstPoints[j][1]),
27
- -(normSrcPoints[j][1] * normDstPoints[j][1]),
28
- ];
29
- AData.push(row1);
30
- AData.push(row2);
31
- BData.push([normDstPoints[j][0]]);
32
- BData.push([normDstPoints[j][1]]);
33
- }
34
- try {
35
- const A = new Matrix(AData);
36
- const B = new Matrix(BData);
37
- const AT = A.transpose();
38
- const ATA = AT.mmul(A);
39
- const ATB = AT.mmul(B);
40
- const ATAInv = inverse(ATA);
41
- const C = ATAInv.mmul(ATB).to1DArray();
42
- const H = _denormalizeHomography(C, srcParam, dstParam);
43
- return H;
44
- }
45
- catch (e) {
46
- return null;
47
- }
48
- };
49
- // centroid at origin and avg distance from origin is sqrt(2)
50
- const _normalizePoints = (coords) => {
51
- //return {normalizedCoords: coords, param: {meanX: 0, meanY: 0, s: 1}}; // skip normalization
52
- let sumX = 0;
53
- let sumY = 0;
54
- for (let i = 0; i < coords.length; i++) {
55
- sumX += coords[i][0];
56
- sumY += coords[i][1];
57
- }
58
- let meanX = sumX / coords.length;
59
- let meanY = sumY / coords.length;
60
- let sumDiff = 0;
61
- for (let i = 0; i < coords.length; i++) {
62
- const diffX = coords[i][0] - meanX;
63
- const diffY = coords[i][1] - meanY;
64
- sumDiff += Math.sqrt(diffX * diffX + diffY * diffY);
65
- }
66
- let s = (Math.sqrt(2) * coords.length) / sumDiff;
67
- const normPoints = [];
68
- for (let i = 0; i < coords.length; i++) {
69
- normPoints.push([(coords[i][0] - meanX) * s, (coords[i][1] - meanY) * s]);
70
- }
71
- return { normPoints, param: { meanX, meanY, s } };
72
- };
73
- // Denormalize homography
74
- // where T is the normalization matrix, i.e.
75
- //
76
- // [1 0 -meanX]
77
- // T = [0 1 -meanY]
78
- // [0 0 1/s]
79
- //
80
- // [1 0 s*meanX]
81
- // inv(T) = [0 1 s*meanY]
82
- // [0 0 s]
83
- //
84
- // H = inv(Tdst) * Hn * Tsrc
85
- //
86
- // @param {
87
- // nH: normH,
88
- // srcParam: param of src transform,
89
- // dstParam: param of dst transform
90
- // }
91
- const _denormalizeHomography = (nH, srcParam, dstParam) => {
92
- /*
93
- Matrix version
94
- const normH = new Matrix([
95
- [nH[0], nH[1], nH[2]],
96
- [nH[3], nH[4], nH[5]],
97
- [nH[6], nH[7], 1],
98
- ]);
99
- const Tsrc = new Matrix([
100
- [1, 0, -srcParam.meanX],
101
- [0, 1, -srcParam.meanY],
102
- [0, 0, 1/srcParam.s],
103
- ]);
104
-
105
- const invTdst = new Matrix([
106
- [1, 0, dstParam.s * dstParam.meanX],
107
- [0, 1, dstParam.s * dstParam.meanY],
108
- [0, 0, dstParam.s],
109
- ]);
110
- const H = invTdst.mmul(normH).mmul(Tsrc);
111
- */
112
- // plain implementation of the above using Matrix
113
- const sMeanX = dstParam.s * dstParam.meanX;
114
- const sMeanY = dstParam.s * dstParam.meanY;
115
- const H = [
116
- nH[0] + sMeanX * nH[6],
117
- nH[1] + sMeanX * nH[7],
118
- (nH[0] + sMeanX * nH[6]) * -srcParam.meanX +
119
- (nH[1] + sMeanX * nH[7]) * -srcParam.meanY +
120
- (nH[2] + sMeanX) / srcParam.s,
121
- nH[3] + sMeanY * nH[6],
122
- nH[4] + sMeanY * nH[7],
123
- (nH[3] + sMeanY * nH[6]) * -srcParam.meanX +
124
- (nH[4] + sMeanY * nH[7]) * -srcParam.meanY +
125
- (nH[5] + sMeanY) / srcParam.s,
126
- dstParam.s * nH[6],
127
- dstParam.s * nH[7],
128
- dstParam.s * nH[6] * -srcParam.meanX +
129
- dstParam.s * nH[7] * -srcParam.meanY +
130
- dstParam.s / srcParam.s,
131
- ];
132
- // make H[8] === 1;
133
- for (let i = 0; i < 9; i++) {
134
- H[i] = H[i] / H[8];
135
- }
136
- return H;
137
- };
138
- export { solveHomography };
1
+ import{Matrix as t,inverse as n}from"ml-matrix";const e=(e,m)=>{const{normPoints:o,param:a}=s(e),{normPoints:l,param:h}=s(m),u=l.length,p=[],c=[];for(let t=0;t<u;t++){const n=[o[t][0],o[t][1],1,0,0,0,-o[t][0]*l[t][0],-o[t][1]*l[t][0]],e=[0,0,0,o[t][0],o[t][1],1,-o[t][0]*l[t][1],-o[t][1]*l[t][1]];p.push(n),p.push(e),c.push([l[t][0]]),c.push([l[t][1]])}try{const e=new t(p),s=new t(c),m=e.transpose(),o=m.mmul(e),l=m.mmul(s),u=n(o).mmul(l).to1DArray();return r(u,a,h)}catch(t){return null}},s=t=>{let n=0,e=0;for(let s=0;s<t.length;s++)n+=t[s][0],e+=t[s][1];let s=n/t.length,r=e/t.length,m=0;for(let n=0;n<t.length;n++){const e=t[n][0]-s,o=t[n][1]-r;m+=Math.sqrt(e*e+o*o)}let o=Math.sqrt(2)*t.length/m;const a=[];for(let n=0;n<t.length;n++)a.push([(t[n][0]-s)*o,(t[n][1]-r)*o]);return{normPoints:a,param:{meanX:s,meanY:r,s:o}}},r=(t,n,e)=>{const s=e.s*e.meanX,r=e.s*e.meanY,m=[t[0]+s*t[6],t[1]+s*t[7],(t[0]+s*t[6])*-n.meanX+(t[1]+s*t[7])*-n.meanY+(t[2]+s)/n.s,t[3]+r*t[6],t[4]+r*t[7],(t[3]+r*t[6])*-n.meanX+(t[4]+r*t[7])*-n.meanY+(t[5]+r)/n.s,e.s*t[6],e.s*t[7],e.s*t[6]*-n.meanX+e.s*t[7]*-n.meanY+e.s/n.s];for(let t=0;t<9;t++)m[t]=m[t]/m[8];return m};export{e as solveHomography};