q3dviewer 1.0.8__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.
@@ -25,6 +25,9 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
25
25
  self.active_keys = set()
26
26
  self.show_center = False
27
27
  self.enable_show_center = True
28
+ self.view_need_update = True
29
+ self.view_matrix = self.get_view_matrix()
30
+ self.projection_matrix = self.get_projection_matrix()
28
31
 
29
32
  def keyPressEvent(self, ev: QtGui.QKeyEvent):
30
33
  if ev.key() == QtCore.Qt.Key_Up or \
@@ -87,15 +90,29 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
87
90
  """
88
91
  for item in self.items:
89
92
  item.initialize()
93
+ # initialize the projection matrix and model view matrix
94
+ self.projection_matrix = self.get_projection_matrix()
95
+ self.update_model_projection()
96
+ self.view_matrix = self.get_view_matrix()
97
+ self.update_model_view()
98
+
99
+ def set_view_matrix(self, view_matrix):
100
+ self.view_matrix = view_matrix
101
+ self.view_need_update = False
90
102
 
91
103
  def mouseReleaseEvent(self, ev):
92
104
  if hasattr(self, 'mousePos'):
93
105
  delattr(self, 'mousePos')
94
106
 
107
+ def set_dist(self, dist):
108
+ self.dist = dist
109
+ self.view_need_update = True
110
+
95
111
  def update_dist(self, delta):
96
112
  self.dist += delta
97
113
  if self.dist < 0.1:
98
114
  self.dist = 0.1
115
+ self.view_need_update = True
99
116
 
100
117
  def wheelEvent(self, ev):
101
118
  delta = ev.angleDelta().x()
@@ -121,17 +138,32 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
121
138
  dist = max(self.dist, 0.5)
122
139
  self.center += Rwc @ Kinv @ np.array([-diff.x(), diff.y(), 0]) * dist
123
140
  self.show_center = True
141
+ self.view_need_update = True
142
+
143
+ def set_center(self, center):
144
+ self.center = center
145
+ self.view_need_update = True
124
146
 
125
147
  def paintGL(self):
126
- pass
127
- self.update_model_projection()
148
+ # if the camera is moved, update the model view matrix.
149
+ if self.view_need_update:
150
+ self.view_matrix = self.get_view_matrix()
151
+ self.view_need_update = False
128
152
  self.update_model_view()
153
+
154
+ # set the background color
129
155
  bgcolor = self.color
130
156
  glClearColor(*bgcolor)
131
157
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT)
132
158
  for item in self.items:
133
159
  if not item.visible():
134
160
  continue
161
+ if not item.is_initialized():
162
+ """
163
+ The item may not be initialized if it is added
164
+ after the widget is shown, so we need to initialize it here.
165
+ """
166
+ item.initialize()
135
167
  glMatrixMode(GL_MODELVIEW)
136
168
  glPushMatrix()
137
169
  glPushAttrib(GL_ALL_ATTRIB_BITS)
@@ -189,11 +221,11 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
189
221
  self.center += Rz @ np.array([-trans_speed, 0, 0])
190
222
  if QtCore.Qt.Key_D in self.active_keys:
191
223
  self.center += Rz @ np.array([trans_speed, 0, 0])
224
+ self.view_need_update = True
192
225
 
193
226
  def update_model_view(self):
194
- m = self.get_view_matrix()
195
227
  glMatrixMode(GL_MODELVIEW)
196
- glLoadMatrixf(m.T)
228
+ glLoadMatrixf(self.view_matrix.T)
197
229
 
198
230
  def get_view_matrix(self):
199
231
  two = self.center # the origin(center) in the world frame
@@ -209,9 +241,9 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
209
241
  pos = kwargs.get('pos', None)
210
242
  distance = kwargs.get('distance', None)
211
243
  if pos is not None:
212
- self.center = pos
244
+ self.set_center(pos)
213
245
  if distance is not None:
214
- self.dist = distance
246
+ self.set_dist(distance)
215
247
 
216
248
  def set_color(self, color):
217
249
  self.color = color
@@ -221,9 +253,8 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
221
253
  super().update()
222
254
 
223
255
  def update_model_projection(self):
224
- m = self.get_projection_matrix()
225
256
  glMatrixMode(GL_PROJECTION)
226
- glLoadMatrixf(m.T)
257
+ glLoadMatrixf(self.projection_matrix.T)
227
258
 
228
259
  def get_projection_matrix(self):
229
260
  w, h = self.current_width(), self.current_height()
@@ -259,3 +290,17 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
259
290
 
260
291
  def change_show_center(self, state):
261
292
  self.enable_show_center = state
293
+
294
+ def resizeEvent(self, event):
295
+ super().resizeEvent(event)
296
+ self.projection_matrix = self.get_projection_matrix()
297
+ self.update_model_projection()
298
+
299
+ def capture_frame(self):
300
+ self.makeCurrent() # Ensure the OpenGL context is current
301
+ width = self.current_width()
302
+ height = self.current_height()
303
+ pixels = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)
304
+ frame = np.frombuffer(pixels, dtype=np.uint8).reshape(height, width, 3)
305
+ frame = np.flip(frame, 0)
306
+ return frame
q3dviewer/base_item.py CHANGED
@@ -16,6 +16,7 @@ class BaseItem(QtCore.QObject):
16
16
  self._glwidget = None
17
17
  self._visible = True
18
18
  self._initialized = False
19
+ self._disable_setting = False
19
20
 
20
21
  def set_glwidget(self, v):
21
22
  self._glwidget = v
@@ -38,6 +39,17 @@ class BaseItem(QtCore.QObject):
38
39
  def initialize(self):
39
40
  if not self._initialized:
40
41
  self.initialize_gl()
42
+ self._initialized = True
43
+
44
+ def is_initialized(self):
45
+ return self._initialized
46
+
47
+ def add_setting(self, layout):
48
+ """
49
+ Add setting widgets to the layout.
50
+ This method should be overridden by subclasses to add any necessary setting widgets to the layout.
51
+ """
52
+ pass
41
53
 
42
54
  def initialize_gl(self):
43
55
  """
@@ -53,5 +65,8 @@ class BaseItem(QtCore.QObject):
53
65
  """
54
66
  pass
55
67
 
68
+ def disable_setting(self):
69
+ self._disable_setting = True
70
+
56
71
 
57
72
 
@@ -4,44 +4,9 @@ Distributed under MIT license. See LICENSE for more information.
4
4
  """
5
5
 
6
6
  from q3dviewer.base_item import BaseItem
7
- from q3dviewer.utils import set_uniform
8
7
  from OpenGL.GL import *
9
8
  import numpy as np
10
- from OpenGL.GL import shaders
11
- from PySide6.QtWidgets import QLabel, QDoubleSpinBox
12
-
13
-
14
- # Vertex and Fragment shader source code
15
- vertex_shader_source = """
16
- #version 330 core
17
- layout(location = 0) in vec3 position;
18
- layout(location = 1) in vec3 color;
19
-
20
- out vec3 ourColor;
21
-
22
- uniform mat4 view_matrix;
23
- uniform mat4 project_matrix;
24
- uniform mat4 model_matrix;
25
- uniform float size;
26
-
27
- void main()
28
- {
29
- vec3 scaled_position = position * size;
30
- gl_Position = project_matrix * view_matrix * model_matrix * vec4(scaled_position, 1.0);
31
- ourColor = color;
32
- }
33
- """
34
-
35
- fragment_shader_source = """
36
- #version 330 core
37
- in vec3 ourColor;
38
- out vec4 color;
39
-
40
- void main()
41
- {
42
- color = vec4(ourColor, 1.0);
43
- }
44
- """
9
+ from PySide6.QtWidgets import QDoubleSpinBox
45
10
 
46
11
 
47
12
  class AxisItem(BaseItem):
@@ -53,72 +18,41 @@ class AxisItem(BaseItem):
53
18
  self.need_update_setting = True
54
19
 
55
20
  def initialize_gl(self):
56
- # Axis vertices and colors
21
+ # Axis vertices
57
22
  self.vertices = np.array([
58
- # positions # colors
59
- [0.0, 0.0, 0.0, 1.0, 0.0, 0.0], # X axis (red)
60
- [1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
61
- [0.0, 0.0, 0.0, 0.0, 1.0, 0.0], # Y axis (green)
62
- [0.0, 1.0, 0.0, 0.0, 1.0, 0.0],
63
- [0.0, 0.0, 0.0, 0.0, 0.0, 1.0], # Z axis (blue)
64
- [0.0, 0.0, 1.0, 0.0, 0.0, 1.0],
23
+ # positions
24
+ [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], # X axis
25
+ [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], # Y axis
26
+ [0.0, 0.0, 0.0], [0.0, 0.0, 1.0], # Z axis
65
27
  ], dtype=np.float32)
66
28
 
67
- self.vao = glGenVertexArrays(1)
68
- vbo = glGenBuffers(1)
69
-
70
- glBindVertexArray(self.vao)
71
-
72
- glBindBuffer(GL_ARRAY_BUFFER, vbo)
73
- glBufferData(GL_ARRAY_BUFFER, self.vertices.nbytes, self.vertices, GL_STATIC_DRAW)
74
-
75
- # Vertex positions
76
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(0))
77
- glEnableVertexAttribArray(0)
78
-
79
- # Vertex colors
80
- glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(12))
81
- glEnableVertexAttribArray(1)
82
-
83
- # Compile shaders and create shader program
84
- self.program = shaders.compileProgram(
85
- shaders.compileShader(vertex_shader_source, GL_VERTEX_SHADER),
86
- shaders.compileShader(fragment_shader_source, GL_FRAGMENT_SHADER),
87
- )
29
+ # Axis colors
30
+ self.colors = np.array([
31
+ [1.0, 0.0, 0.0], [1.0, 0.0, 0.0], # X axis (red)
32
+ [0.0, 1.0, 0.0], [0.0, 1.0, 0.0], # Y axis (green)
33
+ [0.0, 0.0, 1.0], [0.0, 0.0, 1.0], # Z axis (blue)
34
+ ], dtype=np.float32)
88
35
 
89
- glBindVertexArray(0)
90
36
 
91
37
  def add_setting(self, layout):
92
- label_size = QLabel("Set size:")
93
- layout.addWidget(label_size)
94
38
  spinbox_size = QDoubleSpinBox()
39
+ spinbox_size.setPrefix("Size: ")
95
40
  spinbox_size.setSingleStep(0.1)
96
- layout.addWidget(spinbox_size)
97
41
  spinbox_size.setValue(self.size)
98
- spinbox_size.valueChanged.connect(self.set_size)
99
42
  spinbox_size.setRange(0.0, 100)
43
+ spinbox_size.valueChanged.connect(self.set_size)
44
+ layout.addWidget(spinbox_size)
100
45
 
101
- label_width = QLabel("Set width:")
102
- layout.addWidget(label_width)
103
46
  spinbox_width = QDoubleSpinBox()
104
- layout.addWidget(spinbox_width)
47
+ spinbox_width.setPrefix("Width: ")
105
48
  spinbox_width.setSingleStep(0.1)
106
49
  spinbox_width.setValue(self.width)
107
- spinbox_width.valueChanged.connect(self.set_width)
108
50
  spinbox_width.setRange(0, 1000)
51
+ spinbox_width.valueChanged.connect(self.set_width)
52
+ layout.addWidget(spinbox_width)
109
53
 
110
54
  def set_size(self, size):
111
55
  self.size = size
112
- self.need_update_setting = True
113
-
114
- def update_setting(self):
115
- if not self.need_update_setting:
116
- return
117
- glUseProgram(self.program)
118
- set_uniform(self.program, float(self.size), 'size')
119
- set_uniform(self.program, self.T, 'model_matrix')
120
- glUseProgram(0)
121
- self.need_update_setting = False
122
56
 
123
57
  def set_width(self, width):
124
58
  self.width = width
@@ -131,18 +65,21 @@ class AxisItem(BaseItem):
131
65
  self.need_update_setting = True
132
66
 
133
67
  def paint(self):
134
- self.update_setting()
135
68
  glLineWidth(self.width)
136
- glUseProgram(self.program)
137
- glBindVertexArray(self.vao)
138
69
 
139
- view_matrix = self.glwidget().get_view_matrix()
140
- project_matrix = self.glwidget().get_projection_matrix()
141
- set_uniform(self.program, view_matrix, 'view_matrix')
142
- set_uniform(self.program, project_matrix, 'project_matrix')
70
+ glPushMatrix()
71
+ glMultMatrixf(self.T.T)
72
+
73
+ glEnableClientState(GL_VERTEX_ARRAY)
74
+ glVertexPointer(3, GL_FLOAT, 0, self.vertices * self.size)
75
+
76
+ glEnableClientState(GL_COLOR_ARRAY)
77
+ glColorPointer(3, GL_FLOAT, 0, self.colors)
78
+
79
+ glDrawArrays(GL_LINES, 0, len(self.vertices))
143
80
 
144
- glDrawArrays(GL_LINES, 0, 6)
81
+ glDisableClientState(GL_VERTEX_ARRAY)
82
+ glDisableClientState(GL_COLOR_ARRAY)
83
+ glPopMatrix()
145
84
 
146
- glBindVertexArray(0)
147
- glUseProgram(0)
148
85
  glLineWidth(1)
@@ -20,7 +20,11 @@ from PySide6.QtGui import QRegularExpressionValidator
20
20
 
21
21
  # draw points with color (x, y, z, color)
22
22
  class CloudItem(BaseItem):
23
- def __init__(self, size, alpha, color_mode='I', color='#ffffff', point_type='PIXEL'):
23
+ def __init__(self, size, alpha,
24
+ color_mode='I',
25
+ color='#ffffff',
26
+ point_type='PIXEL',
27
+ depth_test=False):
24
28
  super().__init__()
25
29
  self.STRIDE = 16 # stride of cloud array
26
30
  self.valid_buff_top = 0
@@ -42,11 +46,11 @@ class CloudItem(BaseItem):
42
46
  self.need_update_setting = True
43
47
  self.max_cloud_size = 300000000
44
48
  # Enable depth test when full opaque
45
- self.depth_test_enabled = (alpha == 1)
49
+ self.depth_test = depth_test
46
50
  self.path = os.path.dirname(__file__)
47
51
 
48
52
  def add_setting(self, layout):
49
- label_ptype = QLabel("Set point display type:")
53
+ label_ptype = QLabel("Point Type:")
50
54
  layout.addWidget(label_ptype)
51
55
  combo_ptype = QComboBox()
52
56
  combo_ptype.addItem("pixels")
@@ -55,26 +59,25 @@ class CloudItem(BaseItem):
55
59
  combo_ptype.setCurrentIndex(self.point_type_table[self.point_type])
56
60
  combo_ptype.currentIndexChanged.connect(self._on_point_type_selection)
57
61
  layout.addWidget(combo_ptype)
58
- self.label_size = QLabel("Set size: (pixel)")
59
- layout.addWidget(self.label_size)
62
+
60
63
  self.box_size = QDoubleSpinBox()
64
+ self.box_size.setPrefix("Size: ")
61
65
  self.box_size.setSingleStep(1)
62
66
  self.box_size.setDecimals(0)
63
- layout.addWidget(self.box_size)
64
67
  self.box_size.setValue(self.size)
65
- self.box_size.valueChanged.connect(self.set_size)
66
68
  self.box_size.setRange(0, 100)
69
+ self.box_size.valueChanged.connect(self.set_size)
70
+ layout.addWidget(self.box_size)
67
71
 
68
- label_alpha = QLabel("Set Alpha:")
69
- layout.addWidget(label_alpha)
70
72
  box_alpha = QDoubleSpinBox()
71
- layout.addWidget(box_alpha)
73
+ box_alpha.setPrefix("Alpha: ")
72
74
  box_alpha.setSingleStep(0.01)
73
75
  box_alpha.setValue(self.alpha)
74
- box_alpha.valueChanged.connect(self.set_alpha)
75
76
  box_alpha.setRange(0, 1)
77
+ box_alpha.valueChanged.connect(self.set_alpha)
78
+ layout.addWidget(box_alpha)
76
79
 
77
- label_color = QLabel("Set ColorMode:")
80
+ label_color = QLabel("Color Mode:")
78
81
  layout.addWidget(label_color)
79
82
  self.combo_color = QComboBox()
80
83
  self.combo_color.addItem("flat color")
@@ -84,6 +87,8 @@ class CloudItem(BaseItem):
84
87
  self.combo_color.currentIndexChanged.connect(self._on_color_mode)
85
88
  layout.addWidget(self.combo_color)
86
89
 
90
+ label_rgb = QLabel("Color:")
91
+ layout.addWidget(label_rgb)
87
92
  self.edit_rgb = QLineEdit()
88
93
  self.edit_rgb.setToolTip("Hex number, i.e. #FF4500")
89
94
  self.edit_rgb.setText(f"#{self.flat_rgb:06x}")
@@ -96,14 +101,11 @@ class CloudItem(BaseItem):
96
101
  self.slider_v = RangeSlider()
97
102
  self.slider_v.setRange(0, 255)
98
103
  self.slider_v.rangeChanged.connect(self._on_range)
99
-
100
104
  layout.addWidget(self.slider_v)
101
- self.combo_color.setCurrentIndex(self.color_mode)
102
105
 
103
- # Add a checkbox for enabling/disabling depth test
104
106
  self.checkbox_depth_test = QCheckBox(
105
107
  "Show front points first (Depth Test)")
106
- self.checkbox_depth_test.setChecked(self.depth_test_enabled)
108
+ self.checkbox_depth_test.setChecked(self.depth_test)
107
109
  self.checkbox_depth_test.stateChanged.connect(self.set_depthtest)
108
110
  layout.addWidget(self.checkbox_depth_test)
109
111
 
@@ -136,13 +138,13 @@ class CloudItem(BaseItem):
136
138
  def _on_point_type_selection(self, index):
137
139
  self.point_type = list(self.point_type_table.keys())[index]
138
140
  if self.point_type == 'PIXEL':
139
- self.label_size.setText("Set size: (pixel)")
141
+ self.box_size.setPrefix("Set size (pixel): ")
140
142
  self.box_size.setDecimals(0)
141
143
  self.box_size.setSingleStep(1)
142
144
  self.box_size.setValue(1)
143
145
  self.size = 1
144
146
  else:
145
- self.label_size.setText("Set size: (meter)")
147
+ self.box_size.setPrefix("Set size (meter): ")
146
148
  self.box_size.setDecimals(2)
147
149
  self.box_size.setSingleStep(0.01)
148
150
  self.box_size.setValue(0.01)
@@ -172,7 +174,7 @@ class CloudItem(BaseItem):
172
174
  self.need_update_setting = True
173
175
 
174
176
  def set_depthtest(self, state):
175
- self.depth_test_enabled = state
177
+ self.depth_test = state
176
178
 
177
179
  def clear(self):
178
180
  data = np.empty((0), self.data_type)
@@ -241,13 +243,17 @@ class CloudItem(BaseItem):
241
243
  self.buff = new_buff
242
244
 
243
245
  # if exceed the maximum cloud size, randomly select half of the points
244
- while self.buff.shape[0] >= self.max_cloud_size:
245
- print("[Cloud Item] Exceed maximum cloud size, reduce to half")
246
- new_buff = np.empty((self.buff.shape[0] // 2), self.data_type)
247
- indices = np.random.choice(new_buff_top, new_buff_top // 2, replace=False)
248
- new_buff = self.buff[indices]
249
- new_buff_top = new_buff_top // 2
250
- self.buff = new_buff
246
+ exceed_flag = False
247
+ while new_buff.shape[0] > self.max_cloud_size:
248
+ exceed_flag = True
249
+ new_buff_half = new_buff[:new_buff_top:2]
250
+ new_buff_top = new_buff_half.shape[0]
251
+ new_buff = new_buff_half
252
+ if exceed_flag:
253
+ print("[Cloud Item] Exceed maximum cloud size %d, reduce the data size" % self.max_cloud_size)
254
+ self.buff = self.buff[:self.max_cloud_size]
255
+ self.buff[:new_buff_top] = new_buff
256
+
251
257
 
252
258
  glBindBuffer(GL_ARRAY_BUFFER, self.vbo)
253
259
  glBufferData(GL_ARRAY_BUFFER, self.buff.nbytes,
@@ -281,7 +287,7 @@ class CloudItem(BaseItem):
281
287
  glEnable(GL_BLEND)
282
288
  glEnable(GL_PROGRAM_POINT_SIZE)
283
289
  glEnable(GL_POINT_SPRITE)
284
- if self.depth_test_enabled:
290
+ if self.depth_test:
285
291
  glEnable(GL_DEPTH_TEST)
286
292
  else:
287
293
  glDisable(GL_DEPTH_TEST)
@@ -296,9 +302,9 @@ class CloudItem(BaseItem):
296
302
  glEnableVertexAttribArray(0)
297
303
  glEnableVertexAttribArray(1)
298
304
 
299
- view_matrix = self.glwidget().get_view_matrix()
305
+ view_matrix = self.glwidget().view_matrix
300
306
  set_uniform(self.program, view_matrix, 'view_matrix')
301
- project_matrix = self.glwidget().get_projection_matrix()
307
+ project_matrix = self.glwidget().projection_matrix
302
308
  set_uniform(self.program, project_matrix, 'projection_matrix')
303
309
  width = self.glwidget().current_width()
304
310
  focal = project_matrix[0, 0] * width / 2
@@ -314,5 +320,5 @@ class CloudItem(BaseItem):
314
320
  glDisable(GL_POINT_SPRITE)
315
321
  glDisable(GL_PROGRAM_POINT_SIZE)
316
322
  glDisable(GL_BLEND)
317
- if self.depth_test_enabled:
323
+ if self.depth_test:
318
324
  glDisable(GL_DEPTH_TEST) # Disable depth testing if it was enabled
@@ -42,7 +42,7 @@ void main()
42
42
 
43
43
 
44
44
  class FrameItem(BaseItem):
45
- def __init__(self, T=np.eye(4), size=(1, 0.8), width=3, img=None):
45
+ def __init__(self, T=np.eye(4), size=(1, 0.8), width=3, img=None, color='#0000FF'):
46
46
  BaseItem.__init__(self)
47
47
  self.w, self.h = size
48
48
  self.width = width
@@ -50,6 +50,7 @@ class FrameItem(BaseItem):
50
50
  self.img = img
51
51
  self.texture = None
52
52
  self.need_updating = False
53
+ self.set_color(color)
53
54
 
54
55
  def initialize_gl(self):
55
56
  # Rectangle vertices and texture coordinates
@@ -57,11 +58,11 @@ class FrameItem(BaseItem):
57
58
  hh = self.h / 2
58
59
  self.vertices = np.array([
59
60
  # positions # texture coords
60
- [-hw, -hh, 0.0, 0.0, 0.0], # bottom-left
61
- [hw, -hh, 0.0, 1.0, 0.0], # bottom-right
62
- [hw, hh, 0.0, 1.0, 1.0], # top-right
63
- [-hw, hh, 0.0, 0.0, 1.0], # top-left
64
- [0, 0, -hh * 0.66, 0.0, 0.0], # top-left
61
+ [-hw, hh, 0.0, 0.0, 0.0], # bottom-left
62
+ [ hw, hh, 0.0, 1.0, 0.0], # bottom-right
63
+ [ hw, -hh, 0.0, 1.0, 1.0], # top-right
64
+ [-hw, -hh, 0.0, 0.0, 1.0], # top-left
65
+ [ 0.0, 0.0, hh * 0.66, 0.0, 0.0], # center -Z is the front.
65
66
  ], dtype=np.float32)
66
67
 
67
68
  self.indices = np.array([
@@ -123,23 +124,28 @@ class FrameItem(BaseItem):
123
124
 
124
125
  glBindVertexArray(0)
125
126
 
126
- def set_transform(self, T):
127
- self.T = T
128
-
129
- def set_data(self, img=None, transform=None):
127
+ def set_transform(self, Twc, is_opencv_coord=False):
128
+ if is_opencv_coord:
129
+ # convert the opencv camera coordinate to the opengl camera coordinate
130
+ M_conv = np.array([
131
+ [1, 0, 0, 0],
132
+ [0, -1, 0, 0],
133
+ [0, 0, -1, 0],
134
+ [0, 0, 0, 1]
135
+ ])
136
+ Twc = Twc @ M_conv
137
+ self.Twc = Twc
138
+
139
+ def set_data(self, img=None, transform=None, is_opencv_coord=False):
130
140
  if transform is not None:
131
- self.T = transform
141
+ self.set_transform(transform, is_opencv_coord)
132
142
  self.img = img
133
143
  self.need_updating = True
134
144
 
135
145
  def update_img_buffer(self):
136
- if self.img is not None and self.need_updating:
146
+ if self.need_updating:
137
147
  self.texture = glGenTextures(1)
138
148
  glBindTexture(GL_TEXTURE_2D, self.texture)
139
- # glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
140
- # glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
141
- # glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
142
- # glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
143
149
  if self.img.ndim == 2:
144
150
  # Convert grayscale to RGBA
145
151
  self.img = np.stack((self.img,) * 3 + (np.ones_like(self.img) * 255,), axis=-1)
@@ -147,44 +153,57 @@ class FrameItem(BaseItem):
147
153
  # Add an alpha channel
148
154
  alpha_channel = np.ones((self.img.shape[0], self.img.shape[1], 1), dtype=np.uint8) * 255
149
155
  self.img = np.concatenate((self.img, alpha_channel), axis=2)
150
-
151
156
  img = np.ascontiguousarray(self.img, dtype=np.uint8)
152
-
153
157
  # Load image
154
158
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.shape[1],
155
159
  img.shape[0], 0, GL_RGBA, GL_UNSIGNED_BYTE, img)
156
160
  glGenerateMipmap(GL_TEXTURE_2D)
157
161
  glBindTexture(GL_TEXTURE_2D, 0)
158
162
  self.need_updating = False
163
+
164
+ def set_color(self, color):
165
+ if isinstance(color, str):
166
+ self.rgba = hex_to_rgba(color)
167
+ elif isinstance(color, list):
168
+ self.rgba = color
169
+ elif isinstance(color, tuple):
170
+ self.rgba = list(color)
171
+ else:
172
+ raise ValueError("Invalid color format")
173
+
174
+ def set_line_width(self, width):
175
+ self.width = width
159
176
 
160
177
  def paint(self):
161
- self.view_matrix = self.glwidget().get_view_matrix()
162
- project_matrix = self.glwidget().get_projection_matrix()
163
- self.update_img_buffer()
178
+ self.view_matrix = self.glwidget().view_matrix
179
+ project_matrix = self.glwidget().projection_matrix
164
180
 
165
181
  glEnable(GL_DEPTH_TEST)
166
182
  glEnable(GL_BLEND)
167
183
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
168
184
 
169
- glUseProgram(self.program)
170
- set_uniform(self.program, self.view_matrix, 'view_matrix')
171
- set_uniform(self.program, project_matrix, 'project_matrix')
172
- set_uniform(self.program, self.T, 'model_matrix')
173
- glBindVertexArray(self.vao)
174
-
175
- if self.texture is not None:
176
- glBindTexture(GL_TEXTURE_2D, self.texture)
177
- glMultMatrixf(self.T.T) # Apply the transformation matrix
178
- glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
179
- glBindTexture(GL_TEXTURE_2D, 0)
185
+ if self.img is not None:
186
+ self.update_img_buffer()
187
+ glUseProgram(self.program)
188
+ set_uniform(self.program, self.view_matrix, 'view_matrix')
189
+ set_uniform(self.program, project_matrix, 'project_matrix')
190
+ set_uniform(self.program, self.T, 'model_matrix')
191
+ glBindVertexArray(self.vao)
192
+ glBindVertexArray(0)
193
+ glUseProgram(0)
194
+
195
+ # if self.texture is not None:
196
+ # glBindTexture(GL_TEXTURE_2D, self.texture)
197
+ # glMultMatrixf(self.T.T) # Apply the transformation matrix
198
+ # glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
199
+ # glBindTexture(GL_TEXTURE_2D, 0)
180
200
 
181
- glBindVertexArray(0)
182
- glUseProgram(0)
183
-
184
201
  glLineWidth(self.width)
185
- glColor4f(1, 1, 1, 1) # Set the color before drawing the lines
202
+ # set color to bule
203
+ glColor4f(*self.rgba)
186
204
  glBindBuffer(GL_ARRAY_BUFFER, self.line_vbo)
187
205
  glEnableClientState(GL_VERTEX_ARRAY)
206
+ glMultMatrixf(self.T.T)
188
207
  glVertexPointer(3, GL_FLOAT, 0, None)
189
208
  glDrawArrays(GL_LINES, 0, len(self.line_vertices))
190
209
  glDisableClientState(GL_VERTEX_ARRAY)
@@ -192,3 +211,4 @@ class FrameItem(BaseItem):
192
211
 
193
212
  glDisable(GL_DEPTH_TEST)
194
213
  glDisable(GL_BLEND)
214
+
@@ -35,8 +35,8 @@ class GaussianItem(BaseItem):
35
35
  self.sort = self.openg_sort
36
36
 
37
37
  def add_setting(self, layout):
38
- label1 = QLabel("set render mode:")
39
- layout.addWidget(label1)
38
+ label_render_mode = QLabel("Render Mode:")
39
+ layout.addWidget(label_render_mode)
40
40
  combo = QComboBox()
41
41
  combo.addItem("render normal guassian")
42
42
  combo.addItem("render ball")
@@ -168,7 +168,7 @@ class GaussianItem(BaseItem):
168
168
 
169
169
  def paint(self):
170
170
  # get current view matrix
171
- self.view_matrix = self.glwidget().get_view_matrix()
171
+ self.view_matrix = self.glwidget().view_matrix
172
172
 
173
173
  # if gaussian data is update, renew vao, ssbo, etc...
174
174
  self.updateGS()