DepthImage_to_Laserscan.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  * Copyright (c) 2015, IAV Automotive Engineering
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without 
00008  * modification, are permitted provided that the following conditions are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright notice, 
00011  *    this list of conditions and the following disclaimer.
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright notice, 
00014  *    this list of conditions and the following disclaimer in the documentation 
00015  *    and/or other materials provided with the distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
00019  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
00020  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
00021  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00022  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00023  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
00024  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
00025  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
00026  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
00027  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  */
00030 /*
00031  *  IAV Team
00032  *  http://www.iav.com
00033  *
00034  */
00035 
00036 
00037 #include "../include/DepthImage_to_Laserscan.h"
00038 
00039 using namespace iav_depthimage_to_laserscan;
00040 
00041   
00042 DepthImage_to_Laserscan::DepthImage_to_Laserscan() {
00043 }
00044 
00045 DepthImage_to_Laserscan::~DepthImage_to_Laserscan() {
00046 }
00047 
00048 /*
00049 * Determines whether or not new_value should replace old_value in the LaserScan.
00050 *
00051 * Uses the values of range_min, and range_max to determine if new_value is a valid point.  Then it determines if
00052 * new_value is 'more ideal' (currently shorter range) than old_value.
00053 *
00054 * @param new_value The current calculated range.
00055 * @param old_value The current range in the output LaserScan.
00056 * @param range_min The minimum acceptable range for the output LaserScan.
00057 * @param range_max The maximum acceptable range for the output LaserScan.
00058 * @return If true, insert new_value into the output LaserScan. 
00059 */
00060 
00061 bool DepthImage_to_Laserscan::use_point(float new_value, float old_value, float range_min, float range_max) {  
00062   // Check for NaNs and Infs, a real number within our limits is more desirable than these.
00063   bool new_finite = std::isfinite(new_value);
00064   bool old_finite = std::isfinite(old_value);
00065   
00066   // Infs are preferable over NaNs (more information)
00067   if(!new_finite && !old_finite){ // Both are not NaN or Inf.
00068     if(!isnan(new_value)){ // new is not NaN, so use it's +-Inf value.
00069       return true;
00070     }
00071     return false; // Do not replace old_value
00072   }
00073   
00074   // If not in range, don't bother
00075   bool range_check = range_min <= new_value && new_value <= range_max;
00076   if(!range_check){
00077     return false;
00078   }
00079   
00080   if(!old_finite){ // New value is in range and finite, use it.
00081     return true;
00082   }
00083   
00084   // Finally, if they are both numerical and new_value is closer than old_value, use new_value.
00085   bool shorter_check = new_value < old_value;
00086   return shorter_check;
00087 }
00088 
00089 /*
00090 * Create and initiatilize a new parameter LaserScan associated with the image.
00091 *
00092 * This function converts the information in the depth encoded image (UInt16 or Float32 encoding) into
00093 * a sensor_msgs::LaserScan. 
00094 *
00095 * @param depth_msg UInt16 or Float32 encoded depth image.
00096 * @param Param Parameters of the camera(s).
00097 * @return sensor_msgs::LaserScanPtr for the area of the depth image bounded by height_max and height_min. 
00098 */ 
00099 
00100 sensor_msgs::LaserScanPtr DepthImage_to_Laserscan::convert_msg(const sensor_msgs::ImageConstPtr& depth_msg, const CParam& Param, const LSParam& lsparam) 
00101 {
00102   // Create a new parameter LaserScan associated with the header of Image
00103   sensor_msgs::LaserScanPtr scan_msg(new sensor_msgs::LaserScan());
00104   scan_msg->header = depth_msg->header;
00105 
00106   // Add a frame 
00107   if(lsparam.laser_output_frame_id.length() > 0){
00108      scan_msg->header.frame_id = lsparam.laser_output_frame_id;
00109   }
00110 
00111   // Calculate and fill the ranges
00112   uint32_t ranges_size = lsparam.laser_rays - 1;
00113   scan_msg->ranges.assign(ranges_size, std::numeric_limits<float>::quiet_NaN());
00114 
00115   scan_msg->angle_min = lsparam.laser_min_angle;
00116   scan_msg->angle_max = lsparam.laser_max_angle;
00117   scan_msg->angle_increment = (scan_msg->angle_max - scan_msg->angle_min) / (scan_msg->ranges.size() - 1);;
00118   scan_msg->time_increment = 0.0;
00119   scan_msg->scan_time = 0;
00120   scan_msg->range_min = lsparam.laser_min_range;
00121   scan_msg->range_max = lsparam.laser_max_range;
00122   
00123   if (depth_msg->encoding == sensor_msgs::image_encodings::TYPE_16UC1)
00124   {
00125      convert_dtl<uint16_t>(depth_msg, Param, lsparam, scan_msg);
00126   }
00127   else if (depth_msg->encoding == sensor_msgs::image_encodings::TYPE_32FC1)
00128   {
00129      convert_dtl<float>(depth_msg, Param, lsparam, scan_msg);
00130   }     
00131   else
00132   {
00133     std::stringstream ss;
00134     ss << "Depth image has unsupported encoding: " << depth_msg->encoding;
00135     throw std::runtime_error(ss.str());
00136   }
00137   
00138   return scan_msg;
00139 
00140 }
00141 
00142 /*
00143 * Fill the ranges with points of the depth image msg.
00144 *
00145 * This uses a method to project each pixel into a LaserScan angular increment. When multiple points coorespond to
00146 * a specific angular measurement, then the shortest range is used.
00147 *
00148 * @param depth_msg The UInt16 or Float32 encoded depth message.
00149 * @param Param Parameters of the camera(s).
00150 * @param scan_msg The output LaserScan.
00151 */
00152 
00153 template<typename T>
00154 void DepthImage_to_Laserscan::convert_dtl(const sensor_msgs::ImageConstPtr& depth_msg, const CParam& Param, const LSParam& lsparam, const sensor_msgs::LaserScanPtr& scan_msg) 
00155 {
00156 
00157   double r; // range
00158   T depth; // depth point
00159   double d; // depth in meters
00160   int index; // index for the correct depth points
00161 
00162   // Auxiliaries for the Resolution Mapping
00163   int i_start = 0;
00164   int i_stop = 0;
00165 
00166   // Calculate the resolution of the camera and laser
00167   float cam_resolution = Param.cam_image_width/Param.cam_AOV_h;
00168   float laser_resolution = lsparam.laser_rays/(lsparam.laser_max_angle - lsparam.laser_min_angle);
00169 
00170   // Means to acess every depth point of the image
00171   const T* depth_row = reinterpret_cast<const T*>(&depth_msg->data[0]);
00172   int row_step = depth_msg->step / sizeof(T);
00173 
00174   // Initialize the ranges
00175   for (int i=0; i < scan_msg->ranges.size(); i++) scan_msg->ranges[i] = scan_msg->range_max;
00176 
00177   // Loop over all depth image data
00178   for(int row = 0; row < Param.cam_image_height; row++, depth_row += row_step) {
00179      
00180      for(int col = 0; col < Param.cam_image_width; col++) {
00181         depth = depth_row[col];
00182         d = depth * 0.001f - Param.cam_offset; // originally mm
00183         index = Param.cam_index[col];
00184    
00185         // Checks if the distance is between the distances limits (height_max and height_min)
00186         if((Param.cam_min_distances[row] <= d) && (d <= Param.cam_max_distances [row])) {
00187            r = d/Param.cam_cos_h[col];
00188            
00189            // Determines whether or not new_value should replace old_value in the LaserScan.
00190            if(use_point(r, scan_msg->ranges[index], lsparam.laser_min_range, lsparam.laser_max_range)) { 
00191         
00192               // Resolution Mapping
00193               if ((cam_resolution < laser_resolution) && (col < Param.cam_image_width - 1))
00194               {
00195                  // loop over all fitting idx in laserscan i_start = f(col) and i_stop = f(col)
00196                  i_stop = Param.cam_index[col];
00197                  i_start = Param.cam_index[col+1];
00198                  
00199                  for (int i=i_start; i <= i_stop; i++) scan_msg->ranges[i] = r;
00200               }
00201               else
00202               {
00203                  // look for matching idx in laserscan i = f(col)
00204                  scan_msg->ranges[index] = r;
00205               }
00206            }
00207         }
00208      }
00209   }
00210 }


iav_depthimage_to_laserscan
Author(s): Jan Obermueller
autogenerated on Thu Jun 6 2019 20:28:38