9 #define M_PI (3.14159265358979323846) 15 const sensor_msgs::ImageConstPtr & depth_msg,
16 const sensor_msgs::CameraInfoConstPtr & info_msg) {
21 double min_angle, max_angle;
22 using Point = cv::Point2d;
26 Point(
cam_model_.
cx(), depth_msg->height - 1), min_angle, max_angle);
27 double vertical_fov = max_angle - min_angle;
31 Point(depth_msg->width - 1,
cam_model_.
cy()), min_angle, max_angle);
43 scan_msg_->angle_increment = (max_angle - min_angle) / (depth_msg->width - 1);
64 ss <<
"scan_height ( " <<
scan_height_ <<
" pixels) is too large for the image height.";
65 throw std::runtime_error(ss.str());
78 scan_msg_->ranges.assign(depth_msg->width, std::numeric_limits<float>::quiet_NaN());
82 convertDepthToPolarCoords<uint16_t>(depth_msg);
85 convertDepthToPolarCoords<float>(depth_msg);
89 ss <<
"Depth image has unsupported encoding: " << depth_msg->encoding;
90 throw std::runtime_error(ss.str());
103 if (rmin >= 0 && rmin < rmax) {
108 ROS_ERROR(
"Incorrect value of range minimal parameter. Set default value: 0.");
110 if (rmax >= 0 && rmin < rmax) {
115 ROS_ERROR(
"Incorrect value of range maximum parameter. Set default value: 10.");
120 if (scan_height > 0) {
125 ROS_ERROR(
"Incorrect value of scan height parameter. Set default value: 100.");
135 ROS_ERROR(
"Incorrect value depth imgage row step parameter. Set default value: 1.");
145 ROS_ERROR(
"Incorrect value of sensor mount height parameter. Set default value: 0.");
150 if (angle < 90 && angle > -90) {
155 ROS_ERROR(
"Incorrect value of sensor tilt angle parameter. Set default value: 0.");
165 ROS_ERROR(
"Incorrect value of ground margin parameter. Set default value: 0.");
170 if (threads_num >= 1) {
175 ROS_ERROR(
"Incorrect number of threads. Set default value: 1.");
192 for(
int i = 0; i < img_height; ++i) {
194 double delta = vertical_fov * (i -
cam_model_.
cy() - 0.5) / (
static_cast<double>(img_height) - 1);
196 if ((delta - alpha) > 0) {
208 std::ostringstream
s;
209 s <<
" calcGroundDistancesForImgRows:";
210 for (
int i = 0; i < img_height; i+=10) {
224 for(
int i = 0; i < img_height; ++i) {
225 double delta = vertical_fov * (i -
cam_model_.
cy() - 0.5) / ((double)img_height - 1);
236 for (
size_t u = 0; u < static_cast<size_t>(depth_msg->width); u++) {
242 template <
typename T>
244 float depth_min = std::numeric_limits<float>::max();
245 int depth_min_row = -1;
247 const int row_size = depth_msg->width;
248 const T* data =
reinterpret_cast<const T*
>(&depth_msg->data[0]);
253 float depth_raw = 0.0;
256 if (
typeid(T) ==
typeid(uint16_t)) {
257 unsigned depth_raw_mm =
static_cast<unsigned>(data[row_size * i + col]);
258 depth_raw =
static_cast<float>(depth_raw_mm) / 1000.0;
260 else if (
typeid(T) ==
typeid(float)) {
261 depth_raw =
static_cast<float>(data[row_size * i + col]);
281 if (depth_m < depth_min) {
296 template float LaserScanKinect::getSmallestValueInColumn<uint16_t>(
const sensor_msgs::ImageConstPtr&, int);
297 template float LaserScanKinect::getSmallestValueInColumn<float>(
const sensor_msgs::ImageConstPtr&, int);
302 template <
typename T>
306 auto convert_to_polar = [&](
size_t col,
float depth) ->
float {
307 if (depth != std::numeric_limits<T>::max()) {
312 return sqrt(x * x + depth * depth);
318 auto process_columns = [&](
size_t left,
size_t right) {
319 for (
size_t i = left; i <= right; ++i) {
320 const auto depth_min = getSmallestValueInColumn<T>(depth_msg, i);
321 const auto range_in_polar = convert_to_polar(i, depth_min);
329 std::stringstream log;
330 auto start = high_resolution_clock::now();
333 process_columns(0, static_cast<size_t>(depth_msg->width - 1));
336 std::vector<std::thread> workers;
338 size_t step =
static_cast<size_t>(depth_msg->width) /
threads_num_;
339 log <<
"step: " << step;
342 workers.push_back(std::thread(process_columns, left, left + step - 1));
343 log <<
" w" << i <<
": (" << left <<
", " << left + step -1 <<
") ";
347 for (
auto &t : workers) {
352 auto end = (high_resolution_clock::now() - start);
353 log <<
" time[ms]: " << std::chrono::duration<double, std::milli>(end).count() <<
"\n";
358 const std::list<std::pair<int, int>>& min_dist_points_indices) {
360 sensor_msgs::ImagePtr img(
new sensor_msgs::Image);
361 img->header = depth_msg->header;
362 img->height = depth_msg->height;
363 img->width = depth_msg->width;
364 img->encoding =
"rgb8";
365 img->is_bigendian = depth_msg->is_bigendian;
366 img->step = img->width * 3;
368 img->data.resize(img->step * img->height);
369 uint8_t(*rgb_data)[3] =
reinterpret_cast<uint8_t(*)[3]
>(&img->data[0]);
373 const uint16_t* depth_data =
reinterpret_cast<const uint16_t*
>(&depth_msg->data[0]);
374 for (
unsigned i = 0; i < (img->width * img->height); ++i) {
377 rgb_data[i][0] = 255 - val;
378 rgb_data[i][1] = 255 - val;
379 rgb_data[i][2] = 255 - val;
383 const float* depth_data =
reinterpret_cast<const float*
>(&depth_msg->data[0]);
384 for (
unsigned i = 0; i < (img->width * img->height); ++i) {
387 rgb_data[i][0] = 255 - val;
388 rgb_data[i][1] = 255 - val;
389 rgb_data[i][2] = 255 - val;
393 throw std::runtime_error(
"Unsupported depth image encoding");
397 for (
const auto pt : min_dist_points_indices) {
398 const auto row = pt.first;
399 const auto col = pt.second;
400 if (row >= 0 && col >= 0) {
401 rgb_data[row * img->width + col][0] = 255;
402 rgb_data[row * img->width + col][1] = 0;
403 rgb_data[row * img->width + col][2] = 0;
408 std::list<std::pair<unsigned, unsigned>> pts;
409 for (
unsigned i = 0; i < img->width; ++i) {
412 if (line1_row >= 0 && line1_row < img->height && line2_row >= 0 && line2_row < img->height) {
413 pts.push_back({line1_row, i});
414 pts.push_back({line2_row, i});
418 for (
const auto pt : pts) {
419 const auto row = pt.first;
420 const auto col = pt.second;
421 rgb_data[row * img->width + col][0] = 0;
422 rgb_data[row * img->width + col][1] = 255;
423 rgb_data[row * img->width + col][2] = 0;
void setRangeLimits(const float rmin, const float rmax)
setRangeLimits sets depth sensor min and max ranges
void calcScanMsgIndexForImgCols(const sensor_msgs::ImageConstPtr &depth_msg)
calcScanMsgIndexForImgCols
cv::Size fullResolution() const
sensor_msgs::ImagePtr dbg_image_
void setDepthImgRowStep(const int row_step)
setDepthImgRowStep
float getSmallestValueInColumn(const sensor_msgs::ImageConstPtr &depth_msg, int col)
getSmallestValueInColumn finds smallest values in depth image columns
unsigned scan_height_
Number of pixel rows used to scan computing.
bool publish_dbg_image_
Determines if debug image should be published.
sensor_msgs::ImageConstPtr getDbgImage() const
bool tilt_compensation_enable_
Determines if tilt compensation feature is on.
void setSensorTiltAngle(const float angle)
setSensorTiltAngle sets the sensor tilt angle (in degrees)
float sensor_tilt_angle_
Angle of sensor tilt.
float ground_margin_
Margin for floor remove feature (in meters)
bool is_scan_msg_configured_
Determines if laser scan message is configurated.
unsigned depth_img_row_step_
Row step in depth map processing.
std::list< std::pair< int, int > > min_dist_points_indices_
void setThreadsNum(unsigned threads_num)
void setSensorMountHeight(const float height)
setSensorMountHeight sets the height of sensor mount (in meters)
unsigned threads_num_
Determines threads number used in image processing.
image_geometry::PinholeCameraModel cam_model_
Class for managing CameraInfo messages.
float range_min_
Stores the current minimum range to use.
std::mutex points_indices_mutex_
bool fromCameraInfo(const sensor_msgs::CameraInfo &msg)
const std::string TYPE_32FC1
void convertDepthToPolarCoords(const sensor_msgs::ImageConstPtr &depth_msg)
convertDepthToPolarCoords converts depth map to 2D
const std::string TYPE_16UC1
void calcFieldOfView(const image_geometry::PinholeCameraModel &camera_model, const cv::Point2d &&left, const cv::Point2d &¢er, const cv::Point2d &&right, double &min, double &max)
fieldOfView calculates field of view (angle)
bool cam_model_update_
If continously calibration update required.
#define ROS_DEBUG_STREAM(args)
std::vector< unsigned > scan_msg_index_
Calculated laser scan msg indexes for each depth image column.
sensor_msgs::ImagePtr prepareDbgImage(const sensor_msgs::ImageConstPtr &depth_msg, const std::list< std::pair< int, int >> &min_dist_points_indices)
sensor_msgs::LaserScanPtr getLaserScanMsg(const sensor_msgs::ImageConstPtr &depth_msg, const sensor_msgs::CameraInfoConstPtr &info_msg)
prepareLaserScanMsg converts depthimage and prepare new LaserScan message
std::vector< float > tilt_compensation_factor_
Calculated sensor tilt compensation factors.
int image_vertical_offset_
The vertical offset of image based on calibration data.
std::mutex scan_msg_mutex_
void calcGroundDistancesForImgRows(double vertical_fov)
calcGroundDistancesForImgRows calculate coefficients used in ground removing from scan ...
sensor_msgs::LaserScanPtr scan_msg_
Published scan message.
void setScanHeight(const int scan_height)
setScanHeight sets height of depth image which will be used in conversion process ...
void setGroundMargin(const float margin)
setGroundMargin sets the floor margin (in meters)
std::string output_frame_id_
Output frame_id for laserscan message.
void calcTiltCompensationFactorsForImgRows(double vertical_fov)
calcTiltCompensationFactorsForImgRows calculate factors used in tilt compensation ...
float sensor_mount_height_
Height of sensor mount from ground.
#define ROS_INFO_STREAM_THROTTLE(rate, args)
std::vector< float > dist_to_ground_corrected
Calculated maximal distances for measurements not included as floor.
bool ground_remove_enable_
Determines if remove ground from output scan.
float range_max_
Stores the current maximum range to use.