|
| 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