camera_info_display.cpp
Go to the documentation of this file.
00001 // -*- mode: c++ -*-
00002 /*********************************************************************
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2014, JSK Lab
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/o2r other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the JSK Lab nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *********************************************************************/
00035 
00036 #include <rviz/uniform_string_stream.h>
00037 #include "camera_info_display.h"
00038 #include <OGRE/OgreMaterialManager.h>
00039 #include <OGRE/OgreMaterial.h>
00040 #include <OGRE/OgreBlendMode.h>
00041 #include <QImage>
00042 #include <OGRE/OgreHardwarePixelBuffer.h>
00043 
00044 namespace jsk_rviz_plugins
00045 {
00046   TrianglePolygon::TrianglePolygon(
00047     Ogre::SceneManager* manager,
00048     Ogre::SceneNode* node,
00049     const cv::Point3d& O,
00050     const cv::Point3d& A,
00051     const cv::Point3d& B,
00052     const std::string& name,
00053     const Ogre::ColourValue& color,
00054     bool use_color,
00055     bool upper_triangle)
00056   {
00057     // uniq string is requred for name
00058     
00059     manual_ = manager->createManualObject();
00060     manual_->clear();
00061     manual_->begin(name,
00062                    Ogre::RenderOperation::OT_TRIANGLE_STRIP);
00063     manual_->position(O.x, O.y, O.z);
00064     if (upper_triangle) {
00065       manual_->textureCoord(0, 0);
00066     }
00067     else {
00068       manual_->textureCoord(1, 0);
00069     }
00070     if (use_color) {
00071       manual_->colour(color);
00072     }
00073     manual_->position(A.x, A.y, A.z);
00074     if (upper_triangle) {
00075       manual_->textureCoord(1, 0);
00076     }
00077     else {
00078       manual_->textureCoord(1, 1);
00079     }
00080     if (use_color) {
00081       manual_->colour(color);
00082     }
00083     manual_->position(B.x, B.y, B.z);
00084     if (upper_triangle) {
00085       manual_->textureCoord(0, 1);
00086     }
00087     else {
00088       manual_->textureCoord(0, 1);
00089     }
00090     if (use_color) {
00091       manual_->colour(color);
00092     }
00093     manual_->end();
00094     node->attachObject(manual_);
00095   }
00096 
00097   TrianglePolygon::~TrianglePolygon()
00098   {
00099     manual_->detachFromParent();
00100     //manager_->destroyManualObject(manual_); // this crashes rviz
00101   }
00102   
00103   CameraInfoDisplay::CameraInfoDisplay(): image_updated_(true)
00104   {
00106     // initialize properties
00108     far_clip_distance_property_ = new rviz::FloatProperty(
00109       "far clip",
00110       1.0,
00111       "far clip distance from the origin of camera info",
00112       this, SLOT(updateFarClipDistance()));
00113     show_edges_property_ = new rviz::BoolProperty(
00114       "show edges",
00115       true,
00116       "show edges of the region of the camera info",
00117       this, SLOT(updateShowEdges()));
00118     show_polygons_property_ = new rviz::BoolProperty(
00119       "show polygons",
00120       true,
00121       "show polygons of the region of the camera info",
00122       this, SLOT(updateShowPolygons()));
00123     not_show_side_polygons_property_ = new rviz::BoolProperty(
00124       "not show side polygons",
00125       true,
00126       "do not show polygons of the region of the camera info",
00127       this, SLOT(updateNotShowSidePolygons()));
00128     use_image_property_ = new rviz::BoolProperty(
00129       "use image",
00130       false,
00131       "use image as texture",
00132       this, SLOT(updateUseImage()));
00133     image_topic_property_ = new rviz::RosTopicProperty(
00134       "Image Topic", "",
00135       ros::message_traits::datatype<sensor_msgs::Image>(),
00136       "sensor_msgs::Image topic to subscribe to.",
00137       this, SLOT( updateImageTopic() ));
00138     color_property_ = new rviz::ColorProperty(
00139       "color",
00140       QColor(85, 255, 255),
00141       "color of CameraInfo",
00142       this, SLOT(updateColor()));
00143     edge_color_property_ = new rviz::ColorProperty(
00144       "edge color",
00145       QColor(125, 125, 125),
00146       "edge color of CameraInfo",
00147       this, SLOT(updateEdgeColor()));
00148     alpha_property_ = new rviz::FloatProperty(
00149       "alpha",
00150       0.5,
00151       "alpha blending value",
00152       this, SLOT(updateAlpha()));
00153   }
00154   
00155   CameraInfoDisplay::~CameraInfoDisplay()
00156   {
00157     if (edges_) {
00158       edges_->clear();
00159     }
00160     polygons_.clear();
00161     delete far_clip_distance_property_;
00162     delete color_property_;
00163     delete alpha_property_;
00164     delete show_polygons_property_;
00165     delete edge_color_property_;
00166   }
00167 
00168   void CameraInfoDisplay::reset()
00169   {
00170     MFDClass::reset();
00171     if (edges_) {
00172       edges_->clear();
00173     }
00174     polygons_.clear();
00175     camera_info_ = sensor_msgs::CameraInfo::ConstPtr(); // reset to NULL
00176   }
00177 
00178   void CameraInfoDisplay::onInitialize()
00179   {
00180     MFDClass::onInitialize();
00181     scene_node_ = scene_manager_->getRootSceneNode()->createChildSceneNode();
00182     updateColor();
00183     updateAlpha();
00184     updateFarClipDistance();
00185     updateShowPolygons();
00186     updateNotShowSidePolygons();
00187     updateShowEdges();
00188     updateImageTopic();
00189     updateUseImage();
00190     updateEdgeColor();
00191   }
00192   
00193   void CameraInfoDisplay::processMessage(
00194     const sensor_msgs::CameraInfo::ConstPtr& msg)
00195   {
00196     if (!isSameCameraInfo(msg)) {
00197       createCameraInfoShapes(msg);
00198     }
00199     // move scene_node according to tf
00200      Ogre::Vector3 position;
00201      Ogre::Quaternion quaternion;
00202      if(!context_->getFrameManager()->getTransform(msg->header.frame_id,
00203                                                    msg->header.stamp,
00204                                                    position,
00205                                                    quaternion)) {
00206        ROS_ERROR( "Error transforming pose '%s' from frame '%s' to frame '%s'",
00207                   qPrintable( getName() ), msg->header.frame_id.c_str(),
00208                   qPrintable( fixed_frame_ ));
00209      }
00210      scene_node_->setPosition(position);
00211      scene_node_->setOrientation(quaternion);
00212      camera_info_ = msg;        // store for caching
00213   }
00214 
00215   void CameraInfoDisplay::update(float wall_dt, float ros_dt)
00216   {
00217     boost::mutex::scoped_lock lock(mutex_);
00218     if (image_updated_) {
00219       ROS_DEBUG("image updated");
00220       if (!bottom_texture_.isNull()) {
00221         drawImageTexture();
00222         image_updated_ = false;
00223       }
00224     }
00225   }
00226 
00227   bool CameraInfoDisplay::isSameCameraInfo(
00228     const sensor_msgs::CameraInfo::ConstPtr& msg)
00229   {
00230     if (camera_info_) {
00231       bool meta_same_p = 
00232         msg->header.frame_id == camera_info_->header.frame_id &&
00233         msg->height == camera_info_->height &&
00234         msg->width == camera_info_->width &&
00235         msg->distortion_model == camera_info_->distortion_model;
00236       if (meta_same_p) {
00237         for (size_t i = 0; i < msg->P.size(); i++) {
00238           if (msg->P[i] != camera_info_->P[i]) {
00239             return false;
00240           }
00241         }
00242         return true;
00243       }
00244       else {
00245         return false;
00246       }
00247     }
00248     else {
00249       return false;
00250     }
00251   }
00252   
00253   void CameraInfoDisplay::addPointToEdge(
00254     const cv::Point3d& point)
00255   {
00256     Ogre::Vector3 p;
00257     p[0] = point.x;
00258     p[1] = point.y;
00259     p[2] = point.z;
00260     edges_->addPoint(p);
00261   }
00262 
00263   void CameraInfoDisplay::addPolygon(
00264     const cv::Point3d& O, const cv::Point3d& A, const cv::Point3d& B, std::string name, bool use_color, bool upper_triangle)
00265   {
00266     Ogre::ColourValue color = rviz::qtToOgre(color_);
00267     color.a = alpha_;
00268     TrianglePolygon::Ptr triangle (new TrianglePolygon(
00269                                      scene_manager_,
00270                                      scene_node_,
00271                                      O, A, B, name,
00272                                      color,
00273                                      use_color,
00274                                      upper_triangle));
00275     polygons_.push_back(triangle);
00276   }
00277 
00278   void CameraInfoDisplay::createTextureForBottom(int width, int height)
00279   {
00280     ROS_INFO("%dx%d", width, height);
00281     if (bottom_texture_.isNull() 
00282         || bottom_texture_->getWidth() != width
00283         || bottom_texture_->getHeight() != height) {
00284       static uint32_t count = 0;
00285       rviz::UniformStringStream ss;
00286       ss << "CameraInfoDisplayPolygonBottom" << count++;
00287       material_bottom_
00288         = Ogre::MaterialManager::getSingleton().create(
00289           ss.str(),
00290           Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
00291       bottom_texture_ = Ogre::TextureManager::getSingleton().createManual(
00292         material_bottom_->getName() + "Texture",        // name
00293         Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
00294         Ogre::TEX_TYPE_2D, width, height, 0, Ogre::PF_A8R8G8B8, Ogre::TU_DEFAULT);
00295       material_bottom_->getTechnique(0)->getPass(0)->setColourWriteEnabled(true);
00296       Ogre::ColourValue color = rviz::qtToOgre(color_);
00297       color.a = alpha_;
00298       material_bottom_->getTechnique(0)->getPass(0)->setAmbient(color);
00299       material_bottom_->setReceiveShadows(false);
00300       material_bottom_->getTechnique(0)->setLightingEnabled(true);
00301       material_bottom_->getTechnique(0)->getPass(0)->setCullingMode(Ogre::CULL_NONE);
00302       material_bottom_->getTechnique(0)->getPass(0)->setLightingEnabled(false);
00303       material_bottom_->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
00304       material_bottom_->getTechnique(0)->getPass(0)->setDepthCheckEnabled(true);
00305     
00306       material_bottom_->getTechnique(0)->getPass(0)->setVertexColourTracking(Ogre::TVC_DIFFUSE);
00307       material_bottom_->getTechnique(0)->getPass(0)->createTextureUnitState(bottom_texture_->getName());
00308       material_bottom_->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
00309     }
00310   }
00311 
00312   void CameraInfoDisplay::prepareMaterial()
00313   {
00314     if (texture_.isNull()) {
00315       // material
00316       static uint32_t count = 0;
00317       rviz::UniformStringStream ss;
00318       ss << "CameraInfoDisplayPolygon" << count++;
00319       material_
00320         = Ogre::MaterialManager::getSingleton().create(
00321           ss.str(),
00322           Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
00323       texture_ = Ogre::TextureManager::getSingleton().createManual(
00324         material_->getName() + "Texture",        // name
00325         Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
00326         Ogre::TEX_TYPE_2D, 1, 1, 0, Ogre::PF_A8R8G8B8, Ogre::TU_DEFAULT);
00327       material_->getTechnique(0)->getPass(0)->setColourWriteEnabled(true);
00328       Ogre::ColourValue color = rviz::qtToOgre(color_);
00329       color.a = alpha_;
00330       material_->getTechnique(0)->getPass(0)->setAmbient(color);
00331       material_->setReceiveShadows(false);
00332       material_->getTechnique(0)->setLightingEnabled(true);
00333       material_->getTechnique(0)->getPass(0)->setCullingMode(Ogre::CULL_NONE);
00334       material_->getTechnique(0)->getPass(0)->setLightingEnabled(false);
00335       material_->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
00336       material_->getTechnique(0)->getPass(0)->setDepthCheckEnabled(true);
00337       
00338       material_->getTechnique(0)->getPass(0)->setVertexColourTracking(Ogre::TVC_DIFFUSE);
00339       material_->getTechnique(0)->getPass(0)->createTextureUnitState(texture_->getName());
00340       material_->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
00341       createTextureForBottom(640, 480);
00342     }
00343   }
00344 
00345   void CameraInfoDisplay::subscribeImage(std::string topic)
00346   {
00347     
00348     image_sub_.shutdown();
00349     if (topic.empty()) {
00350       ROS_WARN("topic name is empty");
00351     }
00352     ros::NodeHandle nh;
00353     image_sub_ = nh.subscribe(topic, 1, 
00354                               &CameraInfoDisplay::imageCallback, this);
00355   }
00356   
00357   void CameraInfoDisplay::drawImageTexture()
00358   {
00359     bottom_texture_->getBuffer()->lock( Ogre::HardwareBuffer::HBL_NORMAL );
00360     const Ogre::PixelBox& pixelBox 
00361       = bottom_texture_->getBuffer()->getCurrentLock();
00362     Ogre::uint8* pDest = static_cast<Ogre::uint8*> (pixelBox.data);
00363     memset(pDest, 0, bottom_texture_->getWidth() * bottom_texture_->getHeight());
00364     QImage Hud(pDest, bottom_texture_->getWidth(), bottom_texture_->getHeight(), QImage::Format_ARGB32 );
00365     for (size_t j = 0; j < bottom_texture_->getHeight(); j++) {
00366       for (size_t i = 0; i < bottom_texture_->getWidth(); i++) {
00367         if (use_image_ && !image_.empty() &&
00368             bottom_texture_->getHeight() == image_.rows &&
00369             bottom_texture_->getWidth() == image_.cols) {
00370           ROS_DEBUG("bottom_texture_->getHeight(): %lu", bottom_texture_->getHeight());
00371           ROS_DEBUG("bottom_texture_->getWidth(): %lu", bottom_texture_->getWidth());
00372           ROS_DEBUG("image_.rows: %d", image_.rows);
00373           ROS_DEBUG("image_.cols: %d", image_.cols);
00374           QColor color(image_.data[j * image_.step + i * image_.elemSize() + 0],
00375                        image_.data[j * image_.step + i * image_.elemSize() + 1],
00376                        image_.data[j * image_.step + i * image_.elemSize() + 2],
00377                        alpha_ * 255.0);
00378           Hud.setPixel(i, j, color.rgba());
00379         }
00380         else {
00381           Hud.setPixel(i, j, color_.rgba());
00382         }
00383       }
00384     }
00385     bottom_texture_->getBuffer()->unlock();
00386   }
00387 
00388   // convert sensor_msgs::Image into cv::Mat
00389   void CameraInfoDisplay::imageCallback(
00390       const sensor_msgs::Image::ConstPtr& msg)
00391   {
00392     boost::mutex::scoped_lock lock(mutex_);
00393     cv_bridge::CvImagePtr cv_ptr;
00394     try
00395     {
00396       cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::RGB8);
00397       image_ = cv_ptr->image;
00398       // check the size of bottom texture
00399       if (bottom_texture_.isNull()
00400           || bottom_texture_->getWidth() != image_.cols
00401           || bottom_texture_->getHeight() != image_.rows) {
00402         createTextureForBottom(image_.cols, image_.rows);
00403         if (camera_info_) {
00404           createCameraInfoShapes(camera_info_);
00405         }
00406       }
00407       image_updated_ = true;
00408     }
00409     catch (cv_bridge::Exception& e)
00410     {
00411       ROS_ERROR("cv_bridge exception: %s", e.what());
00412     }
00413   }
00414 
00415   void CameraInfoDisplay::createCameraInfoShapes(
00416     const sensor_msgs::CameraInfo::ConstPtr& msg)
00417   {
00418     polygons_.clear();
00419     if (edges_) {
00420       edges_->clear();
00421     }
00422     image_geometry::PinholeCameraModel model;
00423     bool model_success_p = model.fromCameraInfo(msg);
00424     if (!model_success_p) {
00425       ROS_ERROR("failed to create camera model");
00426       return;
00427     }
00428     
00430     // initialize BillboardLine
00432     if (!edges_) {
00433       edges_.reset(new rviz::BillboardLine(context_->getSceneManager(),
00434                                            scene_node_));
00435       edges_->setLineWidth(0.01);
00436     }
00437     
00438     cv::Point2d a(0, 0), b(msg->width, 0),
00439       c(msg->width, msg->height), d(0, msg->height);
00440     // all the z = 1.0
00441     cv::Point3d A = model.projectPixelTo3dRay(a);
00442     cv::Point3d B = model.projectPixelTo3dRay(b);
00443     cv::Point3d C = model.projectPixelTo3dRay(c);
00444     cv::Point3d D = model.projectPixelTo3dRay(d);
00445 
00446     cv::Point3d scaled_A = A * far_clip_distance_;
00447     cv::Point3d scaled_B = B * far_clip_distance_;
00448     cv::Point3d scaled_C = C * far_clip_distance_;
00449     cv::Point3d scaled_D = D * far_clip_distance_;
00450 
00451     cv::Point3d O(0, 0, 0);
00452 
00454     // build polygons
00456     if (show_polygons_) {
00458       // setup color for polygons
00460       Ogre::ColourValue color = rviz::qtToOgre(color_);
00461       color.a = alpha_;
00462       prepareMaterial();
00463       if (!not_show_side_polygons_) {
00464         material_->getTechnique(0)->getPass(0)->setAmbient(color);
00465         {      
00466           texture_->getBuffer()->lock( Ogre::HardwareBuffer::HBL_NORMAL );
00467           const Ogre::PixelBox& pixelBox 
00468             = texture_->getBuffer()->getCurrentLock();
00469           Ogre::uint8* pDest = static_cast<Ogre::uint8*> (pixelBox.data);
00470           memset(pDest, 0, 1);
00471           QImage Hud(pDest, 1, 1, QImage::Format_ARGB32 );
00472           Hud.setPixel(0, 0, color_.rgba());
00473           texture_->getBuffer()->unlock();
00474         }
00475         addPolygon(O, scaled_B, scaled_A, material_->getName(), true, true);
00476         addPolygon(O, scaled_C, scaled_B, material_->getName(), true, true);
00477         addPolygon(O, scaled_D, scaled_C, material_->getName(), true, true);
00478         addPolygon(O, scaled_A, scaled_D, material_->getName(), true, true);
00479       }
00480       // bottom
00481       drawImageTexture();
00482 
00483       addPolygon(scaled_A, scaled_B, scaled_D, material_bottom_->getName(), false, true);
00484       addPolygon(scaled_B, scaled_C, scaled_D, material_bottom_->getName(), false, false);
00485     }
00487     // build edges
00489     if (show_edges_) {
00490       edges_->clear();
00491       edges_->setMaxPointsPerLine(2);
00492       edges_->setNumLines(8);
00493       edges_->setColor(edge_color_.red() / 255.0,
00494                        edge_color_.green() / 255.0,
00495                        edge_color_.blue() / 255.0,
00496                        alpha_);
00497       addPointToEdge(O); addPointToEdge(scaled_A); edges_->newLine();
00498       addPointToEdge(O); addPointToEdge(scaled_B); edges_->newLine();
00499       addPointToEdge(O); addPointToEdge(scaled_C); edges_->newLine();
00500       addPointToEdge(O); addPointToEdge(scaled_D); edges_->newLine();
00501       addPointToEdge(scaled_A); addPointToEdge(scaled_B); edges_->newLine();
00502       addPointToEdge(scaled_B); addPointToEdge(scaled_C); edges_->newLine();
00503       addPointToEdge(scaled_C); addPointToEdge(scaled_D); edges_->newLine();
00504       addPointToEdge(scaled_D); addPointToEdge(scaled_A);
00505     }
00506   }
00507 
00509   // Properties updating functions
00511   void CameraInfoDisplay::updateColor()
00512   {
00513     color_ = color_property_->getColor();
00514     if (camera_info_) {
00515       createCameraInfoShapes(camera_info_);
00516     }
00517   }
00518 
00519   void CameraInfoDisplay::updateEdgeColor()
00520   {
00521     edge_color_ = edge_color_property_->getColor();
00522     if (camera_info_) {
00523       createCameraInfoShapes(camera_info_);
00524     }
00525   }
00526 
00527   void CameraInfoDisplay::updateAlpha()
00528   {
00529     alpha_ = alpha_property_->getFloat();
00530     if (camera_info_) {
00531       createCameraInfoShapes(camera_info_);
00532     }
00533   }
00534 
00535   void CameraInfoDisplay::updateFarClipDistance()
00536   {
00537     far_clip_distance_ = far_clip_distance_property_->getFloat();
00538     if (camera_info_) {
00539       createCameraInfoShapes(camera_info_);
00540     }
00541   }
00542 
00543   void CameraInfoDisplay::updateShowPolygons()
00544   {
00545     show_polygons_ = show_polygons_property_->getBool();
00546     if (camera_info_) {
00547       createCameraInfoShapes(camera_info_);
00548     }
00549   }
00550 
00551   void CameraInfoDisplay::updateShowEdges()
00552   {
00553     show_edges_ = show_edges_property_->getBool();
00554     if (camera_info_) {
00555       createCameraInfoShapes(camera_info_);
00556     }
00557   }
00558 
00559   void CameraInfoDisplay::updateImageTopic()
00560   {
00561     if (use_image_) {
00562       std::string topic = image_topic_property_->getStdString();
00563       subscribeImage(topic);
00564     }
00565   }
00566 
00567   void CameraInfoDisplay::updateUseImage()
00568   {
00569     use_image_ = use_image_property_->getBool();
00570     updateImageTopic();
00571   }
00572   void CameraInfoDisplay::updateNotShowSidePolygons()
00573   {
00574     not_show_side_polygons_ = not_show_side_polygons_property_->getBool();
00575     if (camera_info_) {
00576       createCameraInfoShapes(camera_info_);
00577     }
00578   }
00579 }
00580 
00581 
00582 #include <pluginlib/class_list_macros.h>
00583 PLUGINLIB_EXPORT_CLASS( jsk_rviz_plugins::CameraInfoDisplay, rviz::Display )


jsk_rviz_plugins
Author(s): Kei Okada , Yohei Kakiuchi , Shohei Fujii , Ryohei Ueda
autogenerated on Sun Sep 13 2015 22:29:03