@openhps/openvslam 0.0.0-stage → 0.1.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 (144) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +115 -2
  3. package/cc/config.cc +49 -0
  4. package/cc/config.h +24 -0
  5. package/cc/frame_publisher.cc +62 -0
  6. package/cc/frame_publisher.h +27 -0
  7. package/cc/graph_node.cc +78 -0
  8. package/cc/graph_node.h +26 -0
  9. package/cc/keyframe.cc +81 -0
  10. package/cc/keyframe.h +27 -0
  11. package/cc/landmark.cc +85 -0
  12. package/cc/landmark.h +26 -0
  13. package/cc/map_publisher.cc +119 -0
  14. package/cc/map_publisher.h +33 -0
  15. package/cc/openvslam.cc +26 -0
  16. package/cc/pangolin_viewer/viewer.h +26 -0
  17. package/cc/socket_publisher/publisher.cc +84 -0
  18. package/cc/socket_publisher/publisher.h +26 -0
  19. package/cc/system.cc +190 -0
  20. package/cc/system.h +47 -0
  21. package/dist/cjs/data/VSLAMFrame.js +44 -0
  22. package/dist/cjs/data/VSLAMFrame.js.map +1 -0
  23. package/dist/cjs/data/VSLAMGraphNode.js +7 -0
  24. package/dist/cjs/data/VSLAMGraphNode.js.map +1 -0
  25. package/dist/cjs/data/VSLAMKeyFrame.js +56 -0
  26. package/dist/cjs/data/VSLAMKeyFrame.js.map +1 -0
  27. package/dist/cjs/data/VSLAMLandmark.js +53 -0
  28. package/dist/cjs/data/VSLAMLandmark.js.map +1 -0
  29. package/dist/cjs/data/VSLAMMap.js +36 -0
  30. package/dist/cjs/data/VSLAMMap.js.map +1 -0
  31. package/dist/cjs/data/index.js +8 -0
  32. package/dist/cjs/data/index.js.map +1 -0
  33. package/dist/cjs/index.js +9 -0
  34. package/dist/cjs/index.js.map +1 -0
  35. package/dist/cjs/nodes/VSLAMConfiguration.js +43 -0
  36. package/dist/cjs/nodes/VSLAMConfiguration.js.map +1 -0
  37. package/dist/cjs/nodes/index.js +7 -0
  38. package/dist/cjs/nodes/index.js.map +1 -0
  39. package/dist/cjs/nodes/processing/VSLAMProcessingNode.js +124 -0
  40. package/dist/cjs/nodes/processing/VSLAMProcessingNode.js.map +1 -0
  41. package/dist/cjs/nodes/processing/index.js +5 -0
  42. package/dist/cjs/nodes/processing/index.js.map +1 -0
  43. package/dist/cjs/nodes/sink/VSLAMSocketPublisher.js +68 -0
  44. package/dist/cjs/nodes/sink/VSLAMSocketPublisher.js.map +1 -0
  45. package/dist/cjs/nodes/sink/index.js +5 -0
  46. package/dist/cjs/nodes/sink/index.js.map +1 -0
  47. package/dist/cjs/package.json +3 -0
  48. package/dist/cjs/service/VSLAMService.js +121 -0
  49. package/dist/cjs/service/VSLAMService.js.map +1 -0
  50. package/dist/cjs/service/index.js +5 -0
  51. package/dist/cjs/service/index.js.map +1 -0
  52. package/dist/cjs/tsconfig.bundle.cjs.tsbuildinfo +1 -0
  53. package/dist/esm/data/VSLAMFrame.js +41 -0
  54. package/dist/esm/data/VSLAMFrame.js.map +1 -0
  55. package/dist/esm/data/VSLAMGraphNode.js +3 -0
  56. package/dist/esm/data/VSLAMGraphNode.js.map +1 -0
  57. package/dist/esm/data/VSLAMKeyFrame.js +53 -0
  58. package/dist/esm/data/VSLAMKeyFrame.js.map +1 -0
  59. package/dist/esm/data/VSLAMLandmark.js +50 -0
  60. package/dist/esm/data/VSLAMLandmark.js.map +1 -0
  61. package/dist/esm/data/VSLAMMap.js +33 -0
  62. package/dist/esm/data/VSLAMMap.js.map +1 -0
  63. package/dist/esm/data/index.js +5 -0
  64. package/dist/esm/data/index.js.map +1 -0
  65. package/dist/esm/index.js +5 -0
  66. package/dist/esm/index.js.map +1 -0
  67. package/dist/esm/nodes/VSLAMConfiguration.js +39 -0
  68. package/dist/esm/nodes/VSLAMConfiguration.js.map +1 -0
  69. package/dist/esm/nodes/index.js +4 -0
  70. package/dist/esm/nodes/index.js.map +1 -0
  71. package/dist/esm/nodes/processing/VSLAMProcessingNode.js +120 -0
  72. package/dist/esm/nodes/processing/VSLAMProcessingNode.js.map +1 -0
  73. package/dist/esm/nodes/processing/index.js +2 -0
  74. package/dist/esm/nodes/processing/index.js.map +1 -0
  75. package/dist/esm/nodes/sink/VSLAMSocketPublisher.js +64 -0
  76. package/dist/esm/nodes/sink/VSLAMSocketPublisher.js.map +1 -0
  77. package/dist/esm/nodes/sink/index.js +2 -0
  78. package/dist/esm/nodes/sink/index.js.map +1 -0
  79. package/dist/esm/package.json +3 -0
  80. package/dist/esm/service/VSLAMService.js +117 -0
  81. package/dist/esm/service/VSLAMService.js.map +1 -0
  82. package/dist/esm/service/index.js +2 -0
  83. package/dist/esm/service/index.js.map +1 -0
  84. package/dist/esm/tsconfig.bundle.esm.tsbuildinfo +1 -0
  85. package/dist/esm/tsconfig.bundle.types.tsbuildinfo +1 -0
  86. package/dist/types/data/VSLAMFrame.d.ts +16 -0
  87. package/dist/types/data/VSLAMFrame.d.ts.map +1 -0
  88. package/dist/types/data/VSLAMGraphNode.d.ts +3 -0
  89. package/dist/types/data/VSLAMGraphNode.d.ts.map +1 -0
  90. package/dist/types/data/VSLAMKeyFrame.d.ts +28 -0
  91. package/dist/types/data/VSLAMKeyFrame.d.ts.map +1 -0
  92. package/dist/types/data/VSLAMLandmark.d.ts +20 -0
  93. package/dist/types/data/VSLAMLandmark.d.ts.map +1 -0
  94. package/dist/types/data/VSLAMMap.d.ts +13 -0
  95. package/dist/types/data/VSLAMMap.d.ts.map +1 -0
  96. package/dist/types/data/index.d.ts +5 -0
  97. package/dist/types/data/index.d.ts.map +1 -0
  98. package/dist/types/index.d.ts +5 -0
  99. package/dist/types/index.d.ts.map +1 -0
  100. package/dist/types/nodes/VSLAMConfiguration.d.ts +36 -0
  101. package/dist/types/nodes/VSLAMConfiguration.d.ts.map +1 -0
  102. package/dist/types/nodes/index.d.ts +4 -0
  103. package/dist/types/nodes/index.d.ts.map +1 -0
  104. package/dist/types/nodes/processing/VSLAMProcessingNode.d.ts +36 -0
  105. package/dist/types/nodes/processing/VSLAMProcessingNode.d.ts.map +1 -0
  106. package/dist/types/nodes/processing/index.d.ts +2 -0
  107. package/dist/types/nodes/processing/index.d.ts.map +1 -0
  108. package/dist/types/nodes/sink/VSLAMSocketPublisher.d.ts +17 -0
  109. package/dist/types/nodes/sink/VSLAMSocketPublisher.d.ts.map +1 -0
  110. package/dist/types/nodes/sink/index.d.ts +2 -0
  111. package/dist/types/nodes/sink/index.d.ts.map +1 -0
  112. package/dist/types/service/VSLAMService.d.ts +57 -0
  113. package/dist/types/service/VSLAMService.d.ts.map +1 -0
  114. package/dist/types/service/index.d.ts +2 -0
  115. package/dist/types/service/index.d.ts.map +1 -0
  116. package/install/install.js +85 -0
  117. package/install/parseEnv.js +7 -0
  118. package/package.json +125 -5
  119. package/src/data/VSLAMFrame.ts +48 -0
  120. package/src/data/VSLAMGraphNode.ts +1 -0
  121. package/src/data/VSLAMKeyFrame.ts +50 -0
  122. package/src/data/VSLAMLandmark.ts +42 -0
  123. package/src/data/VSLAMMap.ts +20 -0
  124. package/src/data/index.ts +4 -0
  125. package/src/index.ts +4 -0
  126. package/src/nodes/VSLAMConfiguration.ts +72 -0
  127. package/src/nodes/index.ts +3 -0
  128. package/src/nodes/processing/VSLAMProcessingNode.ts +152 -0
  129. package/src/nodes/processing/index.ts +1 -0
  130. package/src/nodes/sink/VSLAMSocketPublisher.ts +75 -0
  131. package/src/nodes/sink/index.ts +1 -0
  132. package/src/openvslam/index.d.ts +9 -0
  133. package/src/openvslam/index.js +8 -0
  134. package/src/openvslam/typings/Config.d.ts +3 -0
  135. package/src/openvslam/typings/FramePublisher.d.ts +12 -0
  136. package/src/openvslam/typings/GraphNode.d.ts +5 -0
  137. package/src/openvslam/typings/KeyFrame.d.ts +24 -0
  138. package/src/openvslam/typings/Landmark.d.ts +19 -0
  139. package/src/openvslam/typings/MapPublisher.d.ts +21 -0
  140. package/src/openvslam/typings/PangolinViewer.d.ts +9 -0
  141. package/src/openvslam/typings/SocketPublisher.d.ts +9 -0
  142. package/src/openvslam/typings/System.d.ts +45 -0
  143. package/src/service/VSLAMService.ts +130 -0
  144. package/src/service/index.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,126 @@
1
1
  {
2
- "name": "@openhps/openvslam",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@openhps/openvslam",
3
+ "version": "0.1.0",
4
+ "description": "Open Hybrid Positioning System - OpenVSLAM bindings",
5
+ "author": "Maxim Van de Wynckel",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/OpenHPS/openhps-openvslam.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/OpenHPS/openhps-openvslam/issues"
13
+ },
14
+ "homepage": "https://openhps.org",
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "type": "commonjs",
19
+ "sideEffects": false,
20
+ "main": "./dist/cjs/index.js",
21
+ "types": "./dist/types/index.d.ts",
22
+ "module": "./dist/esm/index.js",
23
+ "es2015": "./dist/esm/index.js",
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/types/index.d.ts",
27
+ "import": "./dist/esm/index.js",
28
+ "require": "./dist/cjs/index.js"
29
+ },
30
+ "./package.json": "./package.json"
31
+ },
32
+ "files": [
33
+ "dist/**/*",
34
+ "src/**/*",
35
+ "build/**/*",
36
+ "cc/**/*",
37
+ "install/**/*",
38
+ "LICENSE"
39
+ ],
40
+ "scripts": {
41
+ "install": "node ./install/install.js",
42
+ "test": "mocha --config test/.mocharc.json",
43
+ "test:docker": "docker-compose run openvslam-cpu /opt/app/docker/docker-entrypoint.sh",
44
+ "test:docker:quick": "docker-compose run openvslam-cpu /opt/app/docker/docker-entrypoint-quick.sh",
45
+ "cover": "c8 mocha --config test/.mocharc.json",
46
+ "cover:ci": "c8 mocha --config test/.mocharc.ci.json && c8 report --reporter=cobertura",
47
+ "lint": "eslint . && node scripts/check-peers.mjs",
48
+ "clean": "shx rm -rf ./dist && shx rm -rf ./docs/out",
49
+ "build": "npm run clean && npm-run-all --parallel build:ts:*",
50
+ "build:components": "componentsjs-generator",
51
+ "build:quick": "npm-run-all --parallel build:ts:*",
52
+ "build:typedoc": "typedoc --options docs/typedoc.json",
53
+ "build:ts:cjs": "tsc --build ./tsconfig/tsconfig.bundle.cjs.json",
54
+ "build:ts:esm": "tsc --build ./tsconfig/tsconfig.bundle.esm.json && node ./scripts/finalize-esm.mjs",
55
+ "build:ts:types": "tsc --build ./tsconfig/tsconfig.bundle.types.json",
56
+ "deploy:typedoc": "gh-pages -d ./docs/out",
57
+ "bump:development": "commit-and-tag-version --prerelease alpha -m 'chore(alpha): %s' --skip.changelog",
58
+ "bump:beta": "commit-and-tag-version --prerelease beta -m 'chore(beta): %s' --skip.changelog",
59
+ "bump:release": "commit-and-tag-version -m 'chore(release): %s' --skip.changelog",
60
+ "prepare": "husky"
61
+ },
62
+ "keywords": [
63
+ "openhps",
64
+ "openvslam"
65
+ ],
66
+ "dependencies": {
67
+ "@openhps/opencv": ">=0.3.6 <0.4",
68
+ "nan": "^2.30.0",
69
+ "native-node-utils": "^0.2.7",
70
+ "tslib": "^2.9.1",
71
+ "yaml": "^2.9.1"
72
+ },
73
+ "peerDependencies": {
74
+ "@openhps/core": ">=1.0.16 <2",
75
+ "@openhps/opencv": ">=0.3.6 <0.4",
76
+ "reflect-metadata": ">=0.2.2 <1"
77
+ },
78
+ "devDependencies": {
79
+ "@commitlint/cli": "^21.2.4",
80
+ "@commitlint/config-conventional": "^21.2.4",
81
+ "@eslint/js": "^9.39.5",
82
+ "@openhps/core": "^1.0.16",
83
+ "@openhps/opencv": "^0.3.6",
84
+ "@openhps/video": "^1.0.3",
85
+ "@types/chai": "^5.2.2",
86
+ "@types/mocha": "^10.0.10",
87
+ "@types/node": "^26.6.6",
88
+ "c8": "^12.0.0",
89
+ "chai": "^6.3.0",
90
+ "commit-and-tag-version": "^13.3.0",
91
+ "eslint": "^9.39.5",
92
+ "eslint-config-prettier": "^10.1.8",
93
+ "eslint-plugin-import": "^2.32.0",
94
+ "eslint-plugin-jsdoc": "^65.4.5",
95
+ "eslint-plugin-prettier": "^5.5.7",
96
+ "globals": "^17.14.0",
97
+ "husky": "^9.1.7",
98
+ "jenkins-mocha": "^11.0.0",
99
+ "lint-staged": "^17.6.0",
100
+ "mocha": "^11.8.0",
101
+ "mocha-junit-reporter": "^2.2.1",
102
+ "mocha-multi-reporters": "^1.5.2",
103
+ "npm-run-all": "^4.1.5",
104
+ "prettier": "^3.10.0",
105
+ "reflect-metadata": ">=0.1.13",
106
+ "segfault-handler": "^1.3.0",
107
+ "shx": "^0.4.0",
108
+ "ts-node": "^10.9.2",
109
+ "typedoc": "^0.28.20",
110
+ "typescript": "^5.9.3",
111
+ "typescript-eslint": "^8.72.2"
112
+ },
113
+ "engines": {
114
+ "node": ">=22.0.0"
115
+ },
116
+ "packageManager": "npm@10.9.2",
117
+ "lsd:module": true,
118
+ "gypfile": true,
119
+ "husky": {
120
+ "hooks": {
121
+ "pre-commit": "npm run lint",
122
+ "pre-push": "npm run test",
123
+ "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
124
+ }
125
+ }
126
+ }
@@ -0,0 +1,48 @@
1
+ import {
2
+ SerializableObject,
3
+ Matrix4,
4
+ LengthUnit,
5
+ Absolute3DPosition,
6
+ Orientation,
7
+ SerializableMember,
8
+ } from '@openhps/core';
9
+ import { VideoFrame } from '@openhps/opencv';
10
+
11
+ @SerializableObject()
12
+ export class VSLAMFrame extends VideoFrame {
13
+ @SerializableMember()
14
+ systemUID: string;
15
+
16
+ /**
17
+ * Get the camera pose at the time of the frame
18
+ * @returns {Matrix4} Camera pose as a matrix with translation and rotation
19
+ */
20
+ get cameraPose(): Matrix4 {
21
+ if (this.source && this.source.getPosition()) {
22
+ const vector = this.source.getPosition().toVector3(LengthUnit.METER);
23
+ const matrix = new Matrix4().identity();
24
+ matrix.makeRotationFromQuaternion(this.source.getPosition().orientation);
25
+ matrix.setPosition(vector.x, vector.z, vector.y);
26
+ return matrix;
27
+ } else {
28
+ return new Matrix4().identity();
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Set the camera at the time of the frame
34
+ * @param {Matrix4} pose Camera pose
35
+ */
36
+ set cameraPose(pose: Matrix4) {
37
+ if (this.source) {
38
+ const position = new Absolute3DPosition(
39
+ pose.elements[12],
40
+ pose.elements[14],
41
+ pose.elements[13],
42
+ LengthUnit.METER,
43
+ );
44
+ position.orientation = Orientation.fromRotationMatrix(pose);
45
+ this.source.setPosition(position);
46
+ }
47
+ }
48
+ }
@@ -0,0 +1 @@
1
+ export class VSLAMGraphNode {}
@@ -0,0 +1,50 @@
1
+ import { Matrix4, Quaternion, SerializableObject, TimeService, TimeUnit } from '@openhps/core';
2
+ import { KeyFrame } from '../openvslam';
3
+ import { VSLAMFrame } from './VSLAMFrame';
4
+ import { VSLAMLandmark } from './VSLAMLandmark';
5
+
6
+ @SerializableObject()
7
+ export class VSLAMKeyFrame extends VSLAMFrame {
8
+ willBeErased = false;
9
+
10
+ /**
11
+ * Create a VSLAM keyframe from native object
12
+ * @param {KeyFrame} keyframe Native object
13
+ * @returns {VSLAMKeyFrame} VSLAM keyframe instance
14
+ */
15
+ static fromNative(keyframe: KeyFrame): VSLAMKeyFrame {
16
+ const mapKeyframe = new VSLAMKeyFrame();
17
+ const json = keyframe.toJSON();
18
+ mapKeyframe.uid = json.src_frm_id.toString();
19
+ mapKeyframe.createdTimestamp = TimeUnit.MILLISECOND.convert(json['ts'], TimeService.getUnit());
20
+ const pose = new Matrix4().identity();
21
+ pose.makeRotationFromQuaternion(Quaternion.fromRotationMatrix(new Matrix4().fromArray(json.rot_cw)));
22
+ pose.setPosition(json.trans_cw[0], json.trans_cw[1], json.trans_cw[2]);
23
+ mapKeyframe.cameraPose = pose;
24
+ return mapKeyframe;
25
+ }
26
+
27
+ /**
28
+ * Get frame landmarks
29
+ * @returns {VSLAMLandmark[]} Array of landmarks found in this frame
30
+ */
31
+ get landmarks(): VSLAMLandmark[] {
32
+ return this.getObjects(VSLAMLandmark);
33
+ }
34
+
35
+ /**
36
+ * Set frame landmarks
37
+ * @param {VSLAMLandmark[]} values Array of landmarks
38
+ */
39
+ set landmarks(values: VSLAMLandmark[]) {
40
+ values.forEach(this.addObject.bind(this));
41
+ }
42
+
43
+ /**
44
+ * Add a landmark to the frame
45
+ * @param {VSLAMLandmark} landmark Landmark to add
46
+ */
47
+ addLandmark(landmark: VSLAMLandmark): void {
48
+ this.addObject(landmark);
49
+ }
50
+ }
@@ -0,0 +1,42 @@
1
+ import { Absolute3DPosition, DataObject, LengthUnit, SerializableMember, SerializableObject } from '@openhps/core';
2
+ import { Landmark } from '../openvslam';
3
+
4
+ @SerializableObject()
5
+ export class VSLAMLandmark extends DataObject {
6
+ @SerializableMember()
7
+ keyframeUID: string;
8
+ @SerializableMember()
9
+ referenceKeyframeUID: string;
10
+ @SerializableMember()
11
+ observed: number;
12
+ @SerializableMember()
13
+ observable: number;
14
+
15
+ /**
16
+ * Create a VSLAM landmark from native object
17
+ * @param {Landmark} landmark Native object
18
+ * @returns {VSLAMLandmark} VSLAM landmark instance
19
+ */
20
+ static fromNative(landmark: Landmark): VSLAMLandmark {
21
+ const mapLandmark = new VSLAMLandmark(landmark.id.toString());
22
+ const json = landmark.toJSON();
23
+ mapLandmark.keyframeUID = json['1st_keyfrm'].toString();
24
+ mapLandmark.referenceKeyframeUID = json['ref_keyfrm'].toString();
25
+ mapLandmark.observable = json['n_vis'];
26
+ mapLandmark.observed = json['n_fnd'];
27
+ if (json.pos_w) {
28
+ mapLandmark.setPosition(
29
+ new Absolute3DPosition(json.pos_w[0], json.pos_w[1], json.pos_w[2], LengthUnit.METER),
30
+ );
31
+ }
32
+ return mapLandmark;
33
+ }
34
+
35
+ /**
36
+ * Convert the VSLAM landmark to native JSON serialization
37
+ * @returns {any} Native JSON serialization
38
+ */
39
+ toNativeJSON(): any {
40
+ return undefined;
41
+ }
42
+ }
@@ -0,0 +1,20 @@
1
+ import { DataObject, SerializableObject, SerializableSetMember } from '@openhps/core';
2
+ import { VSLAMKeyFrame } from './VSLAMKeyFrame';
3
+ import { VSLAMLandmark } from './VSLAMLandmark';
4
+
5
+ @SerializableObject()
6
+ export class VSLAMMap extends DataObject {
7
+ @SerializableSetMember(VSLAMLandmark)
8
+ landmarks: Set<VSLAMLandmark> = new Set<VSLAMLandmark>();
9
+ @SerializableSetMember(VSLAMKeyFrame)
10
+ keyFrames: Set<VSLAMKeyFrame> = new Set<VSLAMKeyFrame>();
11
+
12
+ /**
13
+ * Create a VSLAM map from native object
14
+ * @returns {VSLAMMap} VSLAM map instance
15
+ */
16
+ static fromNative(): VSLAMMap {
17
+ const map = new VSLAMMap();
18
+ return map;
19
+ }
20
+ }
@@ -0,0 +1,4 @@
1
+ export * from './VSLAMFrame';
2
+ export * from './VSLAMKeyFrame';
3
+ export * from './VSLAMLandmark';
4
+ export * from './VSLAMMap';
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './data';
2
+ export * from './nodes';
3
+ export * from './service';
4
+ export * as OpenVSLAM from './openvslam';
@@ -0,0 +1,72 @@
1
+ import { CameraObject } from '@openhps/video';
2
+ import * as YAML from 'yaml';
3
+ import * as fs from 'fs';
4
+
5
+ export class VSLAMConfiguration {
6
+ /**
7
+ * Camera object
8
+ */
9
+ camera: CameraObject;
10
+
11
+ /**
12
+ * Convert the configuration to YAML string
13
+ * @returns {string} YAML output string
14
+ */
15
+ toYAML(): string {
16
+ return YAML.stringify(this);
17
+ }
18
+
19
+ static fromYAML(yamlString: string): VSLAMConfiguration {
20
+ return VSLAMConfiguration.fromParsedYAML(YAML.parse(yamlString));
21
+ }
22
+
23
+ static fromYAMLFile(filePath: string): VSLAMConfiguration {
24
+ const file = fs.readFileSync(filePath, 'utf8');
25
+ return VSLAMConfiguration.fromParsedYAML(YAML.parse(file));
26
+ }
27
+
28
+ private static fromParsedYAML(yaml: any): VSLAMConfiguration {
29
+ const instance = new VSLAMConfiguration();
30
+ if (yaml === null || typeof yaml !== 'object') {
31
+ return instance;
32
+ }
33
+ // Copy the properties without letting a malicious document alter the
34
+ // prototype chain (a `__proto__` key) of the instance
35
+ for (const key of Object.keys(yaml)) {
36
+ if (key === '__proto__') {
37
+ continue;
38
+ }
39
+ Object.defineProperty(instance, key, {
40
+ value: yaml[key],
41
+ writable: true,
42
+ enumerable: true,
43
+ configurable: true,
44
+ });
45
+ }
46
+ return instance;
47
+ }
48
+ }
49
+
50
+ export type CameraOptions = RadialDivisionCameraOptions | PerspectiveCameraOptions | FisheyeCameraOptions;
51
+
52
+ export interface RadialDivisionCameraOptions {
53
+ model: 'radial_division';
54
+ distortion: number;
55
+ }
56
+
57
+ export interface PerspectiveCameraOptions {
58
+ model: 'perspective';
59
+ k1: number;
60
+ k2: number;
61
+ p1: number;
62
+ p2: number;
63
+ k3: number;
64
+ }
65
+
66
+ export interface FisheyeCameraOptions {
67
+ model: 'fisheye';
68
+ k1: number;
69
+ k2: number;
70
+ k3: number;
71
+ k4: number;
72
+ }
@@ -0,0 +1,3 @@
1
+ export * from './processing';
2
+ export * from './sink';
3
+ export * from './VSLAMConfiguration';
@@ -0,0 +1,152 @@
1
+ import { Matrix4, ProcessingNode, ProcessingNodeOptions, TimeService, TimeUnit } from '@openhps/core';
2
+ import { DepthImageFrame, StereoVideoFrame, VideoFrame } from '@openhps/opencv';
3
+ import * as fs from 'fs';
4
+ import { VSLAMFrame } from '../../data';
5
+ import { VSLAMService } from '../../service/VSLAMService';
6
+
7
+ /**
8
+ * VSLAM processing node is a node that takes in a video frame and uses
9
+ * OpenVSLAM to process the video frame.
10
+ */
11
+ export class VSLAMProcessingNode<
12
+ In extends VideoFrame | StereoVideoFrame | DepthImageFrame,
13
+ Out extends VSLAMFrame,
14
+ > extends ProcessingNode<In, Out> {
15
+ protected options: VSLAMProcessingNodeOptions;
16
+ protected service: VSLAMService;
17
+ protected systems: string[] = [];
18
+
19
+ constructor(options?: VSLAMProcessingNodeOptions) {
20
+ super(options);
21
+ this.options.mapping = this.options.mapping === undefined ? true : this.options.mapping;
22
+
23
+ this.once('build', this._onBuild.bind(this));
24
+ this.once('destroy', this._onDestroy.bind(this));
25
+ }
26
+
27
+ private _onBuild(): Promise<void> {
28
+ return new Promise((resolve, reject) => {
29
+ if (!this.model) {
30
+ return reject(new Error(`Unable to start VSLAM processing without VSLAMService!`));
31
+ }
32
+ this.service = this.model.findService(VSLAMService);
33
+ this.service
34
+ .createSystem(this.options.config)
35
+ .then((uid) => {
36
+ this.systems.push(uid);
37
+ return this.service.findSystemByUID(uid);
38
+ })
39
+ .then((system) => {
40
+ const mapDatabaseExists =
41
+ this.options.mapDatabaseFile !== undefined && fs.existsSync(this.options.mapDatabaseFile);
42
+
43
+ if (mapDatabaseExists) {
44
+ this.logger('debug', {
45
+ msg: `Loading OpenVSLAM map database ...`,
46
+ file: this.options.mapDatabaseFile,
47
+ });
48
+ system.loadMap(this.options.mapDatabaseFile);
49
+ }
50
+
51
+ system.startup(!mapDatabaseExists);
52
+
53
+ // Global mapper
54
+ if (this.options.mapping) {
55
+ this.logger('debug', {
56
+ msg: `Enable mapping for OpenVSLAM`,
57
+ });
58
+ system.enableMapping();
59
+ } else {
60
+ this.logger('debug', {
61
+ msg: `Disabling mapping for OpenVSLAM`,
62
+ });
63
+ system.disableMapping();
64
+ }
65
+ resolve();
66
+ })
67
+ .catch(reject);
68
+ });
69
+ }
70
+
71
+ private _onDestroy(): Promise<void> {
72
+ return new Promise((resolve, reject) => {
73
+ const promises = this.systems.map((systemUID) => this.service.findSystemByUID(systemUID));
74
+ Promise.all(promises)
75
+ .then((systemInstances) => {
76
+ systemInstances.forEach((system) => {
77
+ if (this.options.mapDatabaseFile && this.options.mapping && this.options.persistMapping) {
78
+ // Save mapping
79
+ this.logger('debug', {
80
+ msg: `Saving OpenVSLAM map database ...`,
81
+ file: this.options.mapDatabaseFile,
82
+ });
83
+ system.saveMap(this.options.mapDatabaseFile);
84
+ }
85
+ });
86
+ // Delete and shutdown systems
87
+ return Promise.all(this.systems.map((systemUID) => this.service.deleteSystem(systemUID)));
88
+ })
89
+ .then(() => {
90
+ resolve();
91
+ })
92
+ .catch(reject);
93
+ });
94
+ }
95
+
96
+ process(data: In): Promise<Out> {
97
+ return new Promise((resolve, reject) => {
98
+ let uid = undefined;
99
+ this.service
100
+ .findSystemUIDByObject(data.source)
101
+ .then((systemUID) => {
102
+ uid = systemUID;
103
+ return this.service.findSystemByUID(uid);
104
+ })
105
+ .then((system) => {
106
+ if (!system) {
107
+ return resolve(undefined);
108
+ }
109
+
110
+ const out = new VSLAMFrame(data);
111
+ const timestamp = TimeService.getUnit().convert(data.phenomenonTimestamp, TimeUnit.SECOND);
112
+ // Process the frame differently depending on the type of video frame
113
+ if (data instanceof VideoFrame) {
114
+ out.image = data.image;
115
+ system.feedMonocularFrame(data.image, timestamp);
116
+ } else if (data instanceof StereoVideoFrame) {
117
+ out.image = data.left.image;
118
+ system.feedStereoFrame(data.left.image, data.right.image, timestamp);
119
+ } else if (data instanceof DepthImageFrame) {
120
+ out.image = data.image;
121
+ system.feedRGBDFrame(data.image, data.depth, timestamp);
122
+ }
123
+
124
+ // Fetch the current camera pose
125
+ const pose = new Matrix4().fromArray(system.getMapPublisher().getCurrentCamPose());
126
+ out.cameraPose = pose;
127
+ out.systemUID = uid;
128
+ resolve(out as Out);
129
+ })
130
+ .catch(reject);
131
+ });
132
+ }
133
+ }
134
+
135
+ export interface VSLAMProcessingNodeOptions extends ProcessingNodeOptions {
136
+ /**
137
+ * Enable mapping and localization
138
+ */
139
+ mapping?: boolean;
140
+ /**
141
+ * Configuration file
142
+ */
143
+ config: string;
144
+ /**
145
+ * Map database file (MSG) for loading and storage
146
+ */
147
+ mapDatabaseFile?: string;
148
+ /**
149
+ * Persist the mapping to the map database file
150
+ */
151
+ persistMapping?: boolean;
152
+ }
@@ -0,0 +1 @@
1
+ export * from './VSLAMProcessingNode';
@@ -0,0 +1,75 @@
1
+ import { PushOptions, SinkNode, SinkNodeOptions } from '@openhps/core';
2
+ import { VSLAMFrame } from '../../data';
3
+ import { SocketPublisher } from '../../openvslam';
4
+ import { VSLAMService } from '../../service/VSLAMService';
5
+
6
+ export class VSLAMSocketPublisher<In extends VSLAMFrame> extends SinkNode<In> {
7
+ protected options: VSLAMSocketViewerOptions;
8
+ protected service: VSLAMService;
9
+ protected publishers: Map<string, SocketPublisher> = new Map();
10
+
11
+ constructor(options?: VSLAMSocketViewerOptions) {
12
+ super(options);
13
+ this.options = options ?? {};
14
+ this.options.url = this.options.url ?? 'http://localhost:3000';
15
+
16
+ this.once('build', this._onBuild.bind(this));
17
+ this.once('destroy', this._onDestroy.bind(this));
18
+ }
19
+
20
+ private _onBuild(): Promise<void> {
21
+ return new Promise((resolve, reject) => {
22
+ if (!this.model) {
23
+ return reject(new Error(`Unable to start VSLAM processing without VSLAMService!`));
24
+ }
25
+ this.service = this.model.findService(VSLAMService);
26
+ if (!this.service) {
27
+ return reject(new Error(`Unable to start VSLAM socket publisher without VSLAMService!`));
28
+ }
29
+ resolve();
30
+ });
31
+ }
32
+
33
+ private _onDestroy(): Promise<void> {
34
+ return new Promise((resolve) => {
35
+ this.publishers.forEach((publisher) => {
36
+ publisher.terminate();
37
+ });
38
+ resolve();
39
+ });
40
+ }
41
+
42
+ onPush(frame: In, options?: PushOptions): Promise<void> {
43
+ return new Promise((resolve, reject) => {
44
+ if (!frame.systemUID) {
45
+ return resolve();
46
+ }
47
+ const existingPublisher = this.publishers.get(frame.systemUID);
48
+ if (existingPublisher) {
49
+ return resolve();
50
+ }
51
+ this.service
52
+ .findSystemByUID(frame.systemUID)
53
+ .then((system) => {
54
+ if (!system) {
55
+ return reject(new Error(`VSLAM system ${frame.systemUID} not found!`));
56
+ }
57
+ // A publisher may have been created by a concurrent push
58
+ if (this.publishers.has(frame.systemUID)) {
59
+ return;
60
+ }
61
+ const publisher = new SocketPublisher(system, this.options.url);
62
+ publisher.run();
63
+ this.publishers.set(frame.systemUID, publisher);
64
+ })
65
+ .then(() => {
66
+ resolve();
67
+ })
68
+ .catch(reject);
69
+ });
70
+ }
71
+ }
72
+
73
+ export interface VSLAMSocketViewerOptions extends SinkNodeOptions {
74
+ url?: string;
75
+ }
@@ -0,0 +1 @@
1
+ export * from './VSLAMSocketPublisher';
@@ -0,0 +1,9 @@
1
+ export * from './typings/Config';
2
+ export * from './typings/FramePublisher';
3
+ export * from './typings/MapPublisher';
4
+ export * from './typings/System';
5
+ export * from './typings/Landmark';
6
+ export * from './typings/KeyFrame';
7
+ export * from './typings/GraphNode';
8
+ export * from './typings/SocketPublisher';
9
+ export * from './typings/PangolinViewer';
@@ -0,0 +1,8 @@
1
+ /* eslint-disable */
2
+ const path = require('path');
3
+
4
+ const requirePath = path.join(
5
+ __dirname,
6
+ process.env.BINDINGS_DEBUG ? '../../build/Debug/openvslam' : '../../build/Release/openvslam',
7
+ );
8
+ module.exports = require(requirePath);
@@ -0,0 +1,3 @@
1
+ export class Config {
2
+ constructor(configFilePath: string);
3
+ }
@@ -0,0 +1,12 @@
1
+ import { Mat } from '@u4/opencv4nodejs';
2
+
3
+ export class FramePublisher {
4
+ private constructor();
5
+
6
+ /**
7
+ * Draw a video frame with landmarks highlighted
8
+ *
9
+ * @returns {Mat} OpenCV Mat image object
10
+ */
11
+ drawFrame(): Mat;
12
+ }
@@ -0,0 +1,5 @@
1
+ export class GraphNode {
2
+ protected constructor();
3
+
4
+ getCovisibilitiesOverWeight(weight: number): Keyframe[];
5
+ }