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