00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "point_cloud_transformers.h"
00031 #include "rviz/common.h"
00032 #include "rviz/properties/property.h"
00033 #include "rviz/properties/property_manager.h"
00034 #include "rviz/validate_floats.h"
00035 #include <OGRE/OgreColourValue.h>
00036 #include <OGRE/OgreVector3.h>
00037 #include <OGRE/OgreMatrix4.h>
00038
00039 namespace rviz
00040 {
00041 uint8_t IntensityPCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud)
00042 {
00043 int32_t index = findChannelIndex(cloud, "intensity");
00044 if (index == -1)
00045 {
00046 index = findChannelIndex(cloud, "intensities");
00047 }
00048
00049 if (index == -1)
00050 {
00051 return Support_None;
00052 }
00053
00054 return Support_Color;
00055 }
00056
00057 uint8_t IntensityPCTransformer::score(const sensor_msgs::PointCloud2ConstPtr& cloud)
00058 {
00059 int32_t index = findChannelIndex(cloud, "intensity");
00060 if (index == -1)
00061 {
00062 index = findChannelIndex(cloud, "intensities");
00063 }
00064
00065 if (index == -1)
00066 {
00067 return 0;
00068 }
00069
00070 return 255;
00071 }
00072
00073 bool IntensityPCTransformer::transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, PointCloud& out)
00074 {
00075 if (!(mask & Support_Color))
00076 {
00077 return false;
00078 }
00079
00080 int32_t index = findChannelIndex(cloud, "intensity");
00081 if (index == -1)
00082 {
00083 index = findChannelIndex(cloud, "intensities");
00084 }
00085
00086 if (index == -1)
00087 {
00088 return false;
00089 }
00090
00091 const uint32_t offset = cloud->fields[index].offset;
00092 const uint8_t type = cloud->fields[index].datatype;
00093 const uint32_t point_step = cloud->point_step;
00094 const uint32_t num_points = cloud->width * cloud->height;
00095
00096 float min_intensity = 999999.0f;
00097 float max_intensity = 0.0f;
00098 if (auto_compute_intensity_bounds_)
00099 {
00100 for (uint32_t i = 0; i < num_points; ++i)
00101 {
00102 float val = valueFromCloud<float>(cloud, offset, type, point_step, i);
00103 min_intensity = std::min(val, min_intensity);
00104 max_intensity = std::max(val, max_intensity);
00105 }
00106
00107 min_intensity = std::max(0.0f, min_intensity);
00108 max_intensity = std::min(999999.0f, max_intensity);
00109 min_intensity_ = min_intensity;
00110 max_intensity_ = max_intensity;
00111 }
00112 else
00113 {
00114 min_intensity = min_intensity_;
00115 max_intensity = max_intensity_;
00116 }
00117 float diff_intensity = max_intensity - min_intensity;
00118 Color max_color = max_color_;
00119 Color min_color = min_color_;
00120
00121 for (uint32_t i = 0; i < num_points; ++i)
00122 {
00123 float val = valueFromCloud<float>(cloud, offset, type, point_step, i);
00124
00125 float normalized_intensity = diff_intensity > 0.0f ? ( val - min_intensity ) / diff_intensity : 1.0f;
00126 normalized_intensity = std::min(1.0f, std::max(0.0f, normalized_intensity));
00127 out.points[i].color.r = max_color.r_*normalized_intensity + min_color.r_*(1.0f - normalized_intensity);
00128 out.points[i].color.g = max_color.g_*normalized_intensity + min_color.g_*(1.0f - normalized_intensity);
00129 out.points[i].color.b = max_color.b_*normalized_intensity + min_color.b_*(1.0f - normalized_intensity);
00130 }
00131
00132 return true;
00133 }
00134
00135 void IntensityPCTransformer::reset()
00136 {
00137 min_intensity_ = 0.0f;
00138 max_intensity_ = 4096.0f;
00139 }
00140
00141 void IntensityPCTransformer::createProperties(PropertyManager* property_man, const CategoryPropertyWPtr& parent, const std::string& prefix, uint32_t mask, V_PropertyBaseWPtr& out_props)
00142 {
00143 if (mask & Support_Color)
00144 {
00145 min_color_property_ = property_man->createProperty<ColorProperty>( "Min Color", prefix, boost::bind( &IntensityPCTransformer::getMinColor, this ),
00146 boost::bind( &IntensityPCTransformer::setMinColor, this, _1 ), parent, this );
00147 setPropertyHelpText(min_color_property_, "Color to assign the points with the minimum intensity. Actual color is interpolated between this and Max Color.");
00148 max_color_property_ = property_man->createProperty<ColorProperty>( "Max Color", prefix, boost::bind( &IntensityPCTransformer::getMaxColor, this ),
00149 boost::bind( &IntensityPCTransformer::setMaxColor, this, _1 ), parent, this );
00150 setPropertyHelpText(max_color_property_, "Color to assign the points with the maximum intensity. Actual color is interpolated between this and Min Color.");
00151 ColorPropertyPtr color_prop = max_color_property_.lock();
00152
00153 color_prop->addLegacyName("Color");
00154
00155 auto_compute_intensity_bounds_property_ = property_man->createProperty<BoolProperty>( "Autocompute Intensity Bounds", prefix, boost::bind( &IntensityPCTransformer::getAutoComputeIntensityBounds, this ),
00156 boost::bind( &IntensityPCTransformer::setAutoComputeIntensityBounds, this, _1 ), parent, this );
00157 setPropertyHelpText(auto_compute_intensity_bounds_property_, "Whether to automatically compute the intensity min/max values.");
00158 min_intensity_property_ = property_man->createProperty<FloatProperty>( "Min Intensity", prefix, boost::bind( &IntensityPCTransformer::getMinIntensity, this ),
00159 boost::bind( &IntensityPCTransformer::setMinIntensity, this, _1 ), parent, this );
00160 setPropertyHelpText(min_intensity_property_, "Minimum possible intensity value, used to interpolate from Min Color to Max Color for a point.");
00161 max_intensity_property_ = property_man->createProperty<FloatProperty>( "Max Intensity", prefix, boost::bind( &IntensityPCTransformer::getMaxIntensity, this ),
00162 boost::bind( &IntensityPCTransformer::setMaxIntensity, this, _1 ), parent, this );
00163 setPropertyHelpText(max_intensity_property_, "Maximum possible intensity value, used to interpolate from Min Color to Max Color for a point.");
00164
00165 out_props.push_back(min_color_property_);
00166 out_props.push_back(max_color_property_);
00167 out_props.push_back(auto_compute_intensity_bounds_property_);
00168 out_props.push_back(min_intensity_property_);
00169 out_props.push_back(max_intensity_property_);
00170
00171 if (auto_compute_intensity_bounds_)
00172 {
00173 hideProperty(min_intensity_property_);
00174 hideProperty(max_intensity_property_);
00175 }
00176 else
00177 {
00178 showProperty(min_intensity_property_);
00179 showProperty(max_intensity_property_);
00180 }
00181 }
00182 }
00183
00184 void IntensityPCTransformer::setMaxColor( const Color& color )
00185 {
00186 max_color_ = color;
00187
00188 propertyChanged(max_color_property_);
00189
00190 causeRetransform();
00191 }
00192
00193 void IntensityPCTransformer::setMinColor( const Color& color )
00194 {
00195 min_color_ = color;
00196
00197 propertyChanged(min_color_property_);
00198
00199 causeRetransform();
00200 }
00201
00202 void IntensityPCTransformer::setMinIntensity( float val )
00203 {
00204 min_intensity_ = val;
00205 if (min_intensity_ > max_intensity_)
00206 {
00207 min_intensity_ = max_intensity_;
00208 }
00209
00210 propertyChanged(min_intensity_property_);
00211
00212 causeRetransform();
00213 }
00214
00215 void IntensityPCTransformer::setMaxIntensity( float val )
00216 {
00217 max_intensity_ = val;
00218 if (max_intensity_ < min_intensity_)
00219 {
00220 max_intensity_ = min_intensity_;
00221 }
00222
00223 propertyChanged(max_intensity_property_);
00224
00225 causeRetransform();
00226 }
00227
00228 void IntensityPCTransformer::setAutoComputeIntensityBounds(bool compute)
00229 {
00230 auto_compute_intensity_bounds_ = compute;
00231
00232 if (auto_compute_intensity_bounds_)
00233 {
00234 hideProperty(min_intensity_property_);
00235 hideProperty(max_intensity_property_);
00236 }
00237 else
00238 {
00239 showProperty(min_intensity_property_);
00240 showProperty(max_intensity_property_);
00241 }
00242
00243 propertyChanged(auto_compute_intensity_bounds_property_);
00244
00245 causeRetransform();
00246 }
00247
00248 uint8_t XYZPCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud)
00249 {
00250 int32_t xi = findChannelIndex(cloud, "x");
00251 int32_t yi = findChannelIndex(cloud, "y");
00252 int32_t zi = findChannelIndex(cloud, "z");
00253
00254 if (xi == -1 || yi == -1 || zi == -1)
00255 {
00256 return Support_None;
00257 }
00258
00259 if (cloud->fields[xi].datatype == sensor_msgs::PointField::FLOAT32)
00260 {
00261 return Support_XYZ;
00262 }
00263
00264 return Support_None;
00265 }
00266
00267 bool XYZPCTransformer::transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, PointCloud& out)
00268 {
00269 if (!(mask & Support_XYZ))
00270 {
00271 return false;
00272 }
00273
00274 int32_t xi = findChannelIndex(cloud, "x");
00275 int32_t yi = findChannelIndex(cloud, "y");
00276 int32_t zi = findChannelIndex(cloud, "z");
00277
00278 const uint32_t xoff = cloud->fields[xi].offset;
00279 const uint32_t yoff = cloud->fields[yi].offset;
00280 const uint32_t zoff = cloud->fields[zi].offset;
00281 const uint32_t point_step = cloud->point_step;
00282 const uint32_t num_points = cloud->width * cloud->height;
00283 uint8_t const* point = &cloud->data.front();
00284 for (uint32_t i = 0; i < num_points; ++i, point += point_step)
00285 {
00286 float x = *reinterpret_cast<const float*>(point + xoff);
00287 float y = *reinterpret_cast<const float*>(point + yoff);
00288 float z = *reinterpret_cast<const float*>(point + zoff);
00289
00290 Ogre::Vector3 pos(x, y, z);
00291 pos = transform * pos;
00292 out.points[i].position = pos;
00293 }
00294
00295 return true;
00296 }
00297
00298 uint8_t RGB8PCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud)
00299 {
00300 int32_t index = findChannelIndex(cloud, "rgb");
00301 if (index == -1)
00302 {
00303 return Support_None;
00304 }
00305
00306 if (cloud->fields[index].datatype == sensor_msgs::PointField::INT32 ||
00307 cloud->fields[index].datatype == sensor_msgs::PointField::FLOAT32)
00308 {
00309 return Support_Color;
00310 }
00311
00312 return Support_None;
00313 }
00314
00315 bool RGB8PCTransformer::transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, PointCloud& out)
00316 {
00317 if (!(mask & Support_Color))
00318 {
00319 return false;
00320 }
00321
00322 int32_t index = findChannelIndex(cloud, "rgb");
00323
00324 const uint32_t off = cloud->fields[index].offset;
00325 const uint32_t point_step = cloud->point_step;
00326 const uint32_t num_points = cloud->width * cloud->height;
00327 uint8_t const* point = &cloud->data.front();
00328 for (uint32_t i = 0; i < num_points; ++i, point += point_step)
00329 {
00330 uint32_t rgb = *reinterpret_cast<const uint32_t*>(point + off);
00331 float r = ((rgb >> 16) & 0xff) / 255.0f;
00332 float g = ((rgb >> 8) & 0xff) / 255.0f;
00333 float b = (rgb & 0xff) / 255.0f;
00334 out.points[i].color = Ogre::ColourValue(r, g, b);
00335 }
00336
00337 return true;
00338 }
00339
00340 uint8_t RGBF32PCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud)
00341 {
00342 int32_t ri = findChannelIndex(cloud, "r");
00343 int32_t gi = findChannelIndex(cloud, "g");
00344 int32_t bi = findChannelIndex(cloud, "b");
00345 if (ri == -1 || gi == -1 || bi == -1)
00346 {
00347 return Support_None;
00348 }
00349
00350 if (cloud->fields[ri].datatype == sensor_msgs::PointField::FLOAT32)
00351 {
00352 return Support_Color;
00353 }
00354
00355 return Support_None;
00356 }
00357
00358 bool RGBF32PCTransformer::transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, PointCloud& out)
00359 {
00360 if (!(mask & Support_Color))
00361 {
00362 return false;
00363 }
00364
00365 int32_t ri = findChannelIndex(cloud, "r");
00366 int32_t gi = findChannelIndex(cloud, "g");
00367 int32_t bi = findChannelIndex(cloud, "b");
00368
00369 const uint32_t roff = cloud->fields[ri].offset;
00370 const uint32_t goff = cloud->fields[gi].offset;
00371 const uint32_t boff = cloud->fields[bi].offset;
00372 const uint32_t point_step = cloud->point_step;
00373 const uint32_t num_points = cloud->width * cloud->height;
00374 uint8_t const* point = &cloud->data.front();
00375 for (uint32_t i = 0; i < num_points; ++i, point += point_step)
00376 {
00377 float r = *reinterpret_cast<const float*>(point + roff);
00378 float g = *reinterpret_cast<const float*>(point + goff);
00379 float b = *reinterpret_cast<const float*>(point + boff);
00380 out.points[i].color = Ogre::ColourValue(r, g, b);
00381 }
00382
00383 return true;
00384 }
00385
00386 uint8_t FlatColorPCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud)
00387 {
00388 return Support_Color;
00389 }
00390
00391 uint8_t FlatColorPCTransformer::score(const sensor_msgs::PointCloud2ConstPtr& cloud)
00392 {
00393 return 0;
00394 }
00395
00396 bool FlatColorPCTransformer::transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, PointCloud& out)
00397 {
00398 if (!(mask & Support_Color))
00399 {
00400 return false;
00401 }
00402
00403 const uint32_t num_points = cloud->width * cloud->height;
00404 for (uint32_t i = 0; i < num_points; ++i)
00405 {
00406 out.points[i].color = Ogre::ColourValue(color_.r_, color_.g_, color_.b_);
00407 }
00408
00409 return true;
00410 }
00411
00412 void FlatColorPCTransformer::setColor(const Color& c)
00413 {
00414 color_ = c;
00415 propertyChanged(color_property_);
00416 causeRetransform();
00417 }
00418
00419 void FlatColorPCTransformer::createProperties(PropertyManager* property_man, const CategoryPropertyWPtr& parent, const std::string& prefix, uint32_t mask, V_PropertyBaseWPtr& out_props)
00420 {
00421 if (mask & Support_Color)
00422 {
00423 color_property_ = property_man->createProperty<ColorProperty>("Color", prefix, boost::bind( &FlatColorPCTransformer::getColor, this ),
00424 boost::bind( &FlatColorPCTransformer::setColor, this, _1 ), parent, this);
00425 setPropertyHelpText(color_property_, "Color to assign to every point.");
00426
00427 out_props.push_back(color_property_);
00428 }
00429 }
00430
00431 uint8_t AxisColorPCTransformer::supports(const sensor_msgs::PointCloud2ConstPtr& cloud)
00432 {
00433 return Support_Color;
00434 }
00435
00436 uint8_t AxisColorPCTransformer::score(const sensor_msgs::PointCloud2ConstPtr& cloud)
00437 {
00438 return 255;
00439 }
00440
00441 bool AxisColorPCTransformer::transform(const sensor_msgs::PointCloud2ConstPtr& cloud, uint32_t mask, const Ogre::Matrix4& transform, PointCloud& out)
00442 {
00443 if (!(mask & Support_Color))
00444 {
00445 return false;
00446 }
00447
00448 int32_t xi = findChannelIndex(cloud, "x");
00449 int32_t yi = findChannelIndex(cloud, "y");
00450 int32_t zi = findChannelIndex(cloud, "z");
00451
00452 const uint32_t xoff = cloud->fields[xi].offset;
00453 const uint32_t yoff = cloud->fields[yi].offset;
00454 const uint32_t zoff = cloud->fields[zi].offset;
00455 const uint32_t point_step = cloud->point_step;
00456 const uint32_t num_points = cloud->width * cloud->height;
00457 uint8_t const* point = &cloud->data.front();
00458
00459
00460
00461 float min_value_current = 9999.0f;
00462 float max_value_current = -9999.0f;
00463 std::vector<float> values;
00464 values.reserve(num_points);
00465
00466 for (uint32_t i = 0; i < num_points; ++i, point += point_step)
00467 {
00468 float x = *reinterpret_cast<const float*>(point + xoff);
00469 float y = *reinterpret_cast<const float*>(point + yoff);
00470 float z = *reinterpret_cast<const float*>(point + zoff);
00471
00472 Ogre::Vector3 pos(x, y, z);
00473
00474 if (use_fixed_frame_)
00475 {
00476 pos = transform * pos;
00477
00478 ogreToRobot(pos);
00479 }
00480
00481 float val = pos[axis_];
00482 min_value_current = std::min(min_value_current, val);
00483 max_value_current = std::max(max_value_current, val);
00484
00485 values.push_back(val);
00486 }
00487
00488 if (auto_compute_bounds_)
00489 {
00490 min_value_ = min_value_current;
00491 max_value_ = max_value_current;
00492 }
00493
00494 for (uint32_t i = 0; i < num_points; ++i)
00495 {
00496 float range = std::max(max_value_ - min_value_, 0.001f);
00497 float value = 1.0 - (values[i] - min_value_)/range;
00498 getColor(value, out.points[i].color);
00499 }
00500
00501 return true;
00502 }
00503
00504 void AxisColorPCTransformer::createProperties(PropertyManager* property_man, const CategoryPropertyWPtr& parent, const std::string& prefix, uint32_t mask, V_PropertyBaseWPtr& out_props)
00505 {
00506 if (mask & Support_Color)
00507 {
00508 axis_property_ = property_man->createProperty<EnumProperty>("Axis", prefix, boost::bind(&AxisColorPCTransformer::getAxis, this), boost::bind(&AxisColorPCTransformer::setAxis, this, _1),
00509 parent, this);
00510 EnumPropertyPtr prop = axis_property_.lock();
00511 prop->addOption("X", AXIS_X);
00512 prop->addOption("Y", AXIS_Y);
00513 prop->addOption("Z", AXIS_Z);
00514 setPropertyHelpText(axis_property_, "The axis to interpolate the color along.");
00515 auto_compute_bounds_property_ = property_man->createProperty<BoolProperty>( "Autocompute Value Bounds", prefix, boost::bind( &AxisColorPCTransformer::getAutoComputeBounds, this ),
00516 boost::bind( &AxisColorPCTransformer::setAutoComputeBounds, this, _1 ), parent, this );
00517
00518 setPropertyHelpText(auto_compute_bounds_property_, "Whether to automatically compute the value min/max values.");
00519 min_value_property_ = property_man->createProperty<FloatProperty>( "Min Value", prefix, boost::bind( &AxisColorPCTransformer::getMinValue, this ),
00520 boost::bind( &AxisColorPCTransformer::setMinValue, this, _1 ), parent, this );
00521 setPropertyHelpText(min_value_property_, "Minimum value value, used to interpolate the color of a point.");
00522 max_value_property_ = property_man->createProperty<FloatProperty>( "Max Value", prefix, boost::bind( &AxisColorPCTransformer::getMaxValue, this ),
00523 boost::bind( &AxisColorPCTransformer::setMaxValue, this, _1 ), parent, this );
00524 setPropertyHelpText(max_value_property_, "Maximum value value, used to interpolate the color of a point.");
00525
00526 use_fixed_frame_property_ = property_man->createProperty<BoolProperty>( "Use Fixed Frame", prefix, boost::bind( &AxisColorPCTransformer::getUseFixedFrame, this ),
00527 boost::bind( &AxisColorPCTransformer::setUseFixedFrame, this, _1 ), parent, this );
00528 setPropertyHelpText(use_fixed_frame_property_, "Whether to color the cloud based on its fixed frame position or its local frame position.");
00529
00530 out_props.push_back(axis_property_);
00531 out_props.push_back(auto_compute_bounds_property_);
00532 out_props.push_back(min_value_property_);
00533 out_props.push_back(max_value_property_);
00534 out_props.push_back(use_fixed_frame_property_);
00535
00536 if (auto_compute_bounds_)
00537 {
00538 hideProperty(min_value_property_);
00539 hideProperty(max_value_property_);
00540 }
00541 else
00542 {
00543 showProperty(min_value_property_);
00544 showProperty(max_value_property_);
00545 }
00546 }
00547 }
00548
00549 void AxisColorPCTransformer::setUseFixedFrame(bool use)
00550 {
00551 use_fixed_frame_ = use;
00552 propertyChanged(use_fixed_frame_property_);
00553 causeRetransform();
00554 }
00555
00556 void AxisColorPCTransformer::setAxis(int axis)
00557 {
00558 axis_ = axis;
00559 propertyChanged(axis_property_);
00560 causeRetransform();
00561 }
00562
00563 void AxisColorPCTransformer::setMinValue( float val )
00564 {
00565 min_value_ = val;
00566 if (min_value_ > max_value_)
00567 {
00568 min_value_ = max_value_;
00569 }
00570
00571 propertyChanged(min_value_property_);
00572
00573 causeRetransform();
00574 }
00575
00576 void AxisColorPCTransformer::setMaxValue( float val )
00577 {
00578 max_value_ = val;
00579 if (max_value_ < min_value_)
00580 {
00581 max_value_ = min_value_;
00582 }
00583
00584 propertyChanged(max_value_property_);
00585
00586 causeRetransform();
00587 }
00588
00589 void AxisColorPCTransformer::setAutoComputeBounds(bool compute)
00590 {
00591 auto_compute_bounds_ = compute;
00592
00593 if (auto_compute_bounds_)
00594 {
00595 hideProperty(min_value_property_);
00596 hideProperty(max_value_property_);
00597 }
00598 else
00599 {
00600 showProperty(min_value_property_);
00601 showProperty(max_value_property_);
00602 }
00603
00604 propertyChanged(auto_compute_bounds_property_);
00605
00606 causeRetransform();
00607 }
00608
00609 void AxisColorPCTransformer::getColor(float value, Ogre::ColourValue& color)
00610 {
00611 value = std::min(value, 1.0f);
00612 value = std::max(value, 0.0f);
00613
00614 #if 0
00615
00616 if (value < 0.5)
00617 {
00618 float nv = value * 2.0;
00619 color = (1.0 - nv) * Ogre::ColourValue(1.0, 0.0, 0.0) + (nv) * Ogre::ColourValue(0.0, 1.0, 0.0);
00620 }
00621 else
00622 {
00623 float nv = (value - 0.5) * 2.0;
00624 color = (1.0 - nv) * Ogre::ColourValue(0.0, 1.0, 0.0) + (nv) * Ogre::ColourValue(0.0, 0.0, 1.0);
00625 }
00626 #else
00627 float h = value * 5.0f + 1.0f;
00628 int i = floor(h);
00629 float f = h - i;
00630 if ( !(i&1) ) f = 1 - f;
00631 float n = 1 - f;
00632
00633 if (i <= 1) color[0] = n, color[1] = 0, color[2] = 1;
00634 else if (i == 2) color[0] = 0, color[1] = n, color[2] = 1;
00635 else if (i == 3) color[0] = 0, color[1] = 1, color[2] = n;
00636 else if (i == 4) color[0] = n, color[1] = 1, color[2] = 0;
00637 else if (i >= 5) color[0] = 1, color[1] = n, color[2] = 0;
00638 #endif
00639 }
00640
00641 }