skeletonization_nodelet.cpp
Go to the documentation of this file.
1 // -*- mode: c++ -*-
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2015, JSK Lab
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/o2r other materials provided
17  * with the distribution.
18  * * Neither the name of the JSK Lab nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 
36 
38 
39 namespace jsk_perception
40 {
42  {
43  DiagnosticNodelet::onInit();
44  pnh_->getParam("num_threads", this->num_threads_);
45  this->pub_image_ = advertise<sensor_msgs::Image>(
46  *pnh_, "image_output", 1);
48  }
49 
51  {
52  this->sub_ = pnh_->subscribe(
53  "input", 1,
55  }
56 
58  {
59  NODELET_DEBUG("Unsubscribing from ROS topic.");
60  this->sub_.shutdown();
61  }
62 
64  const sensor_msgs::Image::ConstPtr& image_msg)
65  {
66  boost::mutex::scoped_lock lock(this->mutex_);
67  cv_bridge::CvImagePtr cv_ptr;
68  try {
69  cv_ptr = cv_bridge::toCvCopy(
71  } catch (cv_bridge::Exception& e) {
72  ROS_ERROR("cv_bridge exception: %s", e.what());
73  return;
74  }
75  cv::Mat image = cv_ptr->image;
76  this->skeletonization(image);
78  out_msg->header = cv_ptr->header;
79  out_msg->encoding = sensor_msgs::image_encodings::TYPE_32FC1;
80  out_msg->image = image.clone();
81  this->pub_image_.publish(out_msg->toImageMsg());
82  }
83 
85  cv::Mat &image)
86  {
87  if (image.empty()) {
88  ROS_ERROR("--CANNOT THIN EMPTY DATA...");
89  return;
90  }
91  if (image.type() == CV_8UC3) {
92  cv::cvtColor(image, image, CV_BGR2GRAY);
93  }
94  cv::Mat img;
95  image.convertTo(img, CV_32F, 1/255.0);
96  cv::Mat prev = cv::Mat::zeros(img.size(), CV_32F);
97  cv::Mat difference;
98  do {
99  this->iterativeThinning(img, 0);
100  this->iterativeThinning(img, 1);
101  cv::absdiff(img, prev, difference);
102  img.copyTo(prev);
103  } while (cv::countNonZero(difference) > 0);
104  image = img.clone();
105  }
106 
108  cv::Mat& img, int iter)
109  {
110  if (img.empty()) {
111  ROS_ERROR("--CANNOT THIN EMPTY DATA...");
112  return;
113  }
114  cv::Mat marker = cv::Mat::zeros(img.size(), CV_32F);
115 #ifdef _OPENMP
116 #pragma omp parallel for collapse(2) num_threads(this->num_threads_)
117 #endif
118  for (int i = 1; i < img.rows-1; i++) {
119  for (int j = 1; j < img.cols-1; j++) {
120  float val[9] = {};
121  int icounter = 0;
122  for (int y = -1; y <= 1; y++) {
123  for (int x = -1; x <= 1; x++) {
124  val[icounter] = img.at<float>(i + y, j + x);
125  icounter++;
126  }
127  }
128  int A = ((val[1] == 0 && val[2] == 1) ? ODD : EVEN)
129  + ((val[2] == 0 && val[5] == 1) ? ODD : EVEN)
130  + ((val[5] == 0 && val[8] == 1) ? ODD : EVEN)
131  + ((val[8] == 0 && val[7] == 1) ? ODD : EVEN)
132  + ((val[7] == 0 && val[6] == 1) ? ODD : EVEN)
133  + ((val[6] == 0 && val[3] == 1) ? ODD : EVEN)
134  + ((val[3] == 0 && val[0] == 1) ? ODD : EVEN)
135  + ((val[0] == 0 && val[1] == 1) ? ODD : EVEN);
136  int B = val[0] + val[1] + val[2] + val[3]
137  + val[5] + val[6] + val[7] + val[8];
138  int m1 = iter == EVEN ? (val[1] * val[5] * val[7])
139  : (val[1] * val[3] * val[5]);
140  int m2 = iter == EVEN ? (val[3] * val[5] * val[7])
141  : (val[1] * val[3] * val[7]);
142  if (A == 1 && (B >= 2 && B <= 6) && !m1 && !m2) {
143  marker.at<float>(i, j) = sizeof(char);
144  }
145  }
146  }
147  cv::bitwise_not(marker, marker);
148  cv::bitwise_and(img, marker, img);
149  }
150 } // jsk_perception
151 
void publish(const boost::shared_ptr< M > &message) const
virtual void imageCallback(const sensor_msgs::Image::ConstPtr &)
virtual void iterativeThinning(cv::Mat &, int)
boost::shared_ptr< ros::NodeHandle > pnh_
const std::string TYPE_32FC1
CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
x
y
B
mutex_t * lock
PLUGINLIB_EXPORT_CLASS(jsk_perception::Skeletonization, nodelet::Nodelet)
#define ROS_ERROR(...)
#define NODELET_DEBUG(...)


jsk_perception
Author(s): Manabu Saito, Ryohei Ueda
autogenerated on Mon May 3 2021 03:03:27