Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
range_image.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2012, Willow Garage, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
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 Willow Garage, Inc. 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.
22  *
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.
35  *
36  */
37 
38 #include <pcl/pcl_macros.h>
39 #include <pcl/common/distances.h>
40 
41 namespace pcl
42 {
43 
45 inline float
46 RangeImage::asinLookUp (float value)
47 {
48  return (asin_lookup_table[
49  static_cast<int> (
50  static_cast<float> (pcl_lrintf ( (static_cast<float> (lookup_table_size) / 2.0f) * value)) +
51  static_cast<float> (lookup_table_size) / 2.0f)]);
52 }
53 
55 inline float
56 RangeImage::atan2LookUp (float y, float x)
57 {
58  float ret;
59  if (fabsf (x) < fabsf (y))
60  {
61  ret = atan_lookup_table[
62  static_cast<int> (
63  static_cast<float> (pcl_lrintf ( (static_cast<float> (lookup_table_size) / 2.0f) * (x / y))) +
64  static_cast<float> (lookup_table_size) / 2.0f)];
65  ret = static_cast<float> (x*y > 0 ? M_PI/2-ret : -M_PI/2-ret);
66  }
67  else
68  ret = atan_lookup_table[
69  static_cast<int> (
70  static_cast<float> (pcl_lrintf ( (static_cast<float> (lookup_table_size) / 2.0f) * (y / x))) +
71  static_cast<float> (lookup_table_size)/2.0f)];
72  if (x < 0)
73  ret = static_cast<float> (y < 0 ? ret-M_PI : ret+M_PI);
74 
75  return (ret);
76 }
77 
79 inline float
80 RangeImage::cosLookUp (float value)
81 {
82  int cell_idx = static_cast<int> (pcl_lrintf ( (static_cast<float> (lookup_table_size)-1) * fabsf (value) / (2.0f * M_PI)));
83  return (cos_lookup_table[cell_idx]);
84 }
85 
87 template <typename PointCloudType> void
88 RangeImage::createFromPointCloud (const PointCloudType& point_cloud, float angular_resolution,
89  float max_angle_width, float max_angle_height,
90  const Eigen::Affine3f& sensor_pose, RangeImage::CoordinateFrame coordinate_frame,
91  float noise_level, float min_range, int border_size)
92 {
93  createFromPointCloud (point_cloud, angular_resolution, angular_resolution, max_angle_width, max_angle_height,
94  sensor_pose, coordinate_frame, noise_level, min_range, border_size);
95 }
96 
98 template <typename PointCloudType> void
99 RangeImage::createFromPointCloud (const PointCloudType& point_cloud,
100  float angular_resolution_x, float angular_resolution_y,
101  float max_angle_width, float max_angle_height,
102  const Eigen::Affine3f& sensor_pose, RangeImage::CoordinateFrame coordinate_frame,
103  float noise_level, float min_range, int border_size)
104 {
105  setAngularResolution (angular_resolution_x, angular_resolution_y);
106 
107  width = static_cast<uint32_t> (pcl_lrint (floor (max_angle_width*angular_resolution_x_reciprocal_)));
108  height = static_cast<uint32_t> (pcl_lrint (floor (max_angle_height*angular_resolution_y_reciprocal_)));
109 
110  int full_width = static_cast<int> (pcl_lrint (floor (pcl::deg2rad (360.0f)*angular_resolution_x_reciprocal_))),
111  full_height = static_cast<int> (pcl_lrint (floor (pcl::deg2rad (180.0f)*angular_resolution_y_reciprocal_)));
112  image_offset_x_ = (full_width -static_cast<int> (width) )/2;
113  image_offset_y_ = (full_height-static_cast<int> (height))/2;
114  is_dense = false;
115 
116  getCoordinateFrameTransformation (coordinate_frame, to_world_system_);
117  to_world_system_ = sensor_pose * to_world_system_;
118 
119  to_range_image_system_ = to_world_system_.inverse (Eigen::Isometry);
120  //std::cout << "to_world_system_ is\n"<<to_world_system_<<"\nand to_range_image_system_ is\n"<<to_range_image_system_<<"\n\n";
121 
122  unsigned int size = width*height;
123  points.clear ();
124  points.resize (size, unobserved_point);
125 
126  int top=height, right=-1, bottom=-1, left=width;
127  doZBuffer (point_cloud, noise_level, min_range, top, right, bottom, left);
128 
129  cropImage (border_size, top, right, bottom, left);
130 
132 }
133 
135 template <typename PointCloudType> void
136 RangeImage::createFromPointCloudWithKnownSize (const PointCloudType& point_cloud, float angular_resolution,
137  const Eigen::Vector3f& point_cloud_center, float point_cloud_radius,
138  const Eigen::Affine3f& sensor_pose, RangeImage::CoordinateFrame coordinate_frame,
139  float noise_level, float min_range, int border_size)
140 {
141  createFromPointCloudWithKnownSize (point_cloud, angular_resolution, angular_resolution, point_cloud_center, point_cloud_radius,
142  sensor_pose, coordinate_frame, noise_level, min_range, border_size);
143 }
144 
146 template <typename PointCloudType> void
147 RangeImage::createFromPointCloudWithKnownSize (const PointCloudType& point_cloud,
148  float angular_resolution_x, float angular_resolution_y,
149  const Eigen::Vector3f& point_cloud_center, float point_cloud_radius,
150  const Eigen::Affine3f& sensor_pose, RangeImage::CoordinateFrame coordinate_frame,
151  float noise_level, float min_range, int border_size)
152 {
153  //MEASURE_FUNCTION_TIME;
154 
155  //std::cout << "Starting to create range image from "<<point_cloud.points.size ()<<" points.\n";
156 
157  // If the sensor pose is inside of the sphere we have to calculate the image the normal way
158  if ((point_cloud_center-sensor_pose.translation()).norm() <= point_cloud_radius) {
159  createFromPointCloud (point_cloud, angular_resolution_x, angular_resolution_y,
160  pcl::deg2rad (360.0f), pcl::deg2rad (180.0f),
161  sensor_pose, coordinate_frame, noise_level, min_range, border_size);
162  return;
163  }
164 
165  setAngularResolution (angular_resolution_x, angular_resolution_y);
166 
167  getCoordinateFrameTransformation (coordinate_frame, to_world_system_);
168  to_world_system_ = sensor_pose * to_world_system_;
169  to_range_image_system_ = to_world_system_.inverse (Eigen::Isometry);
170 
171  float max_angle_size = getMaxAngleSize (sensor_pose, point_cloud_center, point_cloud_radius);
172  int pixel_radius_x = pcl_lrint (ceil (0.5f*max_angle_size*angular_resolution_x_reciprocal_)),
173  pixel_radius_y = pcl_lrint (ceil (0.5f*max_angle_size*angular_resolution_y_reciprocal_));
174  width = 2*pixel_radius_x;
175  height = 2*pixel_radius_y;
176  is_dense = false;
177 
178  image_offset_x_ = image_offset_y_ = 0; // temporary values for getImagePoint
179  int center_pixel_x, center_pixel_y;
180  getImagePoint (point_cloud_center, center_pixel_x, center_pixel_y);
181  image_offset_x_ = (std::max) (0, center_pixel_x-pixel_radius_x);
182  image_offset_y_ = (std::max) (0, center_pixel_y-pixel_radius_y);
183 
184  points.clear ();
185  points.resize (width*height, unobserved_point);
186 
187  int top=height, right=-1, bottom=-1, left=width;
188  doZBuffer (point_cloud, noise_level, min_range, top, right, bottom, left);
189 
190  cropImage (border_size, top, right, bottom, left);
191 
193 }
194 
196 template <typename PointCloudTypeWithViewpoints> void
197 RangeImage::createFromPointCloudWithViewpoints (const PointCloudTypeWithViewpoints& point_cloud,
198  float angular_resolution,
199  float max_angle_width, float max_angle_height,
200  RangeImage::CoordinateFrame coordinate_frame,
201  float noise_level, float min_range, int border_size)
202 {
203  createFromPointCloudWithViewpoints (point_cloud, angular_resolution, angular_resolution,
204  max_angle_width, max_angle_height, coordinate_frame,
205  noise_level, min_range, border_size);
206 }
207 
209 template <typename PointCloudTypeWithViewpoints> void
210 RangeImage::createFromPointCloudWithViewpoints (const PointCloudTypeWithViewpoints& point_cloud,
211  float angular_resolution_x, float angular_resolution_y,
212  float max_angle_width, float max_angle_height,
213  RangeImage::CoordinateFrame coordinate_frame,
214  float noise_level, float min_range, int border_size)
215 {
216  Eigen::Vector3f average_viewpoint = getAverageViewPoint (point_cloud);
217  Eigen::Affine3f sensor_pose = static_cast<Eigen::Affine3f> (Eigen::Translation3f (average_viewpoint));
218  createFromPointCloud (point_cloud, angular_resolution_x, angular_resolution_y, max_angle_width, max_angle_height,
219  sensor_pose, coordinate_frame, noise_level, min_range, border_size);
220 }
221 
223 template <typename PointCloudType> void
224 RangeImage::doZBuffer (const PointCloudType& point_cloud, float noise_level, float min_range, int& top, int& right, int& bottom, int& left)
225 {
226  typedef typename PointCloudType::PointType PointType2;
227  const typename pcl::PointCloud<PointType2>::VectorType &points2 = point_cloud.points;
228 
229  unsigned int size = width*height;
230  int* counters = new int[size];
231  ERASE_ARRAY (counters, size);
232 
233  top=height; right=-1; bottom=-1; left=width;
234 
235  float x_real, y_real, range_of_current_point;
236  int x, y;
237  for (typename pcl::PointCloud<PointType2>::VectorType::const_iterator it=points2.begin (); it!=points2.end (); ++it)
238  {
239  if (!isFinite (*it)) // Check for NAN etc
240  continue;
241  Vector3fMapConst current_point = it->getVector3fMap ();
242 
243  this->getImagePoint (current_point, x_real, y_real, range_of_current_point);
244  this->real2DToInt2D (x_real, y_real, x, y);
245 
246  if (range_of_current_point < min_range|| !isInImage (x, y))
247  continue;
248  //std::cout << " ("<<current_point[0]<<", "<<current_point[1]<<", "<<current_point[2]<<") falls into pixel "<<x<<","<<y<<".\n";
249 
250  // Do some minor interpolation by checking the three closest neighbors to the point, that are not filled yet.
251  int floor_x = pcl_lrint (floor (x_real)), floor_y = pcl_lrint (floor (y_real)),
252  ceil_x = pcl_lrint (ceil (x_real)), ceil_y = pcl_lrint (ceil (y_real));
253 
254  int neighbor_x[4], neighbor_y[4];
255  neighbor_x[0]=floor_x; neighbor_y[0]=floor_y;
256  neighbor_x[1]=floor_x; neighbor_y[1]=ceil_y;
257  neighbor_x[2]=ceil_x; neighbor_y[2]=floor_y;
258  neighbor_x[3]=ceil_x; neighbor_y[3]=ceil_y;
259  //std::cout << x_real<<","<<y_real<<": ";
260 
261  for (int i=0; i<4; ++i)
262  {
263  int n_x=neighbor_x[i], n_y=neighbor_y[i];
264  //std::cout << n_x<<","<<n_y<<" ";
265  if (n_x==x && n_y==y)
266  continue;
267  if (isInImage (n_x, n_y))
268  {
269  int neighbor_array_pos = n_y*width + n_x;
270  if (counters[neighbor_array_pos]==0)
271  {
272  float& neighbor_range = points[neighbor_array_pos].range;
273  neighbor_range = (pcl_isinf (neighbor_range) ? range_of_current_point : (std::min) (neighbor_range, range_of_current_point));
274  top= (std::min) (top, n_y); right= (std::max) (right, n_x); bottom= (std::max) (bottom, n_y); left= (std::min) (left, n_x);
275  }
276  }
277  }
278  //std::cout <<std::endl;
279 
280  // The point itself
281  int arrayPos = y*width + x;
282  float& range_at_image_point = points[arrayPos].range;
283  int& counter = counters[arrayPos];
284  bool addCurrentPoint=false, replace_with_current_point=false;
285 
286  if (counter==0)
287  {
288  replace_with_current_point = true;
289  }
290  else
291  {
292  if (range_of_current_point < range_at_image_point-noise_level)
293  {
294  replace_with_current_point = true;
295  }
296  else if (fabs (range_of_current_point-range_at_image_point)<=noise_level)
297  {
298  addCurrentPoint = true;
299  }
300  }
301 
302  if (replace_with_current_point)
303  {
304  counter = 1;
305  range_at_image_point = range_of_current_point;
306  top= (std::min) (top, y); right= (std::max) (right, x); bottom= (std::max) (bottom, y); left= (std::min) (left, x);
307  //std::cout << "Adding point "<<x<<","<<y<<"\n";
308  }
309  else if (addCurrentPoint)
310  {
311  ++counter;
312  range_at_image_point += (range_of_current_point-range_at_image_point)/counter;
313  }
314  }
315 
316  delete[] counters;
317 }
318 
320 void
321 RangeImage::getImagePoint (float x, float y, float z, float& image_x, float& image_y, float& range) const
322 {
323  Eigen::Vector3f point (x, y, z);
324  getImagePoint (point, image_x, image_y, range);
325 }
326 
328 void
329 RangeImage::getImagePoint (float x, float y, float z, float& image_x, float& image_y) const
330 {
331  float range;
332  getImagePoint (x, y, z, image_x, image_y, range);
333 }
334 
336 void
337 RangeImage::getImagePoint (float x, float y, float z, int& image_x, int& image_y) const
338 {
339  float image_x_float, image_y_float;
340  getImagePoint (x, y, z, image_x_float, image_y_float);
341  real2DToInt2D (image_x_float, image_y_float, image_x, image_y);
342 }
343 
345 void
346 RangeImage::getImagePoint (const Eigen::Vector3f& point, float& image_x, float& image_y, float& range) const
347 {
348  Eigen::Vector3f transformedPoint = to_range_image_system_ * point;
349  range = transformedPoint.norm ();
350  float angle_x = atan2LookUp (transformedPoint[0], transformedPoint[2]),
351  angle_y = asinLookUp (transformedPoint[1]/range);
352  getImagePointFromAngles (angle_x, angle_y, image_x, image_y);
353  //std::cout << " ("<<point[0]<<","<<point[1]<<","<<point[2]<<")"
354  //<< " => ("<<transformedPoint[0]<<","<<transformedPoint[1]<<","<<transformedPoint[2]<<")"
355  //<< " => "<<angle_x<<","<<angle_y<<" => "<<image_x<<","<<image_y<<"\n";
356 }
357 
359 void
360 RangeImage::getImagePoint (const Eigen::Vector3f& point, int& image_x, int& image_y, float& range) const {
361  float image_x_float, image_y_float;
362  getImagePoint (point, image_x_float, image_y_float, range);
363  real2DToInt2D (image_x_float, image_y_float, image_x, image_y);
364 }
365 
367 void
368 RangeImage::getImagePoint (const Eigen::Vector3f& point, float& image_x, float& image_y) const
369 {
370  float range;
371  getImagePoint (point, image_x, image_y, range);
372 }
373 
375 void
376 RangeImage::getImagePoint (const Eigen::Vector3f& point, int& image_x, int& image_y) const
377 {
378  float image_x_float, image_y_float;
379  getImagePoint (point, image_x_float, image_y_float);
380  real2DToInt2D (image_x_float, image_y_float, image_x, image_y);
381 }
382 
384 float
385 RangeImage::checkPoint (const Eigen::Vector3f& point, PointWithRange& point_in_image) const
386 {
387  int image_x, image_y;
388  float range;
389  getImagePoint (point, image_x, image_y, range);
390  if (!isInImage (image_x, image_y))
391  point_in_image = unobserved_point;
392  else
393  point_in_image = getPoint (image_x, image_y);
394  return range;
395 }
396 
398 float
399 RangeImage::getRangeDifference (const Eigen::Vector3f& point) const
400 {
401  int image_x, image_y;
402  float range;
403  getImagePoint (point, image_x, image_y, range);
404  if (!isInImage (image_x, image_y))
405  return -std::numeric_limits<float>::infinity ();
406  float image_point_range = getPoint (image_x, image_y).range;
407  if (pcl_isinf (image_point_range))
408  {
409  if (image_point_range > 0.0f)
410  return std::numeric_limits<float>::infinity ();
411  else
412  return -std::numeric_limits<float>::infinity ();
413  }
414  return image_point_range - range;
415 }
416 
418 void
419 RangeImage::getImagePointFromAngles (float angle_x, float angle_y, float& image_x, float& image_y) const
420 {
421  image_x = (angle_x*cosLookUp (angle_y) + static_cast<float> (M_PI))*angular_resolution_x_reciprocal_ - static_cast<float> (image_offset_x_);
422  image_y = (angle_y + 0.5f*static_cast<float> (M_PI))*angular_resolution_y_reciprocal_ - static_cast<float> (image_offset_y_);
423 }
424 
426 void
427 RangeImage::real2DToInt2D (float x, float y, int& xInt, int& yInt) const
428 {
429  xInt = static_cast<int> (pcl_lrintf (x));
430  yInt = static_cast<int> (pcl_lrintf (y));
431 }
432 
434 bool
435 RangeImage::isInImage (int x, int y) const
436 {
437  return (x >= 0 && x < static_cast<int> (width) && y >= 0 && y < static_cast<int> (height));
438 }
439 
441 bool
442 RangeImage::isValid (int x, int y) const
443 {
444  return isInImage (x,y) && pcl_isfinite (getPoint (x,y).range);
445 }
446 
448 bool
449 RangeImage::isValid (int index) const
450 {
451  return pcl_isfinite (getPoint (index).range);
452 }
453 
455 bool
456 RangeImage::isObserved (int x, int y) const
457 {
458  if (!isInImage (x,y) || (pcl_isinf (getPoint (x,y).range)&&getPoint (x,y).range<0.0f))
459  return false;
460  return true;
461 }
462 
464 bool
465 RangeImage::isMaxRange (int x, int y) const
466 {
467  float range = getPoint (x,y).range;
468  return pcl_isinf (range) && range>0.0f;
469 }
470 
472 const PointWithRange&
473 RangeImage::getPoint (int image_x, int image_y) const
474 {
475  if (!isInImage (image_x, image_y))
476  return unobserved_point;
477  return points[image_y*width + image_x];
478 }
479 
481 const PointWithRange&
482 RangeImage::getPointNoCheck (int image_x, int image_y) const
483 {
484  return points[image_y*width + image_x];
485 }
486 
489 RangeImage::getPointNoCheck (int image_x, int image_y)
490 {
491  return points[image_y*width + image_x];
492 }
493 
496 RangeImage::getPoint (int image_x, int image_y)
497 {
498  return points[image_y*width + image_x];
499 }
500 
501 
503 const PointWithRange&
504 RangeImage::getPoint (int index) const
505 {
506  return points[index];
507 }
508 
510 const PointWithRange&
511 RangeImage::getPoint (float image_x, float image_y) const
512 {
513  int x, y;
514  real2DToInt2D (image_x, image_y, x, y);
515  return getPoint (x, y);
516 }
517 
520 RangeImage::getPoint (float image_x, float image_y)
521 {
522  int x, y;
523  real2DToInt2D (image_x, image_y, x, y);
524  return getPoint (x, y);
525 }
526 
528 void
529 RangeImage::getPoint (int image_x, int image_y, Eigen::Vector3f& point) const
530 {
531  //std::cout << getPoint (image_x, image_y)<< " - " << getPoint (image_x, image_y).getVector3fMap ()<<"\n";
532  point = getPoint (image_x, image_y).getVector3fMap ();
533 }
534 
536 void
537 RangeImage::getPoint (int index, Eigen::Vector3f& point) const
538 {
539  point = getPoint (index).getVector3fMap ();
540 }
541 
543 const Eigen::Map<const Eigen::Vector3f>
544 RangeImage::getEigenVector3f (int x, int y) const
545 {
546  return getPoint (x, y).getVector3fMap ();
547 }
548 
550 const Eigen::Map<const Eigen::Vector3f>
552 {
553  return getPoint (index).getVector3fMap ();
554 }
555 
557 void
558 RangeImage::calculate3DPoint (float image_x, float image_y, float range, Eigen::Vector3f& point) const
559 {
560  float angle_x, angle_y;
561  //std::cout << image_x<<","<<image_y<<","<<range;
562  getAnglesFromImagePoint (image_x, image_y, angle_x, angle_y);
563 
564  float cosY = cosf (angle_y);
565  point = Eigen::Vector3f (range * sinf (angle_x) * cosY, range * sinf (angle_y), range * cosf (angle_x)*cosY);
566  point = to_world_system_ * point;
567 }
568 
570 void
571 RangeImage::calculate3DPoint (float image_x, float image_y, Eigen::Vector3f& point) const
572 {
573  const PointWithRange& point_in_image = getPoint (image_x, image_y);
574  calculate3DPoint (image_x, image_y, point_in_image.range, point);
575 }
576 
578 void
579 RangeImage::calculate3DPoint (float image_x, float image_y, float range, PointWithRange& point) const {
580  point.range = range;
581  Eigen::Vector3f tmp_point;
582  calculate3DPoint (image_x, image_y, range, tmp_point);
583  point.x=tmp_point[0]; point.y=tmp_point[1]; point.z=tmp_point[2];
584 }
585 
587 void
588 RangeImage::calculate3DPoint (float image_x, float image_y, PointWithRange& point) const
589 {
590  const PointWithRange& point_in_image = getPoint (image_x, image_y);
591  calculate3DPoint (image_x, image_y, point_in_image.range, point);
592 }
593 
595 void
596 RangeImage::getAnglesFromImagePoint (float image_x, float image_y, float& angle_x, float& angle_y) const
597 {
598  angle_y = (image_y+static_cast<float> (image_offset_y_))*angular_resolution_y_ - 0.5f*static_cast<float> (M_PI);
599  float cos_angle_y = cosf (angle_y);
600  angle_x = (cos_angle_y==0.0f ? 0.0f : ( (image_x+ static_cast<float> (image_offset_x_))*angular_resolution_x_ - static_cast<float> (M_PI))/cos_angle_y);
601 }
602 
604 float
605 RangeImage::getImpactAngle (int x1, int y1, int x2, int y2) const
606 {
607  if (!isInImage (x1, y1) || !isInImage (x2,y2))
608  return -std::numeric_limits<float>::infinity ();
609  return getImpactAngle (getPoint (x1,y1),getPoint (x2,y2));
610 }
611 
613 float
614 RangeImage::getImpactAngle (const PointWithRange& point1, const PointWithRange& point2) const {
615  if ( (pcl_isinf (point1.range)&&point1.range<0) || (pcl_isinf (point2.range)&&point2.range<0))
616  return -std::numeric_limits<float>::infinity ();
617 
618  float r1 = (std::min) (point1.range, point2.range),
619  r2 = (std::max) (point1.range, point2.range);
620  float impact_angle = static_cast<float> (0.5f * M_PI);
621 
622  if (pcl_isinf (r2))
623  {
624  if (r2 > 0.0f && !pcl_isinf (r1))
625  impact_angle = 0.0f;
626  }
627  else if (!pcl_isinf (r1))
628  {
629  float r1Sqr = r1*r1,
630  r2Sqr = r2*r2,
631  dSqr = squaredEuclideanDistance (point1, point2),
632  d = sqrtf (dSqr);
633  float cos_impact_angle = (r2Sqr + dSqr - r1Sqr)/ (2.0f*r2*d);
634  cos_impact_angle = (std::max) (0.0f, (std::min) (1.0f, cos_impact_angle));
635  impact_angle = acosf (cos_impact_angle); // Using the cosine rule
636  }
637 
638  if (point1.range > point2.range)
639  impact_angle = -impact_angle;
640 
641  return impact_angle;
642 }
643 
645 float
646 RangeImage::getAcutenessValue (const PointWithRange& point1, const PointWithRange& point2) const
647 {
648  float impact_angle = getImpactAngle (point1, point2);
649  if (pcl_isinf (impact_angle))
650  return -std::numeric_limits<float>::infinity ();
651  float ret = 1.0f - float (fabs (impact_angle)/ (0.5f*M_PI));
652  if (impact_angle < 0.0f)
653  ret = -ret;
654  //if (fabs (ret)>1)
655  //std::cout << PVARAC (impact_angle)<<PVARN (ret);
656  return ret;
657 }
658 
660 float
661 RangeImage::getAcutenessValue (int x1, int y1, int x2, int y2) const
662 {
663  if (!isInImage (x1, y1) || !isInImage (x2,y2))
664  return -std::numeric_limits<float>::infinity ();
665  return getAcutenessValue (getPoint (x1,y1), getPoint (x2,y2));
666 }
667 
669 const Eigen::Vector3f
671 {
672  return Eigen::Vector3f (to_world_system_ (0,3), to_world_system_ (1,3), to_world_system_ (2,3));
673 }
674 
676 void
677 RangeImage::getSurfaceAngleChange (int x, int y, int radius, float& angle_change_x, float& angle_change_y) const
678 {
679  angle_change_x = angle_change_y = -std::numeric_limits<float>::infinity ();
680  if (!isValid (x,y))
681  return;
682  Eigen::Vector3f point;
683  getPoint (x, y, point);
684  Eigen::Affine3f transformation = getTransformationToViewerCoordinateFrame (point);
685 
686  if (isObserved (x-radius, y) && isObserved (x+radius, y))
687  {
688  Eigen::Vector3f transformed_left;
689  if (isMaxRange (x-radius, y))
690  transformed_left = Eigen::Vector3f (0.0f, 0.0f, -1.0f);
691  else
692  {
693  Eigen::Vector3f left;
694  getPoint (x-radius, y, left);
695  transformed_left = - (transformation * left);
696  //std::cout << PVARN (transformed_left[1]);
697  transformed_left[1] = 0.0f;
698  transformed_left.normalize ();
699  }
700 
701  Eigen::Vector3f transformed_right;
702  if (isMaxRange (x+radius, y))
703  transformed_right = Eigen::Vector3f (0.0f, 0.0f, 1.0f);
704  else
705  {
706  Eigen::Vector3f right;
707  getPoint (x+radius, y, right);
708  transformed_right = transformation * right;
709  //std::cout << PVARN (transformed_right[1]);
710  transformed_right[1] = 0.0f;
711  transformed_right.normalize ();
712  }
713  angle_change_x = transformed_left.dot (transformed_right);
714  angle_change_x = (std::max) (0.0f, (std::min) (1.0f, angle_change_x));
715  angle_change_x = acosf (angle_change_x);
716  }
717 
718  if (isObserved (x, y-radius) && isObserved (x, y+radius))
719  {
720  Eigen::Vector3f transformed_top;
721  if (isMaxRange (x, y-radius))
722  transformed_top = Eigen::Vector3f (0.0f, 0.0f, -1.0f);
723  else
724  {
725  Eigen::Vector3f top;
726  getPoint (x, y-radius, top);
727  transformed_top = - (transformation * top);
728  //std::cout << PVARN (transformed_top[0]);
729  transformed_top[0] = 0.0f;
730  transformed_top.normalize ();
731  }
732 
733  Eigen::Vector3f transformed_bottom;
734  if (isMaxRange (x, y+radius))
735  transformed_bottom = Eigen::Vector3f (0.0f, 0.0f, 1.0f);
736  else
737  {
738  Eigen::Vector3f bottom;
739  getPoint (x, y+radius, bottom);
740  transformed_bottom = transformation * bottom;
741  //std::cout << PVARN (transformed_bottom[0]);
742  transformed_bottom[0] = 0.0f;
743  transformed_bottom.normalize ();
744  }
745  angle_change_y = transformed_top.dot (transformed_bottom);
746  angle_change_y = (std::max) (0.0f, (std::min) (1.0f, angle_change_y));
747  angle_change_y = acosf (angle_change_y);
748  }
749 }
750 
751 
752 //inline float RangeImage::getSurfaceChange (const PointWithRange& point, const PointWithRange& neighbor1, const PointWithRange& neighbor2) const
753 //{
754  //if (!pcl_isfinite (point.range) || (!pcl_isfinite (neighbor1.range)&&neighbor1.range<0) || (!pcl_isfinite (neighbor2.range)&&neighbor2.range<0))
755  //return -std::numeric_limits<float>::infinity ();
756  //if (pcl_isinf (neighbor1.range))
757  //{
758  //if (pcl_isinf (neighbor2.range))
759  //return 0.0f;
760  //else
761  //return acosf ( (Eigen::Vector3f (point.x, point.y, point.z)-getSensorPos ()).normalized ().dot ( (Eigen::Vector3f (neighbor2.x, neighbor2.y, neighbor2.z)-Eigen::Vector3f (point.x, point.y, point.z)).normalized ()));
762  //}
763  //if (pcl_isinf (neighbor2.range))
764  //return acosf ( (Eigen::Vector3f (point.x, point.y, point.z)-getSensorPos ()).normalized ().dot ( (Eigen::Vector3f (neighbor1.x, neighbor1.y, neighbor1.z)-Eigen::Vector3f (point.x, point.y, point.z)).normalized ()));
765 
766  //float d1_squared = squaredEuclideanDistance (point, neighbor1),
767  //d1 = sqrtf (d1_squared),
768  //d2_squared = squaredEuclideanDistance (point, neighbor2),
769  //d2 = sqrtf (d2_squared),
770  //d3_squared = squaredEuclideanDistance (neighbor1, neighbor2);
771  //float cos_surface_change = (d1_squared + d2_squared - d3_squared)/ (2.0f*d1*d2),
772  //surface_change = acosf (cos_surface_change);
773  //if (pcl_isnan (surface_change))
774  //surface_change = static_cast<float> (M_PI);
776 
777  //return surface_change;
778 //}
779 
781 float
782 RangeImage::getMaxAngleSize (const Eigen::Affine3f& viewer_pose, const Eigen::Vector3f& center, float radius)
783 {
784  return 2.0f * asinf (radius/ (viewer_pose.translation ()-center).norm ());
785 }
786 
788 Eigen::Vector3f
790 {
791  return Eigen::Vector3f (point.x, point.y, point.z);
792 }
793 
795 void
796 RangeImage::get1dPointAverage (int x, int y, int delta_x, int delta_y, int no_of_points, PointWithRange& average_point) const
797 {
798  //std::cout << __PRETTY_FUNCTION__<<" called.\n";
799  //MEASURE_FUNCTION_TIME;
800  float weight_sum = 1.0f;
801  average_point = getPoint (x,y);
802  if (pcl_isinf (average_point.range))
803  {
804  if (average_point.range>0.0f) // The first point is max range -> return a max range point
805  return;
806  weight_sum = 0.0f;
807  average_point.x = average_point.y = average_point.z = average_point.range = 0.0f;
808  }
809 
810  int x2=x, y2=y;
811  Vector4fMap average_point_eigen = average_point.getVector4fMap ();
812  //std::cout << PVARN (no_of_points);
813  for (int step=1; step<no_of_points; ++step)
814  {
815  //std::cout << PVARC (step);
816  x2+=delta_x; y2+=delta_y;
817  if (!isValid (x2, y2))
818  continue;
819  const PointWithRange& p = getPointNoCheck (x2, y2);
820  average_point_eigen+=p.getVector4fMap (); average_point.range+=p.range;
821  weight_sum += 1.0f;
822  }
823  if (weight_sum<= 0.0f)
824  {
825  average_point = unobserved_point;
826  return;
827  }
828  float normalization_factor = 1.0f/weight_sum;
829  average_point_eigen *= normalization_factor;
830  average_point.range *= normalization_factor;
831  //std::cout << PVARN (average_point);
832 }
833 
835 float
836 RangeImage::getEuclideanDistanceSquared (int x1, int y1, int x2, int y2) const
837 {
838  if (!isObserved (x1,y1)||!isObserved (x2,y2))
839  return -std::numeric_limits<float>::infinity ();
840  const PointWithRange& point1 = getPoint (x1,y1),
841  & point2 = getPoint (x2,y2);
842  if (pcl_isinf (point1.range) && pcl_isinf (point2.range))
843  return 0.0f;
844  if (pcl_isinf (point1.range) || pcl_isinf (point2.range))
845  return std::numeric_limits<float>::infinity ();
846  return squaredEuclideanDistance (point1, point2);
847 }
848 
850 float
851 RangeImage::getAverageEuclideanDistance (int x, int y, int offset_x, int offset_y, int max_steps) const
852 {
853  float average_pixel_distance = 0.0f;
854  float weight=0.0f;
855  for (int i=0; i<max_steps; ++i)
856  {
857  int x1=x+i*offset_x, y1=y+i*offset_y;
858  int x2=x+ (i+1)*offset_x, y2=y+ (i+1)*offset_y;
859  float pixel_distance = getEuclideanDistanceSquared (x1,y1,x2,y2);
860  if (!pcl_isfinite (pixel_distance))
861  {
862  //std::cout << x<<","<<y<<"->"<<x2<<","<<y2<<": "<<pixel_distance<<"\n";
863  if (i==0)
864  return pixel_distance;
865  else
866  break;
867  }
868  //std::cout << x<<","<<y<<"->"<<x2<<","<<y2<<": "<<sqrtf (pixel_distance)<<"m\n";
869  weight += 1.0f;
870  average_pixel_distance += sqrtf (pixel_distance);
871  }
872  average_pixel_distance /= weight;
873  //std::cout << x<<","<<y<<","<<offset_x<<","<<offset_y<<" => "<<average_pixel_distance<<"\n";
874  return average_pixel_distance;
875 }
876 
878 float
879 RangeImage::getImpactAngleBasedOnLocalNormal (int x, int y, int radius) const
880 {
881  if (!isValid (x,y))
882  return -std::numeric_limits<float>::infinity ();
883  const PointWithRange& point = getPoint (x, y);
884  int no_of_nearest_neighbors = static_cast<int> (pow (static_cast<double> ( (radius + 1.0)), 2.0));
885  Eigen::Vector3f normal;
886  if (!getNormalForClosestNeighbors (x, y, radius, point, no_of_nearest_neighbors, normal, 1))
887  return -std::numeric_limits<float>::infinity ();
888  return deg2rad (90.0f) - acosf (normal.dot ( (getSensorPos ()-getEigenVector3f (point)).normalized ()));
889 }
890 
891 
893 bool
894 RangeImage::getNormal (int x, int y, int radius, Eigen::Vector3f& normal, int step_size) const
895 {
896  VectorAverage3f vector_average;
897  for (int y2=y-radius; y2<=y+radius; y2+=step_size)
898  {
899  for (int x2=x-radius; x2<=x+radius; x2+=step_size)
900  {
901  if (!isInImage (x2, y2))
902  continue;
903  const PointWithRange& point = getPoint (x2, y2);
904  if (!pcl_isfinite (point.range))
905  continue;
906  vector_average.add (Eigen::Vector3f (point.x, point.y, point.z));
907  }
908  }
909  if (vector_average.getNoOfSamples () < 3)
910  return false;
911  Eigen::Vector3f eigen_values, eigen_vector2, eigen_vector3;
912  vector_average.doPCA (eigen_values, normal, eigen_vector2, eigen_vector3);
913  if (normal.dot ( (getSensorPos ()-vector_average.getMean ()).normalized ()) < 0.0f)
914  normal *= -1.0f;
915  return true;
916 }
917 
919 float
920 RangeImage::getNormalBasedAcutenessValue (int x, int y, int radius) const
921 {
922  float impact_angle = getImpactAngleBasedOnLocalNormal (x, y, radius);
923  if (pcl_isinf (impact_angle))
924  return -std::numeric_limits<float>::infinity ();
925  float ret = 1.0f - static_cast<float> ( (impact_angle / (0.5f * M_PI)));
926  //std::cout << PVARAC (impact_angle)<<PVARN (ret);
927  return ret;
928 }
929 
931 bool
932 RangeImage::getNormalForClosestNeighbors (int x, int y, int radius, const PointWithRange& point,
933  int no_of_nearest_neighbors, Eigen::Vector3f& normal, int step_size) const
934 {
935  return getNormalForClosestNeighbors (x, y, radius, Eigen::Vector3f (point.x, point.y, point.z), no_of_nearest_neighbors, normal, NULL, step_size);
936 }
937 
939 bool
940 RangeImage::getNormalForClosestNeighbors (int x, int y, Eigen::Vector3f& normal, int radius) const
941 {
942  if (!isValid (x,y))
943  return false;
944  int no_of_nearest_neighbors = static_cast<int> (pow (static_cast<double> (radius + 1.0), 2.0));
945  return getNormalForClosestNeighbors (x, y, radius, getPoint (x,y).getVector3fMap (), no_of_nearest_neighbors, normal);
946 }
947 
948 namespace
949 { // Anonymous namespace, so that this is only accessible in this file
950  struct NeighborWithDistance
951  { // local struct to help us with sorting
952  float distance;
953  const PointWithRange* neighbor;
954  bool operator < (const NeighborWithDistance& other) const { return distance<other.distance;}
955  };
956 }
957 
959 bool
960 RangeImage::getSurfaceInformation (int x, int y, int radius, const Eigen::Vector3f& point, int no_of_closest_neighbors, int step_size,
961  float& max_closest_neighbor_distance_squared,
962  Eigen::Vector3f& normal, Eigen::Vector3f& mean, Eigen::Vector3f& eigen_values,
963  Eigen::Vector3f* normal_all_neighbors, Eigen::Vector3f* mean_all_neighbors,
964  Eigen::Vector3f* eigen_values_all_neighbors) const
965 {
966  max_closest_neighbor_distance_squared=0.0f;
967  normal.setZero (); mean.setZero (); eigen_values.setZero ();
968  if (normal_all_neighbors!=NULL)
969  normal_all_neighbors->setZero ();
970  if (mean_all_neighbors!=NULL)
971  mean_all_neighbors->setZero ();
972  if (eigen_values_all_neighbors!=NULL)
973  eigen_values_all_neighbors->setZero ();
974 
975  int blocksize = static_cast<int> (pow (static_cast<double> ( (2.0 * radius + 1.0)), 2.0));
976 
977  PointWithRange given_point;
978  given_point.x=point[0]; given_point.y=point[1]; given_point.z=point[2];
979 
980  std::vector<NeighborWithDistance> ordered_neighbors (blocksize);
981  int neighbor_counter = 0;
982  for (int y2=y-radius; y2<=y+radius; y2+=step_size)
983  {
984  for (int x2=x-radius; x2<=x+radius; x2+=step_size)
985  {
986  if (!isValid (x2, y2))
987  continue;
988  NeighborWithDistance& neighbor_with_distance = ordered_neighbors[neighbor_counter];
989  neighbor_with_distance.neighbor = &getPoint (x2, y2);
990  neighbor_with_distance.distance = squaredEuclideanDistance (given_point, *neighbor_with_distance.neighbor);
991  ++neighbor_counter;
992  }
993  }
994  no_of_closest_neighbors = (std::min) (neighbor_counter, no_of_closest_neighbors);
995 
996  std::sort (ordered_neighbors.begin (), ordered_neighbors.begin () + neighbor_counter); // Normal sort seems to be the fastest method (faster than partial_sort)
997  //std::stable_sort (ordered_neighbors, ordered_neighbors+neighbor_counter);
998  //std::partial_sort (ordered_neighbors, ordered_neighbors+no_of_closest_neighbors, ordered_neighbors+neighbor_counter);
999 
1000  max_closest_neighbor_distance_squared = ordered_neighbors[no_of_closest_neighbors-1].distance;
1001  //float max_distance_squared = max_closest_neighbor_distance_squared;
1002  float max_distance_squared = max_closest_neighbor_distance_squared*4.0f; // Double the allowed distance value
1003  //max_closest_neighbor_distance_squared = max_distance_squared;
1004 
1005  VectorAverage3f vector_average;
1006  //for (int neighbor_idx=0; neighbor_idx<no_of_closest_neighbors; ++neighbor_idx)
1007  int neighbor_idx;
1008  for (neighbor_idx=0; neighbor_idx<neighbor_counter; ++neighbor_idx)
1009  {
1010  if (ordered_neighbors[neighbor_idx].distance > max_distance_squared)
1011  break;
1012  //std::cout << ordered_neighbors[neighbor_idx].distance<<"\n";
1013  vector_average.add (ordered_neighbors[neighbor_idx].neighbor->getVector3fMap ());
1014  }
1015 
1016  if (vector_average.getNoOfSamples () < 3)
1017  return false;
1018  //std::cout << PVARN (vector_average.getNoOfSamples ());
1019  Eigen::Vector3f eigen_vector2, eigen_vector3;
1020  vector_average.doPCA (eigen_values, normal, eigen_vector2, eigen_vector3);
1021  Eigen::Vector3f viewing_direction = (getSensorPos ()-point).normalized ();
1022  if (normal.dot (viewing_direction) < 0.0f)
1023  normal *= -1.0f;
1024  mean = vector_average.getMean ();
1025 
1026  if (normal_all_neighbors==NULL)
1027  return true;
1028 
1029  // Add remaining neighbors
1030  for (int neighbor_idx2=neighbor_idx; neighbor_idx2<neighbor_counter; ++neighbor_idx2)
1031  vector_average.add (ordered_neighbors[neighbor_idx2].neighbor->getVector3fMap ());
1032 
1033  vector_average.doPCA (*eigen_values_all_neighbors, *normal_all_neighbors, eigen_vector2, eigen_vector3);
1034  //std::cout << PVARN (vector_average.getNoOfSamples ())<<".\n";
1035  if (normal_all_neighbors->dot (viewing_direction) < 0.0f)
1036  *normal_all_neighbors *= -1.0f;
1037  *mean_all_neighbors = vector_average.getMean ();
1038 
1039  //std::cout << viewing_direction[0]<<","<<viewing_direction[1]<<","<<viewing_direction[2]<<"\n";
1040 
1041  return true;
1042 }
1043 
1045 float
1046 RangeImage::getSquaredDistanceOfNthNeighbor (int x, int y, int radius, int n, int step_size) const
1047 {
1048  const PointWithRange& point = getPoint (x, y);
1049  if (!pcl_isfinite (point.range))
1050  return -std::numeric_limits<float>::infinity ();
1051 
1052  int blocksize = static_cast<int> (pow (static_cast<double> (2.0 * radius + 1.0), 2.0));
1053  std::vector<float> neighbor_distances (blocksize);
1054  int neighbor_counter = 0;
1055  for (int y2=y-radius; y2<=y+radius; y2+=step_size)
1056  {
1057  for (int x2=x-radius; x2<=x+radius; x2+=step_size)
1058  {
1059  if (!isValid (x2, y2) || (x2==x&&y2==y))
1060  continue;
1061  const PointWithRange& neighbor = getPointNoCheck (x2,y2);
1062  float& neighbor_distance = neighbor_distances[neighbor_counter++];
1063  neighbor_distance = squaredEuclideanDistance (point, neighbor);
1064  }
1065  }
1066  std::sort (neighbor_distances.begin (), neighbor_distances.begin () + neighbor_counter); // Normal sort seems to be
1067  // the fastest method (faster than partial_sort)
1068  n = (std::min) (neighbor_counter, n);
1069  return neighbor_distances[n-1];
1070 }
1071 
1072 
1074 bool
1075 RangeImage::getNormalForClosestNeighbors (int x, int y, int radius, const Eigen::Vector3f& point, int no_of_nearest_neighbors,
1076  Eigen::Vector3f& normal, Eigen::Vector3f* point_on_plane, int step_size) const
1077 {
1078  Eigen::Vector3f mean, eigen_values;
1079  float used_squared_max_distance;
1080  bool ret = getSurfaceInformation (x, y, radius, point, no_of_nearest_neighbors, step_size, used_squared_max_distance,
1081  normal, mean, eigen_values);
1082 
1083  if (ret)
1084  {
1085  if (point_on_plane != NULL)
1086  *point_on_plane = (normal.dot (mean) - normal.dot (point))*normal + point;
1087  }
1088  return ret;
1089 }
1090 
1091 
1093 float
1094 RangeImage::getCurvature (int x, int y, int radius, int step_size) const
1095 {
1096  VectorAverage3f vector_average;
1097  for (int y2=y-radius; y2<=y+radius; y2+=step_size)
1098  {
1099  for (int x2=x-radius; x2<=x+radius; x2+=step_size)
1100  {
1101  if (!isInImage (x2, y2))
1102  continue;
1103  const PointWithRange& point = getPoint (x2, y2);
1104  if (!pcl_isfinite (point.range))
1105  continue;
1106  vector_average.add (Eigen::Vector3f (point.x, point.y, point.z));
1107  }
1108  }
1109  if (vector_average.getNoOfSamples () < 3)
1110  return false;
1111  Eigen::Vector3f eigen_values;
1112  vector_average.doPCA (eigen_values);
1113  return eigen_values[0]/eigen_values.sum ();
1114 }
1115 
1116 
1118 template <typename PointCloudTypeWithViewpoints> Eigen::Vector3f
1119 RangeImage::getAverageViewPoint (const PointCloudTypeWithViewpoints& point_cloud)
1120 {
1121  Eigen::Vector3f average_viewpoint (0,0,0);
1122  int point_counter = 0;
1123  for (unsigned int point_idx=0; point_idx<point_cloud.points.size (); ++point_idx)
1124  {
1125  const typename PointCloudTypeWithViewpoints::PointType& point = point_cloud.points[point_idx];
1126  if (!pcl_isfinite (point.vp_x) || !pcl_isfinite (point.vp_y) || !pcl_isfinite (point.vp_z))
1127  continue;
1128  average_viewpoint[0] += point.vp_x;
1129  average_viewpoint[1] += point.vp_y;
1130  average_viewpoint[2] += point.vp_z;
1131  ++point_counter;
1132  }
1133  average_viewpoint /= point_counter;
1134 
1135  return average_viewpoint;
1136 }
1137 
1139 bool
1140 RangeImage::getViewingDirection (int x, int y, Eigen::Vector3f& viewing_direction) const
1141 {
1142  if (!isValid (x, y))
1143  return false;
1144  viewing_direction = (getPoint (x,y).getVector3fMap ()-getSensorPos ()).normalized ();
1145  return true;
1146 }
1147 
1149 void
1150 RangeImage::getViewingDirection (const Eigen::Vector3f& point, Eigen::Vector3f& viewing_direction) const
1151 {
1152  viewing_direction = (point-getSensorPos ()).normalized ();
1153 }
1154 
1156 Eigen::Affine3f
1157 RangeImage::getTransformationToViewerCoordinateFrame (const Eigen::Vector3f& point) const
1158 {
1159  Eigen::Affine3f transformation;
1160  getTransformationToViewerCoordinateFrame (point, transformation);
1161  return transformation;
1162 }
1163 
1165 void
1166 RangeImage::getTransformationToViewerCoordinateFrame (const Eigen::Vector3f& point, Eigen::Affine3f& transformation) const
1167 {
1168  Eigen::Vector3f viewing_direction = (point-getSensorPos ()).normalized ();
1169  getTransformationFromTwoUnitVectorsAndOrigin (Eigen::Vector3f (0.0f, -1.0f, 0.0f), viewing_direction, point, transformation);
1170 }
1171 
1173 void
1174 RangeImage::getRotationToViewerCoordinateFrame (const Eigen::Vector3f& point, Eigen::Affine3f& transformation) const
1175 {
1176  Eigen::Vector3f viewing_direction = (point-getSensorPos ()).normalized ();
1177  getTransformationFromTwoUnitVectors (Eigen::Vector3f (0.0f, -1.0f, 0.0f), viewing_direction, transformation);
1178 }
1179 
1181 inline void
1182 RangeImage::setAngularResolution (float angular_resolution)
1183 {
1184  angular_resolution_x_ = angular_resolution_y_ = angular_resolution;
1185  angular_resolution_x_reciprocal_ = angular_resolution_y_reciprocal_ = 1.0f / angular_resolution;
1186 }
1187 
1189 inline void
1190 RangeImage::setAngularResolution (float angular_resolution_x, float angular_resolution_y)
1191 {
1192  angular_resolution_x_ = angular_resolution_x;
1193  angular_resolution_x_reciprocal_ = 1.0f / angular_resolution_x_;
1194  angular_resolution_y_ = angular_resolution_y;
1195  angular_resolution_y_reciprocal_ = 1.0f / angular_resolution_y_;
1196 }
1197 
1198 inline void
1199 RangeImage::setTransformationToRangeImageSystem (const Eigen::Affine3f& to_range_image_system)
1200 {
1201  to_range_image_system_ = to_range_image_system;
1202  to_world_system_ = to_range_image_system_.inverse ();
1203 }
1204 
1205 inline void
1206 RangeImage::getAngularResolution (float& angular_resolution_x, float& angular_resolution_y) const
1207 {
1208  angular_resolution_x = angular_resolution_x_;
1209  angular_resolution_y = angular_resolution_y_;
1210 }
1211 
1212 } // namespace end