q3dviewer 1.0.7__tar.gz → 1.1.1__tar.gz

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.
Files changed (52) hide show
  1. q3dviewer-1.1.1/LICENSE +21 -0
  2. q3dviewer-1.1.1/PKG-INFO +205 -0
  3. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/README.md +54 -25
  4. q3dviewer-1.1.1/pyproject.toml +26 -0
  5. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/base_glwidget.py +71 -10
  6. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/base_item.py +15 -0
  7. q3dviewer-1.1.1/q3dviewer/custom_items/axis_item.py +85 -0
  8. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/custom_items/cloud_item.py +43 -31
  9. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/custom_items/frame_item.py +56 -36
  10. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/custom_items/gaussian_item.py +3 -3
  11. q3dviewer-1.1.1/q3dviewer/custom_items/grid_item.py +139 -0
  12. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/custom_items/image_item.py +1 -2
  13. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/custom_items/line_item.py +4 -5
  14. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/glwidget.py +22 -17
  15. q3dviewer-1.1.1/q3dviewer/shaders/cloud_frag.glsl +28 -0
  16. q3dviewer-1.1.1/q3dviewer/shaders/cloud_vert.glsl +72 -0
  17. q3dviewer-1.1.1/q3dviewer/shaders/gau_frag.glsl +42 -0
  18. q3dviewer-1.1.1/q3dviewer/shaders/gau_prep.glsl +249 -0
  19. q3dviewer-1.1.1/q3dviewer/shaders/gau_vert.glsl +77 -0
  20. q3dviewer-1.1.1/q3dviewer/shaders/sort_by_key.glsl +56 -0
  21. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/tools/cloud_viewer.py +2 -2
  22. q3dviewer-1.1.1/q3dviewer/tools/film_maker.py +421 -0
  23. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/tools/lidar_calib.py +11 -22
  24. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/tools/lidar_cam_calib.py +9 -20
  25. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/tools/ros_viewer.py +7 -8
  26. q3dviewer-1.1.1/q3dviewer/utils/maths.py +318 -0
  27. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/viewer.py +30 -7
  28. q3dviewer-1.1.1/q3dviewer.egg-info/PKG-INFO +205 -0
  29. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer.egg-info/SOURCES.txt +9 -0
  30. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer.egg-info/entry_points.txt +1 -0
  31. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer.egg-info/requires.txt +2 -0
  32. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/setup.py +15 -2
  33. q3dviewer-1.0.7/PKG-INFO +0 -10
  34. q3dviewer-1.0.7/q3dviewer/custom_items/axis_item.py +0 -148
  35. q3dviewer-1.0.7/q3dviewer/custom_items/grid_item.py +0 -88
  36. q3dviewer-1.0.7/q3dviewer/utils/maths.py +0 -168
  37. q3dviewer-1.0.7/q3dviewer.egg-info/PKG-INFO +0 -10
  38. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/__init__.py +0 -0
  39. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/custom_items/__init__.py +0 -0
  40. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/custom_items/cloud_io_item.py +0 -0
  41. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/custom_items/text_item.py +0 -0
  42. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/tools/__init__.py +0 -0
  43. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/tools/example_viewer.py +0 -0
  44. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/tools/gaussian_viewer.py +0 -0
  45. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/utils/__init__.py +0 -0
  46. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/utils/cloud_io.py +0 -0
  47. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/utils/convert_ros_msg.py +0 -0
  48. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/utils/gl_helper.py +0 -0
  49. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer/utils/range_slider.py +0 -0
  50. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer.egg-info/dependency_links.txt +0 -0
  51. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/q3dviewer.egg-info/top_level.txt +0 -0
  52. {q3dviewer-1.0.7 → q3dviewer-1.1.1}/setup.cfg +0 -0
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright 2024 Panasonic Advanced Technology Development Co.,Ltd. (Liu Yang)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,205 @@
1
+ Metadata-Version: 2.1
2
+ Name: q3dviewer
3
+ Version: 1.1.1
4
+ Summary: A library designed for quickly deploying a 3D viewer.
5
+ Home-page: https://github.com/scomup/q3dviewer
6
+ Author: Liu Yang
7
+ License: UNKNOWN
8
+ Description: ## q3dviewer
9
+
10
+ `q3dviewer` is a library designed for quickly deploying a 3D viewer. It is based on Qt (PySide6) and provides efficient OpenGL items for displaying 3D objects (e.g., point clouds, cameras, and 3D Gaussians). You can use it to visualize your 3D data or set up an efficient viewer application. It is inspired by PyQtGraph but focuses more on efficient 3D rendering.
11
+
12
+ ## Installation
13
+
14
+ To install `q3dviewer`, execute the following command in your terminal on either Linux or Windows:
15
+
16
+ ```bash
17
+ pip install q3dviewer
18
+ ```
19
+
20
+ ### Note for Windows Users
21
+
22
+ - Ensure that you have a Python 3 environment set up:
23
+ - Download and install Python 3 from the [official Python website](https://www.python.org/downloads/).
24
+ - During installation, make sure to check the "Add Python to PATH" option.
25
+
26
+ ### Note for Linux Users
27
+
28
+ If you encounter an error related to loading the shared library `libxcb-cursor.so.0` on Ubuntu 20.04 or 22.04, please install `libxcb-cursor0`:
29
+
30
+ ```bash
31
+ sudo apt-get install libxcb-cursor0
32
+ ```
33
+
34
+ ## Tools
35
+
36
+ Once installed, you can directly use the following tools:
37
+
38
+ ### 1. Cloud Viewer
39
+
40
+ A tool for visualizing point cloud files. Launch it by executing the following command in your terminal:
41
+
42
+ ```sh
43
+ cloud_viewer # The viewer will be displayed
44
+ ```
45
+
46
+ *Alternatively*, if the path is not set (though it's not recommended):
47
+
48
+ ```sh
49
+ python3 -m q3dviewer.tools.cloud_viewer
50
+ ```
51
+
52
+ After the viewer launches, you can drag and drop files onto the window to display the point clouds. Multiple files can be dropped simultaneously to view them together. Supported formats include LAS, PCD, PLY, and E57.
53
+
54
+ For example, you can download and view point clouds of Tokyo in LAS format from the following link:
55
+
56
+ [Tokyo Point Clouds](https://www.geospatial.jp/ckan/dataset/tokyopc-23ku-2024/resource/7807d6d1-29f3-4b36-b0c8-f7aa0ea2cff3)
57
+
58
+ ![Cloud Viewer Screenshot](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/03c981c6-1aec-e5b9-4536-e07e1e56ff29.png)
59
+
60
+ Press `M` on your keyboard to display a menu on the screen, where you can modify visualization settings for each item. For example, you can adjust various settings such as shape, size, color, and transparency for `CloudItem`.
61
+
62
+ ![Cloud Viewer Settings](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/deeb996a-e419-58f4-6bc2-535099b1b73a.png)
63
+
64
+ ### 2. ROS Viewer
65
+
66
+ A high-performance SLAM viewer compatible with ROS, serving as an alternative to RVIZ.
67
+
68
+ ```sh
69
+ roscore &
70
+ ros_viewer
71
+ ```
72
+
73
+ ### 3. Film Maker
74
+
75
+ Would you like to create a video from point cloud data? With Film Maker, you can easily create videos with simple operations. Just edit keyframes using the user-friendly GUI, and the software will automatically interpolate the keyframes to generate the video.
76
+
77
+ ```sh
78
+ film_maker # drag and drop your cloud file to the window
79
+ ```
80
+
81
+ * Space key to add a keyframe.
82
+ * Delete key to remove a keyframe.
83
+
84
+ Film Maker GUI:
85
+
86
+ ![Screenshot from 2025-02-02 18-20-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/a1a6ad63-237c-482e-439d-e760223c59ca.png)
87
+
88
+ ### 4. Gaussian Viewer
89
+
90
+ A simple viewer for 3D Gaussians. See [EasyGaussianSplatting](https://github.com/scomup/EasyGaussianSplatting) for more information.
91
+
92
+ ```sh
93
+ gaussian_viewer # Drag and drop your Gaussian file onto the window
94
+ ```
95
+
96
+ ![Gaussian Viewer GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/441e6f5a-214d-f7c1-11bf-5fa79e63b38e.gif)
97
+
98
+ ### 5. LiDAR-LiDAR Calibration Tools
99
+
100
+ A tool to compute the relative pose between two LiDARs. It allows for both manual adjustment in the settings screen and automatic calibration.
101
+
102
+ ```sh
103
+ lidar_calib --lidar0=/YOUR_LIDAR0_TOPIC --lidar1=/YOUR_LIDAR1_TOPIC
104
+ ```
105
+
106
+ ![LiDAR Calibration](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/5a8a9903-a42a-8322-1d23-0cbecd3fa99a.png)
107
+
108
+ ### 6. LiDAR-Camera Calibration Tools
109
+
110
+ A tool for calculating the relative pose between a LiDAR and a camera. It allows for manual adjustment in the settings screen and real-time verification of LiDAR point projection onto images.
111
+
112
+ ```sh
113
+ lidar_cam_calib --lidar=/YOUR_LIDAR_TOPIC --camera=/YOUR_CAMERA_TOPIC --camera_info=/YOUR_CAMERA_INFO_TOPIC
114
+ ```
115
+
116
+ ![LiDAR-Camera Calibration](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/f8359820-2ae7-aa37-6577-0fa035f4dd95.png)
117
+
118
+ ## Using as a Library
119
+
120
+ Using the examples above, you can easily customize and develop your own 3D viewer with `q3dviewer`. Below is a coding example.
121
+
122
+ ### Custom 3D Viewer
123
+
124
+ ```python
125
+ #!/usr/bin/env python3
126
+
127
+ import q3dviewer as q3d # Import q3dviewer
128
+
129
+ def main():
130
+ # Create a Qt application
131
+ app = q3d.QApplication([])
132
+
133
+ # Create various 3D items
134
+ axis_item = q3d.AxisItem(size=0.5, width=5)
135
+ grid_item = q3d.GridItem(size=10, spacing=1)
136
+
137
+ # Create a viewer
138
+ viewer = q3d.Viewer(name='example')
139
+
140
+ # Add items to the viewer
141
+ viewer.add_items({
142
+ 'grid': grid_item,
143
+ 'axis': axis_item,
144
+ })
145
+
146
+ # Show the viewer & run the Qt application
147
+ viewer.show()
148
+ app.exec()
149
+
150
+ if __name__ == '__main__':
151
+ main()
152
+ ```
153
+
154
+ `q3dviewer` provides the following 3D items:
155
+
156
+ - **AxisItem**: Displays coordinate axes or the origin position.
157
+ - **CloudItem**: Displays point clouds.
158
+ - **CloudIOItem**: Displays point clouds with input/output capabilities.
159
+ - **GaussianItem**: Displays 3D Gaussians.
160
+ - **GridItem**: Displays grids.
161
+ - **ImageItem**: Displays 2D images.
162
+ - **Text2DItem**: Displays 2D text.
163
+ - **LineItem**: Displays lines or trajectories.
164
+
165
+ ### Developing Custom Items
166
+
167
+ In addition to the standard 3D items provided, you can visualize custom 3D items with simple coding. Below is a sample:
168
+
169
+ ```python
170
+ from OpenGL.GL import *
171
+ import numpy as np
172
+ import q3dviewer as q3d
173
+ from PySide6.QtWidgets import QLabel, QSpinBox
174
+
175
+ class YourItem(q3d.BaseItem):
176
+ def __init__(self):
177
+ super(YourItem, self).__init__()
178
+ # Necessary initialization
179
+
180
+ def add_setting(self, layout):
181
+ # Initialize the settings screen
182
+ label = QLabel("Add your setting:")
183
+ layout.addWidget(label)
184
+ box = QSpinBox()
185
+ layout.addWidget(box)
186
+
187
+ def set_data(self, data):
188
+ # Obtain the data you want to visualize
189
+ pass
190
+
191
+ def initialize_gl(self):
192
+ # OpenGL initialization settings (if needed)
193
+ pass
194
+
195
+ def paint(self):
196
+ # Visualize 3D objects using OpenGL
197
+ pass
198
+ ```
199
+
200
+ Enjoy using `q3dviewer`!
201
+ Platform: UNKNOWN
202
+ Classifier: Programming Language :: Python :: 3
203
+ Classifier: License :: OSI Approved :: MIT License
204
+ Classifier: Operating System :: OS Independent
205
+ Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  ## q3dviewer
2
2
 
3
- `q3dviewer` is a library designed for quickly deploying a 3D viewer. It is based on Qt (pyside6) and provides efficient OpenGL items for displaying 3D objects (e.g., point clouds, cameras, and 3D Gaussians). You can use it to visualize your 3D data or set up an efficient viewer application. It is inspired by PyQtGraph, but it focuses more on efficient 3D rendering.
3
+ `q3dviewer` is a library designed for quickly deploying a 3D viewer. It is based on Qt (PySide6) and provides efficient OpenGL items for displaying 3D objects (e.g., point clouds, cameras, and 3D Gaussians). You can use it to visualize your 3D data or set up an efficient viewer application. It is inspired by PyQtGraph but focuses more on efficient 3D rendering.
4
4
 
5
5
  ## Installation
6
6
 
@@ -16,6 +16,14 @@ pip install q3dviewer
16
16
  - Download and install Python 3 from the [official Python website](https://www.python.org/downloads/).
17
17
  - During installation, make sure to check the "Add Python to PATH" option.
18
18
 
19
+ ### Note for Linux Users
20
+
21
+ If you encounter an error related to loading the shared library `libxcb-cursor.so.0` on Ubuntu 20.04 or 22.04, please install `libxcb-cursor0`:
22
+
23
+ ```bash
24
+ sudo apt-get install libxcb-cursor0
25
+ ```
26
+
19
27
  ## Tools
20
28
 
21
29
  Once installed, you can directly use the following tools:
@@ -26,44 +34,61 @@ A tool for visualizing point cloud files. Launch it by executing the following c
26
34
 
27
35
  ```sh
28
36
  cloud_viewer # The viewer will be displayed
29
- # Use the command below if the path is not set, though it's not recommended
37
+ ```
38
+
39
+ *Alternatively*, if the path is not set (though it's not recommended):
40
+
41
+ ```sh
30
42
  python3 -m q3dviewer.tools.cloud_viewer
31
43
  ```
32
44
 
33
45
  After the viewer launches, you can drag and drop files onto the window to display the point clouds. Multiple files can be dropped simultaneously to view them together. Supported formats include LAS, PCD, PLY, and E57.
34
46
 
35
- For example, you can download and check point clouds of Tokyo in LAS format from the following link:
47
+ For example, you can download and view point clouds of Tokyo in LAS format from the following link:
36
48
 
37
49
  [Tokyo Point Clouds](https://www.geospatial.jp/ckan/dataset/tokyopc-23ku-2024/resource/7807d6d1-29f3-4b36-b0c8-f7aa0ea2cff3)
38
50
 
39
- ![Screenshot](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/03c981c6-1aec-e5b9-4536-e07e1e56ff29.png)
51
+ ![Cloud Viewer Screenshot](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/03c981c6-1aec-e5b9-4536-e07e1e56ff29.png)
40
52
 
41
- Press `M` on your keyboard to display a menu on the screen, where you can modify visualization settings for each item. for example, You can adjust various settings such as shape, size, color, and transparency of the point clouds for CloudItem,.
53
+ Press `M` on your keyboard to display a menu on the screen, where you can modify visualization settings for each item. For example, you can adjust various settings such as shape, size, color, and transparency for `CloudItem`.
42
54
 
43
- ![Screenshot](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/deeb996a-e419-58f4-6bc2-535099b1b73a.png)
55
+ ![Cloud Viewer Settings](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/deeb996a-e419-58f4-6bc2-535099b1b73a.png)
44
56
 
45
57
  ### 2. ROS Viewer
46
58
 
47
- A high-performance SLAM viewer with strong compatibility with ROS, serving as an alternative to RVIZ.
59
+ A high-performance SLAM viewer compatible with ROS, serving as an alternative to RVIZ.
48
60
 
49
61
  ```sh
50
62
  roscore &
51
63
  ros_viewer
52
64
  ```
53
65
 
54
- ### 3. Gaussian Viewer
66
+ ### 3. Film Maker
67
+
68
+ Would you like to create a video from point cloud data? With Film Maker, you can easily create videos with simple operations. Just edit keyframes using the user-friendly GUI, and the software will automatically interpolate the keyframes to generate the video.
69
+
70
+ ```sh
71
+ film_maker # drag and drop your cloud file to the window
72
+ ```
73
+
74
+ * Space key to add a keyframe.
75
+ * Delete key to remove a keyframe.
76
+
77
+ Film Maker GUI:
78
+
79
+ ![Screenshot from 2025-02-02 18-20-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/a1a6ad63-237c-482e-439d-e760223c59ca.png)
55
80
 
56
- A simple viewer for 3D Gaussian.
57
- see: https://github.com/scomup/EasyGaussianSplatting
81
+ ### 4. Gaussian Viewer
58
82
 
83
+ A simple viewer for 3D Gaussians. See [EasyGaussianSplatting](https://github.com/scomup/EasyGaussianSplatting) for more information.
59
84
 
60
85
  ```sh
61
86
  gaussian_viewer # Drag and drop your Gaussian file onto the window
62
87
  ```
63
88
 
64
- ![Viewer GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/441e6f5a-214d-f7c1-11bf-5fa79e63b38e.gif)
89
+ ![Gaussian Viewer GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/441e6f5a-214d-f7c1-11bf-5fa79e63b38e.gif)
65
90
 
66
- ### 4. LiDAR-LiDAR Calibration Tools
91
+ ### 5. LiDAR-LiDAR Calibration Tools
67
92
 
68
93
  A tool to compute the relative pose between two LiDARs. It allows for both manual adjustment in the settings screen and automatic calibration.
69
94
 
@@ -73,7 +98,7 @@ lidar_calib --lidar0=/YOUR_LIDAR0_TOPIC --lidar1=/YOUR_LIDAR1_TOPIC
73
98
 
74
99
  ![LiDAR Calibration](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149168/5a8a9903-a42a-8322-1d23-0cbecd3fa99a.png)
75
100
 
76
- ### 5. LiDAR-Camera Calibration Tools
101
+ ### 6. LiDAR-Camera Calibration Tools
77
102
 
78
103
  A tool for calculating the relative pose between a LiDAR and a camera. It allows for manual adjustment in the settings screen and real-time verification of LiDAR point projection onto images.
79
104
 
@@ -104,6 +129,7 @@ def main():
104
129
 
105
130
  # Create a viewer
106
131
  viewer = q3d.Viewer(name='example')
132
+
107
133
  # Add items to the viewer
108
134
  viewer.add_items({
109
135
  'grid': grid_item,
@@ -120,14 +146,14 @@ if __name__ == '__main__':
120
146
 
121
147
  `q3dviewer` provides the following 3D items:
122
148
 
123
- - **AxisItem**: Displaying coordinate axes or self-position
124
- - **CloudItem**: Displaying point clouds
125
- - **CloudIOItem**: Displaying point clouds with I/O capabilities
126
- - **GaussianItem**: Displaying 3D Gaussians
127
- - **GridItem**: Displaying grids
128
- - **ImageItem**: Displaying 2D images
129
- - **Text2DItem**: Displaying 2D text
130
- - **LineItem**: Displaying lines or trajectories
149
+ - **AxisItem**: Displays coordinate axes or the origin position.
150
+ - **CloudItem**: Displays point clouds.
151
+ - **CloudIOItem**: Displays point clouds with input/output capabilities.
152
+ - **GaussianItem**: Displays 3D Gaussians.
153
+ - **GridItem**: Displays grids.
154
+ - **ImageItem**: Displays 2D images.
155
+ - **Text2DItem**: Displays 2D text.
156
+ - **LineItem**: Displays lines or trajectories.
131
157
 
132
158
  ### Developing Custom Items
133
159
 
@@ -142,7 +168,7 @@ from PySide6.QtWidgets import QLabel, QSpinBox
142
168
  class YourItem(q3d.BaseItem):
143
169
  def __init__(self):
144
170
  super(YourItem, self).__init__()
145
- pass # Necessary initialization
171
+ # Necessary initialization
146
172
 
147
173
  def add_setting(self, layout):
148
174
  # Initialize the settings screen
@@ -152,13 +178,16 @@ class YourItem(q3d.BaseItem):
152
178
  layout.addWidget(box)
153
179
 
154
180
  def set_data(self, data):
155
- pass # Obtain the data you want to visualize
181
+ # Obtain the data you want to visualize
182
+ pass
156
183
 
157
184
  def initialize_gl(self):
158
- pass # OpenGL initialization settings (if needed)
185
+ # OpenGL initialization settings (if needed)
186
+ pass
159
187
 
160
188
  def paint(self):
161
- pass # Visualize 3D objects using OpenGL
189
+ # Visualize 3D objects using OpenGL
190
+ pass
162
191
  ```
163
192
 
164
193
  Enjoy using `q3dviewer`!
@@ -0,0 +1,26 @@
1
+ [tool.poetry]
2
+ name = "q3dviewer"
3
+ version = "1.1.0"
4
+ description = "A library designed for quickly deploying a 3D viewer."
5
+ authors = ["Liu Yang <scomup@gmail.com>"]
6
+
7
+ [tool.poetry.dependencies]
8
+ python = "^3.8"
9
+ numpy = "^1.21"
10
+ pyside6 = "^6.2"
11
+ PyOpenGL = "^3.1"
12
+ pillow = "^8.3"
13
+ meshio = "^4.4"
14
+ pypcd4 = "^0.1"
15
+ pye57 = "^0.1"
16
+ laspy = "^2.0"
17
+ imageio = "^2.9"
18
+
19
+ [tool.poetry.scripts]
20
+ cloud_viewer = "q3dviewer.tools.cloud_viewer:main"
21
+ ros_viewer = "q3dviewer.tools.ros_viewer:main"
22
+ mesh_viewer = "q3dviewer.tools.mesh_viewer:main"
23
+ gaussian_viewer = "q3dviewer.tools.gaussian_viewer:main"
24
+ lidar_cam_calib = "q3dviewer.tools.lidar_cam_calib:main"
25
+ lidar_calib = "q3dviewer.tools.lidar_calib:main"
26
+ film_maker = "q3dviewer.tools.film_maker:main"
@@ -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)
@@ -163,37 +195,46 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
163
195
  # Handle rotation keys
164
196
  if QtCore.Qt.Key_Up in self.active_keys:
165
197
  self.rotate(radians(rot_speed), 0, 0)
198
+ self.view_need_update = True
166
199
  if QtCore.Qt.Key_Down in self.active_keys:
167
200
  self.rotate(radians(-rot_speed), 0, 0)
201
+ self.view_need_update = True
168
202
  if QtCore.Qt.Key_Left in self.active_keys:
169
203
  self.rotate(0, 0, radians(rot_speed))
204
+ self.view_need_update = True
170
205
  if QtCore.Qt.Key_Right in self.active_keys:
171
206
  self.rotate(0, 0, radians(-rot_speed))
207
+ self.view_need_update = True
172
208
  # Handle zoom keys
173
209
  xz_keys = {QtCore.Qt.Key_Z, QtCore.Qt.Key_X}
174
210
  if self.active_keys & xz_keys:
175
211
  Rwc = euler_to_matrix(self.euler)
176
212
  if QtCore.Qt.Key_Z in self.active_keys:
177
213
  self.center += Rwc @ np.array([0, 0, -trans_speed])
214
+ self.view_need_update = True
178
215
  if QtCore.Qt.Key_X in self.active_keys:
179
216
  self.center += Rwc @ np.array([0, 0, trans_speed])
217
+ self.view_need_update = True
180
218
  # Handle translation keys on the z plane
181
219
  dir_keys = {QtCore.Qt.Key_W, QtCore.Qt.Key_S, QtCore.Qt.Key_A, QtCore.Qt.Key_D}
182
220
  if self.active_keys & dir_keys:
183
221
  Rz = euler_to_matrix([0, 0, self.euler[2]])
184
222
  if QtCore.Qt.Key_W in self.active_keys:
185
223
  self.center += Rz @ np.array([0, trans_speed, 0])
224
+ self.view_need_update = True
186
225
  if QtCore.Qt.Key_S in self.active_keys:
187
226
  self.center += Rz @ np.array([0, -trans_speed, 0])
227
+ self.view_need_update = True
188
228
  if QtCore.Qt.Key_A in self.active_keys:
189
229
  self.center += Rz @ np.array([-trans_speed, 0, 0])
230
+ self.view_need_update = True
190
231
  if QtCore.Qt.Key_D in self.active_keys:
191
232
  self.center += Rz @ np.array([trans_speed, 0, 0])
233
+ self.view_need_update = True
192
234
 
193
235
  def update_model_view(self):
194
- m = self.get_view_matrix()
195
236
  glMatrixMode(GL_MODELVIEW)
196
- glLoadMatrixf(m.T)
237
+ glLoadMatrixf(self.view_matrix.T)
197
238
 
198
239
  def get_view_matrix(self):
199
240
  two = self.center # the origin(center) in the world frame
@@ -206,12 +247,19 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
206
247
  return Tcw
207
248
 
208
249
  def set_cam_position(self, **kwargs):
209
- pos = kwargs.get('pos', None)
250
+ center = kwargs.get('center', None)
210
251
  distance = kwargs.get('distance', None)
211
- if pos is not None:
212
- self.center = pos
252
+ euler = kwargs.get('euler', None)
253
+ if center is not None:
254
+ self.set_center(center)
213
255
  if distance is not None:
214
- self.dist = distance
256
+ self.set_dist(distance)
257
+ if euler is not None:
258
+ self.set_euler(euler)
259
+
260
+ def set_euler(self, euler):
261
+ self.euler = euler
262
+ self.view_need_update = True
215
263
 
216
264
  def set_color(self, color):
217
265
  self.color = color
@@ -221,9 +269,8 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
221
269
  super().update()
222
270
 
223
271
  def update_model_projection(self):
224
- m = self.get_projection_matrix()
225
272
  glMatrixMode(GL_PROJECTION)
226
- glLoadMatrixf(m.T)
273
+ glLoadMatrixf(self.projection_matrix.T)
227
274
 
228
275
  def get_projection_matrix(self):
229
276
  w, h = self.current_width(), self.current_height()
@@ -259,3 +306,17 @@ class BaseGLWidget(QtOpenGLWidgets.QOpenGLWidget):
259
306
 
260
307
  def change_show_center(self, state):
261
308
  self.enable_show_center = state
309
+
310
+ def resizeEvent(self, event):
311
+ super().resizeEvent(event)
312
+ self.projection_matrix = self.get_projection_matrix()
313
+ self.update_model_projection()
314
+
315
+ def capture_frame(self):
316
+ self.makeCurrent() # Ensure the OpenGL context is current
317
+ width = self.current_width()
318
+ height = self.current_height()
319
+ pixels = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)
320
+ frame = np.frombuffer(pixels, dtype=np.uint8).reshape(height, width, 3)
321
+ frame = np.flip(frame, 0)
322
+ return frame
@@ -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