heightmap_morphological_filtering_nodelet.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 #define BOOST_PARAMETER_MAX_ARITY 7
00037 #include "jsk_pcl_ros/heightmap_morphological_filtering.h"
00038 #include "jsk_pcl_ros/heightmap_utils.h"
00039 #include <sensor_msgs/image_encodings.h>
00040 
00041 namespace jsk_pcl_ros
00042 {
00043   void HeightmapMorphologicalFiltering::onInit()
00044   {
00045     DiagnosticNodelet::onInit();
00046     pub_config_ = pnh_->advertise<jsk_recognition_msgs::HeightmapConfig>("output/config",
00047                                                                          1, true);
00048     srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
00049     typename dynamic_reconfigure::Server<Config>::CallbackType f =
00050       boost::bind (&HeightmapMorphologicalFiltering::configCallback, this, _1, _2);
00051     srv_->setCallback (f);
00052 
00053     pnh_->param("max_queue_size", max_queue_size_, 10);
00054     pub_ = advertise<sensor_msgs::Image>(*pnh_, "output", 1);
00055     sub_config_ = pnh_->subscribe(getHeightmapConfigTopic(pnh_->resolveName("input")), 1,
00056                                   &HeightmapMorphologicalFiltering::configTopicCallback,
00057                                   this);
00058     onInitPostProcess();
00059 
00060   }
00061 
00062   void HeightmapMorphologicalFiltering::subscribe()
00063   {
00064     sub_ = pnh_->subscribe(
00065       "input", max_queue_size_,
00066       &HeightmapMorphologicalFiltering::filter, this);
00067   }
00068 
00069   void HeightmapMorphologicalFiltering::unsubscribe()
00070   {
00071     sub_.shutdown();
00072   }
00073 
00074   void HeightmapMorphologicalFiltering::configTopicCallback(const jsk_recognition_msgs::HeightmapConfig::ConstPtr& msg)
00075   {
00076     pub_config_.publish(msg);
00077   }
00078 
00079   void HeightmapMorphologicalFiltering::configCallback(
00080     Config& config, uint32_t level)
00081   {
00082     boost::mutex::scoped_lock lock(mutex_);
00083     mask_size_ = config.mask_size;
00084     max_variance_ = config.max_variance;
00085     smooth_method_ = config.smooth_method;
00086     bilateral_filter_size_ = config.bilateral_filter_size;
00087     bilateral_sigma_color_ = config.bilateral_sigma_color;
00088     bilateral_sigma_space_ = config.bilateral_sigma_space;
00089     use_bilateral_ = config.use_bilateral;
00090   }
00091 
00092   void HeightmapMorphologicalFiltering::filter(
00093     const sensor_msgs::Image::ConstPtr& msg)
00094   {
00095     boost::mutex::scoped_lock lock(mutex_);
00096     vital_checker_->poke();
00097     cv::Mat input = cv_bridge::toCvShare(
00098       msg, sensor_msgs::image_encodings::TYPE_32FC2)->image;
00099 
00100     cv::Mat filtered_image;
00101     filtered_image = input.clone();
00102 
00103     if (smooth_method_ == "average_variance") {
00104       for (size_t j = 0; j < input.rows; j++) {
00105         for (size_t i = 0; i < input.cols; i++) {
00106           float v = input.at<cv::Vec2f>(j, i)[0];
00107           if (std::isnan(v) || v == -FLT_MAX) { // Need to filter
00108             Accumulator acc;
00109             // store valid values around the target point
00110             for (int jj = - mask_size_; jj <= mask_size_; jj++) {
00111               int target_j = j + jj;
00112               if (target_j >= 0 && target_j < input.rows) {
00113                 for (int ii = - mask_size_; ii <= mask_size_; ii++) {
00114                   int target_i = i + ii;
00115                   if (target_i >= 0 && target_i < input.cols) {
00116                     if (std::abs(jj) + std::abs(ii) <= mask_size_) {
00117                       float vv = input.at<cv::Vec2f>(target_j, target_i)[0];
00118                       if (!std::isnan(vv) && vv != -FLT_MAX) {
00119                         acc(vv);
00120                       }
00121                     }
00122                   }
00123                 }
00124               }
00125             }
00126             // if valid values exist, add new value to the target point as interpolation
00127             if (boost::accumulators::count(acc) != 0) {
00128               float newv = boost::accumulators::mean(acc);
00129               float variance = boost::accumulators::variance(acc);
00130               if (variance < max_variance_) {
00131                 filtered_image.at<cv::Vec2f>(j, i)[0] = newv;
00132                 filtered_image.at<cv::Vec2f>(j, i)[1] = 1 - variance/max_variance_;
00133               }
00134             }
00135           }
00136         }
00137       }
00138     }
00139     else if (smooth_method_ == "average_distance") {
00140       for (size_t j = 0; j < input.rows; j++) {
00141         for (size_t i = 0; i < input.cols; i++) {
00142           float v = input.at<cv::Vec2f>(j, i)[0];
00143           if (std::isnan(v) || v == -FLT_MAX) { // Need to filter
00144             Accumulator height_acc;
00145             Accumulator dist_acc;
00146             // store valid values around the target point
00147             for (int jj = - mask_size_; jj <= mask_size_; jj++) {
00148               int target_j = j + jj;
00149               if (target_j >= 0 && target_j < input.rows) {
00150                 for (int ii = - mask_size_; ii <= mask_size_; ii++) {
00151                   int target_i = i + ii;
00152                   if (target_i >= 0 && target_i < input.cols) {
00153                     int len = std::abs(jj) + std::abs(ii);
00154                     if (len <= mask_size_) {
00155                       float vv = input.at<cv::Vec2f>(target_j, target_i)[0];
00156                       if (!std::isnan(vv) && vv != -FLT_MAX) {
00157                         height_acc(vv);
00158                         dist_acc(len);
00159                       }
00160                     }
00161                   }
00162                 }
00163               }
00164             }
00165             // if valid values exist, add new value to the target point as interpolation
00166             if (boost::accumulators::count(height_acc) != 0) {
00167               float newv = boost::accumulators::mean(height_acc);
00168               float variance = boost::accumulators::variance(height_acc);
00169               if (variance < max_variance_) {
00170                 filtered_image.at<cv::Vec2f>(j, i)[0] = newv;
00171                 filtered_image.at<cv::Vec2f>(j, i)[1] = (float)(1.0/(1.0 + boost::accumulators::mean(dist_acc)));
00172               }
00173             }
00174           }
00175         }
00176       }
00177     }
00178 
00179     if (use_bilateral_) {
00180       std::vector<cv::Mat> fimages;
00181       cv::split(filtered_image, fimages);
00182       cv::Mat res_image;
00183       // filter
00184       cv::bilateralFilter(fimages[0], res_image, bilateral_filter_size_, bilateral_sigma_color_, bilateral_sigma_space_);
00185       {
00186         for (size_t j = 0; j < res_image.rows; j++) {
00187           for (size_t i = 0; i < res_image.cols; i++) {
00188             float ov = fimages[0].at<float>(j, i);
00189             if (ov == -FLT_MAX) {
00190               res_image.at<float>(j, i) = -FLT_MAX;
00191             }
00192           }
00193         }
00194       }
00195       // reconstruct images
00196       std::vector<cv::Mat> ret_images;
00197       ret_images.push_back(res_image);
00198       ret_images.push_back(fimages[1]);
00199       cv::merge(ret_images, filtered_image);
00200     }
00201 
00202     pub_.publish(cv_bridge::CvImage(
00203                    msg->header,
00204                    sensor_msgs::image_encodings::TYPE_32FC2,
00205                    filtered_image).toImageMsg());
00206   }
00207 }
00208 
00209 #include <pluginlib/class_list_macros.h>
00210 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::HeightmapMorphologicalFiltering, nodelet::Nodelet);


jsk_pcl_ros
Author(s): Yohei Kakiuchi
autogenerated on Sun Oct 8 2017 02:43:49