2 * Software License Agreement (BSD License)
4 * Point Cloud Library (PCL) - www.pointclouds.org
5 * Copyright (c) 2013-, Open Perception, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution.
19 * * Neither the name of the copyright holder(s) nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
36 * main_ground_based_people_detection_app.cpp
37 * Created on: Nov 30, 2012
38 * Author: Matteo Munaro
40 * Example file for performing people detection on a Kinect live stream.
41 * As a first step, the ground is manually initialized, then people detection is performed with the GroundBasedPeopleDetectionApp class,
42 * which implements the people detection algorithm described here:
43 * M. Munaro, F. Basso and E. Menegatti,
44 * Tracking people within groups with RGB-D data,
45 * In Proceedings of the International Conference on Intelligent Robots and Systems (IROS) 2012, Vilamoura (Portugal), 2012.
48 #include <pcl/console/parse.h>
49 #include <pcl/point_types.h>
50 #include <pcl/visualization/pcl_visualizer.h>
51 #include <pcl/io/openni_grabber.h>
52 #include <pcl/sample_consensus/sac_model_plane.h>
53 #include <pcl/people/ground_based_people_detection_app.h>
54 #include <pcl/common/time.h>
60 using namespace std::chrono_literals;
62 typedef pcl::PointXYZRGBA PointT;
63 typedef pcl::PointCloud<PointT> PointCloudT;
66 pcl::visualization::PCLVisualizer viewer("PCL Viewer");
69 std::mutex cloud_mutex;
71 enum { COLS = 640, ROWS = 480 };
75 std::cout << "*******************************************************" << std::endl;
76 std::cout << "Ground based people detection app options:" << std::endl;
77 std::cout << " --help <show_this_help>" << std::endl;
78 std::cout << " --svm <path_to_svm_file>" << std::endl;
79 std::cout << " --conf <minimum_HOG_confidence (default = -1.5)>" << std::endl;
80 std::cout << " --min_h <minimum_person_height (default = 1.3)>" << std::endl;
81 std::cout << " --max_h <maximum_person_height (default = 2.3)>" << std::endl;
82 std::cout << "*******************************************************" << std::endl;
86 void cloud_cb_ (const PointCloudT::ConstPtr &callback_cloud, PointCloudT::Ptr& cloud,
87 bool* new_cloud_available_flag)
89 cloud_mutex.lock (); // for not overwriting the point cloud from another thread
90 *cloud = *callback_cloud;
91 *new_cloud_available_flag = true;
92 cloud_mutex.unlock ();
96 // structure used to pass arguments to the callback function
97 PointCloudT::Ptr clicked_points_3d;
98 pcl::visualization::PCLVisualizer::Ptr viewerPtr;
102 pp_callback (const pcl::visualization::PointPickingEvent& event, void* args)
104 struct callback_args* data = (struct callback_args *)args;
105 if (event.getPointIndex () == -1)
107 PointT current_point;
108 event.getPoint(current_point.x, current_point.y, current_point.z);
109 data->clicked_points_3d->points.push_back(current_point);
110 // Draw clicked points in red:
111 pcl::visualization::PointCloudColorHandlerCustom<PointT> red (data->clicked_points_3d, 255, 0, 0);
112 data->viewerPtr->removePointCloud("clicked_points");
113 data->viewerPtr->addPointCloud(data->clicked_points_3d, red, "clicked_points");
114 data->viewerPtr->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "clicked_points");
115 std::cout << current_point.x << " " << current_point.y << " " << current_point.z << std::endl;
118 int main (int argc, char** argv)
120 if(pcl::console::find_switch (argc, argv, "--help") || pcl::console::find_switch (argc, argv, "-h"))
123 // Algorithm parameters:
124 std::string svm_filename = "../../people/data/trainedLinearSVMForPeopleDetectionWithHOG.yaml";
125 float min_confidence = -1.5;
126 float min_height = 1.3;
127 float max_height = 2.3;
128 float voxel_size = 0.06;
129 Eigen::Matrix3f rgb_intrinsics_matrix;
130 rgb_intrinsics_matrix << 525, 0.0, 319.5, 0.0, 525, 239.5, 0.0, 0.0, 1.0; // Kinect RGB camera intrinsics
132 // Read if some parameters are passed from command line:
133 pcl::console::parse_argument (argc, argv, "--svm", svm_filename);
134 pcl::console::parse_argument (argc, argv, "--conf", min_confidence);
135 pcl::console::parse_argument (argc, argv, "--min_h", min_height);
136 pcl::console::parse_argument (argc, argv, "--max_h", max_height);
138 // Read Kinect live stream:
139 PointCloudT::Ptr cloud (new PointCloudT);
140 bool new_cloud_available_flag = false;
141 pcl::Grabber* interface = new pcl::OpenNIGrabber();
142 std::function<void (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&)> f =
143 [&] (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr& callback_cloud) { cloud_cb_ (callback_cloud, cloud, &new_cloud_available_flag); };
144 interface->registerCallback (f);
147 // Wait for the first frame:
148 while(!new_cloud_available_flag)
149 std::this_thread::sleep_for(1ms);
150 new_cloud_available_flag = false;
152 cloud_mutex.lock (); // for not overwriting the point cloud
154 // Display pointcloud:
155 pcl::visualization::PointCloudColorHandlerRGBField<PointT> rgb(cloud);
156 viewer.addPointCloud<PointT> (cloud, rgb, "input_cloud");
157 viewer.setCameraPosition(0,0,-2,0,-1,0,0);
159 // Add point picking callback to viewer:
160 struct callback_args cb_args;
161 PointCloudT::Ptr clicked_points_3d (new PointCloudT);
162 cb_args.clicked_points_3d = clicked_points_3d;
163 cb_args.viewerPtr = pcl::visualization::PCLVisualizer::Ptr(&viewer);
164 viewer.registerPointPickingCallback (pp_callback, (void*)&cb_args);
165 std::cout << "Shift+click on three floor points, then press 'Q'..." << std::endl;
167 // Spin until 'Q' is pressed:
169 std::cout << "done." << std::endl;
171 cloud_mutex.unlock ();
173 // Ground plane estimation:
174 Eigen::VectorXf ground_coeffs;
175 ground_coeffs.resize(4);
176 std::vector<int> clicked_points_indices;
177 for (unsigned int i = 0; i < clicked_points_3d->size(); i++)
178 clicked_points_indices.push_back(i);
179 pcl::SampleConsensusModelPlane<PointT> model_plane(clicked_points_3d);
180 model_plane.computeModelCoefficients(clicked_points_indices,ground_coeffs);
181 std::cout << "Ground plane: " << ground_coeffs(0) << " " << ground_coeffs(1) << " " << ground_coeffs(2) << " " << ground_coeffs(3) << std::endl;
183 // Initialize new viewer:
184 pcl::visualization::PCLVisualizer viewer("PCL Viewer"); // viewer initialization
185 viewer.setCameraPosition(0,0,-2,0,-1,0,0);
187 // Create classifier for people detection:
188 pcl::people::PersonClassifier<pcl::RGB> person_classifier;
189 person_classifier.loadSVMFromFile(svm_filename); // load trained SVM
191 // People detection app initialization:
192 pcl::people::GroundBasedPeopleDetectionApp<PointT> people_detector; // people detection object
193 people_detector.setVoxelSize(voxel_size); // set the voxel size
194 people_detector.setIntrinsics(rgb_intrinsics_matrix); // set RGB camera intrinsic parameters
195 people_detector.setClassifier(person_classifier); // set person classifier
196 people_detector.setPersonClusterLimits(min_height, max_height, 0.1, 8.0); // set person classifier
197 // people_detector.setSensorPortraitOrientation(true); // set sensor orientation to vertical
200 static unsigned count = 0;
201 static double last = pcl::getTime ();
204 while (!viewer.wasStopped())
206 if (new_cloud_available_flag && cloud_mutex.try_lock ()) // if a new cloud is available
208 new_cloud_available_flag = false;
210 // Perform people detection on the new cloud:
211 std::vector<pcl::people::PersonCluster<PointT> > clusters; // vector containing persons clusters
212 people_detector.setInputCloud(cloud);
213 people_detector.setGround(ground_coeffs); // set floor coefficients
214 people_detector.compute(clusters); // perform people detection
216 ground_coeffs = people_detector.getGround(); // get updated floor coefficients
218 // Draw cloud and people bounding boxes in the viewer:
219 viewer.removeAllPointClouds();
220 viewer.removeAllShapes();
221 pcl::visualization::PointCloudColorHandlerRGBField<PointT> rgb(cloud);
222 viewer.addPointCloud<PointT> (cloud, rgb, "input_cloud");
224 for(std::vector<pcl::people::PersonCluster<PointT> >::iterator it = clusters.begin(); it != clusters.end(); ++it)
226 if(it->getPersonConfidence() > min_confidence) // draw only people with confidence above a threshold
228 // draw theoretical person bounding box in the PCL viewer:
229 it->drawTBoundingBox(viewer, k);
233 std::cout << k << " people found" << std::endl;
236 // Display average framerate:
239 double now = pcl::getTime ();
240 std::cout << "Average framerate: " << double(count)/double(now - last) << " Hz" << std::endl;
244 cloud_mutex.unlock ();