@srsergio/taptapp-ar 1.0.0

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 (207) hide show
  1. package/README.md +62 -0
  2. package/dist/compiler/aframe.d.ts +1 -0
  3. package/dist/compiler/aframe.js +275 -0
  4. package/dist/compiler/compiler-base.d.ts +12 -0
  5. package/dist/compiler/compiler-base.js +165 -0
  6. package/dist/compiler/compiler.d.ts +9 -0
  7. package/dist/compiler/compiler.js +24 -0
  8. package/dist/compiler/compiler.worker.d.ts +1 -0
  9. package/dist/compiler/compiler.worker.js +28 -0
  10. package/dist/compiler/controller.d.ts +101 -0
  11. package/dist/compiler/controller.js +400 -0
  12. package/dist/compiler/controller.worker.d.ts +1 -0
  13. package/dist/compiler/controller.worker.js +61 -0
  14. package/dist/compiler/detector/crop-detector.d.ts +65 -0
  15. package/dist/compiler/detector/crop-detector.js +59 -0
  16. package/dist/compiler/detector/detector.d.ts +98 -0
  17. package/dist/compiler/detector/detector.js +1049 -0
  18. package/dist/compiler/detector/freak.d.ts +1 -0
  19. package/dist/compiler/detector/freak.js +89 -0
  20. package/dist/compiler/detector/kernels/cpu/binomialFilter.d.ts +6 -0
  21. package/dist/compiler/detector/kernels/cpu/binomialFilter.js +51 -0
  22. package/dist/compiler/detector/kernels/cpu/buildExtremas.d.ts +6 -0
  23. package/dist/compiler/detector/kernels/cpu/buildExtremas.js +89 -0
  24. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.d.ts +7 -0
  25. package/dist/compiler/detector/kernels/cpu/computeExtremaAngles.js +79 -0
  26. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.d.ts +6 -0
  27. package/dist/compiler/detector/kernels/cpu/computeExtremaFreak.js +68 -0
  28. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.d.ts +6 -0
  29. package/dist/compiler/detector/kernels/cpu/computeFreakDescriptors.js +57 -0
  30. package/dist/compiler/detector/kernels/cpu/computeLocalization.d.ts +6 -0
  31. package/dist/compiler/detector/kernels/cpu/computeLocalization.js +54 -0
  32. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.d.ts +6 -0
  33. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.js +118 -0
  34. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.d.ts +6 -0
  35. package/dist/compiler/detector/kernels/cpu/downsampleBilinear.js +29 -0
  36. package/dist/compiler/detector/kernels/cpu/extremaReduction.d.ts +6 -0
  37. package/dist/compiler/detector/kernels/cpu/extremaReduction.js +50 -0
  38. package/dist/compiler/detector/kernels/cpu/fakeShader.d.ts +20 -0
  39. package/dist/compiler/detector/kernels/cpu/fakeShader.js +80 -0
  40. package/dist/compiler/detector/kernels/cpu/index.d.ts +1 -0
  41. package/dist/compiler/detector/kernels/cpu/index.js +25 -0
  42. package/dist/compiler/detector/kernels/cpu/prune.d.ts +1 -0
  43. package/dist/compiler/detector/kernels/cpu/prune.js +103 -0
  44. package/dist/compiler/detector/kernels/cpu/smoothHistograms.d.ts +6 -0
  45. package/dist/compiler/detector/kernels/cpu/smoothHistograms.js +47 -0
  46. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.d.ts +6 -0
  47. package/dist/compiler/detector/kernels/cpu/upsampleBilinear.js +43 -0
  48. package/dist/compiler/detector/kernels/index.d.ts +1 -0
  49. package/dist/compiler/detector/kernels/index.js +2 -0
  50. package/dist/compiler/detector/kernels/webgl/binomialFilter.d.ts +6 -0
  51. package/dist/compiler/detector/kernels/webgl/binomialFilter.js +67 -0
  52. package/dist/compiler/detector/kernels/webgl/buildExtremas.d.ts +6 -0
  53. package/dist/compiler/detector/kernels/webgl/buildExtremas.js +101 -0
  54. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.d.ts +6 -0
  55. package/dist/compiler/detector/kernels/webgl/computeExtremaAngles.js +78 -0
  56. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.d.ts +6 -0
  57. package/dist/compiler/detector/kernels/webgl/computeExtremaFreak.js +86 -0
  58. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.d.ts +6 -0
  59. package/dist/compiler/detector/kernels/webgl/computeFreakDescriptors.js +52 -0
  60. package/dist/compiler/detector/kernels/webgl/computeLocalization.d.ts +6 -0
  61. package/dist/compiler/detector/kernels/webgl/computeLocalization.js +58 -0
  62. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.d.ts +6 -0
  63. package/dist/compiler/detector/kernels/webgl/computeOrientationHistograms.js +116 -0
  64. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.d.ts +6 -0
  65. package/dist/compiler/detector/kernels/webgl/downsampleBilinear.js +46 -0
  66. package/dist/compiler/detector/kernels/webgl/extremaReduction.d.ts +6 -0
  67. package/dist/compiler/detector/kernels/webgl/extremaReduction.js +48 -0
  68. package/dist/compiler/detector/kernels/webgl/index.d.ts +1 -0
  69. package/dist/compiler/detector/kernels/webgl/index.js +25 -0
  70. package/dist/compiler/detector/kernels/webgl/smoothHistograms.d.ts +6 -0
  71. package/dist/compiler/detector/kernels/webgl/smoothHistograms.js +49 -0
  72. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.d.ts +6 -0
  73. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.js +56 -0
  74. package/dist/compiler/estimation/esimate-experiment.d.ts +5 -0
  75. package/dist/compiler/estimation/esimate-experiment.js +267 -0
  76. package/dist/compiler/estimation/estimate.d.ts +5 -0
  77. package/dist/compiler/estimation/estimate.js +51 -0
  78. package/dist/compiler/estimation/estimator.d.ts +13 -0
  79. package/dist/compiler/estimation/estimator.js +30 -0
  80. package/dist/compiler/estimation/refine-estimate-experiment.d.ts +6 -0
  81. package/dist/compiler/estimation/refine-estimate-experiment.js +429 -0
  82. package/dist/compiler/estimation/refine-estimate.d.ts +6 -0
  83. package/dist/compiler/estimation/refine-estimate.js +299 -0
  84. package/dist/compiler/estimation/utils.d.ts +10 -0
  85. package/dist/compiler/estimation/utils.js +80 -0
  86. package/dist/compiler/image-list.d.ts +13 -0
  87. package/dist/compiler/image-list.js +52 -0
  88. package/dist/compiler/index.d.ts +3 -0
  89. package/dist/compiler/index.js +10 -0
  90. package/dist/compiler/input-loader.d.ts +23 -0
  91. package/dist/compiler/input-loader.js +88 -0
  92. package/dist/compiler/matching/hamming-distance.d.ts +1 -0
  93. package/dist/compiler/matching/hamming-distance.js +20 -0
  94. package/dist/compiler/matching/hierarchical-clustering.d.ts +7 -0
  95. package/dist/compiler/matching/hierarchical-clustering.js +109 -0
  96. package/dist/compiler/matching/hough.d.ts +1 -0
  97. package/dist/compiler/matching/hough.js +169 -0
  98. package/dist/compiler/matching/matcher.d.ts +28 -0
  99. package/dist/compiler/matching/matcher.js +48 -0
  100. package/dist/compiler/matching/matching.d.ts +41 -0
  101. package/dist/compiler/matching/matching.js +197 -0
  102. package/dist/compiler/matching/ransacHomography.d.ts +1 -0
  103. package/dist/compiler/matching/ransacHomography.js +136 -0
  104. package/dist/compiler/offline-compiler.d.ts +10 -0
  105. package/dist/compiler/offline-compiler.js +450 -0
  106. package/dist/compiler/tensorflow-setup.d.ts +7 -0
  107. package/dist/compiler/tensorflow-setup.js +73 -0
  108. package/dist/compiler/three.d.ts +66 -0
  109. package/dist/compiler/three.js +310 -0
  110. package/dist/compiler/tracker/extract-utils.d.ts +1 -0
  111. package/dist/compiler/tracker/extract-utils.js +29 -0
  112. package/dist/compiler/tracker/extract.d.ts +4 -0
  113. package/dist/compiler/tracker/extract.js +349 -0
  114. package/dist/compiler/tracker/tracker.d.ts +38 -0
  115. package/dist/compiler/tracker/tracker.js +327 -0
  116. package/dist/compiler/utils/cumsum.d.ts +5 -0
  117. package/dist/compiler/utils/cumsum.js +39 -0
  118. package/dist/compiler/utils/geometry.d.ts +8 -0
  119. package/dist/compiler/utils/geometry.js +101 -0
  120. package/dist/compiler/utils/homography.d.ts +1 -0
  121. package/dist/compiler/utils/homography.js +138 -0
  122. package/dist/compiler/utils/images.d.ts +24 -0
  123. package/dist/compiler/utils/images.js +99 -0
  124. package/dist/compiler/utils/randomizer.d.ts +5 -0
  125. package/dist/compiler/utils/randomizer.js +25 -0
  126. package/dist/index.d.ts +6 -0
  127. package/dist/index.js +7 -0
  128. package/dist/react/AREditor.d.ts +5 -0
  129. package/dist/react/AREditor.js +159 -0
  130. package/dist/react/ProgressDialog.d.ts +13 -0
  131. package/dist/react/ProgressDialog.js +57 -0
  132. package/dist/react/types.d.ts +22 -0
  133. package/dist/react/types.js +14 -0
  134. package/package.json +53 -0
  135. package/src/astro/ARScene.astro +59 -0
  136. package/src/astro/ARVideoTrigger.astro +73 -0
  137. package/src/astro/overlays/ErrorOverlay.astro +40 -0
  138. package/src/astro/overlays/LoadingOverlay.astro +28 -0
  139. package/src/astro/overlays/ScanningOverlay.astro +119 -0
  140. package/src/astro/scripts/ARScripts.astro +118 -0
  141. package/src/astro/styles/ARStyles.astro +147 -0
  142. package/src/compiler/aframe.js +343 -0
  143. package/src/compiler/compiler-base.js +195 -0
  144. package/src/compiler/compiler.js +25 -0
  145. package/src/compiler/compiler.worker.js +30 -0
  146. package/src/compiler/controller.js +473 -0
  147. package/src/compiler/controller.worker.js +77 -0
  148. package/src/compiler/detector/crop-detector.js +68 -0
  149. package/src/compiler/detector/detector.js +1130 -0
  150. package/src/compiler/detector/freak.js +91 -0
  151. package/src/compiler/detector/kernels/cpu/binomialFilter.js +59 -0
  152. package/src/compiler/detector/kernels/cpu/buildExtremas.js +108 -0
  153. package/src/compiler/detector/kernels/cpu/computeExtremaAngles.js +91 -0
  154. package/src/compiler/detector/kernels/cpu/computeExtremaFreak.js +92 -0
  155. package/src/compiler/detector/kernels/cpu/computeFreakDescriptors.js +68 -0
  156. package/src/compiler/detector/kernels/cpu/computeLocalization.js +71 -0
  157. package/src/compiler/detector/kernels/cpu/computeOrientationHistograms.js +141 -0
  158. package/src/compiler/detector/kernels/cpu/downsampleBilinear.js +33 -0
  159. package/src/compiler/detector/kernels/cpu/extremaReduction.js +53 -0
  160. package/src/compiler/detector/kernels/cpu/fakeShader.js +88 -0
  161. package/src/compiler/detector/kernels/cpu/index.js +26 -0
  162. package/src/compiler/detector/kernels/cpu/prune.js +114 -0
  163. package/src/compiler/detector/kernels/cpu/smoothHistograms.js +57 -0
  164. package/src/compiler/detector/kernels/cpu/upsampleBilinear.js +51 -0
  165. package/src/compiler/detector/kernels/index.js +2 -0
  166. package/src/compiler/detector/kernels/webgl/binomialFilter.js +72 -0
  167. package/src/compiler/detector/kernels/webgl/buildExtremas.js +109 -0
  168. package/src/compiler/detector/kernels/webgl/computeExtremaAngles.js +82 -0
  169. package/src/compiler/detector/kernels/webgl/computeExtremaFreak.js +105 -0
  170. package/src/compiler/detector/kernels/webgl/computeFreakDescriptors.js +56 -0
  171. package/src/compiler/detector/kernels/webgl/computeLocalization.js +70 -0
  172. package/src/compiler/detector/kernels/webgl/computeOrientationHistograms.js +129 -0
  173. package/src/compiler/detector/kernels/webgl/downsampleBilinear.js +50 -0
  174. package/src/compiler/detector/kernels/webgl/extremaReduction.js +50 -0
  175. package/src/compiler/detector/kernels/webgl/index.js +26 -0
  176. package/src/compiler/detector/kernels/webgl/smoothHistograms.js +53 -0
  177. package/src/compiler/detector/kernels/webgl/upsampleBilinear.js +62 -0
  178. package/src/compiler/estimation/esimate-experiment.js +316 -0
  179. package/src/compiler/estimation/estimate.js +67 -0
  180. package/src/compiler/estimation/estimator.js +34 -0
  181. package/src/compiler/estimation/refine-estimate-experiment.js +512 -0
  182. package/src/compiler/estimation/refine-estimate.js +365 -0
  183. package/src/compiler/estimation/utils.js +97 -0
  184. package/src/compiler/image-list.js +62 -0
  185. package/src/compiler/index.js +13 -0
  186. package/src/compiler/input-loader.js +107 -0
  187. package/src/compiler/matching/hamming-distance.js +23 -0
  188. package/src/compiler/matching/hierarchical-clustering.js +131 -0
  189. package/src/compiler/matching/hough.js +206 -0
  190. package/src/compiler/matching/matcher.js +59 -0
  191. package/src/compiler/matching/matching.js +237 -0
  192. package/src/compiler/matching/ransacHomography.js +192 -0
  193. package/src/compiler/offline-compiler.js +553 -0
  194. package/src/compiler/tensorflow-setup.js +88 -0
  195. package/src/compiler/three.js +368 -0
  196. package/src/compiler/tracker/extract-utils.js +34 -0
  197. package/src/compiler/tracker/extract.js +419 -0
  198. package/src/compiler/tracker/tracker.js +397 -0
  199. package/src/compiler/utils/cumsum.js +40 -0
  200. package/src/compiler/utils/geometry.js +114 -0
  201. package/src/compiler/utils/homography.js +150 -0
  202. package/src/compiler/utils/images.js +111 -0
  203. package/src/compiler/utils/randomizer.js +29 -0
  204. package/src/index.ts +8 -0
  205. package/src/react/AREditor.tsx +394 -0
  206. package/src/react/ProgressDialog.tsx +185 -0
  207. package/src/react/types.ts +35 -0
@@ -0,0 +1,131 @@
1
+ import { compute as hammingCompute } from "./hamming-distance.js";
2
+ import { createRandomizer } from "../utils/randomizer.js";
3
+
4
+ const MIN_FEATURE_PER_NODE = 16;
5
+ const NUM_ASSIGNMENT_HYPOTHESES = 128;
6
+ const NUM_CENTERS = 8;
7
+
8
+ const _computeKMedoids = (options) => {
9
+ const { points, pointIndexes, randomizer } = options;
10
+
11
+ const randomPointIndexes = [];
12
+ for (let i = 0; i < pointIndexes.length; i++) {
13
+ randomPointIndexes.push(i);
14
+ }
15
+
16
+ let bestSumD = Number.MAX_SAFE_INTEGER;
17
+ let bestAssignmentIndex = -1;
18
+
19
+ const assignments = [];
20
+ for (let i = 0; i < NUM_ASSIGNMENT_HYPOTHESES; i++) {
21
+ randomizer.arrayShuffle({ arr: randomPointIndexes, sampleSize: NUM_CENTERS });
22
+
23
+ let sumD = 0;
24
+ const assignment = [];
25
+ for (let j = 0; j < pointIndexes.length; j++) {
26
+ let bestD = Number.MAX_SAFE_INTEGER;
27
+ for (let k = 0; k < NUM_CENTERS; k++) {
28
+ const centerIndex = pointIndexes[randomPointIndexes[k]];
29
+ const d = hammingCompute({
30
+ v1: points[pointIndexes[j]].descriptors,
31
+ v2: points[centerIndex].descriptors,
32
+ });
33
+ if (d < bestD) {
34
+ assignment[j] = randomPointIndexes[k];
35
+ bestD = d;
36
+ }
37
+ }
38
+ sumD += bestD;
39
+ }
40
+ assignments.push(assignment);
41
+
42
+ if (sumD < bestSumD) {
43
+ bestSumD = sumD;
44
+ bestAssignmentIndex = i;
45
+ }
46
+ }
47
+ return assignments[bestAssignmentIndex];
48
+ };
49
+
50
+ // kmedoids clustering of points, with hamming distance of FREAK descriptor
51
+ //
52
+ // node = {
53
+ // isLeaf: bool,
54
+ // children: [], list of children node
55
+ // pointIndexes: [], list of int, point indexes
56
+ // centerPointIndex: int
57
+ // }
58
+ const build = ({ points }) => {
59
+ const pointIndexes = [];
60
+ for (let i = 0; i < points.length; i++) {
61
+ pointIndexes.push(i);
62
+ }
63
+
64
+ const randomizer = createRandomizer();
65
+
66
+ const rootNode = _build({
67
+ points: points,
68
+ pointIndexes: pointIndexes,
69
+ centerPointIndex: null,
70
+ randomizer,
71
+ });
72
+ return { rootNode };
73
+ };
74
+
75
+ // recursive build hierarchy clusters
76
+ const _build = (options) => {
77
+ const { points, pointIndexes, centerPointIndex, randomizer } = options;
78
+
79
+ let isLeaf = false;
80
+
81
+ if (pointIndexes.length <= NUM_CENTERS || pointIndexes.length <= MIN_FEATURE_PER_NODE) {
82
+ isLeaf = true;
83
+ }
84
+
85
+ const clusters = {};
86
+ if (!isLeaf) {
87
+ // compute clusters
88
+ const assignment = _computeKMedoids({ points, pointIndexes, randomizer });
89
+
90
+ for (let i = 0; i < assignment.length; i++) {
91
+ if (clusters[pointIndexes[assignment[i]]] === undefined) {
92
+ clusters[pointIndexes[assignment[i]]] = [];
93
+ }
94
+ clusters[pointIndexes[assignment[i]]].push(pointIndexes[i]);
95
+ }
96
+ }
97
+ if (Object.keys(clusters).length === 1) {
98
+ isLeaf = true;
99
+ }
100
+
101
+ const node = {
102
+ centerPointIndex: centerPointIndex,
103
+ };
104
+
105
+ if (isLeaf) {
106
+ node.leaf = true;
107
+ node.pointIndexes = [];
108
+ for (let i = 0; i < pointIndexes.length; i++) {
109
+ node.pointIndexes.push(pointIndexes[i]);
110
+ }
111
+ return node;
112
+ }
113
+
114
+ // recursive build children
115
+ node.leaf = false;
116
+ node.children = [];
117
+
118
+ Object.keys(clusters).forEach((centerIndex) => {
119
+ node.children.push(
120
+ _build({
121
+ points: points,
122
+ pointIndexes: clusters[centerIndex],
123
+ centerPointIndex: centerIndex,
124
+ randomizer,
125
+ }),
126
+ );
127
+ });
128
+ return node;
129
+ };
130
+
131
+ export { build };
@@ -0,0 +1,206 @@
1
+ const kHoughBinDelta = 1;
2
+
3
+ // mathces [querypointIndex:x, keypointIndex: x]
4
+ const computeHoughMatches = (options) => {
5
+ const { keywidth, keyheight, querywidth, queryheight, matches } = options;
6
+
7
+ const maxX = querywidth * 1.2;
8
+ const minX = -maxX;
9
+ const maxY = queryheight * 1.2;
10
+ const minY = -maxY;
11
+ const numAngleBins = 12;
12
+ const numScaleBins = 10;
13
+ const minScale = -1;
14
+ const maxScale = 1;
15
+ const scaleK = 10.0;
16
+ const scaleOneOverLogK = 1.0 / Math.log(scaleK);
17
+ const maxDim = Math.max(keywidth, keyheight);
18
+ const keycenterX = Math.floor(keywidth / 2);
19
+ const keycenterY = Math.floor(keyheight / 2);
20
+
21
+ // compute numXBins and numYBins based on matches
22
+ const projectedDims = [];
23
+ for (let i = 0; i < matches.length; i++) {
24
+ const queryscale = matches[i].querypoint.scale;
25
+ const keyscale = matches[i].keypoint.scale;
26
+ if (keyscale == 0) console.log("ERROR divide zero");
27
+ const scale = queryscale / keyscale;
28
+ projectedDims.push(scale * maxDim);
29
+ }
30
+
31
+ // TODO optimize median
32
+ // weird. median should be [Math.floor(projectedDims.length/2) - 1] ?
33
+ projectedDims.sort((a1, a2) => {
34
+ return a1 - a2;
35
+ });
36
+ const medianProjectedDim =
37
+ projectedDims[
38
+ Math.floor(projectedDims.length / 2) - (projectedDims.length % 2 == 0 ? 1 : 0) - 1
39
+ ];
40
+
41
+ const binSize = 0.25 * medianProjectedDim;
42
+ const numXBins = Math.max(5, Math.ceil((maxX - minX) / binSize));
43
+ const numYBins = Math.max(5, Math.ceil((maxY - minY) / binSize));
44
+
45
+ const numXYBins = numXBins * numYBins;
46
+ const numXYAngleBins = numXYBins * numAngleBins;
47
+
48
+ // do voting
49
+ const querypointValids = [];
50
+ const querypointBinLocations = [];
51
+ const votes = {};
52
+ for (let i = 0; i < matches.length; i++) {
53
+ const querypoint = matches[i].querypoint;
54
+ const keypoint = matches[i].keypoint;
55
+
56
+ const { x, y, scale, angle } = _mapCorrespondence({
57
+ querypoint,
58
+ keypoint,
59
+ keycenterX,
60
+ keycenterY,
61
+ scaleOneOverLogK,
62
+ });
63
+
64
+ // Check that the vote is within range
65
+ if (
66
+ x < minX ||
67
+ x >= maxX ||
68
+ y < minY ||
69
+ y >= maxY ||
70
+ angle <= -Math.PI ||
71
+ angle > Math.PI ||
72
+ scale < minScale ||
73
+ scale >= maxScale
74
+ ) {
75
+ querypointValids[i] = false;
76
+ continue;
77
+ }
78
+
79
+ // map properties to bins
80
+ let fbinX = (numXBins * (x - minX)) / (maxX - minX);
81
+ let fbinY = (numYBins * (y - minY)) / (maxY - minY);
82
+ let fbinAngle = (numAngleBins * (angle + Math.PI)) / (2.0 * Math.PI);
83
+ let fbinScale = (numScaleBins * (scale - minScale)) / (maxScale - minScale);
84
+
85
+ querypointBinLocations[i] = {
86
+ binX: fbinX,
87
+ binY: fbinY,
88
+ binAngle: fbinAngle,
89
+ binScale: fbinScale,
90
+ };
91
+
92
+ let binX = Math.floor(fbinX - 0.5);
93
+ let binY = Math.floor(fbinY - 0.5);
94
+ let binScale = Math.floor(fbinScale - 0.5);
95
+ let binAngle = (Math.floor(fbinAngle - 0.5) + numAngleBins) % numAngleBins;
96
+
97
+ // check can vote all 16 bins
98
+ if (
99
+ binX < 0 ||
100
+ binX + 1 >= numXBins ||
101
+ binY < 0 ||
102
+ binY + 1 >= numYBins ||
103
+ binScale < 0 ||
104
+ binScale + 1 >= numScaleBins
105
+ ) {
106
+ querypointValids[i] = false;
107
+ continue;
108
+ }
109
+
110
+ for (let dx = 0; dx < 2; dx++) {
111
+ let binX2 = binX + dx;
112
+
113
+ for (let dy = 0; dy < 2; dy++) {
114
+ let binY2 = binY + dy;
115
+
116
+ for (let dangle = 0; dangle < 2; dangle++) {
117
+ let binAngle2 = (binAngle + dangle) % numAngleBins;
118
+
119
+ for (let dscale = 0; dscale < 2; dscale++) {
120
+ let binScale2 = binScale + dscale;
121
+
122
+ const binIndex =
123
+ binX2 + binY2 * numXBins + binAngle2 * numXYBins + binScale2 * numXYAngleBins;
124
+
125
+ if (votes[binIndex] === undefined) votes[binIndex] = 0;
126
+ votes[binIndex] += 1;
127
+ }
128
+ }
129
+ }
130
+ }
131
+ querypointValids[i] = true;
132
+ }
133
+
134
+ let maxVotes = 0;
135
+ let maxVoteIndex = -1;
136
+ Object.keys(votes).forEach((index) => {
137
+ if (votes[index] > maxVotes) {
138
+ maxVotes = votes[index];
139
+ maxVoteIndex = index;
140
+ }
141
+ });
142
+
143
+ if (maxVotes < 3) return [];
144
+
145
+ // get back bins from vote index
146
+ const binX = Math.floor(((maxVoteIndex % numXYAngleBins) % numXYBins) % numXBins);
147
+ const binY = Math.floor((((maxVoteIndex - binX) % numXYAngleBins) % numXYBins) / numXBins);
148
+ const binAngle = Math.floor(
149
+ ((maxVoteIndex - binX - binY * numXBins) % numXYAngleBins) / numXYBins,
150
+ );
151
+ const binScale = Math.floor(
152
+ (maxVoteIndex - binX - binY * numXBins - binAngle * numXYBins) / numXYAngleBins,
153
+ );
154
+
155
+ //console.log("hough voted: ", {binX, binY, binAngle, binScale, maxVoteIndex});
156
+
157
+ const houghMatches = [];
158
+ for (let i = 0; i < matches.length; i++) {
159
+ if (!querypointValids[i]) continue;
160
+
161
+ const queryBins = querypointBinLocations[i];
162
+ // compute bin difference
163
+ const distBinX = Math.abs(queryBins.binX - (binX + 0.5));
164
+ if (distBinX >= kHoughBinDelta) continue;
165
+
166
+ const distBinY = Math.abs(queryBins.binY - (binY + 0.5));
167
+ if (distBinY >= kHoughBinDelta) continue;
168
+
169
+ const distBinScale = Math.abs(queryBins.binScale - (binScale + 0.5));
170
+ if (distBinScale >= kHoughBinDelta) continue;
171
+
172
+ const temp = Math.abs(queryBins.binAngle - (binAngle + 0.5));
173
+ const distBinAngle = Math.min(temp, numAngleBins - temp);
174
+ if (distBinAngle >= kHoughBinDelta) continue;
175
+
176
+ houghMatches.push(matches[i]);
177
+ }
178
+ return houghMatches;
179
+ };
180
+
181
+ const _mapCorrespondence = ({ querypoint, keypoint, keycenterX, keycenterY, scaleOneOverLogK }) => {
182
+ // map angle to (-pi, pi]
183
+ let angle = querypoint.angle - keypoint.angle;
184
+ if (angle <= -Math.PI) angle += 2 * Math.PI;
185
+ else if (angle > Math.PI) angle -= 2 * Math.PI;
186
+
187
+ const scale = querypoint.scale / keypoint.scale;
188
+
189
+ // 2x2 similarity
190
+ const cos = scale * Math.cos(angle);
191
+ const sin = scale * Math.sin(angle);
192
+ const S = [cos, -sin, sin, cos];
193
+
194
+ const tp = [S[0] * keypoint.x + S[1] * keypoint.y, S[2] * keypoint.x + S[3] * keypoint.y];
195
+ const tx = querypoint.x - tp[0];
196
+ const ty = querypoint.y - tp[1];
197
+
198
+ return {
199
+ x: S[0] * keycenterX + S[1] * keycenterY + tx,
200
+ y: S[2] * keycenterX + S[3] * keycenterY + ty,
201
+ angle: angle,
202
+ scale: Math.log(scale) * scaleOneOverLogK,
203
+ };
204
+ };
205
+
206
+ export { computeHoughMatches };
@@ -0,0 +1,59 @@
1
+ import { match } from "./matching.js";
2
+
3
+ class Matcher {
4
+ constructor(queryWidth, queryHeight, debugMode = false) {
5
+ this.queryWidth = queryWidth;
6
+ this.queryHeight = queryHeight;
7
+ this.debugMode = debugMode;
8
+ }
9
+
10
+ matchDetection(keyframes, featurePoints) {
11
+ let debugExtra = { frames: [] };
12
+
13
+ let bestResult = null;
14
+ for (let i = 0; i < keyframes.length; i++) {
15
+ const {
16
+ H,
17
+ matches,
18
+ debugExtra: frameDebugExtra,
19
+ } = match({
20
+ keyframe: keyframes[i],
21
+ querypoints: featurePoints,
22
+ querywidth: this.queryWidth,
23
+ queryheight: this.queryHeight,
24
+ debugMode: this.debugMode,
25
+ });
26
+ debugExtra.frames.push(frameDebugExtra);
27
+
28
+ if (H) {
29
+ if (bestResult === null || bestResult.matches.length < matches.length) {
30
+ bestResult = { keyframeIndex: i, H, matches };
31
+ }
32
+ }
33
+ }
34
+
35
+ if (bestResult === null) {
36
+ return { keyframeIndex: -1, debugExtra };
37
+ }
38
+
39
+ const screenCoords = [];
40
+ const worldCoords = [];
41
+ const keyframe = keyframes[bestResult.keyframeIndex];
42
+ for (let i = 0; i < bestResult.matches.length; i++) {
43
+ const querypoint = bestResult.matches[i].querypoint;
44
+ const keypoint = bestResult.matches[i].keypoint;
45
+ screenCoords.push({
46
+ x: querypoint.x,
47
+ y: querypoint.y,
48
+ });
49
+ worldCoords.push({
50
+ x: (keypoint.x + 0.5) / keyframe.scale,
51
+ y: (keypoint.y + 0.5) / keyframe.scale,
52
+ z: 0,
53
+ });
54
+ }
55
+ return { screenCoords, worldCoords, keyframeIndex: bestResult.keyframeIndex, debugExtra };
56
+ }
57
+ }
58
+
59
+ export { Matcher };
@@ -0,0 +1,237 @@
1
+ import TinyQueue from "tinyqueue";
2
+ import { compute as hammingCompute } from "./hamming-distance.js";
3
+ import { computeHoughMatches } from "./hough.js";
4
+ import { computeHomography } from "./ransacHomography.js";
5
+ import { multiplyPointHomographyInhomogenous, matrixInverse33 } from "../utils/geometry.js";
6
+
7
+ const INLIER_THRESHOLD = 3;
8
+ //const MIN_NUM_INLIERS = 8; //default
9
+ const MIN_NUM_INLIERS = 6;
10
+ const CLUSTER_MAX_POP = 8;
11
+ const HAMMING_THRESHOLD = 0.7;
12
+
13
+ // match list of querpoints against pre-built list of keyframes
14
+ const match = ({ keyframe, querypoints, querywidth, queryheight, debugMode }) => {
15
+ let debugExtra = {};
16
+
17
+ const matches = [];
18
+ for (let j = 0; j < querypoints.length; j++) {
19
+ const querypoint = querypoints[j];
20
+ const keypoints = querypoint.maxima ? keyframe.maximaPoints : keyframe.minimaPoints;
21
+ if (keypoints.length === 0) continue;
22
+
23
+ const rootNode = querypoint.maxima
24
+ ? keyframe.maximaPointsCluster.rootNode
25
+ : keyframe.minimaPointsCluster.rootNode;
26
+
27
+ const keypointIndexes = [];
28
+ const queue = new TinyQueue([], (a1, a2) => {
29
+ return a1.d - a2.d;
30
+ });
31
+
32
+ // query all potential keypoints
33
+ _query({ node: rootNode, keypoints, querypoint, queue, keypointIndexes, numPop: 0 });
34
+
35
+ let bestIndex = -1;
36
+ let bestD1 = Number.MAX_SAFE_INTEGER;
37
+ let bestD2 = Number.MAX_SAFE_INTEGER;
38
+
39
+ for (let k = 0; k < keypointIndexes.length; k++) {
40
+ const keypoint = keypoints[keypointIndexes[k]];
41
+
42
+ const d = hammingCompute({ v1: keypoint.descriptors, v2: querypoint.descriptors });
43
+ if (d < bestD1) {
44
+ bestD2 = bestD1;
45
+ bestD1 = d;
46
+ bestIndex = keypointIndexes[k];
47
+ } else if (d < bestD2) {
48
+ bestD2 = d;
49
+ }
50
+ }
51
+ if (
52
+ bestIndex !== -1 &&
53
+ (bestD2 === Number.MAX_SAFE_INTEGER || (1.0 * bestD1) / bestD2 < HAMMING_THRESHOLD)
54
+ ) {
55
+ matches.push({ querypoint, keypoint: keypoints[bestIndex] });
56
+ }
57
+ }
58
+
59
+ if (debugMode) {
60
+ debugExtra.matches = matches;
61
+ }
62
+
63
+ if (matches.length < MIN_NUM_INLIERS) return { debugExtra };
64
+
65
+ const houghMatches = computeHoughMatches({
66
+ keywidth: keyframe.width,
67
+ keyheight: keyframe.height,
68
+ querywidth,
69
+ queryheight,
70
+ matches,
71
+ });
72
+
73
+ if (debugMode) {
74
+ debugExtra.houghMatches = houghMatches;
75
+ }
76
+
77
+ const H = computeHomography({
78
+ srcPoints: houghMatches.map((m) => [m.keypoint.x, m.keypoint.y]),
79
+ dstPoints: houghMatches.map((m) => [m.querypoint.x, m.querypoint.y]),
80
+ keyframe,
81
+ });
82
+
83
+ if (H === null) return { debugExtra };
84
+
85
+ const inlierMatches = _findInlierMatches({
86
+ H,
87
+ matches: houghMatches,
88
+ threshold: INLIER_THRESHOLD,
89
+ });
90
+
91
+ if (debugMode) {
92
+ debugExtra.inlierMatches = inlierMatches;
93
+ }
94
+
95
+ if (inlierMatches.length < MIN_NUM_INLIERS) return { debugExtra };
96
+
97
+ // do another loop of match using the homography
98
+ const HInv = matrixInverse33(H, 0.00001);
99
+ const dThreshold2 = 10 * 10;
100
+ const matches2 = [];
101
+ for (let j = 0; j < querypoints.length; j++) {
102
+ const querypoint = querypoints[j];
103
+ const mapquerypoint = multiplyPointHomographyInhomogenous([querypoint.x, querypoint.y], HInv);
104
+
105
+ let bestIndex = -1;
106
+ let bestD1 = Number.MAX_SAFE_INTEGER;
107
+ let bestD2 = Number.MAX_SAFE_INTEGER;
108
+
109
+ const keypoints = querypoint.maxima ? keyframe.maximaPoints : keyframe.minimaPoints;
110
+
111
+ for (let k = 0; k < keypoints.length; k++) {
112
+ const keypoint = keypoints[k];
113
+
114
+ // check distance threshold
115
+ const d2 =
116
+ (keypoint.x - mapquerypoint[0]) * (keypoint.x - mapquerypoint[0]) +
117
+ (keypoint.y - mapquerypoint[1]) * (keypoint.y - mapquerypoint[1]);
118
+ if (d2 > dThreshold2) continue;
119
+
120
+ const d = hammingCompute({ v1: keypoint.descriptors, v2: querypoint.descriptors });
121
+ if (d < bestD1) {
122
+ bestD2 = bestD1;
123
+ bestD1 = d;
124
+ bestIndex = k;
125
+ } else if (d < bestD2) {
126
+ bestD2 = d;
127
+ }
128
+ }
129
+
130
+ if (
131
+ bestIndex !== -1 &&
132
+ (bestD2 === Number.MAX_SAFE_INTEGER || (1.0 * bestD1) / bestD2 < HAMMING_THRESHOLD)
133
+ ) {
134
+ matches2.push({ querypoint, keypoint: keypoints[bestIndex] });
135
+ }
136
+ }
137
+
138
+ if (debugMode) {
139
+ debugExtra.matches2 = matches2;
140
+ }
141
+
142
+ const houghMatches2 = computeHoughMatches({
143
+ keywidth: keyframe.width,
144
+ keyheight: keyframe.height,
145
+ querywidth,
146
+ queryheight,
147
+ matches: matches2,
148
+ });
149
+
150
+ if (debugMode) {
151
+ debugExtra.houghMatches2 = houghMatches2;
152
+ }
153
+
154
+ const H2 = computeHomography({
155
+ srcPoints: houghMatches2.map((m) => [m.keypoint.x, m.keypoint.y]),
156
+ dstPoints: houghMatches2.map((m) => [m.querypoint.x, m.querypoint.y]),
157
+ keyframe,
158
+ });
159
+
160
+ if (H2 === null) return { debugExtra };
161
+
162
+ const inlierMatches2 = _findInlierMatches({
163
+ H: H2,
164
+ matches: houghMatches2,
165
+ threshold: INLIER_THRESHOLD,
166
+ });
167
+
168
+ if (debugMode) {
169
+ debugExtra.inlierMatches2 = inlierMatches2;
170
+ }
171
+
172
+ return { H: H2, matches: inlierMatches2, debugExtra };
173
+ };
174
+
175
+ const _query = ({ node, keypoints, querypoint, queue, keypointIndexes, numPop }) => {
176
+ if (node.leaf) {
177
+ for (let i = 0; i < node.pointIndexes.length; i++) {
178
+ keypointIndexes.push(node.pointIndexes[i]);
179
+ }
180
+ return;
181
+ }
182
+
183
+ const distances = [];
184
+ for (let i = 0; i < node.children.length; i++) {
185
+ const childNode = node.children[i];
186
+ const centerPointIndex = childNode.centerPointIndex;
187
+ const d = hammingCompute({
188
+ v1: keypoints[centerPointIndex].descriptors,
189
+ v2: querypoint.descriptors,
190
+ });
191
+ distances.push(d);
192
+ }
193
+
194
+ let minD = Number.MAX_SAFE_INTEGER;
195
+ for (let i = 0; i < node.children.length; i++) {
196
+ minD = Math.min(minD, distances[i]);
197
+ }
198
+
199
+ for (let i = 0; i < node.children.length; i++) {
200
+ if (distances[i] !== minD) {
201
+ queue.push({ node: node.children[i], d: distances[i] });
202
+ }
203
+ }
204
+ for (let i = 0; i < node.children.length; i++) {
205
+ if (distances[i] === minD) {
206
+ _query({ node: node.children[i], keypoints, querypoint, queue, keypointIndexes, numPop });
207
+ }
208
+ }
209
+
210
+ if (numPop < CLUSTER_MAX_POP && queue.length > 0) {
211
+ const { node, d } = queue.pop();
212
+ numPop += 1;
213
+ _query({ node, keypoints, querypoint, queue, keypointIndexes, numPop });
214
+ }
215
+ };
216
+
217
+ const _findInlierMatches = (options) => {
218
+ const { H, matches, threshold } = options;
219
+
220
+ const threshold2 = threshold * threshold;
221
+
222
+ const goodMatches = [];
223
+ for (let i = 0; i < matches.length; i++) {
224
+ const querypoint = matches[i].querypoint;
225
+ const keypoint = matches[i].keypoint;
226
+ const mp = multiplyPointHomographyInhomogenous([keypoint.x, keypoint.y], H);
227
+ const d2 =
228
+ (mp[0] - querypoint.x) * (mp[0] - querypoint.x) +
229
+ (mp[1] - querypoint.y) * (mp[1] - querypoint.y);
230
+ if (d2 <= threshold2) {
231
+ goodMatches.push(matches[i]);
232
+ }
233
+ }
234
+ return goodMatches;
235
+ };
236
+
237
+ export { match };