Go to the documentation of this file.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 #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) {
00108 Accumulator acc;
00109
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
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) {
00144 Accumulator height_acc;
00145 Accumulator dist_acc;
00146
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
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
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
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);