q3dviewer 1.0.7__py3-none-any.whl → 1.0.9__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.
@@ -0,0 +1,395 @@
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
+ import numpy as np
9
+ import q3dviewer as q3d
10
+ from PySide6.QtWidgets import QVBoxLayout, QListWidget, QListWidgetItem, QPushButton, QDoubleSpinBox, QCheckBox, QLineEdit, QMessageBox, QLabel, QHBoxLayout, QDockWidget, QWidget, QComboBox
11
+ from PySide6.QtCore import QTimer
12
+ from q3dviewer.tools.cloud_viewer import ProgressDialog, FileLoaderThread
13
+ from PySide6 import QtCore
14
+ from PySide6.QtGui import QKeyEvent
15
+ from q3dviewer import GLWidget
16
+ import imageio.v2 as imageio
17
+ import os
18
+
19
+
20
+ class KeyFrame:
21
+ def __init__(self, Twc, lin_vel=10, ang_vel=np.pi/3, stop_time=0):
22
+ self.Twc = Twc
23
+ self.lin_vel = lin_vel
24
+ self.ang_vel = ang_vel # rad/s
25
+ self.stop_time = stop_time
26
+ self.item = q3d.FrameItem(Twc, width=3, color='#0000FF')
27
+
28
+
29
+ class CustomGLWidget(GLWidget):
30
+ def __init__(self, viewer):
31
+ super().__init__()
32
+ self.viewer = viewer # Add a viewer handle
33
+
34
+ def keyPressEvent(self, ev: QKeyEvent):
35
+ if ev.key() == QtCore.Qt.Key_Space:
36
+ self.viewer.add_key_frame()
37
+ elif ev.key() == QtCore.Qt.Key_Delete:
38
+ self.viewer.del_key_frame()
39
+ elif ev.key() == QtCore.Qt.Key_C:
40
+ self.viewer.dock.show()
41
+ super().keyPressEvent(ev)
42
+
43
+ class CMMViewer(q3d.Viewer):
44
+ """
45
+ This class is a subclass of Viewer, which is used to create a cloud movie maker.
46
+ """
47
+ def __init__(self, **kwargs):
48
+ self.key_frames = []
49
+ self.video_path = os.path.join(os.path.expanduser("~"), "output.mp4")
50
+ super().__init__(**kwargs, gl_widget_class=lambda: CustomGLWidget(self))
51
+ # for drop cloud file
52
+ self.setAcceptDrops(True)
53
+
54
+ def add_control_panel(self, main_layout):
55
+ """
56
+ Add a control panel to the viewer.
57
+ """
58
+ # Create a vertical layout for the settings
59
+ setting_layout = QVBoxLayout()
60
+
61
+ # Buttons to add and delete key frames
62
+ add_button = QPushButton("Add Key Frame (Key Space)")
63
+ add_button.clicked.connect(self.add_key_frame)
64
+ setting_layout.addWidget(add_button)
65
+ del_button = QPushButton("Delete Key Frame (Key Delete)")
66
+ del_button.clicked.connect(self.del_key_frame)
67
+ setting_layout.addWidget(del_button)
68
+
69
+ # Add play/stop button
70
+ self.play_button = QPushButton("Play")
71
+ self.play_button.clicked.connect(self.toggle_playback)
72
+ setting_layout.addWidget(self.play_button)
73
+
74
+ # add a timer to play the frames
75
+ self.timer = QTimer()
76
+ self.timer.timeout.connect(self.play_frames)
77
+ self.current_frame_index = 0
78
+ self.is_playing = False
79
+ self.is_recording = False
80
+
81
+ # Add record checkbox
82
+ self.record_checkbox = QCheckBox("Record")
83
+ self.record_checkbox.stateChanged.connect(self.toggle_recording)
84
+ setting_layout.addWidget(self.record_checkbox)
85
+
86
+ # Add video path setting
87
+ video_path_layout = QHBoxLayout()
88
+ label_video_path = QLabel("Video Path:")
89
+ video_path_layout.addWidget(label_video_path)
90
+ self.video_path_edit = QLineEdit()
91
+ self.video_path_edit.setText(self.video_path)
92
+ self.video_path_edit.textChanged.connect(self.update_video_path)
93
+ video_path_layout.addWidget(self.video_path_edit)
94
+ setting_layout.addLayout(video_path_layout)
95
+
96
+ # Add codec setting
97
+ codec_layout = QHBoxLayout()
98
+ label_codec = QLabel("Codec:")
99
+ codec_layout.addWidget(label_codec)
100
+ self.codec_combo = QComboBox()
101
+ self.codec_combo.addItems(["mjpeg", "mpeg4", "libx264", "libx265"])
102
+ codec_layout.addWidget(self.codec_combo)
103
+ setting_layout.addLayout(codec_layout)
104
+
105
+ # Add a list of key frames
106
+ self.frame_list = QListWidget()
107
+ setting_layout.addWidget(self.frame_list)
108
+ self.frame_list.itemSelectionChanged.connect(self.on_select_frame)
109
+ self.installEventFilter(self)
110
+
111
+ # Add spin boxes for linear / angular velocity and stop time
112
+ self.lin_vel_spinbox = QDoubleSpinBox()
113
+ self.lin_vel_spinbox.setPrefix("Linear Velocity (m/s): ")
114
+ self.lin_vel_spinbox.setRange(0, 1000)
115
+ self.lin_vel_spinbox.valueChanged.connect(self.set_frame_lin_vel)
116
+ setting_layout.addWidget(self.lin_vel_spinbox)
117
+
118
+ self.lin_ang_spinbox = QDoubleSpinBox()
119
+ self.lin_ang_spinbox.setPrefix("Angular Velocity (deg/s): ")
120
+ self.lin_ang_spinbox.setRange(0, 360)
121
+ self.lin_ang_spinbox.valueChanged.connect(self.set_frame_ang_vel)
122
+ setting_layout.addWidget(self.lin_ang_spinbox)
123
+
124
+ self.stop_time_spinbox = QDoubleSpinBox()
125
+ self.stop_time_spinbox.setPrefix("Stop Time: ")
126
+ self.stop_time_spinbox.setRange(0, 100)
127
+ self.stop_time_spinbox.valueChanged.connect(self.set_frame_stop_time)
128
+ setting_layout.addWidget(self.stop_time_spinbox)
129
+
130
+ setting_layout.setAlignment(QtCore.Qt.AlignTop)
131
+
132
+ # Create a dock widget for the settings
133
+ dock_widget = QDockWidget("Settings", self)
134
+ dock_widget.setWidget(QWidget())
135
+ dock_widget.widget().setLayout(setting_layout)
136
+ self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock_widget)
137
+
138
+ # Add the dock widget to the main layout
139
+ main_layout.addWidget(dock_widget)
140
+ self.dock = dock_widget
141
+
142
+
143
+ def update_video_path(self, path):
144
+ self.video_path = path
145
+
146
+ def add_key_frame(self):
147
+ view_matrix = self.glwidget.view_matrix
148
+ # Get camera pose in world frame
149
+ Twc = np.linalg.inv(view_matrix)
150
+ # Add the key frame to the end of the list
151
+ if self.key_frames:
152
+ prev = self.key_frames[-1]
153
+ key_frame = KeyFrame(Twc,
154
+ lin_vel=prev.lin_vel,
155
+ ang_vel=prev.ang_vel)
156
+ else:
157
+ key_frame = KeyFrame(Twc)
158
+ self.key_frames.append(key_frame)
159
+ # visualize this key frame using FrameItem
160
+ self.glwidget.add_item(key_frame.item)
161
+ # move the camera back to 0.5 meter, let the user see the frame
162
+ self.glwidget.update_dist(0.5)
163
+ # Add the key frame to the Qt ListWidget
164
+ item = QListWidgetItem(f"Frame {len(self.key_frames)}")
165
+ self.frame_list.addItem(item)
166
+ self.frame_list.setCurrentRow(len(self.key_frames) - 1)
167
+
168
+ def del_key_frame(self):
169
+ current_index = self.frame_list.currentRow()
170
+ if current_index >= 0:
171
+ self.glwidget.remove_item(self.key_frames[current_index].item)
172
+ self.key_frames.pop(current_index)
173
+ self.frame_list.itemSelectionChanged.disconnect(self.on_select_frame)
174
+ self.frame_list.takeItem(current_index)
175
+ self.frame_list.itemSelectionChanged.connect(self.on_select_frame)
176
+ self.on_select_frame()
177
+ # Update frame labels
178
+ for i in range(len(self.key_frames)):
179
+ self.frame_list.item(i).setText(f"Frame {i + 1}")
180
+
181
+ def on_select_frame(self):
182
+ current = self.frame_list.currentRow()
183
+ for i, frame in enumerate(self.key_frames):
184
+ if i == current:
185
+ # Highlight the selected frame
186
+ frame.item.set_color('#FF0000')
187
+ frame.item.set_line_width(5)
188
+ # show current frame's parameters in the spinboxes
189
+ self.lin_vel_spinbox.setValue(frame.lin_vel)
190
+ self.lin_ang_spinbox.setValue(np.rad2deg(frame.ang_vel))
191
+ self.stop_time_spinbox.setValue(frame.stop_time)
192
+ else:
193
+ frame.item.set_color('#0000FF')
194
+ frame.item.set_line_width(3)
195
+
196
+ def set_frame_lin_vel(self, value):
197
+ current_index = self.frame_list.currentRow()
198
+ if current_index >= 0:
199
+ self.key_frames[current_index].lin_vel = value
200
+
201
+ def set_frame_ang_vel(self, value):
202
+ current_index = self.frame_list.currentRow()
203
+ if current_index >= 0:
204
+ self.key_frames[current_index].ang_vel = np.deg2rad(value)
205
+
206
+ def set_frame_stop_time(self, value):
207
+ current_index = self.frame_list.currentRow()
208
+ if current_index >= 0:
209
+ self.key_frames[current_index].stop_time = value
210
+
211
+ def create_frames(self):
212
+ """
213
+ Create the frames for playback by interpolating between key frames.
214
+ """
215
+ self.frames = []
216
+ dt = 1 / float(self.update_interval)
217
+ for i in range(len(self.key_frames) - 1):
218
+ current_frame = self.key_frames[i]
219
+ if current_frame.stop_time > 0:
220
+ num_steps = int(current_frame.stop_time / dt)
221
+ for j in range(num_steps):
222
+ self.frames.append([i, current_frame.Twc])
223
+ next_frame = self.key_frames[i + 1]
224
+ Ts = q3d.interpolate_pose(current_frame.Twc, next_frame.Twc,
225
+ current_frame.lin_vel,
226
+ current_frame.ang_vel,
227
+ dt)
228
+ for T in Ts:
229
+ self.frames.append([i, T])
230
+
231
+ print(f"Total frames: {len(self.frames)}")
232
+ print(f"Total time: {len(self.frames) * dt:.2f} seconds")
233
+
234
+ def toggle_playback(self):
235
+ if self.is_playing:
236
+ self.stop_playback()
237
+ else:
238
+ self.start_playback()
239
+
240
+ def start_playback(self):
241
+ if self.key_frames:
242
+ self.create_frames()
243
+ self.current_frame_index = 0
244
+ self.timer.start(self.update_interval) # Adjust the interval as needed
245
+ self.is_playing = True
246
+ self.play_button.setStyleSheet("")
247
+ self.play_button.setText("Stop")
248
+ self.record_checkbox.setEnabled(False)
249
+ if self.is_recording is True:
250
+ self.start_recording()
251
+
252
+ def stop_playback(self):
253
+ self.timer.stop()
254
+ self.is_playing = False
255
+ self.play_button.setStyleSheet("")
256
+ self.play_button.setText("Play")
257
+ self.record_checkbox.setEnabled(True)
258
+ self.frame_list.setCurrentRow(len(self.key_frames) - 1)
259
+ if self.is_recording:
260
+ self.stop_recording()
261
+
262
+ def play_frames(self):
263
+ """
264
+ callback function for the timer to play the frames
265
+ """
266
+ # play the frames
267
+ if self.current_frame_index < len(self.frames):
268
+ key_id, Tcw = self.frames[self.current_frame_index]
269
+ self.glwidget.set_view_matrix(np.linalg.inv(Tcw))
270
+ self.frame_list.setCurrentRow(key_id)
271
+ self.current_frame_index += 1
272
+ if self.is_recording:
273
+ self.record_frame()
274
+ else:
275
+ self.stop_playback()
276
+
277
+ def toggle_recording(self, state):
278
+ if state == 2:
279
+ self.is_recording = True
280
+ else:
281
+ self.is_recording = False
282
+
283
+ def start_recording(self):
284
+ self.is_recording = True
285
+ self.frames_to_record = []
286
+ video_path = self.video_path_edit.text()
287
+ codec = self.codec_combo.currentText()
288
+ self.play_button.setStyleSheet("background-color: red")
289
+ self.play_button.setText("Recording")
290
+ self.writer = imageio.get_writer(video_path,
291
+ fps=self.update_interval,
292
+ codec=codec) # quality=10
293
+ # disable the all the frame_item while recording
294
+ for frame in self.key_frames:
295
+ frame.item.hide()
296
+ self.dock.hide() # Hide the dock while recording
297
+
298
+ def stop_recording(self, save_movie=True):
299
+ self.is_recording = False
300
+ self.record_checkbox.setChecked(False)
301
+ # enable the all the frame_item after recording
302
+ for frame in self.key_frames:
303
+ frame.item.show()
304
+ if hasattr(self, 'writer') and save_movie:
305
+ self.writer.close()
306
+ self.show_save_message()
307
+ self.dock.show() # Show the dock when recording stops
308
+
309
+ def show_save_message(self):
310
+ msg_box = QMessageBox()
311
+ msg_box.setIcon(QMessageBox.Information)
312
+ msg_box.setWindowTitle("Video Saved")
313
+ msg_box.setText(f"Video saved to {self.video_path_edit.text()}")
314
+ msg_box.setStandardButtons(QMessageBox.Ok)
315
+ msg_box.exec()
316
+
317
+ def record_frame(self):
318
+ frame = self.glwidget.capture_frame()
319
+ # make sure the frame size is multiple of 16
320
+ height, width, _ = frame.shape
321
+ if height % 16 != 0 or width % 16 != 0:
322
+ frame = frame[:-(height % 16), :-(width % 16), :]
323
+ frame = np.ascontiguousarray(frame)
324
+ self.frames_to_record.append(frame)
325
+ try:
326
+ self.writer.append_data(frame)
327
+ except Exception as e:
328
+ print("Don't change the window size during recording.")
329
+ self.stop_recording(False) # Stop recording without saving
330
+ self.stop_playback()
331
+
332
+ def eventFilter(self, obj, event):
333
+ if event.type() == QtCore.QEvent.KeyPress:
334
+ if event.key() == QtCore.Qt.Key_Delete:
335
+ self.del_key_frame()
336
+ return True
337
+ return super().eventFilter(obj, event)
338
+
339
+ def dragEnterEvent(self, event):
340
+ if event.mimeData().hasUrls():
341
+ event.accept()
342
+ else:
343
+ event.ignore()
344
+
345
+ def dropEvent(self, event):
346
+ """
347
+ Overwrite the drop event to open the cloud file.
348
+ """
349
+ self.progress_dialog = ProgressDialog(self)
350
+ self.progress_dialog.show()
351
+ files = event.mimeData().urls()
352
+ self.progress_thread = FileLoaderThread(self, files)
353
+ self['cloud'].load(files[0].toLocalFile(), append=False)
354
+ self.progress_thread.progress.connect(self.file_loading_progress)
355
+ self.progress_thread.finished.connect(self.file_loading_finished)
356
+ self.progress_thread.start()
357
+
358
+ def file_loading_progress(self, value):
359
+ self.progress_dialog.set_value(value)
360
+
361
+ def file_loading_finished(self):
362
+ self.progress_dialog.close()
363
+
364
+ def open_cloud_file(self, file, append=False):
365
+ cloud_item = self['cloud']
366
+ if cloud_item is None:
367
+ print("Can't find clouditem.")
368
+ return
369
+ cloud = cloud_item.load(file, append=append)
370
+ center = np.nanmean(cloud['xyz'].astype(np.float64), axis=0)
371
+ self.glwidget.set_cam_position(pos=center)
372
+
373
+ def main():
374
+ import argparse
375
+ parser = argparse.ArgumentParser()
376
+ parser.add_argument("--path", help="the cloud file path")
377
+ args = parser.parse_args()
378
+ app = q3d.QApplication(['Film Maker'])
379
+ viewer = CMMViewer(name='Film Maker', update_interval=30)
380
+ cloud_item = q3d.CloudIOItem(size=0.1, point_type='SPHERE', alpha=0.5, depth_test=True)
381
+ grid_item = q3d.GridItem(size=1000, spacing=20)
382
+
383
+ viewer.add_items(
384
+ {'cloud': cloud_item, 'grid': grid_item})
385
+
386
+ if args.path:
387
+ pcd_fn = args.path
388
+ viewer.open_cloud_file(pcd_fn)
389
+
390
+ viewer.show()
391
+ app.exec()
392
+
393
+
394
+ if __name__ == '__main__':
395
+ main()
@@ -43,7 +43,7 @@ class CustomDoubleSpinBox(QDoubleSpinBox):
43
43
  return float(text)
44
44
 
45
45
 
46
- class ViewerWithPanel(q3d.Viewer):
46
+ class LiDARCalibViewer(q3d.Viewer):
47
47
  def __init__(self, **kwargs):
48
48
  self.t01 = np.array([0, 0, 0])
49
49
  self.R01 = np.eye(3)
@@ -51,15 +51,15 @@ class ViewerWithPanel(q3d.Viewer):
51
51
  self.radius = 0.2
52
52
  super().__init__(**kwargs)
53
53
 
54
- def init_ui(self):
55
- center_widget = QWidget()
56
- self.setCentralWidget(center_widget)
57
- main_layout = QHBoxLayout()
58
- center_widget.setLayout(main_layout)
59
-
54
+ def default_gl_setting(self, glwidget):
55
+ # Set camera position and background color
56
+ glwidget.set_bg_color('#ffffff')
57
+ glwidget.set_cam_position(distance=5)
58
+
59
+ def add_control_panel(self, main_layout):
60
60
  # Create a vertical layout for the settings
61
61
  setting_layout = QVBoxLayout()
62
-
62
+ setting_layout.setAlignment(QtCore.Qt.AlignTop)
63
63
  # Add XYZ spin boxes
64
64
  label_xyz = QLabel("Set XYZ:")
65
65
  setting_layout.addWidget(label_xyz)
@@ -135,19 +135,8 @@ class ViewerWithPanel(q3d.Viewer):
135
135
  self.box_pitch.valueChanged.connect(self.update_rpy)
136
136
  self.box_yaw.valueChanged.connect(self.update_rpy)
137
137
 
138
- # Add a stretch to push the widgets to the top
139
- setting_layout.addStretch(1)
140
-
141
- self.glwidget = q3d.GLWidget()
142
138
  main_layout.addLayout(setting_layout)
143
- main_layout.addWidget(self.glwidget, 1)
144
-
145
- timer = QtCore.QTimer(self)
146
- timer.setInterval(20) # period, in milliseconds
147
- timer.timeout.connect(self.update)
148
- self.glwidget.set_cam_position(distance=5)
149
- self.glwidget.set_bg_color('#ffffff')
150
- timer.start()
139
+
151
140
 
152
141
  def update_radius(self):
153
142
  self.radius = self.box_radius.value()
@@ -271,8 +260,8 @@ def main():
271
260
  args = parser.parse_args()
272
261
 
273
262
  app = q3d.QApplication(["LiDAR Calib"])
274
- viewer = ViewerWithPanel(name='LiDAR Calib')
275
- grid_item = q3d.GridItem(size=10, spacing=1, color=(0, 0, 0, 70))
263
+ viewer = LiDARCalibViewer(name='LiDAR Calib')
264
+ grid_item = q3d.GridItem(size=10, spacing=1, color='#00000040')
276
265
  scan0_item = q3d.CloudItem(
277
266
  size=2, alpha=1, color_mode='FLAT', color='#ff0000')
278
267
  scan1_item = q3d.CloudItem(
@@ -36,7 +36,7 @@ class CustomDoubleSpinBox(QDoubleSpinBox):
36
36
  return float(text)
37
37
 
38
38
 
39
- class ViewerWithPanel(q3d.Viewer):
39
+ class LidarCamViewer(q3d.Viewer):
40
40
  def __init__(self, **kwargs):
41
41
  # b: camera body frame
42
42
  # c: camera image frame
@@ -54,15 +54,15 @@ class ViewerWithPanel(q3d.Viewer):
54
54
  self.en_rgb = False
55
55
  super().__init__(**kwargs)
56
56
 
57
- def init_ui(self):
58
- center_widget = QWidget()
59
- self.setCentralWidget(center_widget)
60
- main_layout = QHBoxLayout()
61
- center_widget.setLayout(main_layout)
57
+ def default_gl_setting(self, glwidget):
58
+ # Set camera position and background color
59
+ glwidget.set_bg_color('#ffffff')
60
+ glwidget.set_cam_position(distance=5)
62
61
 
62
+ def add_control_panel(self, main_layout):
63
63
  # Create a vertical layout for the settings
64
64
  setting_layout = QVBoxLayout()
65
-
65
+ setting_layout.setAlignment(QtCore.Qt.AlignTop)
66
66
  # Add a checkbox for RGB
67
67
  self.checkbox_rgb = QCheckBox("Enable RGB Cloud")
68
68
  self.checkbox_rgb.setChecked(False)
@@ -148,19 +148,8 @@ class ViewerWithPanel(q3d.Viewer):
148
148
  self.box_pitch.valueChanged.connect(self.update_rpy)
149
149
  self.box_yaw.valueChanged.connect(self.update_rpy)
150
150
 
151
- # Add a stretch to push the widgets to the top
152
- setting_layout.addStretch(1)
153
-
154
- self.glwidget = q3d.GLWidget()
155
151
  main_layout.addLayout(setting_layout)
156
- main_layout.addWidget(self.glwidget, 1)
157
152
 
158
- timer = QtCore.QTimer(self)
159
- timer.setInterval(20) # period, in milliseconds
160
- timer.timeout.connect(self.update)
161
- self.glwidget.set_cam_position(distance=5)
162
- self.glwidget.set_bg_color('#ffffff')
163
- timer.start()
164
153
 
165
154
  def update_point_size(self):
166
155
  self.psize = self.box_psize.value()
@@ -292,8 +281,8 @@ def main():
292
281
  args = parser.parse_args()
293
282
 
294
283
  app = q3d.QApplication(['LiDAR Cam Calib'])
295
- viewer = ViewerWithPanel(name='LiDAR Cam Calib')
296
- grid_item = q3d.GridItem(size=10, spacing=1, color=(0, 0, 0, 70))
284
+ viewer = LidarCamViewer(name='LiDAR Cam Calib')
285
+ grid_item = q3d.GridItem(size=10, spacing=1, color='#00000040')
297
286
  scan_item = q3d.CloudItem(size=2, alpha=1, color_mode='I')
298
287
  img_item = q3d.ImageItem(pos=np.array([0, 0]), size=np.array([800, 600]))
299
288
  viewer.add_items({'scan': scan_item, 'grid': grid_item, 'img': img_item})
@@ -18,7 +18,7 @@ from q3dviewer.utils.convert_ros_msg import convert_pointcloud2_msg, convert_odo
18
18
  viewer = None
19
19
  point_num_per_scan = None
20
20
  color_mode = None
21
-
21
+ auto_set_color_mode = True
22
22
 
23
23
  def odom_cb(data):
24
24
  global viewer
@@ -29,16 +29,15 @@ def odom_cb(data):
29
29
  def scan_cb(data):
30
30
  global viewer
31
31
  global point_num_per_scan
32
+ global auto_set_color_mode
32
33
  cloud, fields, _ = convert_pointcloud2_msg(data)
33
34
  if (cloud.shape[0] > point_num_per_scan):
34
35
  idx = random.sample(range(cloud.shape[0]), point_num_per_scan)
35
36
  cloud = cloud[idx]
36
- color_mode = 'FLAT'
37
- if 'intensity' in fields:
38
- color_mode = 'I'
39
- if 'rgb' in fields:
40
- color_mode = 'RGB'
41
- viewer['map'].set_color_mode(color_mode)
37
+ if 'rgb' in fields and auto_set_color_mode:
38
+ print("Set color mode to RGB")
39
+ viewer['map'].set_color_mode('RGB')
40
+ auto_set_color_mode = False
42
41
  viewer['map'].set_data(data=cloud, append=True)
43
42
  viewer['scan'].set_data(data=cloud)
44
43
 
@@ -54,7 +53,7 @@ def main():
54
53
  global viewer
55
54
  global point_num_per_scan
56
55
  point_num_per_scan = 10000
57
- map_item = q3d.CloudIOItem(size=1, alpha=0.1, color_mode='RGB')
56
+ map_item = q3d.CloudIOItem(size=1, alpha=0.1, color_mode='I')
58
57
  scan_item = q3d.CloudItem(
59
58
  size=2, alpha=1, color_mode='FLAT', color='#ffffff')
60
59
  odom_item = q3d.AxisItem(size=0.5, width=5)