q3dviewer 1.0.0__py3-none-any.whl

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.
q3dviewer/gau_io.py ADDED
@@ -0,0 +1,168 @@
1
+ import numpy as np
2
+ from plyfile import PlyData
3
+
4
+
5
+ def gsdata_type(sh_dim):
6
+ return [('pw', '<f4', (3,)),
7
+ ('rot', '<f4', (4,)),
8
+ ('scale', '<f4', (3,)),
9
+ ('alpha', '<f4'),
10
+ ('sh', '<f4', (sh_dim))]
11
+
12
+
13
+ def matrix_to_quaternion_wxyz(matrices):
14
+ m00, m01, m02 = matrices[:, 0, 0], matrices[:, 0, 1], matrices[:, 0, 2]
15
+ m10, m11, m12 = matrices[:, 1, 0], matrices[:, 1, 1], matrices[:, 1, 2]
16
+ m20, m21, m22 = matrices[:, 2, 0], matrices[:, 2, 1], matrices[:, 2, 2]
17
+ t = 1 + m00 + m11 + m22
18
+ s = np.ones_like(m00)
19
+ w = np.ones_like(m00)
20
+ x = np.ones_like(m00)
21
+ y = np.ones_like(m00)
22
+ z = np.ones_like(m00)
23
+
24
+ t_positive = t > 0.0000001
25
+ s[t_positive] = 0.5 / np.sqrt(t[t_positive])
26
+ w[t_positive] = 0.25 / s[t_positive]
27
+ x[t_positive] = (m21[t_positive] - m12[t_positive]) * s[t_positive]
28
+ y[t_positive] = (m02[t_positive] - m20[t_positive]) * s[t_positive]
29
+ z[t_positive] = (m10[t_positive] - m01[t_positive]) * s[t_positive]
30
+
31
+ c1 = np.logical_and(m00 > m11, m00 > m22)
32
+ cond1 = np.logical_and(np.logical_not(t_positive), np.logical_and(m00 > m11, m00 > m22))
33
+
34
+ s[cond1] = 2.0 * np.sqrt(1.0 + m00[cond1] - m11[cond1] - m22[cond1])
35
+ w[cond1] = (m21[cond1] - m12[cond1]) / s[cond1]
36
+ x[cond1] = 0.25 * s[cond1]
37
+ y[cond1] = (m01[cond1] + m10[cond1]) / s[cond1]
38
+ z[cond1] = (m02[cond1] + m20[cond1]) / s[cond1]
39
+
40
+ c2 = np.logical_and(np.logical_not(c1), m11 > m22)
41
+ cond2 = np.logical_and(np.logical_not(t_positive), c2)
42
+ s[cond2] = 2.0 * np.sqrt(1.0 + m11[cond2] - m00[cond2] - m22[cond2])
43
+ w[cond2] = (m02[cond2] - m20[cond2]) / s[cond2]
44
+ x[cond2] = (m01[cond2] + m10[cond2]) / s[cond2]
45
+ y[cond2] = 0.25 * s[cond2]
46
+ z[cond2] = (m12[cond2] + m21[cond2]) / s[cond2]
47
+
48
+ c3 = np.logical_and(np.logical_not(c1), np.logical_not(c2))
49
+ cond3 = np.logical_and(np.logical_not(t_positive), c3)
50
+ s[cond3] = 2.0 * np.sqrt(1.0 + m22[cond3] - m00[cond3] - m11[cond3])
51
+ w[cond3] = (m10[cond3] - m01[cond3]) / s[cond3]
52
+ x[cond3] = (m02[cond3] + m20[cond3]) / s[cond3]
53
+ y[cond3] = (m12[cond3] + m21[cond3]) / s[cond3]
54
+ z[cond3] = 0.25 * s[cond3]
55
+ return np.array([w, x, y, z]).T
56
+
57
+
58
+ def load_ply(path, T=None):
59
+ plydata = PlyData.read(path)
60
+ pws = np.stack((np.asarray(plydata.elements[0]["x"]),
61
+ np.asarray(plydata.elements[0]["y"]),
62
+ np.asarray(plydata.elements[0]["z"])), axis=1)
63
+
64
+ alphas = np.asarray(plydata.elements[0]["opacity"])
65
+ alphas = 1/(1 + np.exp(-alphas))
66
+
67
+ scales = np.stack((np.asarray(plydata.elements[0]["scale_0"]),
68
+ np.asarray(plydata.elements[0]["scale_1"]),
69
+ np.asarray(plydata.elements[0]["scale_2"])), axis=1)
70
+
71
+ rots = np.stack((np.asarray(plydata.elements[0]["rot_0"]),
72
+ np.asarray(plydata.elements[0]["rot_1"]),
73
+ np.asarray(plydata.elements[0]["rot_2"]),
74
+ np.asarray(plydata.elements[0]["rot_3"])), axis=1)
75
+
76
+ rots /= np.linalg.norm(rots, axis=1)[:, np.newaxis]
77
+
78
+ sh_dim = len(plydata.elements[0][0])-14
79
+ shs = np.zeros([pws.shape[0], sh_dim])
80
+ shs[:, 0] = np.asarray(plydata.elements[0]["f_dc_0"])
81
+ shs[:, 1] = np.asarray(plydata.elements[0]["f_dc_1"])
82
+ shs[:, 2] = np.asarray(plydata.elements[0]["f_dc_2"])
83
+
84
+ sh_rest_dim = sh_dim - 3
85
+ for i in range(sh_rest_dim):
86
+ name = "f_rest_%d" % i
87
+ shs[:, 3 + i] = np.asarray(plydata.elements[0][name])
88
+
89
+ shs[:, 3:] = shs[:, 3:].reshape(-1, 3, sh_rest_dim//3).transpose([0, 2, 1]).reshape(-1, sh_rest_dim)
90
+
91
+ pws = pws.astype(np.float32)
92
+ rots = rots.astype(np.float32)
93
+ scales = np.exp(scales)
94
+ scales = scales.astype(np.float32)
95
+ alphas = alphas.astype(np.float32)
96
+ shs = shs.astype(np.float32)
97
+
98
+ dtypes = gsdata_type(sh_dim)
99
+
100
+ gs = np.rec.fromarrays(
101
+ [pws, rots, scales, alphas, shs], dtype=dtypes)
102
+
103
+ return gs
104
+
105
+
106
+ def rotate_gaussian(T, gs):
107
+ # Transform to world
108
+ pws = (T @ gs['pw'].T).T
109
+ w = gs['rot'][:, 0]
110
+ x = gs['rot'][:, 1]
111
+ y = gs['rot'][:, 2]
112
+ z = gs['rot'][:, 3]
113
+ R = np.array([
114
+ [1.0 - 2*(y**2 + z**2), 2*(x*y - z*w), 2*(x * z + y * w)],
115
+ [2*(x*y + z*w), 1.0 - 2*(x**2 + z**2), 2*(y*z - x*w)],
116
+ [2*(x*z - y*w), 2*(y*z + x*w), 1.0 - 2*(x**2 + y**2)]
117
+ ]).transpose(2, 0, 1)
118
+ R_new = T @ R
119
+ rots = matrix_to_quaternion_wxyz(R_new)
120
+ gs['pw'] = pws
121
+ gs['rot'] = rots
122
+ return gs
123
+
124
+
125
+ def load_gs(fn):
126
+ if fn.endswith('.ply'):
127
+ return load_ply(fn)
128
+ elif fn.endswith('.npy'):
129
+ return np.load(fn)
130
+ else:
131
+ print("%s is not a supported file." % fn)
132
+ exit(0)
133
+
134
+
135
+ def save_gs(fn, gs):
136
+ np.save(fn, gs)
137
+
138
+
139
+ def get_example_gs():
140
+ gs_data = np.array([[0., 0., 0., # xyz
141
+ 1., 0., 0., 0., # rot
142
+ 0.05, 0.05, 0.05, # size
143
+ 1.,
144
+ 1.772484, -1.772484, 1.772484],
145
+ [1., 0., 0.,
146
+ 1., 0., 0., 0.,
147
+ 0.2, 0.05, 0.05,
148
+ 1.,
149
+ 1.772484, -1.772484, -1.772484],
150
+ [0., 1., 0.,
151
+ 1., 0., 0., 0.,
152
+ 0.05, 0.2, 0.05,
153
+ 1.,
154
+ -1.772484, 1.772484, -1.772484],
155
+ [0., 0., 1.,
156
+ 1., 0., 0., 0.,
157
+ 0.05, 0.05, 0.2,
158
+ 1.,
159
+ -1.772484, -1.772484, 1.772484]
160
+ ], dtype=np.float32)
161
+ dtypes = gsdata_type(3)
162
+ gs = np.frombuffer(gs_data.tobytes(), dtype=dtypes)
163
+ return gs
164
+
165
+
166
+ if __name__ == "__main__":
167
+ gs = load_gs("/home/liu/workspace/EasyGaussianSplatting/data/final.npy")
168
+ print(gs.shape)
q3dviewer/utils.py ADDED
@@ -0,0 +1,146 @@
1
+ import numpy as np
2
+ import time
3
+
4
+
5
+ def rainbow(scalars, scalar_min=0, scalar_max=255):
6
+ range = scalar_max - scalar_min
7
+ values = 1.0 - (scalars - scalar_min) / range
8
+ # values = (scalars - scalar_min) / range # using inverted color
9
+ colors = np.zeros([scalars.shape[0], 3], dtype=np.float32)
10
+ values = np.clip(values, 0, 1)
11
+
12
+ h = values * 5.0 + 1.0
13
+ i = np.floor(h).astype(int)
14
+ f = h - i
15
+ f[np.logical_not(i % 2)] = 1 - f[np.logical_not(i % 2)]
16
+ n = 1 - f
17
+
18
+ # idx = i <= 1
19
+ colors[i <= 1, 0] = n[i <= 1] * 255
20
+ colors[i <= 1, 1] = 0
21
+ colors[i <= 1, 2] = 255
22
+
23
+ colors[i == 2, 0] = 0
24
+ colors[i == 2, 1] = n[i == 2] * 255
25
+ colors[i == 2, 2] = 255
26
+
27
+ colors[i == 3, 0] = 0
28
+ colors[i == 3, 1] = 255
29
+ colors[i == 3, 2] = n[i == 3] * 255
30
+
31
+ colors[i == 4, 0] = n[i == 4] * 255
32
+ colors[i == 4, 1] = 255
33
+ colors[i == 4, 2] = 0
34
+
35
+ colors[i >= 5, 0] = 255
36
+ colors[i >= 5, 1] = n[i >= 5] * 255
37
+ colors[i >= 5, 2] = 0
38
+ return colors
39
+
40
+
41
+ def euler_to_matrix(rpy):
42
+ roll, pitch, yaw = rpy
43
+ Rx = np.array([[1, 0, 0],
44
+ [0, np.cos(roll), -np.sin(roll)],
45
+ [0, np.sin(roll), np.cos(roll)]])
46
+ Ry = np.array([[np.cos(pitch), 0, np.sin(pitch)],
47
+ [0, 1, 0],
48
+ [-np.sin(pitch), 0, np.cos(pitch)]])
49
+ Rz = np.array([[np.cos(yaw), -np.sin(yaw), 0],
50
+ [np.sin(yaw), np.cos(yaw), 0],
51
+ [0, 0, 1]])
52
+ R = Rz @ Ry @ Rx
53
+ return R
54
+
55
+
56
+ def matrix_to_euler(R):
57
+ sy = np.sqrt(R[0, 0]**2 + R[1, 0]**2)
58
+ singular = sy < 1e-6 # Check for gimbal lock
59
+ if not singular:
60
+ roll = np.arctan2(R[2, 1], R[2, 2]) # X-axis rotation
61
+ pitch = np.arctan2(-R[2, 0], sy) # Y-axis rotation
62
+ yaw = np.arctan2(R[1, 0], R[0, 0]) # Z-axis rotation
63
+ else:
64
+ # Gimbal lock case
65
+ roll = np.arctan2(-R[1, 2], R[1, 1])
66
+ pitch = np.arctan2(-R[2, 0], sy)
67
+ yaw = 0 # Arbitrarily set yaw to 0
68
+
69
+ return np.array([roll, pitch, yaw])
70
+
71
+
72
+ def matrix_to_quaternion(matrix):
73
+ trace = matrix[0, 0] + matrix[1, 1] + matrix[2, 2]
74
+ if trace > 0:
75
+ s = 0.5 / np.sqrt(trace + 1.0)
76
+ w = 0.25 / s
77
+ x = (matrix[2, 1] - matrix[1, 2]) * s
78
+ y = (matrix[0, 2] - matrix[2, 0]) * s
79
+ z = (matrix[1, 0] - matrix[0, 1]) * s
80
+ else:
81
+ if matrix[0, 0] > matrix[1, 1] and matrix[0, 0] > matrix[2, 2]:
82
+ s = 2.0 * np.sqrt(1.0 + matrix[0, 0] - matrix[1, 1] - matrix[2, 2])
83
+ w = (matrix[2, 1] - matrix[1, 2]) / s
84
+ x = 0.25 * s
85
+ y = (matrix[0, 1] + matrix[1, 0]) / s
86
+ z = (matrix[0, 2] + matrix[2, 0]) / s
87
+ elif matrix[1, 1] > matrix[2, 2]:
88
+ s = 2.0 * np.sqrt(1.0 + matrix[1, 1] - matrix[0, 0] - matrix[2, 2])
89
+ w = (matrix[0, 2] - matrix[2, 0]) / s
90
+ x = (matrix[0, 1] + matrix[1, 0]) / s
91
+ y = 0.25 * s
92
+ z = (matrix[1, 2] + matrix[2, 1]) / s
93
+ else:
94
+ s = 2.0 * np.sqrt(1.0 + matrix[2, 2] - matrix[0, 0] - matrix[1, 1])
95
+ w = (matrix[1, 0] - matrix[0, 1]) / s
96
+ x = (matrix[0, 2] + matrix[2, 0]) / s
97
+ y = (matrix[1, 2] + matrix[2, 1]) / s
98
+ z = 0.25 * s
99
+ return np.array([x, y, z, w])
100
+
101
+
102
+ def quaternion_to_matrix(quaternion):
103
+ x, y, z, w = quaternion
104
+ q = np.array(quaternion[:4], dtype=np.float64, copy=True)
105
+ n = np.linalg.norm(q)
106
+ if np.any(n == 0.0):
107
+ raise ZeroDivisionError("bad quaternion input")
108
+ else:
109
+ m = np.empty((3, 3))
110
+ m[0, 0] = 1.0 - 2*(y**2 + z**2)/n
111
+ m[0, 1] = 2*(x*y - z*w)/n
112
+ m[0, 2] = 2*(x*z + y*w)/n
113
+ m[1, 0] = 2*(x*y + z*w)/n
114
+ m[1, 1] = 1.0 - 2*(x**2 + z**2)/n
115
+ m[1, 2] = 2*(y*z - x*w)/n
116
+ m[2, 0] = 2*(x*z - y*w)/n
117
+ m[2, 1] = 2*(y*z + x*w)/n
118
+ m[2, 2] = 1.0 - 2*(x**2 + y**2)/n
119
+ return m
120
+
121
+
122
+ def make_transform(pose, rotation):
123
+ transform = np.eye(4)
124
+ transform[0:3, 0:3] = quaternion_to_matrix(rotation)
125
+ transform[0:3, 3] = pose
126
+ return transform
127
+
128
+
129
+ class FPSMonitor():
130
+ def __init__(self):
131
+ self.stamp_record = []
132
+
133
+ def count(self):
134
+ cur_stamp = time.time()
135
+ self.stamp_record.append(cur_stamp)
136
+ while len(self.stamp_record) > 0:
137
+ if(cur_stamp - self.stamp_record[0] > 1.):
138
+ self.stamp_record.pop(0)
139
+ else:
140
+ break
141
+ return len(self.stamp_record)
142
+
143
+
144
+ # euler = np.array([1, 0.1, 0.1])
145
+ # euler_angles = matrix_to_euler(euler_to_matrix(euler))
146
+ # print("Euler Angles:", euler_angles)
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import numpy as np
4
+ import pyqtgraph.opengl as gl
5
+ from pyqtgraph.Qt import QtCore
6
+ from PyQt5.QtWidgets import QWidget, QComboBox, QVBoxLayout, QHBoxLayout, \
7
+ QSizePolicy, QSpacerItem, QMainWindow
8
+ from OpenGL.GL import *
9
+ from PyQt5.QtGui import QKeyEvent, QVector3D
10
+ from PyQt5.QtWidgets import QApplication, QWidget
11
+ import numpy as np
12
+ from PyQt5.QtWidgets import QLabel, QLineEdit, \
13
+ QDoubleSpinBox, QSpinBox, QCheckBox
14
+
15
+
16
+ class SettingWindow(QWidget):
17
+ def __init__(self):
18
+ super().__init__()
19
+ self.combo_items = QComboBox()
20
+ self.combo_items.currentIndexChanged.connect(self.onComboboxSelection)
21
+ main_layout = QVBoxLayout()
22
+ self.stretch = QSpacerItem(
23
+ 10, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)
24
+ main_layout.addWidget(self.combo_items)
25
+ self.layout = QVBoxLayout()
26
+ self.layout.addItem(self.stretch)
27
+ main_layout.addLayout(self.layout)
28
+ self.setLayout(main_layout)
29
+ self.setWindowTitle("Setting Window")
30
+ self.setGeometry(200, 200, 300, 200)
31
+ self.items = {}
32
+
33
+ def addSetting(self, name, item):
34
+ self.items.update({name: item})
35
+ self.combo_items.addItem("%s(%s)" % (name, item.__class__.__name__))
36
+
37
+ def clearSetting(self):
38
+ while self.layout.count():
39
+ child = self.layout.takeAt(0)
40
+ if child.widget():
41
+ child.widget().deleteLater()
42
+
43
+ def onComboboxSelection(self, index):
44
+ self.layout.removeItem(self.stretch)
45
+ # remove all setting of previous widget
46
+ self.clearSetting()
47
+
48
+ key = list(self.items.keys())
49
+ try:
50
+ item = self.items[key[index]]
51
+ item.addSetting(self.layout)
52
+ self.layout.addItem(self.stretch)
53
+ except AttributeError:
54
+ print("%s: No setting." % (item.__class__.__name__))
55
+
56
+
57
+ class ViewWidget(gl.GLViewWidget):
58
+ def __init__(self):
59
+ self.followed_name = 'none'
60
+ self.named_items = {}
61
+ self.color = '#000000'
62
+ self.followable_item_name = ['none']
63
+ self.setting_window = SettingWindow()
64
+ super(ViewWidget, self).__init__()
65
+
66
+ def onFollowableSelection(self, index):
67
+ self.followed_name = self.followable_item_name[index]
68
+
69
+ def update(self):
70
+ if self.followed_name != 'none':
71
+ pos = self.named_items[self.followed_name].T[:3, 3]
72
+ self.opts['center'] = QVector3D(pos[0], pos[1], pos[2])
73
+ super().update()
74
+
75
+ def addSetting(self, layout):
76
+ label1 = QLabel("Set background color:")
77
+ label1.setToolTip("using '#xxxxxx', i.e. #FF4500")
78
+ box1 = QLineEdit()
79
+ box1.setToolTip("'using '#xxxxxx', i.e. #FF4500")
80
+ box1.setText(str(self.color))
81
+ box1.textChanged.connect(self.setBKColor)
82
+ layout.addWidget(label1)
83
+ layout.addWidget(box1)
84
+ label2 = QLabel("Set Focus:")
85
+ combo2 = QComboBox()
86
+ for name in self.followable_item_name:
87
+ combo2.addItem(name)
88
+ combo2.currentIndexChanged.connect(self.onFollowableSelection)
89
+ layout.addWidget(label2)
90
+ layout.addWidget(combo2)
91
+
92
+ def setBKColor(self, color):
93
+ if (type(color) != str):
94
+ return
95
+ if color.startswith("#"):
96
+ try:
97
+ self.setBackgroundColor(color)
98
+ self.color = color
99
+ except ValueError:
100
+ return
101
+
102
+ def addItem(self, name, item):
103
+ self.named_items.update({name: item})
104
+ if (item.__class__.__name__ == 'GLAxisItem'):
105
+ self.followable_item_name.append(name)
106
+ self.setting_window.addSetting(name, item)
107
+ super().addItem(item)
108
+
109
+ def mouseReleaseEvent(self, ev):
110
+ if hasattr(self, 'mousePos'):
111
+ delattr(self, 'mousePos')
112
+
113
+ def mouseMoveEvent(self, ev):
114
+ lpos = ev.localPos()
115
+ if not hasattr(self, 'mousePos'):
116
+ self.mousePos = lpos
117
+ diff = lpos - self.mousePos
118
+ self.mousePos = lpos
119
+ if ev.buttons() == QtCore.Qt.MouseButton.RightButton:
120
+ self.orbit(-diff.x(), diff.y())
121
+ elif ev.buttons() == QtCore.Qt.MouseButton.LeftButton:
122
+ pitch_abs = np.abs(self.opts['elevation'])
123
+ camera_mode = 'view-upright'
124
+ if (pitch_abs <= 45.0 or pitch_abs == 90):
125
+ camera_mode = 'view'
126
+ self.pan(diff.x(), diff.y(), 0, relative=camera_mode)
127
+
128
+ def keyPressEvent(self, ev: QKeyEvent):
129
+ step = 10
130
+ zoom_delta = 20
131
+ speed = 2
132
+ self.projectionMatrix().data()
133
+
134
+ pitch_abs = np.abs(self.opts['elevation'])
135
+ camera_mode = 'view-upright'
136
+ if (pitch_abs <= 45.0 or pitch_abs == 90):
137
+ camera_mode = 'view'
138
+
139
+ if ev.key() == QtCore.Qt.Key_M: # setting meun
140
+ print("Open setting windows")
141
+ self.openSettingWindow()
142
+ elif ev.key() == QtCore.Qt.Key_R:
143
+ print("Clear viewer")
144
+ for item in self.named_items.values():
145
+ try:
146
+ item.clear()
147
+ except AttributeError:
148
+ pass
149
+ elif ev.key() == QtCore.Qt.Key_Up:
150
+ if ev.modifiers() & QtCore.Qt.KeyboardModifier.ControlModifier:
151
+ self.pan(0, +step, 0, relative=camera_mode)
152
+ else:
153
+ self.orbit(azim=0, elev=-speed)
154
+ elif ev.key() == QtCore.Qt.Key_Down:
155
+ if ev.modifiers() & QtCore.Qt.KeyboardModifier.ControlModifier:
156
+ self.pan(0, -step, 0, relative=camera_mode)
157
+ else:
158
+ self.orbit(azim=0, elev=speed)
159
+ elif ev.key() == QtCore.Qt.Key_Left:
160
+ if ev.modifiers() & QtCore.Qt.KeyboardModifier.ControlModifier:
161
+ self.pan(+step, 0, 0, relative=camera_mode)
162
+ else:
163
+ self.orbit(azim=speed, elev=0)
164
+
165
+ elif ev.key() == QtCore.Qt.Key_Right:
166
+ if ev.modifiers() & QtCore.Qt.KeyboardModifier.ControlModifier:
167
+ self.pan(-step, 0, 0, relative=camera_mode)
168
+ else:
169
+ self.orbit(azim=-speed, elev=0)
170
+
171
+ elif ev.key() == QtCore.Qt.Key_Z:
172
+ self.opts['distance'] *= 0.999**(+zoom_delta)
173
+ elif ev.key() == QtCore.Qt.Key_X:
174
+ self.opts['distance'] *= 0.999**(-zoom_delta)
175
+ else:
176
+ super().keyPressEvent(ev)
177
+
178
+ def openSettingWindow(self):
179
+ if self.setting_window.isVisible():
180
+ self.setting_window.raise_()
181
+
182
+ else:
183
+ self.setting_window.show()
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.1
2
+ Name: q3dviewer
3
+ Version: 1.0.0
4
+ Requires-Dist: numpy
5
+ Requires-Dist: pyqtgraph
6
+ Requires-Dist: pyqt5
7
+ Requires-Dist: PyOpenGL
8
+ Requires-Dist: pypcd4
9
+ Requires-Dist: pillow
10
+
@@ -0,0 +1,20 @@
1
+ q3dviewer/__init__.py,sha256=BCrGWEtwjdvK4CHgp1e5Wkyhabk6WdvY_7FKJdGJwGE,142
2
+ q3dviewer/basic_viewer.py,sha256=A7bMxutP1grnqE5A4tjODGrzNfFq6-c6MlNYj8t54WU,1609
3
+ q3dviewer/gau_io.py,sha256=fKry1eyeFdw_JO5JZqU3l66dzt43NGpHhX89ER_y38A,5900
4
+ q3dviewer/utils.py,sha256=xzUAXUhgxoJyPrnivnyrJWoQQg9LrDPhxgZo1Cp35kQ,4596
5
+ q3dviewer/viewer_widget.py,sha256=repcGWZZXRxua8C-3CYHumvkVoPQl8ycFPTBx5zovRg,6561
6
+ q3dviewer/custom_items/__init__.py,sha256=Isb3HPtymuxEev1hc81x51inzH6epomtBHBQsPp4gZY,446
7
+ q3dviewer/custom_items/axis_item.py,sha256=Er8HRSnOscROZ7fOZEESnrZp62A5kY4oqP-GCAXczYU,2353
8
+ q3dviewer/custom_items/camera_frame_item.py,sha256=hvpZ3UEnkbs1nHNr2R7huuy1MdvBmwQPiqqKImWWG8c,5622
9
+ q3dviewer/custom_items/cloud_io_item.py,sha256=nbZbZLX72CWNFrInpxwysA2usbCkgAUrwZEOOVWx9Mc,2816
10
+ q3dviewer/custom_items/cloud_item.py,sha256=gOIun2VOfarA4Xo_2vdyWpIII0vvWVcQ4VqCZsYj584,9711
11
+ q3dviewer/custom_items/gaussian_item.py,sha256=3YXdJxHNSdk0D2HS2VJvuGTUjbi9D_UcrWEXSzxP7BY,10177
12
+ q3dviewer/custom_items/grid_item.py,sha256=WuNzIHBhjAQ6e4fP5aBp5jSgYbrY7wrbP9PhRptuz7s,1150
13
+ q3dviewer/custom_items/image_item.py,sha256=qOT0r6p8_NcF5GVeJrrR8rJNe68U_jW1qrUDZ05O5hI,5312
14
+ q3dviewer/custom_items/text_item.py,sha256=lbJaXfpeyyxr6lhlMjypk4a079-aUpsrXFjGi-BTzPU,1872
15
+ q3dviewer/custom_items/trajectory_item.py,sha256=9gM5voiYk0j4JMEp3drF7VFYSPsJcEK7mibdx45OQDs,2778
16
+ q3dviewer-1.0.0.dist-info/METADATA,sha256=YkgPKWnfC-R9Q26DXkrAwih_KwyqAeAPVbOgzRwiMIk,189
17
+ q3dviewer-1.0.0.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
18
+ q3dviewer-1.0.0.dist-info/entry_points.txt,sha256=6zSxtJ5cjcpc32sR_wkRqOaeiJFpEuLnJQckZE3niU0,316
19
+ q3dviewer-1.0.0.dist-info/top_level.txt,sha256=HFFDCbGu28txcGe2HPc46A7EPaguBa_b5oH7bufmxHM,10
20
+ q3dviewer-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.34.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,7 @@
1
+ [console_scripts]
2
+ cloud_viewer = q3dviewer.tools.cloud_viewer:main
3
+ gaussian_viewer = q3dviewer.tools.gaussian_viewer:main
4
+ lidar_calib = q3dviewer.tools.lidar_calib:main
5
+ lidar_cam_calib = q3dviewer.tools.lidar_cam_calib:main
6
+ mesh_viewer = q3dviewer.tools.mesh_viewer:main
7
+ ros_viewer = q3dviewer.tools.ros_viewer:main
@@ -0,0 +1 @@
1
+ q3dviewer