q3dviewer 1.1.0__py3-none-any.whl → 1.1.2__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 CHANGED
@@ -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(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(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)
@@ -107,7 +107,7 @@ class CMMViewer(q3d.Viewer):
107
107
  label_codec = QLabel("Codec:")
108
108
  codec_layout.addWidget(label_codec)
109
109
  self.codec_combo = QComboBox()
110
- self.codec_combo.addItems(["mjpeg", "mpeg4", "libx264", "libx265"])
110
+ self.codec_combo.addItems(["libx264", "mjpeg", "mpeg4", "libx265"])
111
111
  codec_layout.addWidget(self.codec_combo)
112
112
  setting_layout.addLayout(codec_layout)
113
113
 
@@ -143,6 +143,8 @@ class CMMViewer(q3d.Viewer):
143
143
  dock_widget = QDockWidget("Settings", self)
144
144
  dock_widget.setWidget(QWidget())
145
145
  dock_widget.widget().setLayout(setting_layout)
146
+ # Hide close and undock buttons, I don't want the user to close the dock
147
+ dock_widget.setFeatures(QDockWidget.DockWidgetMovable)
146
148
  self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock_widget)
147
149
 
148
150
  # Add the dock widget to the main layout
@@ -269,8 +271,8 @@ class CMMViewer(q3d.Viewer):
269
271
  self.current_frame_index = 0
270
272
  self.timer.start(self.update_interval) # Adjust the interval as needed
271
273
  self.is_playing = True
272
- self.play_button.setStyleSheet("")
273
- self.play_button.setText("Stop")
274
+ self.play_button.setStyleSheet("background-color: red")
275
+ self.play_button.setText("Playing")
274
276
  self.record_checkbox.setEnabled(False)
275
277
  if self.is_recording is True:
276
278
  self.start_recording()
@@ -308,14 +310,16 @@ class CMMViewer(q3d.Viewer):
308
310
 
309
311
  def start_recording(self):
310
312
  self.is_recording = True
311
- self.frames_to_record = []
313
+ self.prv_frame_shape = None
312
314
  video_path = self.video_path_edit.text()
313
315
  codec = self.codec_combo.currentText()
314
316
  self.play_button.setStyleSheet("background-color: red")
315
317
  self.play_button.setText("Recording")
316
318
  self.writer = imageio.get_writer(video_path,
317
319
  fps=self.update_interval,
318
- codec=codec) # quality=10
320
+ codec=codec,
321
+ quality=10,
322
+ pixelformat='yuvj420p')
319
323
  # disable the all the frame_item while recording
320
324
  for frame in self.key_frames:
321
325
  frame.item.hide()
@@ -323,6 +327,7 @@ class CMMViewer(q3d.Viewer):
323
327
 
324
328
  def stop_recording(self, save_movie=True):
325
329
  self.is_recording = False
330
+ self.prv_frame_shape = None
326
331
  self.record_checkbox.setChecked(False)
327
332
  # enable the all the frame_item after recording
328
333
  for frame in self.key_frames:
@@ -342,17 +347,27 @@ class CMMViewer(q3d.Viewer):
342
347
 
343
348
  def record_frame(self):
344
349
  frame = self.glwidget.capture_frame()
345
- # make sure the frame size is multiple of 16
350
+
351
+ # restart recording if the window size changes
352
+ if self.prv_frame_shape is not None and frame.shape != self.prv_frame_shape:
353
+ self.writer.close()
354
+ self.start_recording()
355
+ return
356
+ self.prv_frame_shape = frame.shape
357
+
346
358
  height, width, _ = frame.shape
347
- if height % 16 != 0 or width % 16 != 0:
348
- frame = frame[:-(height % 16), :-(width % 16), :]
349
- frame = np.ascontiguousarray(frame)
350
- self.frames_to_record.append(frame)
359
+ # Adjust frame dimensions to be multiples of 16
360
+ new_height = height - (height % 16)
361
+ new_width = width - (width % 16)
362
+ frame = frame[:new_height, :new_width, :]
363
+ frame = np.ascontiguousarray(frame)
351
364
  try:
352
365
  self.writer.append_data(frame)
353
366
  except Exception as e:
354
- print("Don't change the window size during recording.")
355
- self.stop_recording(False) # Stop recording without saving
367
+ # unexpected error, stop recording without saving
368
+ print("Error while recording:")
369
+ print(e)
370
+ self.stop_recording(False)
356
371
  self.stop_playback()
357
372
 
358
373
  def eventFilter(self, obj, event):
q3dviewer/utils.py ADDED
@@ -0,0 +1,71 @@
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,23 +1,25 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: q3dviewer
3
- Version: 1.1.0
3
+ Version: 1.1.2
4
4
  Summary: A library designed for quickly deploying a 3D viewer.
5
5
  Home-page: https://github.com/scomup/q3dviewer
6
6
  Author: Liu Yang
7
+ License: UNKNOWN
8
+ Platform: UNKNOWN
7
9
  Classifier: Programming Language :: Python :: 3
8
10
  Classifier: License :: OSI Approved :: MIT License
9
11
  Classifier: Operating System :: OS Independent
10
12
  Description-Content-Type: text/markdown
11
- License-File: LICENSE
12
- Requires-Dist: numpy
13
- Requires-Dist: pyside6
14
13
  Requires-Dist: PyOpenGL
15
- Requires-Dist: pillow
14
+ Requires-Dist: imageio
15
+ Requires-Dist: imageio[ffmpeg]
16
+ Requires-Dist: laspy
16
17
  Requires-Dist: meshio
17
- Requires-Dist: pypcd4
18
+ Requires-Dist: numpy
19
+ Requires-Dist: pillow
18
20
  Requires-Dist: pye57
19
- Requires-Dist: laspy
20
- Requires-Dist: imageio
21
+ Requires-Dist: pypcd4
22
+ Requires-Dist: pyside6
21
23
 
22
24
  ## q3dviewer
23
25
 
@@ -150,7 +152,7 @@ def main():
150
152
 
151
153
  # Create a viewer
152
154
  viewer = q3d.Viewer(name='example')
153
-
155
+
154
156
  # Add items to the viewer
155
157
  viewer.add_items({
156
158
  'grid': grid_item,
@@ -212,3 +214,4 @@ class YourItem(q3d.BaseItem):
212
214
  ```
213
215
 
214
216
  Enjoy using `q3dviewer`!
217
+
@@ -1,32 +1,34 @@
1
1
  q3dviewer/__init__.py,sha256=rP5XX_x8g7hxIMqNHlU89BN4dt5MSvoYYwip68fCmhc,173
2
- q3dviewer/base_glwidget.py,sha256=k4fVwV2A_0CS7zZgHargbKE7push-l2UN7rmr2Z9vFo,10916
2
+ q3dviewer/base_glwidget.py,sha256=tk8icQsRZ3OrSLkHvywmrxElk6jpMooLDZdbZ3sRLnk,11313
3
3
  q3dviewer/base_item.py,sha256=lzb04oRaS4rRJrAP6C1Bu4ugK237FgupMTB97zjNVFw,1768
4
- q3dviewer/gau_io.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
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
5
7
  q3dviewer/glwidget.py,sha256=im8hjVYEL0Zl7fOIHTQMJdWu7WNOHlvTdIDYjebz9WA,4940
8
+ q3dviewer/utils.py,sha256=evF0d-v17hbTmquC24fmMIp9CsXpUnSQZr4MVy2sfao,2426
6
9
  q3dviewer/viewer.py,sha256=LH1INLFhi6pRjzazzQJ0AWT4hgyXI6GnmqoJFUwUZVE,2517
7
10
  q3dviewer/custom_items/__init__.py,sha256=gOiAxdjDaAnFL8YbqSEWWWOwUrJfvzP9JLR34sCB9-4,434
8
11
  q3dviewer/custom_items/axis_item.py,sha256=PTBSf5DmQI8ieSinYjY_aC7P8q1nzE-2Vc2GNd1O3Os,2568
12
+ q3dviewer/custom_items/camera_frame_item.py,sha256=VBsr3Avly_YWXViIh4DJkGc_HJt227GeOYLpGtbYTOw,5605
9
13
  q3dviewer/custom_items/cloud_io_item.py,sha256=gjK3n9WKB7JwxC93ijkweEHA5EezpgNJ8KO-PBaDKCs,2835
10
- q3dviewer/custom_items/cloud_item.py,sha256=7r6s_j1qEUfLe70t-M68-oIrGRrPOUcZp18ML6jST0s,12542
14
+ q3dviewer/custom_items/cloud_item.py,sha256=s46TxNDw7E6DW3V-ek_PF7egB3kRbnqpOBNUKdaC8IY,12620
11
15
  q3dviewer/custom_items/frame_item.py,sha256=6BOM3MXi-Akv6KUXDC3QYEAXKxwk0Eo1KQn-F7jkqrQ,7559
12
16
  q3dviewer/custom_items/gaussian_item.py,sha256=CZoXMmj2JPFfMqu7v4q4dLUI2cg_WfE1DHWGXjEYn6M,9869
13
17
  q3dviewer/custom_items/grid_item.py,sha256=20n4TGm5YEaudhnEOCOk-HtsKwxVxaPr8YV36kO04yU,4802
14
18
  q3dviewer/custom_items/image_item.py,sha256=ctNR81fVgxkdl2n3U_TPFL6yn086UhNI_A9fFHgkc-4,5491
15
19
  q3dviewer/custom_items/line_item.py,sha256=u0oFN2iHzsRHtnbvyvC_iglEkCwEU2NnTuE536sKUAE,4348
16
20
  q3dviewer/custom_items/text_item.py,sha256=nuHMVMQrwy50lNk9hxB94criFxbJJK-SYiK2fSXWUMQ,2158
21
+ q3dviewer/custom_items/trajectory_item.py,sha256=uoKQSrTs_m_m1M8iNAm3peiXnZ9uVPsYQLYas3Gksjg,2754
17
22
  q3dviewer/shaders/cloud_frag.glsl,sha256=tbCsDUp9YlPe0hRWlFS724SH6TtMeLO-GVYROzEElZg,609
18
23
  q3dviewer/shaders/cloud_vert.glsl,sha256=Vxgw-Zrr0knAK0z4qMXKML6IC4EbffKMwYN2TMXROoI,2117
19
24
  q3dviewer/shaders/gau_frag.glsl,sha256=5_UY84tWDts59bxP8x4I-wgnzY8aGeGuo28wX--LW7E,975
20
25
  q3dviewer/shaders/gau_prep.glsl,sha256=eCT9nm65uz32w8NaDjeGKhyAZh42Aea-QTwr3yQVr9U,7218
21
26
  q3dviewer/shaders/gau_vert.glsl,sha256=NNbVhv_JyqZDK9iXAyBAcIHAtim7G9yWbC9IaUfTL1w,1666
22
27
  q3dviewer/shaders/sort_by_key.glsl,sha256=CA2zOcbyDGYAJSJEUvgjUqNshg9NAehf8ipL3Jsv4qE,1097
23
- q3dviewer/test/test_interpolation.py,sha256=rR_CXsYFLpn0zO0mHf_jL-naluDBMSky--FviOQga0Q,1657
24
- q3dviewer/test/test_rendering.py,sha256=gbTcu7-cg20DgC5Zoi17C1s5lBGLfAE1rW9biqPjRsA,2164
25
28
  q3dviewer/tools/__init__.py,sha256=01wG7BGM6VX0QyFBKsqPmyf2e-vrmV_N3-mo-VQ1VBg,20
26
- q3dviewer/tools/cinematographer.py,sha256=o_24SSQ4mF062QQ7Gv3i90v7fA79PcHLB03UHXufuEA,13950
27
29
  q3dviewer/tools/cloud_viewer.py,sha256=10f2LSWpmsXzxrGobXw188doVjJbgBfPoqZPUi35EtI,3867
28
30
  q3dviewer/tools/example_viewer.py,sha256=yeVXT0k4-h1vTLKnGzWADZD3our6XUaYUTy0p5daTkE,959
29
- q3dviewer/tools/film_maker.py,sha256=CC4RuK0bE_-0kcdU6xyzqR47pB4TEcm0g4LlDrFs3qY,16004
31
+ q3dviewer/tools/film_maker.py,sha256=KXl0H03vnS7eAFw7nSRvTG3J0Y7gYt6YFUYaoxJf3xM,16600
30
32
  q3dviewer/tools/gaussian_viewer.py,sha256=vIwWmiFhjNmknrEkBLzt2yiegeH7LP3OeNjnGM6GzaI,1633
31
33
  q3dviewer/tools/lidar_calib.py,sha256=M01bGg2mT8LwVcYybolr4UW_UUaR-f-BFciEHtjeK-w,10488
32
34
  q3dviewer/tools/lidar_cam_calib.py,sha256=SYNLDvi15MX7Q3aGn771fvu1cES9xeXgP0_WmDq33w4,11200
@@ -37,9 +39,9 @@ q3dviewer/utils/convert_ros_msg.py,sha256=sAoQfy3qLQKsIArBAVm8H--wlQXOcmkKK3-Ox9
37
39
  q3dviewer/utils/gl_helper.py,sha256=dRY_kUqyPMr7NTcupUr6_VTvgnj53iE2C0Lk0-oFYsI,1435
38
40
  q3dviewer/utils/maths.py,sha256=5TmjWUX1K3UjygXxrUsydjbo7tPzu0gD-yy7qtQUGBU,10588
39
41
  q3dviewer/utils/range_slider.py,sha256=jZJQL-uQgnpgLvtYSWpKTrJlLkt3aqNpaRQAePEpNd0,3174
40
- q3dviewer-1.1.0.dist-info/LICENSE,sha256=81cMOyNfw8KLb1JnPYngGHJ5W83gSbZEBU9MEP3tl-E,1124
41
- q3dviewer-1.1.0.dist-info/METADATA,sha256=hiWxWsKDWmCaXB-lJYhi-kutcydCeafxfzDSgeQv5Y8,6991
42
- q3dviewer-1.1.0.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
43
- q3dviewer-1.1.0.dist-info/entry_points.txt,sha256=aeUdGH7UIgMZEMFUc-0xPZWspY95GoPdZcZuLceq85g,361
44
- q3dviewer-1.1.0.dist-info/top_level.txt,sha256=HFFDCbGu28txcGe2HPc46A7EPaguBa_b5oH7bufmxHM,10
45
- q3dviewer-1.1.0.dist-info/RECORD,,
42
+ q3dviewer-1.1.2.dist-info/LICENSE,sha256=81cMOyNfw8KLb1JnPYngGHJ5W83gSbZEBU9MEP3tl-E,1124
43
+ q3dviewer-1.1.2.dist-info/METADATA,sha256=c8ONBUQAOF1v0UYF_6_w_vZ25fagwH-bL-k0Mj6x71I,7032
44
+ q3dviewer-1.1.2.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
45
+ q3dviewer-1.1.2.dist-info/entry_points.txt,sha256=EOjker7XYaBk70ffvNB_knPcfA33Bnlg21ZjEeM1EyI,362
46
+ q3dviewer-1.1.2.dist-info/top_level.txt,sha256=HFFDCbGu28txcGe2HPc46A7EPaguBa_b5oH7bufmxHM,10
47
+ q3dviewer-1.1.2.dist-info/RECORD,,
@@ -6,3 +6,4 @@ lidar_calib = q3dviewer.tools.lidar_calib:main
6
6
  lidar_cam_calib = q3dviewer.tools.lidar_cam_calib:main
7
7
  mesh_viewer = q3dviewer.tools.mesh_viewer:main
8
8
  ros_viewer = q3dviewer.tools.ros_viewer:main
9
+
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- """
4
- Copyright 2024 Panasonic Advanced Technology Development Co.,Ltd. (Liu Yang)
5
- Distributed under MIT license. See LICENSE for more information.
6
- """
7
-
8
- """
9
- this script tests interpolation of 3D poses.
10
- """
11
-
12
-
13
- import numpy as np
14
- from q3dviewer.utils.maths import expSO3, logSO3, makeT, makeRt
15
-
16
-
17
- def interpolate_pose(T1, T2, v_max, omega_max, dt=0.1):
18
- R1, t1 = makeRt(T1)
19
- R2, t2 = makeRt(T2)
20
-
21
- # Get transform time based on linear velocity
22
- d = np.linalg.norm(t2 - t1)
23
- t_lin = d / v_max
24
-
25
- # Get transform time based on angular velocity
26
- omega = logSO3(R2 @ R1.T)
27
- theta = np.linalg.norm(omega)
28
- t_ang = theta / omega_max
29
-
30
- # Get total time based on the linear and angular time
31
- t_total = max(t_lin, t_ang)
32
- num_steps = int(np.ceil(t_total / dt))
33
-
34
- # Generate interpolated transforms
35
- interpolated_Ts = []
36
- for i in range(num_steps + 1):
37
- s = i / num_steps
38
- t_interp = (1 - s) * t1 + s * t2
39
- # Interpolate rotation using SO3
40
- R_interp = expSO3(s * omega) @ R1
41
- T_interp = makeT(R_interp, t_interp)
42
- interpolated_Ts.append(T_interp)
43
-
44
- return interpolated_Ts
45
-
46
- if __name__ == "__main__":
47
- T1 = np.eye(4) # Identity transformation
48
- T2 = np.array([[0, -1, 0, 1], [1, 0, 0, 2], [0, 0, 1, 3], [0, 0, 0, 1]]) # Target transformation
49
-
50
- v_max = 1.0 # Maximum linear velocity (m/s)
51
- omega_max = np.pi / 4 # Maximum angular velocity (rad/s)
52
-
53
- # Perform interpolation
54
- interpolated_poses = interpolate_pose(T1, T2, v_max, omega_max)
55
- for i, T in enumerate(interpolated_poses):
56
- print(f"Step {i}:\n{T}\n")
57
-
58
-
@@ -1,72 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- """
4
- Copyright 2024 Panasonic Advanced Technology Development Co.,Ltd. (Liu Yang)
5
- Distributed under MIT license. See LICENSE for more information.
6
- """
7
-
8
- """
9
- this script tests the rendering of a cloud in a camera frame based on the
10
- camera pose and intrinsic matrix
11
- """
12
-
13
- import numpy as np
14
- import q3dviewer as q3d
15
- import cv2
16
-
17
- cloud, _ = q3d.load_pcd('/home/liu/lab.pcd')
18
-
19
-
20
- Tcw = np.array([[7.07106781e-01, 7.07106781e-01, 0.00000000e+00,
21
- 0.00000000e+00],
22
- [-3.53553391e-01, 3.53553391e-01, 8.66025404e-01,
23
- 3.55271368e-15],
24
- [6.12372436e-01, -6.12372436e-01, 5.00000000e-01,
25
- -4.00000000e+01],
26
- [0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
27
- 1.00000000e+00]])
28
- # convert the opengl camera coordinate to the opencv camera coordinate
29
- Tconv = np.array([[1, 0, 0, 0],
30
- [0, -1, 0, 0],
31
- [0, 0, -1, 0],
32
- [0, 0, 0, 1]])
33
-
34
- Tcw = Tconv @ Tcw
35
-
36
- K = np.array([[1.64718029e+03, 0.00000000e+00, 9.51000000e+02],
37
- [0.00000000e+00, 1.64718036e+03, 5.31000000e+02],
38
- [0.00000000e+00, 0.00000000e+00, 1.00000000e+00]])
39
-
40
-
41
- def render_frame(cloud, Tcw, K, width, height):
42
- image = np.zeros((height, width, 3), dtype=np.uint8)
43
- Rcw, tcw = Tcw[:3, :3], Tcw[:3, 3]
44
- pc = (Rcw @ cloud['xyz'].T).T + tcw
45
- uv = (K @ pc.T).T
46
- uv = uv[:, :2] / uv[:, 2][:, np.newaxis]
47
- mask = (pc[:, 2] > 0) & (uv[:, 0] > 0) & (
48
- uv[:, 0] < width) & (uv[:, 1] > 0) & (uv[:, 1] < height)
49
- uv = uv[mask]
50
- u = uv[:, 0].astype(int)
51
- v = uv[:, 1].astype(int)
52
- rgb = cloud['irgb'][mask]
53
- r = rgb >> 16 & 0xff
54
- g = rgb >> 8 & 0xff
55
- b = rgb & 0xff
56
-
57
- # Sort by depth to ensure front points are drawn first
58
- depth = pc[mask, 2]
59
- sorted_indices = np.argsort(depth)
60
- u = u[sorted_indices]
61
- v = v[sorted_indices]
62
- r = r[sorted_indices]
63
- g = g[sorted_indices]
64
- b = b[sorted_indices]
65
-
66
- image[v, u] = np.stack([b, g, r], axis=1)
67
- return image
68
-
69
-
70
- image = render_frame(cloud, Tcw, K, 1902, 1062)
71
- cv2.imshow('image', image)
72
- cv2.waitKey(0)