1 /*
2  * Software License Agreement (BSD License)
3  *
4  *  Copyright (c) 2011, Willow Garage, Inc.
5  *  All rights reserved.
6  *
7  *  Redistribution and use in source and binary forms, with or without
8  *  modification, are permitted provided that the following conditions
9  *  are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *   * Neither the name of Willow Garage, Inc. nor the names of its
18  *     contributors may be used to endorse or promote products derived
19  *     from this software without specific prior written permission.
20  *
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  *  POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Author: Julius Kammerl (julius@kammerl.de)
35  */
36 
37 #include <pcl/common/time.h>
38 #include <pcl/io/openni_grabber.h>
39 #include <pcl/visualization/cloud_viewer.h>
40 #include <pcl/point_cloud.h>
41 #include <pcl/point_types.h>
42 
43 #include <boost/asio.hpp>
44 
45 #include <iostream>
46 #include <thread>
47 #include <vector>
48 
49 using boost::asio::ip::tcp;
50 
51 using namespace pcl;
52 using namespace pcl::io;
53 
54 using namespace std::chrono_literals;
55 
56 class SimpleOpenNIViewer {
57 public:
SimpleOpenNIViewer()58   SimpleOpenNIViewer()
59   : viewer_("Input Point Cloud - Shift-to-depth conversion viewer")
60   , grabber_("",
61              pcl::OpenNIGrabber::OpenNI_Default_Mode,
62              pcl::OpenNIGrabber::OpenNI_Default_Mode)
63   {}
64 
65   void
image_callback(const openni_wrapper::Image::Ptr & image,const openni_wrapper::DepthImage::Ptr & depth_image,float)66   image_callback(const openni_wrapper::Image::Ptr& image,
67                  const openni_wrapper::DepthImage::Ptr& depth_image,
68                  float)
69   {
70 
71     std::vector<std::uint16_t> raw_shift_data;
72     std::vector<std::uint16_t> raw_depth_data;
73 
74     std::vector<std::uint8_t> rgb_data;
75 
76     std::uint32_t width = depth_image->getWidth();
77     std::uint32_t height = depth_image->getHeight();
78 
79     // copy raw shift data from depth_image
80     raw_shift_data.resize(width * height);
81     depth_image->fillDepthImageRaw(
82         width,
83         height,
84         &raw_shift_data[0],
85         static_cast<unsigned int>(width * sizeof(std::uint16_t)));
86 
87     // convert raw shift data to raw depth data
88     raw_depth_data.resize(width * height);
89     grabber_.convertShiftToDepth(
90         &raw_shift_data[0], &raw_depth_data[0], raw_shift_data.size());
91 
92     // check for color data
93     if (image->getEncoding() != openni_wrapper::Image::RGB) {
94       // copy raw rgb data from image
95       rgb_data.resize(width * height * 3);
96       image->fillRGB(width,
97                      height,
98                      &rgb_data[0],
99                      static_cast<unsigned int>(width * sizeof(std::uint8_t) * 3));
100     }
101 
102     // empty pointcloud
103     pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud =
104         pcl::PointCloud<pcl::PointXYZRGB>::Ptr(new pcl::PointCloud<pcl::PointXYZRGB>());
105 
106     // convert raw depth and rgb data to pointcloud
107     convert(
108         raw_depth_data, rgb_data, width, height, depth_image->getFocalLength(), *cloud);
109 
110     // display pointcloud
111     viewer_.showCloud(cloud);
112   }
113 
114   void
run()115   run()
116   {
117     // initialize OpenNIDevice to shift-value mode
118     int depthformat = openni_wrapper::OpenNIDevice::OpenNI_shift_values;
119 
120     // Set the depth output format
121     grabber_.getDevice()->setDepthOutputFormat(
122         static_cast<openni_wrapper::OpenNIDevice::DepthMode>(depthformat));
123 
124     // define image callback
125     std::function<void(const openni_wrapper::Image::Ptr&,
126                        const openni_wrapper::DepthImage::Ptr&,
127                        float)>
128         image_cb = [this](const openni_wrapper::Image::Ptr& img,
129                           const openni_wrapper::DepthImage::Ptr& depth,
130                           float f) { image_callback(img, depth, f); };
131     grabber_.registerCallback(image_cb);
132 
133     // start grabber thread
134     grabber_.start();
135     while (true) {
136       std::this_thread::sleep_for(1s);
137     }
138     grabber_.stop();
139   }
140 
141 protected:
142   /* helper method to convert depth&rgb data to pointcloud*/
143   void
convert(std::vector<std::uint16_t> & depthData_arg,std::vector<std::uint8_t> & rgbData_arg,std::size_t width_arg,std::size_t height_arg,float focalLength_arg,pcl::PointCloud<PointXYZRGB> & cloud_arg) const144   convert(std::vector<std::uint16_t>& depthData_arg,
145           std::vector<std::uint8_t>& rgbData_arg,
146           std::size_t width_arg,
147           std::size_t height_arg,
148           float focalLength_arg,
149           pcl::PointCloud<PointXYZRGB>& cloud_arg) const
150   {
151     std::size_t cloud_size = width_arg * height_arg;
152 
153     // Reset point cloud
154     cloud_arg.clear();
155     cloud_arg.reserve(cloud_size);
156 
157     // Define point cloud parameters
158     cloud_arg.width = static_cast<std::uint32_t>(width_arg);
159     cloud_arg.height = static_cast<std::uint32_t>(height_arg);
160     cloud_arg.is_dense = false;
161 
162     // Calculate center of disparity image
163     int centerX = static_cast<int>(width_arg / 2);
164     int centerY = static_cast<int>(height_arg / 2);
165 
166     const float fl_const = 1.0f / focalLength_arg;
167     static const float bad_point = std::numeric_limits<float>::quiet_NaN();
168 
169     std::size_t i = 0;
170     for (int y = -centerY; y < +centerY; ++y)
171       for (int x = -centerX; x < +centerX; ++x) {
172         PointXYZRGB newPoint;
173 
174         const std::uint16_t& pixel_depth = depthData_arg[i];
175 
176         if (pixel_depth) {
177           float depth = pixel_depth / 1000.0f; // raw mm -> m
178 
179           // Define point location
180           newPoint.z = depth;
181           newPoint.x = static_cast<float>(x) * depth * fl_const;
182           newPoint.y = static_cast<float>(y) * depth * fl_const;
183 
184           // Define point color
185           newPoint.r = rgbData_arg[i * 3 + 0];
186           newPoint.g = rgbData_arg[i * 3 + 1];
187           newPoint.b = rgbData_arg[i * 3 + 2];
188         }
189         else {
190           // Define bad point
191           newPoint.x = newPoint.y = newPoint.z = bad_point;
192           newPoint.rgba = 0;
193         }
194 
195         // Add point to cloud
196         cloud_arg.push_back(newPoint);
197         // Increment point iterator
198         ++i;
199       }
200   }
201 
202   pcl::visualization::CloudViewer viewer_;
203   pcl::OpenNIGrabber grabber_;
204 };
205 
206 int
main(int,char **)207 main(int, char**)
208 {
209   SimpleOpenNIViewer v;
210   v.run();
211 
212   return 0;
213 }
214