Skip to content

Commit 87fb483

Browse files
oseiskarkaatrasa
andcommitted
Copy visualizer code from SDK examples
Co-authored-by: Valtteri Kaatrasalo <[email protected]>
1 parent 758b049 commit 87fb483

File tree

11 files changed

+1429
-0
lines changed

11 files changed

+1429
-0
lines changed

python/cli/visualization/__init__.py

Whitespace-only changes.
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
"""
2+
An example code to deserialize data serialized by cpp/mapping_visu C++ example
3+
"""
4+
5+
# Needed when SLAM is disabled (no final map flag to indicate end of data)
6+
EXIT_AFTER_NO_DATA_FOR_N_SECONDS = 5
7+
8+
import struct
9+
import json
10+
import numpy as np
11+
import spectacularAI
12+
import time
13+
14+
def input_stream_reader(in_stream):
15+
MAGIC_BYTES = 2727221974
16+
shouldQuit = False
17+
exitCounter = 0
18+
19+
while not shouldQuit:
20+
messageHeader = in_stream.read(16)
21+
22+
if len(messageHeader) == 0:
23+
time.sleep(0.01)
24+
exitCounter += 0.01
25+
shouldQuit = exitCounter >= EXIT_AFTER_NO_DATA_FOR_N_SECONDS
26+
continue
27+
exitCounter = 0
28+
29+
magicBytes, messageId, jsonSize, binarySize = struct.unpack('@4I', messageHeader)
30+
if magicBytes != MAGIC_BYTES:
31+
raise Exception(f"Wrong magic bytes! Expected {MAGIC_BYTES} and received {magicBytes}")
32+
json_output = json.loads(in_stream.read(jsonSize).decode('ascii'))
33+
34+
if 'cameraPoses' in json_output: # Vio output
35+
assert(binarySize == 0)
36+
else: # Mapper output, deserialize binary data
37+
shouldQuit = json_output["finalMap"]
38+
for keyFrameId in json_output["updatedKeyFrames"]:
39+
keyFrame = json_output["map"]["keyFrames"].get(str(keyFrameId))
40+
if not keyFrame: continue # Deleted key frame
41+
if "pointCloud" in keyFrame:
42+
pointCloud = keyFrame["pointCloud"]
43+
points = pointCloud["size"]
44+
pointCloud["positionData"] = np.frombuffer(in_stream.read(points * 4 * 3), dtype=np.float32)
45+
pointCloud["positionData"].shape = (points, 3)
46+
if pointCloud["hasNormals"]:
47+
pointCloud["normalData"] = np.frombuffer(in_stream.read(points * 4 * 3), dtype=np.float32)
48+
pointCloud["normalData"].shape = (points, 3)
49+
if pointCloud["hasColors"]:
50+
pointCloud["rgb24Data"] = np.frombuffer(in_stream.read(points * 3), dtype=np.ubyte)
51+
pointCloud["rgb24Data"].shape = (points, 3)
52+
yield json_output
53+
54+
def invert_se3(a):
55+
b = np.eye(4)
56+
b[:3, :3] = a[:3, :3].transpose()
57+
b[:3, 3] = -np.dot(b[:3, :3], a[:3, 3])
58+
return b
59+
60+
class MockCamera:
61+
def __init__(self, data):
62+
self.intrinsics = np.array(data["intrinsics"])
63+
self.projectionMatrixOpenGL = np.array(data["projectionMatrixOpenGL"])
64+
65+
def getIntrinsicMatrix(self):
66+
return self.intrinsics
67+
68+
def getProjectionMatrixOpenGL(self, near, far):
69+
m22 = (near + far) / (far - near)
70+
m23 = -2.0*near*far/(far-near)
71+
projectionMatrixOpenGL = self.projectionMatrixOpenGL
72+
projectionMatrixOpenGL[2, 2] = m22
73+
projectionMatrixOpenGL[2, 3] = m23
74+
return projectionMatrixOpenGL
75+
76+
class MockCameraPose:
77+
def __init__(self, data):
78+
self.camera = MockCamera(data["camera"])
79+
self.cameraToWorld = np.array(data["cameraToWorld"])
80+
self.worldToCamera = invert_se3(self.cameraToWorld)
81+
self.position = spectacularAI.Vector3d(*self.cameraToWorld[:3, 3])
82+
83+
def getCameraToWorldMatrix(self):
84+
return self.cameraToWorld
85+
86+
def getWorldToCameraMatrix(self):
87+
return self.worldToCamera
88+
89+
def getPosition(self):
90+
return self.position
91+
92+
class MockVioOutput:
93+
def __init__(self, data):
94+
self.data = data
95+
def getCameraPose(self, index):
96+
return MockCameraPose(self.data["cameraPoses"][index])
97+
98+
class MockFrame:
99+
def __init__(self, data):
100+
self.cameraPose = MockCameraPose(data["cameraPose"])
101+
102+
class MockFrameSet:
103+
def __init__(self, data):
104+
self.primaryFrame = MockFrame(data["primaryFrame"])
105+
106+
class MockPointCloud:
107+
def __init__(self, data):
108+
self.data = data
109+
def getPositionData(self):
110+
return self.data["positionData"]
111+
def getRGB24Data(self):
112+
return self.data["rgb24Data"]
113+
def getNormalData(self):
114+
return self.data["normalData"]
115+
def hasColors(self):
116+
return 'rgb24Data' in self.data
117+
def hasNormals(self):
118+
return 'normalData' in self.data
119+
def empty(self):
120+
return len(self.data["positionData"]) == 0
121+
122+
class MockKeyFrame:
123+
def __init__(self, data):
124+
self.frameSet = MockFrameSet(data["frameSet"])
125+
if "pointCloud" in data:
126+
self.pointCloud = MockPointCloud(data["pointCloud"])
127+
else:
128+
self.pointCloud = None
129+
130+
class MockMap:
131+
def __init__(self, data):
132+
self.keyFrames = {}
133+
for keyFrameId in data["keyFrames"]:
134+
keyFrame = data["keyFrames"][keyFrameId]
135+
self.keyFrames[int(keyFrameId)] = MockKeyFrame(keyFrame)
136+
137+
class MockMapperOutput:
138+
def __init__(self, data):
139+
self.updatedKeyFrames = data["updatedKeyFrames"]
140+
self.finalMap = data["finalMap"]
141+
self.map = MockMap(data["map"])
142+
143+
if __name__ == '__main__':
144+
import argparse
145+
parser = argparse.ArgumentParser(__doc__)
146+
parser.add_argument('--file', type=argparse.FileType('rb'),
147+
help='Read data from file or pipe',
148+
default=None)
149+
args = parser.parse_args()
150+
vio_source = input_stream_reader(args.file)
151+
for vio_out in vio_source:
152+
# Do something with output
153+
if 'cameraPoses' in vio_out:
154+
vioOutput = MockVioOutput(vio_out)
155+
print(vioOutput.getCameraPose(0).getCameraToWorldMatrix())
156+
else:
157+
mapperOutput = MockMapperOutput(vio_out)
158+
print(f"Updated keyframes: {mapperOutput.updatedKeyFrames}")

0 commit comments

Comments
 (0)