Program Listing for File DepthImageToLaserScan.hpp

Return to documentation for file (/tmp/ws/src/depthimage_to_laserscan/include/depthimage_to_laserscan/DepthImageToLaserScan.hpp)

// Copyright (c) 2012, Willow Garage, Inc.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the copyright holder nor the names of its
//      contributors may be used to endorse or promote products derived from
//      this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

/*
 * Author: Chad Rockey
 */

#ifndef DEPTHIMAGE_TO_LASERSCAN__DEPTHIMAGETOLASERSCAN_HPP_
#define DEPTHIMAGE_TO_LASERSCAN__DEPTHIMAGETOLASERSCAN_HPP_

#include <cmath>
#include <string>

#include "depthimage_to_laserscan/DepthImageToLaserScan_export.h"
#include "depthimage_to_laserscan/depth_traits.hpp"
#if __has_include("image_geometry/pinhole_camera_model.hpp")
#include "image_geometry/pinhole_camera_model.hpp"
#else
// This header was deprecated as of https://github.com/ros-perception/vision_opencv/pull/448
// (for Iron), and will be completely removed for J-Turtle.  However, we still need it in
// Humble, since the .hpp doesn't exist there.
#include "image_geometry/pinhole_camera_model.h"
#endif
#include <opencv2/core/core.hpp>
#include <sensor_msgs/msg/camera_info.hpp>
#include <sensor_msgs/msg/image.hpp>
#include <sensor_msgs/msg/laser_scan.hpp>

namespace depthimage_to_laserscan
{
class DEPTHIMAGETOLASERSCAN_EXPORT DepthImageToLaserScan final
{
public:
  explicit DepthImageToLaserScan(
    float scan_time, float range_min, float range_max, int scan_height,
    const std::string & frame_id);

  ~DepthImageToLaserScan();

  sensor_msgs::msg::LaserScan::UniquePtr convert_msg(
    const sensor_msgs::msg::Image::ConstSharedPtr & depth_msg,
    const sensor_msgs::msg::CameraInfo::ConstSharedPtr & info_msg);

private:
  double magnitude_of_ray(const cv::Point3d & ray) const;

  double angle_between_rays(const cv::Point3d & ray1, const cv::Point3d & ray2) const;

  bool use_point(
    const float new_value, const float old_value, const float range_min,
    const float range_max) const;

  template<typename T>
  void convert(
    const sensor_msgs::msg::Image::ConstSharedPtr & depth_msg,
    const image_geometry::PinholeCameraModel & cam_model,
    const sensor_msgs::msg::LaserScan::UniquePtr & scan_msg, const int & scan_height) const
  {
    // Use correct principal point from calibration
    float center_x = cam_model.cx();

    // Combine unit conversion (if necessary) with scaling by focal length for computing (X,Y)
    double unit_scaling = depthimage_to_laserscan::DepthTraits<T>::toMeters(T(1));
    float constant_x = unit_scaling / cam_model.fx();

    const T * depth_row = reinterpret_cast<const T *>(&depth_msg->data[0]);
    int row_step = depth_msg->step / sizeof(T);

    int offset = static_cast<int>(cam_model.cy() - static_cast<double>(scan_height) / 2.0);
    depth_row += offset * row_step;  // Offset to center of image
    for (int v = offset; v < offset + scan_height_; v++, depth_row += row_step) {
      for (uint32_t u = 0; u < depth_msg->width; u++) {  // Loop over each pixel in row
        T depth = depth_row[u];

        double r = depth;  // Assign to pass through NaNs and Infs
        // Atan2(x, z), but depth divides out
        double th = -std::atan2(static_cast<double>(u - center_x) * constant_x, unit_scaling);
        int index = (th - scan_msg->angle_min) / scan_msg->angle_increment;

        if (depthimage_to_laserscan::DepthTraits<T>::valid(depth)) {  // Not NaN or Inf
          // Calculate in XYZ
          double x = (u - center_x) * depth * constant_x;
          double z = depthimage_to_laserscan::DepthTraits<T>::toMeters(depth);

          // Calculate actual distance
          r = std::sqrt(std::pow(x, 2.0) + std::pow(z, 2.0));
        }

        // Determine if this point should be used.
        if (use_point(r, scan_msg->ranges[index], scan_msg->range_min, scan_msg->range_max)) {
          scan_msg->ranges[index] = r;
        }
      }
    }
  }

  image_geometry::PinholeCameraModel cam_model_;

  float scan_time_;
  float range_min_;
  float range_max_;
  int scan_height_;
  std::string output_frame_id_;
};
}  // namespace depthimage_to_laserscan

#endif  // DEPTHIMAGE_TO_LASERSCAN__DEPTHIMAGETOLASERSCAN_HPP_