q3dviewer 1.0.1__py3-none-any.whl → 1.0.3__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-1.0.1.dist-info → q3dviewer-1.0.3.dist-info}/METADATA +1 -1
- q3dviewer-1.0.3.dist-info/RECORD +5 -0
- q3dviewer-1.0.3.dist-info/top_level.txt +1 -0
- q3dviewer/__init__.py +0 -4
- q3dviewer/basic_viewer.py +0 -56
- q3dviewer/custom_items/__init__.py +0 -9
- q3dviewer/custom_items/axis_item.py +0 -73
- q3dviewer/custom_items/camera_frame_item.py +0 -173
- q3dviewer/custom_items/cloud_io_item.py +0 -83
- q3dviewer/custom_items/cloud_item.py +0 -297
- q3dviewer/custom_items/gaussian_item.py +0 -267
- q3dviewer/custom_items/grid_item.py +0 -37
- q3dviewer/custom_items/image_item.py +0 -169
- q3dviewer/custom_items/text_item.py +0 -53
- q3dviewer/custom_items/trajectory_item.py +0 -78
- q3dviewer/gau_io.py +0 -168
- q3dviewer/tools/__init__.py +0 -6
- q3dviewer/tools/cloud_viewer.py +0 -75
- q3dviewer/tools/example_viewer.py +0 -38
- q3dviewer/tools/gaussian_viewer.py +0 -55
- q3dviewer/tools/lidar_calib.py +0 -274
- q3dviewer/tools/lidar_cam_calib.py +0 -299
- q3dviewer/tools/mesh_viewer.py +0 -57
- q3dviewer/tools/ros_viewer.py +0 -102
- q3dviewer/utils.py +0 -146
- q3dviewer/viewer_widget.py +0 -183
- q3dviewer-1.0.1.dist-info/RECORD +0 -28
- q3dviewer-1.0.1.dist-info/top_level.txt +0 -1
- {q3dviewer-1.0.1.dist-info → q3dviewer-1.0.3.dist-info}/WHEEL +0 -0
- {q3dviewer-1.0.1.dist-info → q3dviewer-1.0.3.dist-info}/entry_points.txt +0 -0
|
@@ -1,169 +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 as PIL_Image
|
|
6
|
-
from PyQt5.QtWidgets import QLabel, QSpinBox
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# Vertex and Fragment shader source code
|
|
10
|
-
vertex_shader_source = """
|
|
11
|
-
#version 330 core
|
|
12
|
-
layout(location = 0) in vec3 position;
|
|
13
|
-
layout(location = 1) in vec2 texCoord;
|
|
14
|
-
|
|
15
|
-
out vec2 TexCoord;
|
|
16
|
-
|
|
17
|
-
uniform mat4 view_matrix;
|
|
18
|
-
uniform mat4 project_matrix;
|
|
19
|
-
|
|
20
|
-
void main()
|
|
21
|
-
{
|
|
22
|
-
gl_Position = vec4(position, 1.0);
|
|
23
|
-
TexCoord = texCoord;
|
|
24
|
-
}
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
fragment_shader_source = """
|
|
28
|
-
#version 330 core
|
|
29
|
-
in vec2 TexCoord;
|
|
30
|
-
out vec4 color;
|
|
31
|
-
uniform sampler2D ourTexture;
|
|
32
|
-
void main()
|
|
33
|
-
{
|
|
34
|
-
color = texture(ourTexture, TexCoord);
|
|
35
|
-
}
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def set_uniform_mat4(shader, content, name):
|
|
40
|
-
content = content.T
|
|
41
|
-
glUniformMatrix4fv(
|
|
42
|
-
glGetUniformLocation(shader, name),
|
|
43
|
-
1,
|
|
44
|
-
GL_FALSE,
|
|
45
|
-
content.astype(np.float32)
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class ImageItem(gl.GLGraphicsItem.GLGraphicsItem):
|
|
50
|
-
def __init__(self, pos=np.array([0, 0]), size=np.array([1280/2, 720/2])):
|
|
51
|
-
gl.GLGraphicsItem.GLGraphicsItem.__init__(self)
|
|
52
|
-
self.pos = pos # bottom-left
|
|
53
|
-
self.size = size
|
|
54
|
-
self.image = np.zeros((self.size[0], self.size[1], 4), dtype=np.uint8)
|
|
55
|
-
self.alpha = 255
|
|
56
|
-
|
|
57
|
-
def initializeGL(self):
|
|
58
|
-
# Rectangle vertices and texture coordinates
|
|
59
|
-
width = self._GLGraphicsItem__view.deviceWidth()
|
|
60
|
-
height = self._GLGraphicsItem__view.deviceHeight()
|
|
61
|
-
x0, y0 = self.pos
|
|
62
|
-
x1, y1 = self.pos + self.size
|
|
63
|
-
x0 = x0 / width * 2 - 1
|
|
64
|
-
y0 = y0 / height * 2 - 1
|
|
65
|
-
x1 = x1 / width * 2 - 1
|
|
66
|
-
y1 = y1 / height * 2 - 1
|
|
67
|
-
|
|
68
|
-
self.vertices = np.array([
|
|
69
|
-
# positions # texture coords
|
|
70
|
-
[x0, y0, 0.0, 0.0, 0.0], # bottom-left
|
|
71
|
-
[x1, y0, 0.0, 1.0, 0.0], # bottom-right
|
|
72
|
-
[x1, y1, 0.0, 1.0, 1.0], # top-right
|
|
73
|
-
[x0, y1, 0.0, 0.0, 1.0], # top-left
|
|
74
|
-
], dtype=np.float32)
|
|
75
|
-
|
|
76
|
-
indices = np.array([
|
|
77
|
-
0, 1, 2, # first triangle
|
|
78
|
-
2, 3, 0 # second triangle
|
|
79
|
-
], dtype=np.uint32)
|
|
80
|
-
|
|
81
|
-
self.vao = glGenVertexArrays(1)
|
|
82
|
-
vbo = glGenBuffers(1)
|
|
83
|
-
ebo = glGenBuffers(1)
|
|
84
|
-
|
|
85
|
-
glBindVertexArray(self.vao)
|
|
86
|
-
|
|
87
|
-
glBindBuffer(GL_ARRAY_BUFFER, vbo)
|
|
88
|
-
glBufferData(GL_ARRAY_BUFFER, self.vertices.itemsize *
|
|
89
|
-
5 * 4, self.vertices, GL_STATIC_DRAW)
|
|
90
|
-
|
|
91
|
-
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
|
|
92
|
-
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
|
93
|
-
indices.nbytes, indices, GL_STATIC_DRAW)
|
|
94
|
-
|
|
95
|
-
# Vertex positions
|
|
96
|
-
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
|
|
97
|
-
20, ctypes.c_void_p(0))
|
|
98
|
-
glEnableVertexAttribArray(0)
|
|
99
|
-
|
|
100
|
-
# Texture coordinates
|
|
101
|
-
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,
|
|
102
|
-
20, ctypes.c_void_p(12))
|
|
103
|
-
glEnableVertexAttribArray(1)
|
|
104
|
-
|
|
105
|
-
# Compile shaders and create shader program
|
|
106
|
-
self.program = shaders.compileProgram(
|
|
107
|
-
shaders.compileShader(vertex_shader_source, GL_VERTEX_SHADER),
|
|
108
|
-
shaders.compileShader(fragment_shader_source, GL_FRAGMENT_SHADER),
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
self.texture = glGenTextures(1)
|
|
112
|
-
glBindTexture(GL_TEXTURE_2D, self.texture)
|
|
113
|
-
glBindVertexArray(0)
|
|
114
|
-
|
|
115
|
-
def setData(self, data):
|
|
116
|
-
if isinstance(data, np.ndarray):
|
|
117
|
-
pass
|
|
118
|
-
elif isinstance(data, PIL_Image.Image):
|
|
119
|
-
data = np.array(data)
|
|
120
|
-
else:
|
|
121
|
-
print("not support image type")
|
|
122
|
-
raise NotImplementedError
|
|
123
|
-
|
|
124
|
-
if data.ndim == 2: # Grayscale image
|
|
125
|
-
data = np.stack((data,) * 3 + (np.ones_like(data) * 255,), axis=-1)
|
|
126
|
-
elif data.shape[-1] == 3: # RGB image
|
|
127
|
-
alpha_channel = np.ones((data.shape[0], data.shape[1], 1), dtype=data.dtype) * self.alpha
|
|
128
|
-
data = np.concatenate((data, alpha_channel), axis=-1)
|
|
129
|
-
self.image = data
|
|
130
|
-
|
|
131
|
-
def paint(self):
|
|
132
|
-
if self.image is not None:
|
|
133
|
-
img_data = self.image
|
|
134
|
-
img_data = np.flipud(img_data) # Flip the image vertically
|
|
135
|
-
img_data = img_data.tobytes()
|
|
136
|
-
glBindTexture(GL_TEXTURE_2D, self.texture)
|
|
137
|
-
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.image.shape[1],
|
|
138
|
-
self.image.shape[0], 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)
|
|
139
|
-
glGenerateMipmap(GL_TEXTURE_2D)
|
|
140
|
-
glBindTexture(GL_TEXTURE_2D, 0)
|
|
141
|
-
self.image = None
|
|
142
|
-
|
|
143
|
-
glEnable(GL_DEPTH_TEST)
|
|
144
|
-
glEnable(GL_BLEND)
|
|
145
|
-
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
|
146
|
-
|
|
147
|
-
glUseProgram(self.program)
|
|
148
|
-
glBindVertexArray(self.vao)
|
|
149
|
-
glBindTexture(GL_TEXTURE_2D, self.texture)
|
|
150
|
-
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
|
|
151
|
-
glBindTexture(GL_TEXTURE_2D, 0)
|
|
152
|
-
glBindVertexArray(0)
|
|
153
|
-
glUseProgram(0)
|
|
154
|
-
|
|
155
|
-
glDisable(GL_DEPTH_TEST)
|
|
156
|
-
glDisable(GL_BLEND)
|
|
157
|
-
|
|
158
|
-
def addSetting(self, layout):
|
|
159
|
-
label1 = QLabel("Set Alpha:")
|
|
160
|
-
layout.addWidget(label1)
|
|
161
|
-
box1 = QSpinBox()
|
|
162
|
-
box1.setSingleStep(1)
|
|
163
|
-
box1.setRange(0, 255)
|
|
164
|
-
box1.setValue(self.alpha)
|
|
165
|
-
box1.valueChanged.connect(self.setAlpha)
|
|
166
|
-
layout.addWidget(box1)
|
|
167
|
-
|
|
168
|
-
def setAlpha(self, alpha):
|
|
169
|
-
self.alpha = alpha
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
from pyqtgraph.Qt import QtCore
|
|
2
|
-
import pyqtgraph.opengl as gl
|
|
3
|
-
from OpenGL.GL import *
|
|
4
|
-
from PyQt5 import QtGui, QtCore
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class GL2DTextItem(gl.GLGraphicsItem.GLGraphicsItem):
|
|
8
|
-
"""Draws text over opengl 3D."""
|
|
9
|
-
|
|
10
|
-
def __init__(self, **kwds):
|
|
11
|
-
"""All keyword arguments are passed to setData()"""
|
|
12
|
-
gl.GLGraphicsItem.GLGraphicsItem.__init__(self)
|
|
13
|
-
glopts = kwds.pop('glOptions', 'additive')
|
|
14
|
-
self.setGLOptions(glopts)
|
|
15
|
-
self.pos = (100, 100)
|
|
16
|
-
self.color = QtCore.Qt.GlobalColor.white
|
|
17
|
-
self.text = ''
|
|
18
|
-
self.font = QtGui.QFont('Helvetica', 16)
|
|
19
|
-
self.setData(**kwds)
|
|
20
|
-
|
|
21
|
-
def setData(self, **kwds):
|
|
22
|
-
args = ['pos', 'color', 'text', 'size', 'font']
|
|
23
|
-
for k in kwds.keys():
|
|
24
|
-
if k not in args:
|
|
25
|
-
raise ValueError('Invalid keyword argument: %s (allowed arguments are %s)' % (k, str(args)))
|
|
26
|
-
for arg in args:
|
|
27
|
-
if arg in kwds:
|
|
28
|
-
value = kwds[arg]
|
|
29
|
-
if arg == 'pos':
|
|
30
|
-
self.pos = value
|
|
31
|
-
elif arg == 'color':
|
|
32
|
-
value = value
|
|
33
|
-
elif arg == 'font':
|
|
34
|
-
if isinstance(value, QtGui.QFont) is False:
|
|
35
|
-
raise TypeError('"font" must be QFont.')
|
|
36
|
-
elif arg == 'size':
|
|
37
|
-
self.font.setPointSize(value)
|
|
38
|
-
setattr(self, arg, value)
|
|
39
|
-
self.update()
|
|
40
|
-
|
|
41
|
-
def paint(self):
|
|
42
|
-
if len(self.text) < 1:
|
|
43
|
-
return
|
|
44
|
-
self.setupGLState()
|
|
45
|
-
|
|
46
|
-
text_pos = QtCore.QPointF(*self.pos)
|
|
47
|
-
painter = QtGui.QPainter(self.view())
|
|
48
|
-
painter.setPen(self.color)
|
|
49
|
-
painter.setFont(self.font)
|
|
50
|
-
painter.setRenderHints(QtGui.QPainter.RenderHint.Antialiasing | QtGui.QPainter.RenderHint.TextAntialiasing)
|
|
51
|
-
painter.drawText(text_pos, self.text)
|
|
52
|
-
painter.end()
|
|
53
|
-
|
|
@@ -1,78 +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
|
-
def updateRenderBuffer(self):
|
|
36
|
-
if (self.wait_add_data is None):
|
|
37
|
-
return
|
|
38
|
-
self.mutex.acquire()
|
|
39
|
-
|
|
40
|
-
new_buff_top = self.add_buff_loc + self.wait_add_data.shape[0]
|
|
41
|
-
if new_buff_top > self.buff.shape[0]:
|
|
42
|
-
buff_capacity = self.buff.shape[0]
|
|
43
|
-
while (new_buff_top > buff_capacity):
|
|
44
|
-
buff_capacity += self.CAPACITY
|
|
45
|
-
self.buff = np.empty((buff_capacity, 3), np.float32)
|
|
46
|
-
self.buff[self.add_buff_loc:new_buff_top] = self.wait_add_data
|
|
47
|
-
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
|
|
48
|
-
glBufferData(GL_ARRAY_BUFFER, self.buff.nbytes,
|
|
49
|
-
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
|
-
def paint(self):
|
|
64
|
-
self.setupGLState()
|
|
65
|
-
self.updateRenderBuffer()
|
|
66
|
-
glEnable(GL_BLEND)
|
|
67
|
-
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
|
68
|
-
glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
|
|
69
|
-
glEnableClientState(GL_VERTEX_ARRAY)
|
|
70
|
-
glVertexPointer(3, GL_FLOAT, 0, None)
|
|
71
|
-
glLineWidth(self.width)
|
|
72
|
-
glColor4f(*self.color) # z is blue
|
|
73
|
-
|
|
74
|
-
glDrawArrays(GL_LINE_STRIP, 0, self.valid_buff_top)
|
|
75
|
-
glDisableClientState(GL_VERTEX_ARRAY)
|
|
76
|
-
|
|
77
|
-
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
|
78
|
-
glUseProgram(0)
|
q3dviewer/gau_io.py
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
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/tools/__init__.py
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
from q3dviewer.tools.cloud_viewer import main as cloud_viewer
|
|
2
|
-
from q3dviewer.tools.ros_viewer import main as ros_viewer
|
|
3
|
-
from q3dviewer.tools.mesh_viewer import main as mesh_viewer
|
|
4
|
-
from q3dviewer.tools.gaussian_viewer import main as gaussian_viewer
|
|
5
|
-
from q3dviewer.tools.lidar_cam_calib import main as lidar_cam_calib
|
|
6
|
-
from q3dviewer.tools.lidar_calib import main as lidar_calib
|
q3dviewer/tools/cloud_viewer.py
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
from pypcd4 import PointCloud
|
|
5
|
-
import q3dviewer as q3d
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class CloudViewer(q3d.Viewer):
|
|
9
|
-
def __init__(self, **kwargs):
|
|
10
|
-
super(CloudViewer, self).__init__(**kwargs)
|
|
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),
|
|
47
|
-
pc[:, 3].astype(np.uint32)],
|
|
48
|
-
dtype=cloud_item.data_type)
|
|
49
|
-
cloud_item.setData(data=cloud)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def main():
|
|
53
|
-
import argparse
|
|
54
|
-
parser = argparse.ArgumentParser()
|
|
55
|
-
parser.add_argument("--pcd", help="the pcd path")
|
|
56
|
-
args = parser.parse_args()
|
|
57
|
-
app = q3d.QApplication(['Cloud Viewer'])
|
|
58
|
-
viewer = CloudViewer(name='Cloud Viewer')
|
|
59
|
-
cloud_item = q3d.CloudIOItem(size=1, alpha=0.1)
|
|
60
|
-
axis_item = q3d.GLAxisItem(size=0.5, width=5)
|
|
61
|
-
grid_item = q3d.GridItem(size=1000, spacing=20)
|
|
62
|
-
|
|
63
|
-
viewer.addItems(
|
|
64
|
-
{'cloud': cloud_item, 'grid': grid_item, 'axis': axis_item})
|
|
65
|
-
|
|
66
|
-
if args.pcd:
|
|
67
|
-
pcd_fn = args.pcd
|
|
68
|
-
viewer.openCloudFile(pcd_fn)
|
|
69
|
-
|
|
70
|
-
viewer.show()
|
|
71
|
-
app.exec_()
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if __name__ == '__main__':
|
|
75
|
-
main()
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
import threading
|
|
5
|
-
import time
|
|
6
|
-
import q3dviewer as q3d
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def update(viewer):
|
|
10
|
-
i = 0.0
|
|
11
|
-
while True:
|
|
12
|
-
i += 0.05
|
|
13
|
-
time.sleep(0.1)
|
|
14
|
-
viewer['traj'].setData(np.array([np.sin(i) * i, np.cos(i) * i, i]))
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def main():
|
|
18
|
-
app = q3d.QApplication([])
|
|
19
|
-
|
|
20
|
-
axis_item = q3d.GLAxisItem(size=0.5, width=5)
|
|
21
|
-
grid_item = q3d.GridItem(size=10, spacing=1)
|
|
22
|
-
traj_item = q3d.TrajectoryItem(width=2)
|
|
23
|
-
|
|
24
|
-
viewer = q3d.Viewer(name='example')
|
|
25
|
-
th = threading.Thread(target=update, args=(viewer, ))
|
|
26
|
-
th.start()
|
|
27
|
-
|
|
28
|
-
viewer.addItems({
|
|
29
|
-
'grid': grid_item,
|
|
30
|
-
'axis': axis_item,
|
|
31
|
-
'traj': traj_item})
|
|
32
|
-
|
|
33
|
-
viewer.show()
|
|
34
|
-
app.exec_()
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if __name__ == '__main__':
|
|
38
|
-
main()
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
import q3dviewer as q3d
|
|
5
|
-
from q3dviewer.gau_io import load_gs, rotate_gaussian
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class GuassianViewer(q3d.Viewer):
|
|
9
|
-
def __init__(self):
|
|
10
|
-
super(GuassianViewer, self).__init__(name="Guassian 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.openGuassianFile(file_path)
|
|
23
|
-
|
|
24
|
-
def openGuassianFile(self, file):
|
|
25
|
-
gau_item = self['gaussian']
|
|
26
|
-
if gau_item is None:
|
|
27
|
-
print("Can't find gaussianitem")
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
print("Try to load %s ..." % file)
|
|
31
|
-
gs = load_gs(file)
|
|
32
|
-
# convert camera optical frame (b) to camera frame (c).
|
|
33
|
-
Rcb = np.array([[0, -1, 0],
|
|
34
|
-
[0, 0, -1],
|
|
35
|
-
[1, 0, 0]]).T
|
|
36
|
-
gs = rotate_gaussian(Rcb, gs)
|
|
37
|
-
gs_data = gs.view(np.float32).reshape(gs.shape[0], -1)
|
|
38
|
-
gau_item.setData(gs_data=gs_data)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def main():
|
|
42
|
-
app = q3d.QApplication(['Guassian Viewer'])
|
|
43
|
-
viewer = GuassianViewer(name='Guassian Viewer')
|
|
44
|
-
|
|
45
|
-
grid_item = q3d.GridItem(size=1000, spacing=20)
|
|
46
|
-
gau_item = q3d.GaussianItem()
|
|
47
|
-
|
|
48
|
-
viewer.addItems({'grid': grid_item, 'gaussian': gau_item})
|
|
49
|
-
|
|
50
|
-
viewer.show()
|
|
51
|
-
app.exec_()
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if __name__ == '__main__':
|
|
55
|
-
main()
|