@srsergio/taptapp-ar 1.0.2 → 1.0.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 (83) hide show
  1. package/README.md +47 -45
  2. package/dist/compiler/aframe.js +0 -3
  3. package/dist/compiler/compiler-base.d.ts +3 -7
  4. package/dist/compiler/compiler-base.js +28 -14
  5. package/dist/compiler/compiler.js +1 -1
  6. package/dist/compiler/compiler.worker.js +1 -1
  7. package/dist/compiler/controller.js +4 -5
  8. package/dist/compiler/controller.worker.js +0 -2
  9. package/dist/compiler/detector/crop-detector.js +0 -2
  10. package/dist/compiler/detector/detector-lite.d.ts +73 -0
  11. package/dist/compiler/detector/detector-lite.js +430 -0
  12. package/dist/compiler/detector/detector.js +236 -243
  13. package/dist/compiler/detector/kernels/cpu/binomialFilter.js +0 -1
  14. package/dist/compiler/detector/kernels/cpu/computeLocalization.js +0 -4
  15. package/dist/compiler/detector/kernels/cpu/computeOrientationHistograms.js +0 -18
  16. package/dist/compiler/detector/kernels/cpu/fakeShader.js +1 -1
  17. package/dist/compiler/detector/kernels/cpu/prune.d.ts +7 -1
  18. package/dist/compiler/detector/kernels/cpu/prune.js +1 -42
  19. package/dist/compiler/detector/kernels/webgl/upsampleBilinear.js +2 -2
  20. package/dist/compiler/estimation/refine-estimate.js +0 -1
  21. package/dist/compiler/estimation/utils.d.ts +1 -1
  22. package/dist/compiler/estimation/utils.js +1 -14
  23. package/dist/compiler/image-list.js +4 -4
  24. package/dist/compiler/input-loader.js +2 -2
  25. package/dist/compiler/matching/hamming-distance.js +13 -13
  26. package/dist/compiler/matching/hierarchical-clustering.js +1 -1
  27. package/dist/compiler/matching/matching.d.ts +20 -4
  28. package/dist/compiler/matching/matching.js +67 -41
  29. package/dist/compiler/matching/ransacHomography.js +1 -2
  30. package/dist/compiler/node-worker.d.ts +1 -0
  31. package/dist/compiler/node-worker.js +84 -0
  32. package/dist/compiler/offline-compiler.d.ts +171 -6
  33. package/dist/compiler/offline-compiler.js +303 -421
  34. package/dist/compiler/tensorflow-setup.js +27 -1
  35. package/dist/compiler/three.js +3 -5
  36. package/dist/compiler/tracker/extract.d.ts +1 -0
  37. package/dist/compiler/tracker/extract.js +200 -244
  38. package/dist/compiler/tracker/tracker.d.ts +1 -1
  39. package/dist/compiler/tracker/tracker.js +13 -18
  40. package/dist/compiler/utils/cumsum.d.ts +4 -2
  41. package/dist/compiler/utils/cumsum.js +17 -19
  42. package/dist/compiler/utils/gpu-compute.d.ts +57 -0
  43. package/dist/compiler/utils/gpu-compute.js +262 -0
  44. package/dist/compiler/utils/images.d.ts +4 -4
  45. package/dist/compiler/utils/images.js +67 -53
  46. package/dist/compiler/utils/worker-pool.d.ts +14 -0
  47. package/dist/compiler/utils/worker-pool.js +84 -0
  48. package/package.json +11 -13
  49. package/src/compiler/aframe.js +2 -4
  50. package/src/compiler/compiler-base.js +29 -14
  51. package/src/compiler/compiler.js +1 -1
  52. package/src/compiler/compiler.worker.js +1 -1
  53. package/src/compiler/controller.js +4 -5
  54. package/src/compiler/controller.worker.js +0 -2
  55. package/src/compiler/detector/crop-detector.js +0 -2
  56. package/src/compiler/detector/detector-lite.js +494 -0
  57. package/src/compiler/detector/detector.js +1052 -1063
  58. package/src/compiler/detector/kernels/cpu/binomialFilter.js +0 -1
  59. package/src/compiler/detector/kernels/cpu/computeLocalization.js +0 -4
  60. package/src/compiler/detector/kernels/cpu/computeOrientationHistograms.js +0 -17
  61. package/src/compiler/detector/kernels/cpu/fakeShader.js +1 -1
  62. package/src/compiler/detector/kernels/cpu/prune.js +1 -37
  63. package/src/compiler/detector/kernels/webgl/upsampleBilinear.js +2 -2
  64. package/src/compiler/estimation/refine-estimate.js +0 -1
  65. package/src/compiler/estimation/utils.js +9 -24
  66. package/src/compiler/image-list.js +4 -4
  67. package/src/compiler/input-loader.js +2 -2
  68. package/src/compiler/matching/hamming-distance.js +11 -15
  69. package/src/compiler/matching/hierarchical-clustering.js +1 -1
  70. package/src/compiler/matching/matching.js +72 -42
  71. package/src/compiler/matching/ransacHomography.js +0 -2
  72. package/src/compiler/node-worker.js +93 -0
  73. package/src/compiler/offline-compiler.js +339 -504
  74. package/src/compiler/tensorflow-setup.js +29 -1
  75. package/src/compiler/three.js +3 -5
  76. package/src/compiler/tracker/extract.js +211 -267
  77. package/src/compiler/tracker/tracker.js +13 -22
  78. package/src/compiler/utils/cumsum.js +17 -19
  79. package/src/compiler/utils/gpu-compute.js +303 -0
  80. package/src/compiler/utils/images.js +84 -53
  81. package/src/compiler/utils/worker-pool.js +89 -0
  82. package/src/compiler/estimation/esimate-experiment.js +0 -316
  83. package/src/compiler/estimation/refine-estimate-experiment.js +0 -512
@@ -0,0 +1,84 @@
1
+ import { Worker } from 'node:worker_threads';
2
+ import os from 'node:os';
3
+ export class WorkerPool {
4
+ constructor(workerPath, poolSize = os.cpus().length) {
5
+ this.workerPath = workerPath;
6
+ this.poolSize = poolSize;
7
+ this.workers = [];
8
+ this.queue = [];
9
+ this.activeWorkers = 0;
10
+ }
11
+ runTask(taskData) {
12
+ return new Promise((resolve, reject) => {
13
+ const task = { taskData, resolve, reject };
14
+ if (this.workers.length > 0) {
15
+ this._executeTask(this.workers.pop(), task);
16
+ }
17
+ else if (this.activeWorkers < this.poolSize) {
18
+ this._executeTask(this._createWorker(), task);
19
+ }
20
+ else {
21
+ this.queue.push(task);
22
+ }
23
+ });
24
+ }
25
+ _createWorker() {
26
+ this.activeWorkers++;
27
+ const worker = new Worker(this.workerPath);
28
+ return worker;
29
+ }
30
+ _executeTask(worker, task) {
31
+ const onMessage = (msg) => {
32
+ if (msg.type === 'progress' && task.taskData.onProgress) {
33
+ task.taskData.onProgress(msg.percent);
34
+ }
35
+ else if (msg.type === 'compileDone') {
36
+ cleanup();
37
+ this._finishTask(worker, task.resolve, msg.trackingData);
38
+ }
39
+ else if (msg.type === 'matchDone') {
40
+ cleanup();
41
+ this._finishTask(worker, task.resolve, msg.matchingData);
42
+ }
43
+ else if (msg.type === 'error') {
44
+ cleanup();
45
+ this._finishTask(worker, task.reject, new Error(msg.error));
46
+ }
47
+ };
48
+ const onError = (err) => {
49
+ cleanup();
50
+ this._finishTask(worker, task.reject, err);
51
+ };
52
+ const cleanup = () => {
53
+ worker.removeListener('message', onMessage);
54
+ worker.removeListener('error', onError);
55
+ };
56
+ worker.on('message', onMessage);
57
+ worker.on('error', onError);
58
+ // Create a copy of taskData without functions for the worker
59
+ const serializableData = {};
60
+ for (const [key, value] of Object.entries(task.taskData)) {
61
+ if (typeof value !== 'function') {
62
+ serializableData[key] = value;
63
+ }
64
+ }
65
+ worker.postMessage({
66
+ type: 'compile',
67
+ ...serializableData
68
+ });
69
+ }
70
+ _finishTask(worker, callback, result) {
71
+ if (this.queue.length > 0) {
72
+ this._executeTask(worker, this.queue.shift());
73
+ }
74
+ else {
75
+ this.workers.push(worker);
76
+ }
77
+ callback(result);
78
+ }
79
+ async destroy() {
80
+ await Promise.all(this.workers.map(w => w.terminate()));
81
+ this.workers = [];
82
+ this.activeWorkers = 0;
83
+ }
84
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@srsergio/taptapp-ar",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "AR Visualizer and Compiler for Astro and React",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,31 +29,29 @@
29
29
  ],
30
30
  "scripts": {
31
31
  "build": "tsc",
32
- "prepublishOnly": "npm run build"
32
+ "prepublishOnly": "npm run build",
33
+ "test": "vitest"
33
34
  },
34
35
  "peerDependencies": {
36
+ "aframe": ">=1.5.0",
35
37
  "astro": ">=4.0.0",
36
38
  "react": ">=18.0.0",
37
39
  "react-dom": ">=18.0.0",
38
- "three": ">=0.160.0",
39
- "aframe": ">=1.5.0"
40
+ "three": ">=0.160.0"
40
41
  },
41
42
  "dependencies": {
42
- "@tensorflow/tfjs": "^4.22.0",
43
- "@tensorflow/tfjs-backend-cpu": "^4.22.0",
44
- "@tensorflow/tfjs-backend-webgl": "^4.22.0",
43
+ "gpu.js": "^2.16.0",
45
44
  "ml-matrix": "^6.10.4",
46
- "svd-js": "^1.1.1",
47
- "tinyqueue": "^2.0.3",
48
- "lucide-react": "^0.477.0",
49
- "nanoid": "^5.0.7"
45
+ "tinyqueue": "^2.0.3"
50
46
  },
51
47
  "devDependencies": {
52
- "typescript": "^5.4.5",
53
48
  "@types/react": "^18.3.3",
54
49
  "@types/react-dom": "^18.3.0",
55
50
  "@types/three": "^0.170.0",
56
- "astro": "5.16.4"
51
+ "astro": "5.16.4",
52
+ "jimp": "^1.6.0",
53
+ "typescript": "^5.4.5",
54
+ "vitest": "^4.0.16"
57
55
  },
58
56
  "publishConfig": {
59
57
  "access": "public"
@@ -1,6 +1,6 @@
1
1
  import { Controller, UI } from "./index.js";
2
2
 
3
- const needsDOMRefresh = document.readyState === "complete" || document.readyState == "interactive";
3
+
4
4
  AFRAME.registerSystem("mindar-image-system", {
5
5
  container: null,
6
6
  video: null,
@@ -10,7 +10,7 @@ AFRAME.registerSystem("mindar-image-system", {
10
10
  this.anchorEntities = [];
11
11
  },
12
12
 
13
- tick: function () {},
13
+ tick: function () { },
14
14
 
15
15
  setup: function ({
16
16
  imageTargetSrc,
@@ -121,7 +121,6 @@ AFRAME.registerSystem("mindar-image-system", {
121
121
 
122
122
  _startAR: async function () {
123
123
  const video = this.video;
124
- const container = this.container;
125
124
 
126
125
  this.controller = new Controller({
127
126
  inputWidth: video.videoWidth,
@@ -196,7 +195,6 @@ AFRAME.registerSystem("mindar-image-system", {
196
195
  const fov = (2 * Math.atan((1 / proj[5] / vh) * container.clientHeight) * 180) / Math.PI; // vertical fov
197
196
  const near = proj[14] / (proj[10] - 1.0);
198
197
  const far = proj[14] / (proj[10] + 1.0);
199
- const ratio = proj[5] / proj[0]; // (r-l) / (t-b)
200
198
  //console.log("loaded proj: ", proj, ". fov: ", fov, ". near: ", near, ". far: ", far, ". ratio: ", ratio);
201
199
  const newAspect = container.clientWidth / container.clientHeight;
202
200
  const cameraEle = container.getElementsByTagName("a-camera")[0];
@@ -65,21 +65,35 @@ class CompilerBase {
65
65
  }
66
66
 
67
67
  // compute matching data: 50% progress
68
- const percentPerImage = 50.0 / targetImages.length;
69
- let percent = 0.0;
68
+ let matchingDataList;
69
+ if (this.compileMatch) {
70
+ matchingDataList = await this.compileMatch({
71
+ progressCallback,
72
+ targetImages,
73
+ basePercent: 0,
74
+ });
75
+ } else {
76
+ const percentPerImage = 50.0 / targetImages.length;
77
+ let percent = 0.0;
78
+ const matchingPromises = targetImages.map(async (targetImage, i) => {
79
+ const imageList = buildImageList(targetImage);
80
+ const percentPerAction = percentPerImage / imageList.length;
81
+
82
+ const matchingData = await _extractMatchingFeatures(imageList, () => {
83
+ percent += percentPerAction;
84
+ progressCallback(percent);
85
+ });
86
+ return matchingData;
87
+ });
88
+ matchingDataList = await Promise.all(matchingPromises);
89
+ }
90
+
70
91
  this.data = [];
71
92
  for (let i = 0; i < targetImages.length; i++) {
72
- const targetImage = targetImages[i];
73
- const imageList = buildImageList(targetImage);
74
- const percentPerAction = percentPerImage / imageList.length;
75
- const matchingData = await _extractMatchingFeatures(imageList, () => {
76
- percent += percentPerAction;
77
- progressCallback(percent);
78
- });
79
93
  this.data.push({
80
- targetImage: targetImage,
81
- imageList: imageList,
82
- matchingData: matchingData,
94
+ targetImage: targetImages[i],
95
+ imageList: buildImageList(targetImages[i]),
96
+ matchingData: matchingDataList[i],
83
97
  });
84
98
  }
85
99
 
@@ -145,14 +159,15 @@ class CompilerBase {
145
159
  return this.data;
146
160
  }
147
161
 
148
- createProcessCanvas(img) {
162
+ createProcessCanvas() {
149
163
  // sub-class implements
150
164
  console.warn("missing createProcessCanvas implementation");
151
165
  }
152
166
 
153
- compileTrack({ progressCallback, targetImages, basePercent }) {
167
+ compileTrack() {
154
168
  // sub-class implements
155
169
  console.warn("missing compileTrack implementation");
170
+ return Promise.resolve([]);
156
171
  }
157
172
  }
158
173
 
@@ -10,7 +10,7 @@ export class Compiler extends CompilerBase {
10
10
  }
11
11
 
12
12
  compileTrack({ progressCallback, targetImages, basePercent }) {
13
- return new Promise((resolve, reject) => {
13
+ return new Promise((resolve) => {
14
14
  const worker = new CompilerWorker();
15
15
  worker.onmessage = (e) => {
16
16
  if (e.data.type === "progress") {
@@ -15,7 +15,7 @@ onmessage = (msg) => {
15
15
  const percentPerAction = percentPerImage / imageList.length;
16
16
 
17
17
  //console.log("compiling tracking...", i);
18
- const trackingData = extractTrackingFeatures(imageList, (index) => {
18
+ const trackingData = extractTrackingFeatures(imageList, () => {
19
19
  //console.log("done tracking", i, index);
20
20
  percent += percentPerAction;
21
21
  postMessage({ type: "progress", percent });
@@ -81,7 +81,7 @@ class Controller {
81
81
  }
82
82
 
83
83
  addImageTargets(fileURL) {
84
- return new Promise(async (resolve, reject) => {
84
+ return new Promise(async (resolve) => {
85
85
  const content = await fetch(fileURL);
86
86
  const buffer = await content.arrayBuffer();
87
87
  const result = this.addImageTargetsFromBuffer(buffer);
@@ -95,7 +95,6 @@ class Controller {
95
95
 
96
96
  const trackingDataList = [];
97
97
  const matchingDataList = [];
98
- const imageListList = [];
99
98
  const dimensions = [];
100
99
  for (let i = 0; i < dataList.length; i++) {
101
100
  matchingDataList.push(dataList[i].matchingData);
@@ -329,7 +328,7 @@ class Controller {
329
328
 
330
329
  async detect(input) {
331
330
  const inputT = this.inputLoader.loadInput(input);
332
- const { featurePoints, debugExtra } = await this.cropDetector.detect(inputT);
331
+ const { featurePoints, debugExtra } = this.cropDetector.detect(inputT);
333
332
  inputT.dispose();
334
333
  return { featurePoints, debugExtra };
335
334
  }
@@ -355,7 +354,7 @@ class Controller {
355
354
  }
356
355
 
357
356
  _workerMatch(featurePoints, targetIndexes) {
358
- return new Promise(async (resolve, reject) => {
357
+ return new Promise((resolve) => {
359
358
  this.workerMatchDone = (data) => {
360
359
  resolve({
361
360
  targetIndex: data.targetIndex,
@@ -368,7 +367,7 @@ class Controller {
368
367
  }
369
368
 
370
369
  _workerTrackUpdate(modelViewTransform, trackingFeatures) {
371
- return new Promise(async (resolve, reject) => {
370
+ return new Promise((resolve) => {
372
371
  this.workerTrackDone = (data) => {
373
372
  resolve(data.modelViewTransform);
374
373
  };
@@ -1,7 +1,6 @@
1
1
  import { Matcher } from "./matching/matcher.js";
2
2
  import { Estimator } from "./estimation/estimator.js";
3
3
 
4
- let projectionTransform = null;
5
4
  let matchingDataList = null;
6
5
  let debugMode = false;
7
6
  let matcher = null;
@@ -12,7 +11,6 @@ onmessage = (msg) => {
12
11
 
13
12
  switch (data.type) {
14
13
  case "setup":
15
- projectionTransform = data.projectionTransform;
16
14
  matchingDataList = data.matchingDataList;
17
15
  debugMode = data.debugMode;
18
16
  matcher = new Matcher(data.inputWidth, data.inputHeight, debugMode);
@@ -1,6 +1,4 @@
1
- import * as tf from "@tensorflow/tfjs";
2
1
  import { Detector } from "./detector.js";
3
- import { buildModelViewProjectionTransform, computeScreenCoordiate } from "../estimation/utils.js";
4
2
 
5
3
  class CropDetector {
6
4
  constructor(width, height, debugMode = false) {