grasp
All Data Structures Namespaces Functions Modules
visThread.cpp
1 #include "visThread.h"
2 
3 using namespace std;
4 using namespace yarp::os;
5 
6 // Empty constructor
7 VisThread::VisThread(int period, const string &_cloudname):RateThread(period), id(_cloudname){}
8 
9 // Initialize Variables
10 bool VisThread::threadInit()
11 {
12  cloud = pcl::PointCloud<pcl::PointXYZRGB>::Ptr (new pcl::PointCloud<pcl::PointXYZRGB>); // Point cloud
13  viewer = boost::shared_ptr<pcl::visualization::PCLVisualizer> (new pcl::visualization::PCLVisualizer("Point Cloud Viewer")); //viewer
14 
15  //initialize here variables
16  printf("\nStarting visualizer Thread\n");
17 
18  // Flags
19  initialized = false;
20  addClouds = false;
21  clearing = false;
22  updatingCloud = false;
23  displayBB = false;
24  displayNormals = false;
25 
26  // Processing parameters
27  minimumBB = false;
28  radiusSearch = 0.03;
29 
30  return true;
31 }
32 
33 // Module and visualization loop
34 void VisThread::run()
35 {
36  if (initialized)
37  {
38  if (!viewer->wasStopped ())
39  {
40  viewer->spinOnce ();
41  // Get lock on the boolean update and check if cloud was updated
42  boost::mutex::scoped_lock updateLock(updateModelMutex);
43  if(update)
44  {
45  if(updatingCloud){
46  // Clean visualizer to plot new cloud
47  viewer->removePointCloud(id);
48  viewer->removePointCloud("normals");
49  viewer->removeAllShapes();
50 
51  // Check if the loaded file contains color information or not
52  bool colorCloud = false;
53  for (int p = 1; p < cloud->points.size(); ++p) {
54  uint32_t rgb = *reinterpret_cast<int*>(&cloud->points[p].rgb);
55  if (rgb != 0)
56  colorCloud = true;
57  }
58  // Add cloud color if it has not
59  if (!colorCloud) {
60  // Define R,G,B colors for the point cloud
61  pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> cloud_color_handler(cloud, 230, 20, 0); //red
62  viewer->addPointCloud (cloud, cloud_color_handler, id);
63  }else{
64  pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> cloud_color_handler (cloud);
65  viewer->addPointCloud (cloud, cloud_color_handler, id);
66  }
67  viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, id);
68  updatingCloud = false;
69  }
70 
71  // Compute and bounding box to display
72  if (displayBB)
73  {
74  plotBB(minimumBB);
75  displayBB = false;
76  }
77 
78  // Compute and add normals to display
79  if (displayNormals)
80  {
81  plotNormals(radiusSearch);
82  displayNormals = false;
83  }
84 
85  // Clear display
86  if (clearing){
87  viewer->removePointCloud(id);
88  viewer->removePointCloud("normals");
89  viewer->removeAllShapes();
90  clearing = false;
91  }
92 
93  update = false;
94  }
95  updateLock.unlock();
96  }else{
97  //Close viewer
98  printf("Closing Visualizer\n");
99  viewer->close();
100  viewer->removePointCloud(id);
101  this->stop();
102  }
103 
104  }
105 }
106 
107 void VisThread::threadRelease()
108 {
109  printf("Closing Visualizer Thread\n");
110 }
111 
112 // Unlock mutex temporarily to allow an update cycle on the visualizer
113 void VisThread::updateVis()
114 {
115  // Lock mutex while update is on
116  boost::mutex::scoped_lock updateLock(updateModelMutex);
117  update = true;
118  updateLock.unlock();
119 
120  printf("Visualizer updated\n");
121 }
122 
123 // Clear display
124 void VisThread::clearVisualizer()
125 {
126  clearing = true;
127  updateVis();
128 }
129 
130 // Display new cloud received
131 void VisThread::updateCloud(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_in)
132 {
133  printf("Updating displayed cloud\n");
134  if (addClouds)
135  *cloud += *cloud_in; // new cloud is added to last one
136  else
137  *cloud = *cloud_in; // new cloud overwrites last one
138 
139  if (!initialized)
140  {
141  // Set camera position and orientation
142  viewer->setBackgroundColor (0.05, 0.05, 0.05, 0); // Setting background to a dark grey
143  viewer->addCoordinateSystem (0.05);
144  initialized = true;
145  }
146 
147  updatingCloud = true;
148  updateVis();
149  printf("Cloud updated\n");
150 }
151 
152 // Set flow to allow normals to be computed and added on display update.
153 void VisThread::addNormals(double rS)
154 {
155  if (initialized){
156  displayNormals = true;
157  radiusSearch = rS;
158  updateVis();
159  }else{
160  printf("Please load a cloud before trying to compute the normals\n");
161  }
162 }
163 
164 // Compute and display normals
165 void VisThread::plotNormals(double rS)
166 {
167  // Create the normal estimation class, and pass the input dataset to it
168  pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;
169  ne.setInputCloud (cloud);
170 
171  // Create an empty kdtree representation, and pass it to the normal estimation object.
172  // Its content will be filled inside the object, based on the given input dataset (as no other search surface is given).
173  pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGB> ());
174  ne.setSearchMethod (tree);
175 
176  // Output datasets
177  pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
178 
179  // Use all neighbors in a sphere of radius radiusSearch
180  ne.setRadiusSearch (rS);
181 
182  // Compute the features
183  ne.compute (*cloud_normals);
184 
185  viewer->addPointCloudNormals<pcl::PointXYZRGB, pcl::Normal> (cloud, cloud_normals, 30, rS, "normals");
186 }
187 
188 // Set flow to allow bounding box to be computed and added on display update.
189 void VisThread::addBoundingBox(bool minBB)
190 {
191  if (initialized){
192  displayBB = true;
193  minimumBB = minBB;
194 
195  updateVis();
196 
197  if (minBB)
198  printf("Minimal Bounding Box added to display\n");
199  else
200  printf("Axis Aligned Bounding Box added to display\n");
201  }else{
202  printf("Please load cloud to compute Bounding box from.\n");
203  }
204 }
205 
206 // Computes and display Bounding Box
207 void VisThread::plotBB(bool minBB)
208 {
209  // Create the feature extractor estimation class, and pass the input cloud to it
210  pcl::MomentOfInertiaEstimation <pcl::PointXYZRGB> feature_extractor;
211  feature_extractor.setInputCloud (cloud);
212  feature_extractor.compute ();
213 
214  if (minBB) // Oriented bounding box (OBB)
215  { // Declare points and rotational matrix
216  pcl::PointXYZRGB min_point_OBB;
217  pcl::PointXYZRGB max_point_OBB;
218  pcl::PointXYZRGB position_OBB;
219  Eigen::Matrix3f rotational_matrix_OBB;
220 
221  // Compute extrema of minimum bounding box and rotational matrix wrt axis.
222  feature_extractor.getOBB (min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);
223  Eigen::Vector3f position (position_OBB.x, position_OBB.y, position_OBB.z);
224  Eigen::Quaternionf quat (rotational_matrix_OBB);
225 
226  // Display oriented minimum boinding box
227  viewer->addCube (position, quat, max_point_OBB.x - min_point_OBB.x, max_point_OBB.y - min_point_OBB.y, max_point_OBB.z - min_point_OBB.z, "OBB");
228 
229  }else{ // Axis-aligned bounding box (AABB)
230  // Declare extrema points of AABB
231  pcl::PointXYZRGB min_point_AABB;
232  pcl::PointXYZRGB max_point_AABB;
233 
234  // Compute extrema of AABB
235  feature_extractor.getAABB (min_point_AABB, max_point_AABB);
236 
237  // Display axis aligned minimum boinding box
238  viewer->addCube (min_point_AABB.x, max_point_AABB.x, min_point_AABB.y, max_point_AABB.y, min_point_AABB.z, max_point_AABB.z, 1.0, 1.0, 0.0, "AABB");
239  }
240 }
241 
242 // Selects between displaying each cloud individually or accumulating them on the display.
243 void VisThread::accumulateClouds(bool accum)
244 {
245  if (accum){
246  addClouds = true;
247  printf("Clouds plotted together now\n");
248  }else{
249  addClouds = false;
250  printf("Clouds plotted separately now\n");
251  }
252 }
253