@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.
- package/dist/compiler/node-worker.js +1 -197
- package/dist/compiler/offline-compiler.js +1 -207
- package/dist/core/constants.js +1 -38
- package/dist/core/detector/crop-detector.js +1 -88
- package/dist/core/detector/detector-lite.js +1 -455
- package/dist/core/detector/freak.js +1 -89
- package/dist/core/estimation/estimate.js +1 -16
- package/dist/core/estimation/estimator.js +1 -30
- package/dist/core/estimation/morph-refinement.js +1 -116
- package/dist/core/estimation/non-rigid-refine.js +1 -70
- package/dist/core/estimation/pnp-solver.js +1 -109
- package/dist/core/estimation/refine-estimate.js +1 -311
- package/dist/core/estimation/utils.js +1 -67
- package/dist/core/features/auto-rotation-feature.js +1 -30
- package/dist/core/features/crop-detection-feature.js +1 -26
- package/dist/core/features/feature-base.js +1 -1
- package/dist/core/features/feature-manager.js +1 -55
- package/dist/core/features/one-euro-filter-feature.js +1 -44
- package/dist/core/features/temporal-filter-feature.js +1 -57
- package/dist/core/image-list.js +1 -54
- package/dist/core/input-loader.js +1 -87
- package/dist/core/matching/hamming-distance.js +1 -66
- package/dist/core/matching/hdc.js +1 -102
- package/dist/core/matching/hierarchical-clustering.js +1 -130
- package/dist/core/matching/hough.js +1 -170
- package/dist/core/matching/matcher.js +1 -66
- package/dist/core/matching/matching.js +1 -401
- package/dist/core/matching/ransacHomography.js +1 -132
- package/dist/core/perception/bio-inspired-engine.js +1 -232
- package/dist/core/perception/foveal-attention.js +1 -280
- package/dist/core/perception/index.js +1 -17
- package/dist/core/perception/predictive-coding.js +1 -278
- package/dist/core/perception/saccadic-controller.js +1 -269
- package/dist/core/perception/saliency-map.js +1 -254
- package/dist/core/perception/scale-orchestrator.js +1 -68
- package/dist/core/protocol.js +1 -254
- package/dist/core/tracker/extract-utils.js +1 -29
- package/dist/core/tracker/extract.js +1 -306
- package/dist/core/tracker/tracker.js +1 -352
- package/dist/core/utils/cumsum.js +1 -37
- package/dist/core/utils/delaunay.js +1 -125
- package/dist/core/utils/geometry.js +1 -101
- package/dist/core/utils/gpu-compute.js +1 -231
- package/dist/core/utils/homography.js +1 -138
- package/dist/core/utils/images.js +1 -108
- package/dist/core/utils/lsh-binarizer.js +1 -37
- package/dist/core/utils/lsh-direct.js +1 -76
- package/dist/core/utils/projection.js +1 -51
- package/dist/core/utils/randomizer.js +1 -25
- package/dist/core/utils/worker-pool.js +1 -89
- package/dist/index.js +1 -7
- package/dist/libs/one-euro-filter.js +1 -70
- package/dist/react/TaptappAR.js +1 -151
- package/dist/react/types.js +1 -16
- package/dist/react/use-ar.js +1 -118
- package/dist/runtime/aframe.js +1 -272
- package/dist/runtime/bio-inspired-controller.js +1 -358
- package/dist/runtime/controller.js +1 -592
- package/dist/runtime/controller.worker.js +1 -93
- package/dist/runtime/index.js +1 -5
- package/dist/runtime/three.js +1 -304
- package/dist/runtime/track.js +1 -381
- package/package.json +10 -4
|
@@ -1,37 +1 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
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
|
|
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};
|