q3dviewer 1.0.8__py3-none-any.whl → 1.1.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/base_glwidget.py +62 -10
- q3dviewer/base_item.py +15 -0
- q3dviewer/custom_items/axis_item.py +31 -94
- q3dviewer/custom_items/cloud_item.py +36 -30
- q3dviewer/custom_items/frame_item.py +56 -36
- q3dviewer/custom_items/gaussian_item.py +3 -3
- q3dviewer/custom_items/grid_item.py +88 -37
- q3dviewer/custom_items/image_item.py +1 -2
- q3dviewer/custom_items/line_item.py +4 -5
- q3dviewer/gau_io.py +0 -168
- q3dviewer/glwidget.py +22 -16
- q3dviewer/test/test_interpolation.py +58 -0
- q3dviewer/test/test_rendering.py +72 -0
- q3dviewer/tools/cinematographer.py +367 -0
- q3dviewer/tools/cloud_viewer.py +2 -2
- q3dviewer/tools/film_maker.py +421 -0
- q3dviewer/tools/lidar_calib.py +11 -22
- q3dviewer/tools/lidar_cam_calib.py +9 -20
- q3dviewer/utils/maths.py +155 -5
- q3dviewer/viewer.py +30 -7
- q3dviewer-1.1.0.dist-info/METADATA +214 -0
- q3dviewer-1.1.0.dist-info/RECORD +45 -0
- {q3dviewer-1.0.8.dist-info → q3dviewer-1.1.0.dist-info}/entry_points.txt +1 -1
- q3dviewer/basic_window.py +0 -228
- q3dviewer/cloud_viewer.py +0 -74
- q3dviewer/custom_items/camera_frame_item.py +0 -173
- q3dviewer/custom_items/trajectory_item.py +0 -79
- q3dviewer/utils.py +0 -71
- q3dviewer-1.0.8.dist-info/METADATA +0 -21
- q3dviewer-1.0.8.dist-info/RECORD +0 -46
- {q3dviewer-1.0.8.dist-info → q3dviewer-1.1.0.dist-info}/LICENSE +0 -0
- {q3dviewer-1.0.8.dist-info → q3dviewer-1.1.0.dist-info}/WHEEL +0 -0
- {q3dviewer-1.0.8.dist-info → q3dviewer-1.1.0.dist-info}/top_level.txt +0 -0
q3dviewer/basic_window.py
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
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, QSizePolicy,\
|
|
7
|
-
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
|
-
import signal
|
|
13
|
-
import sys
|
|
14
|
-
from PyQt5.QtWidgets import QLabel, QLineEdit, QDoubleSpinBox, QSpinBox
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class SettingWindow(QWidget):
|
|
18
|
-
def __init__(self):
|
|
19
|
-
super().__init__()
|
|
20
|
-
self.combo_items = QComboBox()
|
|
21
|
-
self.combo_items.currentIndexChanged.connect(self.onComboboxSelection)
|
|
22
|
-
main_layout = QVBoxLayout()
|
|
23
|
-
self.stretch = QSpacerItem(
|
|
24
|
-
10, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
|
25
|
-
main_layout.addWidget(self.combo_items)
|
|
26
|
-
self.layout = QVBoxLayout()
|
|
27
|
-
self.layout.addItem(self.stretch)
|
|
28
|
-
main_layout.addLayout(self.layout)
|
|
29
|
-
self.setLayout(main_layout)
|
|
30
|
-
self.setWindowTitle("Setting Window")
|
|
31
|
-
self.setGeometry(200, 200, 300, 200)
|
|
32
|
-
self.items = {}
|
|
33
|
-
|
|
34
|
-
def addSetting(self, name, item):
|
|
35
|
-
self.items.update({name: item})
|
|
36
|
-
self.combo_items.addItem("%s(%s)" % (name, item.__class__.__name__))
|
|
37
|
-
|
|
38
|
-
def clearSetting(self):
|
|
39
|
-
while self.layout.count():
|
|
40
|
-
child = self.layout.takeAt(0)
|
|
41
|
-
if child.widget():
|
|
42
|
-
child.widget().deleteLater()
|
|
43
|
-
|
|
44
|
-
def onComboboxSelection(self, index):
|
|
45
|
-
self.layout.removeItem(self.stretch)
|
|
46
|
-
# remove all setting of previous widget
|
|
47
|
-
self.clearSetting()
|
|
48
|
-
|
|
49
|
-
key = list(self.items.keys())
|
|
50
|
-
try:
|
|
51
|
-
item = self.items[key[index]]
|
|
52
|
-
item.addSetting(self.layout)
|
|
53
|
-
self.layout.addItem(self.stretch)
|
|
54
|
-
except AttributeError:
|
|
55
|
-
print("%s: No setting." % (item.__class__.__name__))
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class ViewWidget(gl.GLViewWidget):
|
|
59
|
-
def __init__(self):
|
|
60
|
-
self.followed_name = 'none'
|
|
61
|
-
self.named_items = {}
|
|
62
|
-
self.color = '#000000'
|
|
63
|
-
self.followable_item_name = ['none']
|
|
64
|
-
self.setting_window = SettingWindow()
|
|
65
|
-
super(ViewWidget, self).__init__()
|
|
66
|
-
|
|
67
|
-
def onFollowableSelection(self, index):
|
|
68
|
-
self.followed_name = self.followable_item_name[index]
|
|
69
|
-
|
|
70
|
-
def update(self):
|
|
71
|
-
if self.followed_name != 'none':
|
|
72
|
-
pos = self.named_items[self.followed_name].T[:3, 3]
|
|
73
|
-
self.opts['center'] = QVector3D(pos[0], pos[1], pos[2])
|
|
74
|
-
super().update()
|
|
75
|
-
|
|
76
|
-
def addSetting(self, layout):
|
|
77
|
-
label1 = QLabel("Set background color:")
|
|
78
|
-
label1.setToolTip("using '#xxxxxx', i.e. #FF4500")
|
|
79
|
-
box1 = QLineEdit()
|
|
80
|
-
box1.setToolTip("'using '#xxxxxx', i.e. #FF4500")
|
|
81
|
-
box1.setText(str(self.color))
|
|
82
|
-
box1.textChanged.connect(self.setBKColor)
|
|
83
|
-
layout.addWidget(label1)
|
|
84
|
-
layout.addWidget(box1)
|
|
85
|
-
label2 = QLabel("Set Focus:")
|
|
86
|
-
combo2 = QComboBox()
|
|
87
|
-
for name in self.followable_item_name:
|
|
88
|
-
combo2.addItem(name)
|
|
89
|
-
combo2.currentIndexChanged.connect(self.onFollowableSelection)
|
|
90
|
-
layout.addWidget(label2)
|
|
91
|
-
layout.addWidget(combo2)
|
|
92
|
-
|
|
93
|
-
def setBKColor(self, color):
|
|
94
|
-
if (type(color) != str):
|
|
95
|
-
return
|
|
96
|
-
if color.startswith("#"):
|
|
97
|
-
try:
|
|
98
|
-
self.setBackgroundColor(color)
|
|
99
|
-
self.color = color
|
|
100
|
-
except ValueError:
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
def addItem(self, name, item):
|
|
104
|
-
self.named_items.update({name: item})
|
|
105
|
-
if (item.__class__.__name__ == 'GLAxisItem'):
|
|
106
|
-
self.followable_item_name.append(name)
|
|
107
|
-
self.setting_window.addSetting(name, item)
|
|
108
|
-
super().addItem(item)
|
|
109
|
-
|
|
110
|
-
def mouseReleaseEvent(self, ev):
|
|
111
|
-
if hasattr(self, 'mousePos'):
|
|
112
|
-
delattr(self, 'mousePos')
|
|
113
|
-
|
|
114
|
-
def mouseMoveEvent(self, ev):
|
|
115
|
-
lpos = ev.localPos()
|
|
116
|
-
if not hasattr(self, 'mousePos'):
|
|
117
|
-
self.mousePos = lpos
|
|
118
|
-
diff = lpos - self.mousePos
|
|
119
|
-
self.mousePos = lpos
|
|
120
|
-
if ev.buttons() == QtCore.Qt.MouseButton.RightButton:
|
|
121
|
-
self.orbit(-diff.x(), diff.y())
|
|
122
|
-
elif ev.buttons() == QtCore.Qt.MouseButton.LeftButton:
|
|
123
|
-
pitch_abs = np.abs(self.opts['elevation'])
|
|
124
|
-
camera_mode = 'view-upright'
|
|
125
|
-
if(pitch_abs <= 45.0 or pitch_abs == 90):
|
|
126
|
-
camera_mode = 'view'
|
|
127
|
-
self.pan(diff.x(), diff.y(), 0, relative=camera_mode)
|
|
128
|
-
|
|
129
|
-
def keyPressEvent(self, ev: QKeyEvent):
|
|
130
|
-
step = 10
|
|
131
|
-
zoom_delta = 20
|
|
132
|
-
speed = 2
|
|
133
|
-
self.projectionMatrix().data()
|
|
134
|
-
|
|
135
|
-
pitch_abs = np.abs(self.opts['elevation'])
|
|
136
|
-
camera_mode = 'view-upright'
|
|
137
|
-
if(pitch_abs <= 45.0 or pitch_abs == 90):
|
|
138
|
-
camera_mode = 'view'
|
|
139
|
-
|
|
140
|
-
if ev.key() == QtCore.Qt.Key_M: # setting meun
|
|
141
|
-
print("Open setting windows")
|
|
142
|
-
self.openSettingWindow()
|
|
143
|
-
elif ev.key() == QtCore.Qt.Key_R:
|
|
144
|
-
print("Clear viewer")
|
|
145
|
-
for item in self.named_items.values():
|
|
146
|
-
try:
|
|
147
|
-
item.clear()
|
|
148
|
-
except:
|
|
149
|
-
pass
|
|
150
|
-
elif ev.key() == QtCore.Qt.Key_Up:
|
|
151
|
-
if ev.modifiers() & QtCore.Qt.KeyboardModifier.ControlModifier:
|
|
152
|
-
self.pan(0, +step, 0, relative=camera_mode)
|
|
153
|
-
else:
|
|
154
|
-
self.orbit(azim=0, elev=-speed)
|
|
155
|
-
elif ev.key() == QtCore.Qt.Key_Down:
|
|
156
|
-
if ev.modifiers() & QtCore.Qt.KeyboardModifier.ControlModifier:
|
|
157
|
-
self.pan(0, -step, 0, relative=camera_mode)
|
|
158
|
-
else:
|
|
159
|
-
self.orbit(azim=0, elev=speed)
|
|
160
|
-
elif ev.key() == QtCore.Qt.Key_Left:
|
|
161
|
-
if ev.modifiers() & QtCore.Qt.KeyboardModifier.ControlModifier:
|
|
162
|
-
self.pan(+step, 0, 0, relative=camera_mode)
|
|
163
|
-
else:
|
|
164
|
-
self.orbit(azim=speed, elev=0)
|
|
165
|
-
|
|
166
|
-
elif ev.key() == QtCore.Qt.Key_Right:
|
|
167
|
-
if ev.modifiers() & QtCore.Qt.KeyboardModifier.ControlModifier:
|
|
168
|
-
self.pan(-step, 0, 0, relative=camera_mode)
|
|
169
|
-
else:
|
|
170
|
-
self.orbit(azim=-speed, elev=0)
|
|
171
|
-
|
|
172
|
-
elif ev.key() == QtCore.Qt.Key_Z:
|
|
173
|
-
self.opts['distance'] *= 0.999**(+zoom_delta)
|
|
174
|
-
elif ev.key() == QtCore.Qt.Key_X:
|
|
175
|
-
self.opts['distance'] *= 0.999**(-zoom_delta)
|
|
176
|
-
else:
|
|
177
|
-
super().keyPressEvent(ev)
|
|
178
|
-
|
|
179
|
-
def openSettingWindow(self):
|
|
180
|
-
if self.setting_window.isVisible():
|
|
181
|
-
self.setting_window.raise_()
|
|
182
|
-
|
|
183
|
-
else:
|
|
184
|
-
self.setting_window.show()
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
class Viewer(QMainWindow):
|
|
188
|
-
def __init__(self, name='Viewer', win_size=[1920, 1080], vw=ViewWidget):
|
|
189
|
-
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
|
190
|
-
super(Viewer, self).__init__()
|
|
191
|
-
self.vw = vw
|
|
192
|
-
self.setGeometry(0, 0, win_size[0], win_size[1])
|
|
193
|
-
self.initUI()
|
|
194
|
-
self.setWindowTitle(name)
|
|
195
|
-
|
|
196
|
-
def initUI(self):
|
|
197
|
-
centerWidget = QWidget()
|
|
198
|
-
self.setCentralWidget(centerWidget)
|
|
199
|
-
layout = QVBoxLayout()
|
|
200
|
-
centerWidget.setLayout(layout)
|
|
201
|
-
self.viewerWidget = self.vw()
|
|
202
|
-
layout.addWidget(self.viewerWidget, 1)
|
|
203
|
-
timer = QtCore.QTimer(self)
|
|
204
|
-
timer.setInterval(20) # period, in milliseconds
|
|
205
|
-
timer.timeout.connect(self.update)
|
|
206
|
-
self.viewerWidget.setCameraPosition(distance=40)
|
|
207
|
-
timer.start()
|
|
208
|
-
|
|
209
|
-
def addItems(self, named_items: dict):
|
|
210
|
-
for name, item in named_items.items():
|
|
211
|
-
self.viewerWidget.addItem(name, item)
|
|
212
|
-
|
|
213
|
-
def __getitem__(self, name: str):
|
|
214
|
-
if name in self.viewerWidget.named_items:
|
|
215
|
-
return self.viewerWidget.named_items[name]
|
|
216
|
-
else:
|
|
217
|
-
return None
|
|
218
|
-
|
|
219
|
-
def update(self):
|
|
220
|
-
# force update by timer
|
|
221
|
-
self.viewerWidget.update()
|
|
222
|
-
|
|
223
|
-
def closeEvent(self, _):
|
|
224
|
-
sys.exit(0)
|
|
225
|
-
|
|
226
|
-
def show(self):
|
|
227
|
-
self.viewerWidget.setting_window.addSetting("main win", self.viewerWidget)
|
|
228
|
-
super().show()
|
q3dviewer/cloud_viewer.py
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
from q3dviewer.custom_items import *
|
|
5
|
-
from q3dviewer.basic_window import *
|
|
6
|
-
from pypcd4 import PointCloud
|
|
7
|
-
|
|
8
|
-
class CloudViewer(Viewer):
|
|
9
|
-
def __init__(self):
|
|
10
|
-
super(CloudViewer, self).__init__(name="Cloud Viewer")
|
|
11
|
-
self.setAcceptDrops(True)
|
|
12
|
-
|
|
13
|
-
def dragEnterEvent(self, event):
|
|
14
|
-
if event.mimeData().hasUrls():
|
|
15
|
-
event.accept()
|
|
16
|
-
else:
|
|
17
|
-
event.ignore()
|
|
18
|
-
|
|
19
|
-
def dropEvent(self, event):
|
|
20
|
-
for url in event.mimeData().urls():
|
|
21
|
-
file_path = url.toLocalFile()
|
|
22
|
-
self.openCloudFile(file_path)
|
|
23
|
-
|
|
24
|
-
def openCloudFile(self, file):
|
|
25
|
-
cloud_item = self['cloud']
|
|
26
|
-
if cloud_item is None:
|
|
27
|
-
print("Can't find clouditem.")
|
|
28
|
-
return
|
|
29
|
-
if file.endswith('.pcd'):
|
|
30
|
-
pc = PointCloud.from_path(file).pc_data
|
|
31
|
-
if 'rgb' in pc.dtype.names:
|
|
32
|
-
color = pc["rgb"].astype(np.uint32)
|
|
33
|
-
cloud_item.setColorMode('RGB')
|
|
34
|
-
elif 'intensity' in pc.dtype.names:
|
|
35
|
-
color = pc["intensity"].astype(np.uint32)
|
|
36
|
-
cloud_item.setColorMode('I')
|
|
37
|
-
else:
|
|
38
|
-
color = pc['z'].astype(np.uint32)
|
|
39
|
-
cloud_item.setColorMode('#FFFFFF')
|
|
40
|
-
cloud = np.rec.fromarrays(
|
|
41
|
-
[np.stack([pc["x"], pc["y"], pc["z"]], axis=1), color],
|
|
42
|
-
dtype=cloud_item.data_type)
|
|
43
|
-
elif file.endswith('.npy'):
|
|
44
|
-
pc = np.load(file)
|
|
45
|
-
cloud = np.rec.fromarrays(
|
|
46
|
-
[np.stack([pc[:, 0], pc[:, 1], pc[:, 2]], axis=1), pc[:, 3].astype(np.uint32)],
|
|
47
|
-
dtype=cloud_item.data_type)
|
|
48
|
-
cloud_item.setData(data=cloud)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def main():
|
|
52
|
-
import argparse
|
|
53
|
-
parser = argparse.ArgumentParser()
|
|
54
|
-
parser.add_argument("--pcd", help="the pcd path")
|
|
55
|
-
args = parser.parse_args()
|
|
56
|
-
app = QApplication([])
|
|
57
|
-
viewer = CloudViewer()
|
|
58
|
-
cloud_item = CloudIOItem(size=1, alpha=0.1)
|
|
59
|
-
axis_item = GLAxisItem(size=0.5, width=5)
|
|
60
|
-
gird_item = GridItem(size=1000, spacing=20)
|
|
61
|
-
# viewer.viewerWidget.setBackgroundColor(255, 255, 255, 255)
|
|
62
|
-
|
|
63
|
-
viewer.addItems({'cloud': cloud_item, 'grid': gird_item, 'axis': axis_item})
|
|
64
|
-
|
|
65
|
-
if args.pcd:
|
|
66
|
-
pcd_fn = args.pcd
|
|
67
|
-
viewer.openCloudFile(pcd_fn)
|
|
68
|
-
|
|
69
|
-
viewer.show()
|
|
70
|
-
app.exec_()
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if __name__ == '__main__':
|
|
74
|
-
main()
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import pyqtgraph.opengl as gl
|
|
2
|
-
from OpenGL.GL import *
|
|
3
|
-
import numpy as np
|
|
4
|
-
from OpenGL.GL import shaders
|
|
5
|
-
from PIL import Image
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# Vertex and Fragment shader source code
|
|
9
|
-
vertex_shader_source = """
|
|
10
|
-
#version 330 core
|
|
11
|
-
layout(location = 0) in vec3 position;
|
|
12
|
-
layout(location = 1) in vec2 texCoord;
|
|
13
|
-
|
|
14
|
-
out vec2 TexCoord;
|
|
15
|
-
|
|
16
|
-
uniform mat4 view_matrix;
|
|
17
|
-
uniform mat4 project_matrix;
|
|
18
|
-
|
|
19
|
-
void main()
|
|
20
|
-
{
|
|
21
|
-
gl_Position = project_matrix * view_matrix * vec4(position, 1.0);
|
|
22
|
-
TexCoord = texCoord;
|
|
23
|
-
}
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
fragment_shader_source = """
|
|
27
|
-
#version 330 core
|
|
28
|
-
in vec2 TexCoord;
|
|
29
|
-
out vec4 color;
|
|
30
|
-
uniform sampler2D ourTexture;
|
|
31
|
-
void main()
|
|
32
|
-
{
|
|
33
|
-
color = texture(ourTexture, TexCoord);
|
|
34
|
-
}
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def set_uniform_mat4(shader, content, name):
|
|
39
|
-
content = content.T
|
|
40
|
-
glUniformMatrix4fv(
|
|
41
|
-
glGetUniformLocation(shader, name),
|
|
42
|
-
1,
|
|
43
|
-
GL_FALSE,
|
|
44
|
-
content.astype(np.float32)
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class GLCameraFrameItem(gl.GLGraphicsItem.GLGraphicsItem):
|
|
49
|
-
def __init__(self, T=np.eye(4), size=1, width=3, path=None):
|
|
50
|
-
gl.GLGraphicsItem.GLGraphicsItem.__init__(self)
|
|
51
|
-
self.size = size
|
|
52
|
-
self.width = width
|
|
53
|
-
self.T = T
|
|
54
|
-
self.path = path
|
|
55
|
-
|
|
56
|
-
def initializeGL(self):
|
|
57
|
-
# Rectangle vertices and texture coordinates
|
|
58
|
-
hsize = self.size / 2
|
|
59
|
-
self.vertices = np.array([
|
|
60
|
-
# positions # texture coords
|
|
61
|
-
[-hsize, -hsize, 0.0, 0.0, 0.0], # bottom-left
|
|
62
|
-
[hsize, -hsize, 0.0, 1.0, 0.0], # bottom-right
|
|
63
|
-
[hsize, hsize, 0.0, 1.0, 1.0], # top-right
|
|
64
|
-
[-hsize, hsize, 0.0, 0.0, 1.0], # top-left
|
|
65
|
-
[0, 0, -hsize * 0.66, 0.0, 0.0], # top-left
|
|
66
|
-
], dtype=np.float32)
|
|
67
|
-
|
|
68
|
-
R = self.T[:3, :3]
|
|
69
|
-
t = self.T[:3, 3]
|
|
70
|
-
self.vertices[:, :3] = (
|
|
71
|
-
R @ self.vertices[:, :3].T + t[:, np.newaxis]).T
|
|
72
|
-
|
|
73
|
-
self.focal_p = np.array([0, 0, hsize * 0.66])
|
|
74
|
-
|
|
75
|
-
indices = np.array([
|
|
76
|
-
0, 1, 2, # first triangle
|
|
77
|
-
2, 3, 0 # second triangle
|
|
78
|
-
], dtype=np.uint32)
|
|
79
|
-
|
|
80
|
-
self.vao = glGenVertexArrays(1)
|
|
81
|
-
vbo = glGenBuffers(1)
|
|
82
|
-
ebo = glGenBuffers(1)
|
|
83
|
-
|
|
84
|
-
glBindVertexArray(self.vao)
|
|
85
|
-
|
|
86
|
-
glBindBuffer(GL_ARRAY_BUFFER, vbo)
|
|
87
|
-
glBufferData(GL_ARRAY_BUFFER, self.vertices.itemsize *
|
|
88
|
-
5 * 4, self.vertices, GL_STATIC_DRAW)
|
|
89
|
-
|
|
90
|
-
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
|
|
91
|
-
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
|
92
|
-
indices.nbytes, indices, GL_STATIC_DRAW)
|
|
93
|
-
|
|
94
|
-
# Vertex positions
|
|
95
|
-
|
|
96
|
-
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
|
|
97
|
-
20, ctypes.c_void_p(0))
|
|
98
|
-
glEnableVertexAttribArray(0)
|
|
99
|
-
# Texture coordinates
|
|
100
|
-
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,
|
|
101
|
-
20, ctypes.c_void_p(12))
|
|
102
|
-
glEnableVertexAttribArray(1)
|
|
103
|
-
|
|
104
|
-
project_matrix = np.array(self._GLGraphicsItem__view.projectionMatrix().data(),
|
|
105
|
-
np.float32).reshape([4, 4]).T
|
|
106
|
-
# Compile shaders and create shader program
|
|
107
|
-
self.program = shaders.compileProgram(
|
|
108
|
-
shaders.compileShader(vertex_shader_source, GL_VERTEX_SHADER),
|
|
109
|
-
shaders.compileShader(fragment_shader_source, GL_FRAGMENT_SHADER),
|
|
110
|
-
)
|
|
111
|
-
glUseProgram(self.program)
|
|
112
|
-
set_uniform_mat4(self.program, project_matrix, 'project_matrix')
|
|
113
|
-
glUseProgram(0)
|
|
114
|
-
|
|
115
|
-
self.texture = glGenTextures(1)
|
|
116
|
-
glBindTexture(GL_TEXTURE_2D, self.texture)
|
|
117
|
-
|
|
118
|
-
# Load image
|
|
119
|
-
image = Image.open(self.path)
|
|
120
|
-
# image = image.transpose(Image.FLIP_TOP_BOTTOM)
|
|
121
|
-
img_data = image.convert("RGBA").tobytes()
|
|
122
|
-
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width,
|
|
123
|
-
image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)
|
|
124
|
-
glGenerateMipmap(GL_TEXTURE_2D)
|
|
125
|
-
glBindTexture(GL_TEXTURE_2D, 0)
|
|
126
|
-
glBindVertexArray(0)
|
|
127
|
-
|
|
128
|
-
def setTransform(self, T):
|
|
129
|
-
self.T = T
|
|
130
|
-
|
|
131
|
-
def paint(self):
|
|
132
|
-
self.view_matrix = np.array(
|
|
133
|
-
self._GLGraphicsItem__view.viewMatrix().data(), np.float32).reshape([4, 4]).T
|
|
134
|
-
project_matrix = np.array(self._GLGraphicsItem__view.projectionMatrix(
|
|
135
|
-
).data(), np.float32).reshape([4, 4]).T
|
|
136
|
-
|
|
137
|
-
glEnable(GL_DEPTH_TEST)
|
|
138
|
-
glEnable(GL_BLEND)
|
|
139
|
-
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
|
140
|
-
|
|
141
|
-
glUseProgram(self.program)
|
|
142
|
-
set_uniform_mat4(self.program, self.view_matrix, 'view_matrix')
|
|
143
|
-
set_uniform_mat4(self.program, project_matrix, 'project_matrix')
|
|
144
|
-
glBindVertexArray(self.vao)
|
|
145
|
-
glBindTexture(GL_TEXTURE_2D, self.texture)
|
|
146
|
-
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
|
|
147
|
-
glBindTexture(GL_TEXTURE_2D, 0)
|
|
148
|
-
glBindVertexArray(0)
|
|
149
|
-
glUseProgram(0)
|
|
150
|
-
|
|
151
|
-
glLineWidth(self.width)
|
|
152
|
-
glBegin(GL_LINES)
|
|
153
|
-
glColor4f(1, 1, 1, 1) # z is blue
|
|
154
|
-
glVertex3f(*self.vertices[0, :3])
|
|
155
|
-
glVertex3f(*self.vertices[1, :3])
|
|
156
|
-
glVertex3f(*self.vertices[1, :3])
|
|
157
|
-
glVertex3f(*self.vertices[2, :3])
|
|
158
|
-
glVertex3f(*self.vertices[2, :3])
|
|
159
|
-
glVertex3f(*self.vertices[3, :3])
|
|
160
|
-
glVertex3f(*self.vertices[3, :3])
|
|
161
|
-
glVertex3f(*self.vertices[0, :3])
|
|
162
|
-
glVertex3f(*self.vertices[4, :3])
|
|
163
|
-
glVertex3f(*self.vertices[0, :3])
|
|
164
|
-
glVertex3f(*self.vertices[4, :3])
|
|
165
|
-
glVertex3f(*self.vertices[1, :3])
|
|
166
|
-
glVertex3f(*self.vertices[4, :3])
|
|
167
|
-
glVertex3f(*self.vertices[2, :3])
|
|
168
|
-
glVertex3f(*self.vertices[4, :3])
|
|
169
|
-
glVertex3f(*self.vertices[3, :3])
|
|
170
|
-
glEnd()
|
|
171
|
-
|
|
172
|
-
glDisable(GL_DEPTH_TEST)
|
|
173
|
-
glDisable(GL_BLEND)
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import pyqtgraph.opengl as gl
|
|
2
|
-
from OpenGL.GL import *
|
|
3
|
-
import numpy as np
|
|
4
|
-
import threading
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class TrajectoryItem(gl.GLGridItem):
|
|
8
|
-
def __init__(self, width=1, color=(0, 1, 0, 1)):
|
|
9
|
-
super(TrajectoryItem, self).__init__()
|
|
10
|
-
self.width = width
|
|
11
|
-
self.buff = np.empty((0, 3), np.float32)
|
|
12
|
-
self.wait_add_data = None
|
|
13
|
-
self.mutex = threading.Lock()
|
|
14
|
-
self.CAPACITY = 100000
|
|
15
|
-
self.valid_buff_top = 0
|
|
16
|
-
self.color = color
|
|
17
|
-
|
|
18
|
-
def addSetting(self, layout):
|
|
19
|
-
pass
|
|
20
|
-
|
|
21
|
-
def setData(self, data, append=True):
|
|
22
|
-
self.mutex.acquire()
|
|
23
|
-
data = data.astype(np.float32).reshape(-1, 3)
|
|
24
|
-
if (append is False):
|
|
25
|
-
self.wait_add_data = data
|
|
26
|
-
self.add_buff_loc = 0
|
|
27
|
-
else:
|
|
28
|
-
if (self.wait_add_data is None):
|
|
29
|
-
self.wait_add_data = data
|
|
30
|
-
else:
|
|
31
|
-
self.wait_add_data = np.concatenate([self.wait_add_data, data])
|
|
32
|
-
self.add_buff_loc = self.valid_buff_top
|
|
33
|
-
self.mutex.release()
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def updateRenderBuffer(self):
|
|
37
|
-
if(self.wait_add_data is None):
|
|
38
|
-
return
|
|
39
|
-
self.mutex.acquire()
|
|
40
|
-
|
|
41
|
-
new_buff_top = self.add_buff_loc + self.wait_add_data.shape[0]
|
|
42
|
-
if new_buff_top > self.buff.shape[0]:
|
|
43
|
-
buff_capacity = self.buff.shape[0]
|
|
44
|
-
while (new_buff_top > buff_capacity):
|
|
45
|
-
buff_capacity += self.CAPACITY
|
|
46
|
-
self.buff = np.empty((buff_capacity, 3), np.float32)
|
|
47
|
-
self.buff[self.add_buff_loc:new_buff_top] = self.wait_add_data
|
|
48
|
-
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
|
|
49
|
-
glBufferData(GL_ARRAY_BUFFER, self.buff.nbytes, self.buff, GL_DYNAMIC_DRAW)
|
|
50
|
-
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
|
51
|
-
else:
|
|
52
|
-
self.buff[self.add_buff_loc:new_buff_top] = self.wait_add_data
|
|
53
|
-
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
|
|
54
|
-
glBufferSubData(GL_ARRAY_BUFFER, self.add_buff_loc * 12,
|
|
55
|
-
self.wait_add_data.shape[0] * 12, self.wait_add_data)
|
|
56
|
-
self.valid_buff_top = new_buff_top
|
|
57
|
-
self.wait_add_data = None
|
|
58
|
-
self.mutex.release()
|
|
59
|
-
|
|
60
|
-
def initializeGL(self):
|
|
61
|
-
self.vbo = glGenBuffers(1)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def paint(self):
|
|
65
|
-
self.setupGLState()
|
|
66
|
-
self.updateRenderBuffer()
|
|
67
|
-
glEnable(GL_BLEND)
|
|
68
|
-
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
|
69
|
-
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
|
|
70
|
-
glEnableClientState(GL_VERTEX_ARRAY)
|
|
71
|
-
glVertexPointer(3, GL_FLOAT, 0, None)
|
|
72
|
-
glLineWidth(self.width)
|
|
73
|
-
glColor4f(*self.color) # z is blue
|
|
74
|
-
|
|
75
|
-
glDrawArrays(GL_LINE_STRIP, 0, self.valid_buff_top)
|
|
76
|
-
glDisableClientState(GL_VERTEX_ARRAY)
|
|
77
|
-
|
|
78
|
-
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
|
79
|
-
glUseProgram(0)
|
q3dviewer/utils.py
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import time
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def matrix_to_quaternion(matrix):
|
|
6
|
-
trace = matrix[0, 0] + matrix[1, 1] + matrix[2, 2]
|
|
7
|
-
if trace > 0:
|
|
8
|
-
s = 0.5 / np.sqrt(trace + 1.0)
|
|
9
|
-
w = 0.25 / s
|
|
10
|
-
x = (matrix[2, 1] - matrix[1, 2]) * s
|
|
11
|
-
y = (matrix[0, 2] - matrix[2, 0]) * s
|
|
12
|
-
z = (matrix[1, 0] - matrix[0, 1]) * s
|
|
13
|
-
else:
|
|
14
|
-
if matrix[0, 0] > matrix[1, 1] and matrix[0, 0] > matrix[2, 2]:
|
|
15
|
-
s = 2.0 * np.sqrt(1.0 + matrix[0, 0] - matrix[1, 1] - matrix[2, 2])
|
|
16
|
-
w = (matrix[2, 1] - matrix[1, 2]) / s
|
|
17
|
-
x = 0.25 * s
|
|
18
|
-
y = (matrix[0, 1] + matrix[1, 0]) / s
|
|
19
|
-
z = (matrix[0, 2] + matrix[2, 0]) / s
|
|
20
|
-
elif matrix[1, 1] > matrix[2, 2]:
|
|
21
|
-
s = 2.0 * np.sqrt(1.0 + matrix[1, 1] - matrix[0, 0] - matrix[2, 2])
|
|
22
|
-
w = (matrix[0, 2] - matrix[2, 0]) / s
|
|
23
|
-
x = (matrix[0, 1] + matrix[1, 0]) / s
|
|
24
|
-
y = 0.25 * s
|
|
25
|
-
z = (matrix[1, 2] + matrix[2, 1]) / s
|
|
26
|
-
else:
|
|
27
|
-
s = 2.0 * np.sqrt(1.0 + matrix[2, 2] - matrix[0, 0] - matrix[1, 1])
|
|
28
|
-
w = (matrix[1, 0] - matrix[0, 1]) / s
|
|
29
|
-
x = (matrix[0, 2] + matrix[2, 0]) / s
|
|
30
|
-
y = (matrix[1, 2] + matrix[2, 1]) / s
|
|
31
|
-
z = 0.25 * s
|
|
32
|
-
return np.array([w, x, y, z])
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def quaternion_to_matrix(quaternion):
|
|
36
|
-
_EPS = np.finfo(float).eps * 4.0
|
|
37
|
-
q = np.array(quaternion[:4], dtype=np.float64, copy=True)
|
|
38
|
-
nq = np.dot(q, q)
|
|
39
|
-
if nq < _EPS:
|
|
40
|
-
return np.identity(4)
|
|
41
|
-
q *= np.sqrt(2.0 / nq)
|
|
42
|
-
q = np.outer(q, q)
|
|
43
|
-
return np.array((
|
|
44
|
-
(1.0-q[1, 1]-q[2, 2], q[0, 1]-q[2, 3], q[0, 2]+q[1, 3], 0.0),
|
|
45
|
-
(q[0, 1]+q[2, 3], 1.0-q[0, 0]-q[2, 2], q[1, 2]-q[0, 3], 0.0),
|
|
46
|
-
(q[0, 2]-q[1, 3], q[1, 2]+q[0, 3], 1.0-q[0, 0]-q[1, 1], 0.0),
|
|
47
|
-
(0.0, 0.0, 0.0, 1.0)
|
|
48
|
-
), dtype=np.float64)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def make_transform(pose, rotation):
|
|
52
|
-
transform = np.matrix(np.identity(4, dtype=np.float64))
|
|
53
|
-
transform = quaternion_to_matrix(rotation)
|
|
54
|
-
transform[0:3, 3] = np.transpose(pose)
|
|
55
|
-
return transform
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class FPSMonitor():
|
|
59
|
-
def __init__(self):
|
|
60
|
-
self.stamp_record = []
|
|
61
|
-
|
|
62
|
-
def count(self):
|
|
63
|
-
cur_stamp = time.time()
|
|
64
|
-
self.stamp_record.append(cur_stamp)
|
|
65
|
-
while len(self.stamp_record) > 0:
|
|
66
|
-
if(cur_stamp - self.stamp_record[0] > 1.):
|
|
67
|
-
self.stamp_record.pop(0)
|
|
68
|
-
else:
|
|
69
|
-
break
|
|
70
|
-
return len(self.stamp_record)
|
|
71
|
-
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: q3dviewer
|
|
3
|
-
Version: 1.0.8
|
|
4
|
-
Summary: UNKNOWN
|
|
5
|
-
Home-page: UNKNOWN
|
|
6
|
-
Author: UNKNOWN
|
|
7
|
-
Author-email: UNKNOWN
|
|
8
|
-
License: UNKNOWN
|
|
9
|
-
Platform: UNKNOWN
|
|
10
|
-
Requires-Dist: PyOpenGL
|
|
11
|
-
Requires-Dist: laspy
|
|
12
|
-
Requires-Dist: meshio
|
|
13
|
-
Requires-Dist: numpy
|
|
14
|
-
Requires-Dist: pillow
|
|
15
|
-
Requires-Dist: pye57
|
|
16
|
-
Requires-Dist: pypcd4
|
|
17
|
-
Requires-Dist: pyside6
|
|
18
|
-
|
|
19
|
-
UNKNOWN
|
|
20
|
-
|
|
21
|
-
|
q3dviewer-1.0.8.dist-info/RECORD
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
q3dviewer/__init__.py,sha256=rP5XX_x8g7hxIMqNHlU89BN4dt5MSvoYYwip68fCmhc,173
|
|
2
|
-
q3dviewer/base_glwidget.py,sha256=i1GOuPJMd_HeOu6-Y0mMe73tM4U0z1gdM-XOJszXGnM,8916
|
|
3
|
-
q3dviewer/base_item.py,sha256=-6GogOKrjVRSTszio9ELPDhehBaUlTyNaag2bUl81l8,1337
|
|
4
|
-
q3dviewer/basic_window.py,sha256=CFErOPRMysFcCqq3vhDsQ-xZzLArO3m1yABCTIhq5do,7946
|
|
5
|
-
q3dviewer/cloud_viewer.py,sha256=IxxrB6Sl6aPCr9P9QzKHGkMcDP_DjsBWbkmIbsAoIM4,2358
|
|
6
|
-
q3dviewer/gau_io.py,sha256=S6NmqL5vSMgHVxKR-eu4CWCqgZeWBJKYRoOMAwr8Xbo,5890
|
|
7
|
-
q3dviewer/glwidget.py,sha256=BwBxbok40cq705QBYjPbtckf-hbLxnKTxyA6nhaT1Ic,4772
|
|
8
|
-
q3dviewer/utils.py,sha256=evF0d-v17hbTmquC24fmMIp9CsXpUnSQZr4MVy2sfao,2426
|
|
9
|
-
q3dviewer/viewer.py,sha256=Rv_YMo-N2kibh4Bnaz0g32hEtNyn8WXRmoh7GTSPcJg,1708
|
|
10
|
-
q3dviewer/custom_items/__init__.py,sha256=gOiAxdjDaAnFL8YbqSEWWWOwUrJfvzP9JLR34sCB9-4,434
|
|
11
|
-
q3dviewer/custom_items/axis_item.py,sha256=8ZIzBH9rYFD9DWNAlshpJFBpSyXfMcv-eewjqlJ9GIE,4423
|
|
12
|
-
q3dviewer/custom_items/camera_frame_item.py,sha256=VBsr3Avly_YWXViIh4DJkGc_HJt227GeOYLpGtbYTOw,5605
|
|
13
|
-
q3dviewer/custom_items/cloud_io_item.py,sha256=gjK3n9WKB7JwxC93ijkweEHA5EezpgNJ8KO-PBaDKCs,2835
|
|
14
|
-
q3dviewer/custom_items/cloud_item.py,sha256=kkIpJky7-Bbry3yCUodsU08BCZqtRQD69-0EMCLKnUs,12571
|
|
15
|
-
q3dviewer/custom_items/frame_item.py,sha256=YTBOEeRWh95trhAlKoZ9LZ4I2x-A5JjOhNPp4OvD5E0,6983
|
|
16
|
-
q3dviewer/custom_items/gaussian_item.py,sha256=B0mYjlW83Kr6FUtZ6P_f40pjjiASPB8g3CSjMTnjsvY,9857
|
|
17
|
-
q3dviewer/custom_items/grid_item.py,sha256=U4nk16d5Dkbt6U9s23c9PIlG-wPwu15Ho0HsamDuyqM,3436
|
|
18
|
-
q3dviewer/custom_items/image_item.py,sha256=tJryUj5qxaGx1j7W0lbzx-JJmehMPSEqJXPnSkG4FOI,5529
|
|
19
|
-
q3dviewer/custom_items/line_item.py,sha256=ujl78wBlvcotghauAy7ILTa22P_fdrFzrH6RD4TvY3M,4401
|
|
20
|
-
q3dviewer/custom_items/text_item.py,sha256=nuHMVMQrwy50lNk9hxB94criFxbJJK-SYiK2fSXWUMQ,2158
|
|
21
|
-
q3dviewer/custom_items/trajectory_item.py,sha256=uoKQSrTs_m_m1M8iNAm3peiXnZ9uVPsYQLYas3Gksjg,2754
|
|
22
|
-
q3dviewer/shaders/cloud_frag.glsl,sha256=tbCsDUp9YlPe0hRWlFS724SH6TtMeLO-GVYROzEElZg,609
|
|
23
|
-
q3dviewer/shaders/cloud_vert.glsl,sha256=Vxgw-Zrr0knAK0z4qMXKML6IC4EbffKMwYN2TMXROoI,2117
|
|
24
|
-
q3dviewer/shaders/gau_frag.glsl,sha256=5_UY84tWDts59bxP8x4I-wgnzY8aGeGuo28wX--LW7E,975
|
|
25
|
-
q3dviewer/shaders/gau_prep.glsl,sha256=eCT9nm65uz32w8NaDjeGKhyAZh42Aea-QTwr3yQVr9U,7218
|
|
26
|
-
q3dviewer/shaders/gau_vert.glsl,sha256=NNbVhv_JyqZDK9iXAyBAcIHAtim7G9yWbC9IaUfTL1w,1666
|
|
27
|
-
q3dviewer/shaders/sort_by_key.glsl,sha256=CA2zOcbyDGYAJSJEUvgjUqNshg9NAehf8ipL3Jsv4qE,1097
|
|
28
|
-
q3dviewer/tools/__init__.py,sha256=01wG7BGM6VX0QyFBKsqPmyf2e-vrmV_N3-mo-VQ1VBg,20
|
|
29
|
-
q3dviewer/tools/cloud_viewer.py,sha256=lNvOD0XWDAfgdqc2aJGigcCJsaWUS4qxadjFwf59-OY,3861
|
|
30
|
-
q3dviewer/tools/example_viewer.py,sha256=yeVXT0k4-h1vTLKnGzWADZD3our6XUaYUTy0p5daTkE,959
|
|
31
|
-
q3dviewer/tools/gaussian_viewer.py,sha256=vIwWmiFhjNmknrEkBLzt2yiegeH7LP3OeNjnGM6GzaI,1633
|
|
32
|
-
q3dviewer/tools/lidar_calib.py,sha256=beQP6Z9NyW7ME6zCRAxH1RRSm5zMalcmlmF_HzJPLi8,10811
|
|
33
|
-
q3dviewer/tools/lidar_cam_calib.py,sha256=kYR41Eq3o7frHLIWqysHUvVbB29GC0sDLzUigwxG4n4,11539
|
|
34
|
-
q3dviewer/tools/ros_viewer.py,sha256=ARB3I5wohY3maP8dCu0O0hxObd6JFKuK2y7AApVgMWA,2551
|
|
35
|
-
q3dviewer/utils/__init__.py,sha256=irm8Z_bT8l9kzhoMlds2Dal8g4iw4vjmqNPZSs4W6e0,157
|
|
36
|
-
q3dviewer/utils/cloud_io.py,sha256=ttD8FJExdDhXB1Z0Ej9S939i8gcq4JfyqwLXVh8CEFw,11094
|
|
37
|
-
q3dviewer/utils/convert_ros_msg.py,sha256=sAoQfy3qLQKsIArBAVm8H--wlQXOcmkKK3-Ox9UCcrc,1686
|
|
38
|
-
q3dviewer/utils/gl_helper.py,sha256=dRY_kUqyPMr7NTcupUr6_VTvgnj53iE2C0Lk0-oFYsI,1435
|
|
39
|
-
q3dviewer/utils/maths.py,sha256=ghnZQYxQtAQonTqQOmfHAMdSluk0sO1Ps_9bL2vMeb8,5397
|
|
40
|
-
q3dviewer/utils/range_slider.py,sha256=jZJQL-uQgnpgLvtYSWpKTrJlLkt3aqNpaRQAePEpNd0,3174
|
|
41
|
-
q3dviewer-1.0.8.dist-info/LICENSE,sha256=81cMOyNfw8KLb1JnPYngGHJ5W83gSbZEBU9MEP3tl-E,1124
|
|
42
|
-
q3dviewer-1.0.8.dist-info/METADATA,sha256=36WLMFrKUX9e1GTT3s9QgIBgchCmF_7v2QzF4TiNJck,349
|
|
43
|
-
q3dviewer-1.0.8.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
|
|
44
|
-
q3dviewer-1.0.8.dist-info/entry_points.txt,sha256=2vsxH5_1WhM-DnDgY0TDbiAGFPFMfI0Wmfs_6iXEf4Y,317
|
|
45
|
-
q3dviewer-1.0.8.dist-info/top_level.txt,sha256=HFFDCbGu28txcGe2HPc46A7EPaguBa_b5oH7bufmxHM,10
|
|
46
|
-
q3dviewer-1.0.8.dist-info/RECORD,,
|
|
File without changes
|