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 
00031 
00032 
00033 
00034 
00035 
00036 #include "overlay_image_display.h"
00037 
00038 #include <OGRE/OgreMaterialManager.h>
00039 #include <OGRE/OgreTextureManager.h>
00040 #include <OGRE/OgreTexture.h>
00041 #include <OGRE/OgreHardwarePixelBuffer.h>
00042 #include <OGRE/OgreTechnique.h>
00043 
00044 #include <rviz/uniform_string_stream.h>
00045 #include <cv_bridge/cv_bridge.h>
00046 #include <sensor_msgs/image_encodings.h>
00047 
00048 namespace jsk_rviz_plugins
00049 {
00050 
00051   OverlayImageDisplay::OverlayImageDisplay()
00052     : Display(), width_(128), height_(128), left_(128), top_(128), alpha_(0.8),
00053       is_msg_available_(false), require_update_(false)
00054   {
00055     
00056     update_topic_property_ = new rviz::RosTopicProperty(
00057       "Topic", "",
00058       ros::message_traits::datatype<sensor_msgs::Image>(),
00059       "sensor_msgs::Image topic to subscribe to.",
00060       this, SLOT( updateTopic() ));
00061     transport_hint_property_ = new ImageTransportHintsProperty("transport hint",
00062                                                               "transport hint to subscribe topic",
00063                                                               this, SLOT(updateTopic()));
00064     keep_aspect_ratio_property_ = new rviz::BoolProperty("keep aspect ratio", false,
00065                                                          "keep aspect ratio of original image",
00066                                                          this, SLOT(updateKeepAspectRatio()));
00067     width_property_ = new rviz::IntProperty("width", 128,
00068                                             "width of the image window",
00069                                             this, SLOT(updateWidth()));
00070     height_property_ = new rviz::IntProperty("height", 128,
00071                                              "height of the image window",
00072                                              this, SLOT(updateHeight()));
00073     left_property_ = new rviz::IntProperty("left", 128,
00074                                            "left of the image window",
00075                                            this, SLOT(updateLeft()));
00076     top_property_ = new rviz::IntProperty("top", 128,
00077                                           "top of the image window",
00078                                           this, SLOT(updateTop()));
00079     alpha_property_ = new rviz::FloatProperty("alpha", 0.8,
00080                                               "alpha belnding value",
00081                                               this, SLOT(updateAlpha()));
00082   }
00083 
00084   OverlayImageDisplay::~OverlayImageDisplay()
00085   {
00086     delete update_topic_property_;
00087     delete transport_hint_property_;
00088     delete keep_aspect_ratio_property_;
00089     delete width_property_;
00090     delete height_property_;
00091     delete left_property_;
00092     delete top_property_;
00093     delete alpha_property_;
00094   }
00095 
00096   void OverlayImageDisplay::onInitialize()
00097   {
00098     ros::NodeHandle nh;
00099     it_ = std::shared_ptr<image_transport::ImageTransport>(new image_transport::ImageTransport(nh));
00100 
00101     updateWidth();
00102     updateHeight();
00103     updateKeepAspectRatio();
00104     updateTop();
00105     updateLeft();
00106     updateAlpha();
00107     updateTopic();
00108   }
00109 
00110   void OverlayImageDisplay::onEnable()
00111   {
00112     if (overlay_) {
00113       overlay_->show();
00114     }
00115     subscribe();
00116   }
00117   void OverlayImageDisplay::onDisable()
00118   {
00119     if (overlay_) {
00120       overlay_->hide();
00121     }
00122     unsubscribe();
00123   }
00124 
00125   void OverlayImageDisplay::unsubscribe()
00126   {
00127     sub_.shutdown();
00128     
00129   }
00130 
00131   void OverlayImageDisplay::subscribe()
00132   {
00133     if (isEnabled()) {
00134       std::string topic_name = update_topic_property_->getTopicStd();
00135 
00136       if (topic_name.length() > 0 && topic_name != "/") {
00137         const image_transport::TransportHints transport_hint =
00138           transport_hint_property_->getTransportHints();
00139         sub_ = it_->subscribe(topic_name, 1, &OverlayImageDisplay::processMessage, this,
00140                               transport_hint);
00141       }
00142     }
00143   }
00144 
00145   void OverlayImageDisplay::processMessage(
00146     const sensor_msgs::Image::ConstPtr& msg)
00147   {
00148     boost::mutex::scoped_lock(mutex_);
00149     msg_ = msg;
00150     is_msg_available_ = true;
00151     require_update_ = true;
00152     if ((width_property_->getInt() < 0) || (height_property_->getInt() < 0) || keep_aspect_ratio_) {
00153       
00154       updateWidth();
00155       updateHeight();
00156     }
00157   }
00158 
00159 
00160   void OverlayImageDisplay::update(float wall_dt, float ros_dt)
00161   {
00162     boost::mutex::scoped_lock(mutex_);
00163 
00164     if (!isEnabled()) {
00165       return;
00166     }
00167 
00168     if (require_update_ && is_msg_available_) {
00169       if (!overlay_) {
00170         static int count = 0;
00171         rviz::UniformStringStream ss;
00172         ss << "OverlayImageDisplayObject" << count++;
00173         overlay_.reset(new OverlayObject(ss.str()));
00174         overlay_->show();
00175       }
00176       overlay_->updateTextureSize(msg_->width, msg_->height);
00177       
00178       height_property_->setHidden(keep_aspect_ratio_);
00179       setImageSize();
00180       redraw();
00181       require_update_ = false;
00182     }
00183     if (overlay_) {
00184       overlay_->setDimensions(width_, height_);
00185       overlay_->setPosition(left_, top_);
00186     }
00187   }
00188 
00189   void OverlayImageDisplay::redraw()
00190   {
00191     try
00192     {
00193       if (msg_->width == 0 || msg_->height == 0) {
00194         
00195         
00196         return;
00197       }
00198       else {
00199         cv::Mat mat;  
00200 
00201         if (msg_->encoding == sensor_msgs::image_encodings::BGRA8 ||
00202             msg_->encoding == sensor_msgs::image_encodings::RGBA8) {
00203           const cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy(
00204                   msg_, sensor_msgs::image_encodings::BGRA8);
00205           cv_ptr->image.copyTo(mat);
00206         } else {
00207             
00208             const cv_bridge::CvImagePtr cv_ptr =
00209                     cv_bridge::toCvCopy(msg_, sensor_msgs::image_encodings::BGR8);
00210             const cv::Mat bgr_image = cv_ptr->image;
00211             std::vector<cv::Mat> channels;
00212             
00213             
00214             cv::split(bgr_image, channels);
00215             
00216             const cv::Mat alpha(bgr_image.rows, bgr_image.cols, CV_8UC1,
00217                                 cv::Scalar(alpha_ * 255.0));
00218             channels.push_back(alpha);
00219             cv::merge(channels, mat);
00220         }
00221 
00222         ScopedPixelBuffer buffer = overlay_->getBuffer();
00223         QImage Hud = buffer.getQImage(*overlay_);
00224         
00225         memcpy(Hud.scanLine(0), mat.data, mat.cols * mat.rows * mat.elemSize());
00226       }
00227     }
00228     catch (cv_bridge::Exception& e)
00229     {
00230       ROS_ERROR("cv_bridge exception: %s", e.what());
00231     }
00232   }
00233 
00234   void OverlayImageDisplay::updateTopic()
00235   {
00236     unsubscribe();
00237     subscribe();
00238   }
00239 
00240   void OverlayImageDisplay::setImageSize()
00241   {
00242     if (width_ == -1) {
00243       if (is_msg_available_) {
00244         width_ = msg_->width;
00245       }
00246       else {
00247         width_ = 128;
00248       }
00249     }
00250 
00251     if (height_ == -1) {
00252       if (is_msg_available_) {
00253         height_ = msg_->height;
00254       }
00255       else {
00256         height_ = 128;
00257       }
00258     }
00259 
00260     if (keep_aspect_ratio_ && is_msg_available_) {
00261       
00262       double aspect_ratio = msg_->height / (double)msg_->width;
00263       int height_from_width = std::ceil(width_ * aspect_ratio);
00264       height_ = height_from_width;
00265     }
00266 
00267   }
00268 
00269   void OverlayImageDisplay::updateWidth()
00270   {
00271     boost::mutex::scoped_lock lock(mutex_);
00272     width_ = width_property_->getInt();
00273     require_update_ = true;
00274   }
00275 
00276   void OverlayImageDisplay::updateHeight()
00277   {
00278     boost::mutex::scoped_lock lock(mutex_);
00279     height_ = height_property_->getInt();
00280     require_update_ = true;
00281   }
00282 
00283   void OverlayImageDisplay::updateTop()
00284   {
00285     boost::mutex::scoped_lock lock(mutex_);
00286     top_ = top_property_->getInt();
00287   }
00288 
00289   void OverlayImageDisplay::updateLeft()
00290   {
00291     boost::mutex::scoped_lock lock(mutex_);
00292     left_ = left_property_->getInt();
00293   }
00294 
00295   void OverlayImageDisplay::updateAlpha()
00296   {
00297     boost::mutex::scoped_lock lock(mutex_);
00298     alpha_ = alpha_property_->getFloat();
00299   }
00300 
00301   void OverlayImageDisplay::updateKeepAspectRatio()
00302   {
00303     boost::mutex::scoped_lock lock(mutex_);
00304     keep_aspect_ratio_ = keep_aspect_ratio_property_->getBool();
00305     require_update_ = true;
00306   }
00307 
00308   bool OverlayImageDisplay::isInRegion(int x, int y)
00309   {
00310     return (top_ < y && top_ + height_ > y &&
00311             left_ < x && left_ + width_ > x);
00312   }
00313 
00314   void OverlayImageDisplay::movePosition(int x, int y)
00315   {
00316     top_ = y;
00317     left_ = x;
00318   }
00319 
00320   void OverlayImageDisplay::setPosition(int x, int y)
00321   {
00322     top_property_->setValue(y);
00323     left_property_->setValue(x);
00324   }
00325 
00326 }
00327 
00328 #include <pluginlib/class_list_macros.h>
00329 PLUGINLIB_EXPORT_CLASS( jsk_rviz_plugins::OverlayImageDisplay, rviz::Display )