color_filter_nodelet.cpp
Go to the documentation of this file.
1 // -*- coding:utf-8-unix; mode: c++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2016, 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/or other materials provided
17  * with the distribution.
18  * * Neither the name of the Kei Okada 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 #include <ros/ros.h>
36 #include "opencv_apps/nodelet.h"
39 #include <cv_bridge/cv_bridge.h>
40 
41 #include <opencv2/highgui/highgui.hpp>
42 #include <opencv2/imgproc/imgproc.hpp>
43 
44 #include <dynamic_reconfigure/server.h>
45 #include "opencv_apps/RGBColorFilterConfig.h"
46 #include "opencv_apps/HLSColorFilterConfig.h"
47 #include "opencv_apps/HSVColorFilterConfig.h"
48 
49 namespace color_filter
50 {
54 }
55 
56 namespace opencv_apps
57 {
58 class RGBColorFilter;
59 class HLSColorFilter;
60 class HSVColorFilter;
61 
62 template <typename Config>
64 {
65  friend class RGBColorFilter;
66  friend class HLSColorFilter;
67 
68 protected:
72 
74 
75  typedef dynamic_reconfigure::Server<Config> ReconfigureServer;
76  Config config_;
78 
81 
82  std::string window_name_;
83 
84  cv::Scalar lower_color_range_;
85  cv::Scalar upper_color_range_;
86 
87  boost::mutex mutex_;
88 
89  virtual void reconfigureCallback(Config& new_config, uint32_t level) = 0;
90 
91  virtual void filter(const cv::Mat& input_image, cv::Mat& output_image) = 0;
92 
93  const std::string& frameWithDefault(const std::string& frame, const std::string& image_frame)
94  {
95  if (frame.empty())
96  return image_frame;
97  return frame;
98  }
99 
100  void imageCallbackWithInfo(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr& cam_info)
101  {
102  doWork(msg, cam_info->header.frame_id);
103  }
104 
105  void imageCallback(const sensor_msgs::ImageConstPtr& msg)
106  {
107  doWork(msg, msg->header.frame_id);
108  }
109 
110  void doWork(const sensor_msgs::ImageConstPtr& image_msg, const std::string& input_frame_from_msg)
111  {
112  // Work on the image.
113  try
114  {
115  // Convert the image into something opencv can handle.
116  cv::Mat frame = cv_bridge::toCvShare(image_msg, sensor_msgs::image_encodings::BGR8)->image;
117 
118  // Do the work
119  cv::Mat out_frame;
120  filter(frame, out_frame);
121 
123  if (debug_view_)
124  {
125  cv::namedWindow(window_name_, cv::WINDOW_AUTOSIZE);
126  }
127 
128  std::string new_window_name;
129 
130  if (debug_view_)
131  {
132  if (window_name_ != new_window_name)
133  {
134  cv::destroyWindow(window_name_);
135  window_name_ = new_window_name;
136  }
137  cv::imshow(window_name_, out_frame);
138  int c = cv::waitKey(1);
139  }
140 
141  // Publish the image.
142  sensor_msgs::Image::Ptr out_img =
143  cv_bridge::CvImage(image_msg->header, sensor_msgs::image_encodings::MONO8, out_frame).toImageMsg();
144  img_pub_.publish(out_img);
145  }
146  catch (cv::Exception& e)
147  {
148  NODELET_ERROR("Image processing error: %s %s %s %i", e.err.c_str(), e.func.c_str(), e.file.c_str(), e.line);
149  }
150  }
151  void subscribe() // NOLINT(modernize-use-override)
152  {
153  NODELET_DEBUG("Subscribing to image topic.");
154  if (config_.use_camera_info)
155  cam_sub_ = it_->subscribeCamera("image", queue_size_, &ColorFilterNodelet::imageCallbackWithInfo, this);
156  else
157  img_sub_ = it_->subscribe("image", queue_size_, &ColorFilterNodelet::imageCallback, this);
158  }
159 
160  void unsubscribe() // NOLINT(modernize-use-override)
161  {
162  NODELET_DEBUG("Unsubscribing from image topic.");
163  img_sub_.shutdown();
164  cam_sub_.shutdown();
165  }
166 
167 public:
168  virtual void onInit() // NOLINT(modernize-use-override)
169  {
170  Nodelet::onInit();
172 
173  pnh_->param("queue_size", queue_size_, 3);
174  pnh_->param("debug_view", debug_view_, false);
175 
176  if (debug_view_)
177  {
178  always_subscribe_ = true;
179  }
180 
181  window_name_ = "ColorFilter Demo";
182 
183  reconfigure_server_ = boost::make_shared<dynamic_reconfigure::Server<Config> >(*pnh_);
184  typename dynamic_reconfigure::Server<Config>::CallbackType f =
185  boost::bind(&ColorFilterNodelet::reconfigureCallback, this, _1, _2);
186  reconfigure_server_->setCallback(f);
187 
188  img_pub_ = advertiseImage(*pnh_, "image", 1);
189 
190  onInitPostProcess();
191  }
192 };
193 
194 class RGBColorFilterNodelet : public ColorFilterNodelet<opencv_apps::RGBColorFilterConfig>
195 {
196 protected:
197  int r_min_;
198  int r_max_;
199  int b_min_;
200  int b_max_;
201  int g_min_;
202  int g_max_;
203 
204  void reconfigureCallback(opencv_apps::RGBColorFilterConfig& config, uint32_t level) // NOLINT(modernize-use-override)
205  {
206  boost::mutex::scoped_lock lock(mutex_);
207  config_ = config;
208  r_max_ = config.r_limit_max;
209  r_min_ = config.r_limit_min;
210  g_max_ = config.g_limit_max;
211  g_min_ = config.g_limit_min;
212  b_max_ = config.b_limit_max;
213  b_min_ = config.b_limit_min;
214  updateCondition();
215  }
216 
217  virtual void updateCondition()
218  {
219  if (r_max_ < r_min_)
220  std::swap(r_max_, r_min_);
221  if (g_max_ < g_min_)
222  std::swap(g_max_, g_min_);
223  if (b_max_ < b_min_)
224  std::swap(b_max_, b_min_);
225  lower_color_range_ = cv::Scalar(b_min_, g_min_, r_min_);
226  upper_color_range_ = cv::Scalar(b_max_, g_max_, r_max_);
227  }
228 
229  void filter(const cv::Mat& input_image, cv::Mat& output_image) // NOLINT(modernize-use-override)
230  {
231  cv::inRange(input_image, lower_color_range_, upper_color_range_, output_image);
232  }
233 
234 protected:
235  virtual void onInit() // NOLINT(modernize-use-override)
236  {
237  r_max_ = 255;
238  r_min_ = 0;
239  g_max_ = 255;
240  g_min_ = 0;
241  b_max_ = 255;
242  b_min_ = 0;
243 
244  ColorFilterNodelet::onInit();
245  }
249 };
250 
251 class HLSColorFilterNodelet : public ColorFilterNodelet<opencv_apps::HLSColorFilterConfig>
252 {
253 protected:
254  int h_min_;
255  int h_max_;
256  int s_min_;
257  int s_max_;
258  int l_min_;
259  int l_max_;
260 
261  void reconfigureCallback(opencv_apps::HLSColorFilterConfig& config, uint32_t level) // NOLINT(modernize-use-override)
262  {
263  boost::mutex::scoped_lock lock(mutex_);
264  config_ = config;
265  h_max_ = config.h_limit_max;
266  h_min_ = config.h_limit_min;
267  s_max_ = config.s_limit_max;
268  s_min_ = config.s_limit_min;
269  l_max_ = config.l_limit_max;
270  l_min_ = config.l_limit_min;
271  updateCondition();
272  }
273 
274  virtual void updateCondition()
275  {
276  if (s_max_ < s_min_)
277  std::swap(s_max_, s_min_);
278  if (l_max_ < l_min_)
279  std::swap(l_max_, l_min_);
280  lower_color_range_ = cv::Scalar(h_min_ / 2, l_min_, s_min_, 0);
281  upper_color_range_ = cv::Scalar(h_max_ / 2, l_max_, s_max_, 0);
282  }
283 
284  void filter(const cv::Mat& input_image, cv::Mat& output_image) // NOLINT(modernize-use-override)
285  {
286  cv::Mat hls_image;
287  cv::cvtColor(input_image, hls_image, cv::COLOR_BGR2HLS);
288  if (lower_color_range_[0] < upper_color_range_[0])
289  {
290  cv::inRange(hls_image, lower_color_range_, upper_color_range_, output_image);
291  }
292  else
293  {
294  cv::Scalar lower_color_range_0 = cv::Scalar(0, l_min_, s_min_, 0);
295  cv::Scalar upper_color_range_0 = cv::Scalar(h_max_ / 2, l_max_, s_max_, 0);
296  cv::Scalar lower_color_range_360 = cv::Scalar(h_min_ / 2, l_min_, s_min_, 0);
297  cv::Scalar upper_color_range_360 = cv::Scalar(360 / 2, l_max_, s_max_, 0);
298  cv::Mat output_image_0, output_image_360;
299  cv::inRange(hls_image, lower_color_range_0, upper_color_range_0, output_image_0);
300  cv::inRange(hls_image, lower_color_range_360, upper_color_range_360, output_image_360);
301  output_image = output_image_0 | output_image_360;
302  }
303  }
304 
305 public:
306  virtual void onInit() // NOLINT(modernize-use-override)
307  {
308  h_max_ = 360;
309  h_min_ = 0;
310  s_max_ = 256;
311  s_min_ = 0;
312  l_max_ = 256;
313  l_min_ = 0;
314 
315  ColorFilterNodelet::onInit();
316  }
317 };
318 
319 class HSVColorFilterNodelet : public ColorFilterNodelet<opencv_apps::HSVColorFilterConfig>
320 {
321 protected:
322  int h_min_;
323  int h_max_;
324  int s_min_;
325  int s_max_;
326  int v_min_;
327  int v_max_;
328 
329  void reconfigureCallback(opencv_apps::HSVColorFilterConfig& config, uint32_t level) // NOLINT(modernize-use-override)
330  {
331  boost::mutex::scoped_lock lock(mutex_);
332  config_ = config;
333  h_max_ = config.h_limit_max;
334  h_min_ = config.h_limit_min;
335  s_max_ = config.s_limit_max;
336  s_min_ = config.s_limit_min;
337  v_max_ = config.v_limit_max;
338  v_min_ = config.v_limit_min;
339  updateCondition();
340  }
341 
342  virtual void updateCondition()
343  {
344  if (s_max_ < s_min_)
345  std::swap(s_max_, s_min_);
346  if (v_max_ < v_min_)
347  std::swap(v_max_, v_min_);
348  lower_color_range_ = cv::Scalar(h_min_ / 2, s_min_, v_min_, 0);
349  upper_color_range_ = cv::Scalar(h_max_ / 2, s_max_, v_max_, 0);
350  }
351 
352  void filter(const cv::Mat& input_image, cv::Mat& output_image) // NOLINT(modernize-use-override)
353  {
354  cv::Mat hsv_image;
355  cv::cvtColor(input_image, hsv_image, cv::COLOR_BGR2HSV);
356  if (lower_color_range_[0] < upper_color_range_[0])
357  {
358  cv::inRange(hsv_image, lower_color_range_, upper_color_range_, output_image);
359  }
360  else
361  {
362  cv::Scalar lower_color_range_0 = cv::Scalar(0, s_min_, v_min_, 0);
363  cv::Scalar upper_color_range_0 = cv::Scalar(h_max_ / 2, s_max_, v_max_, 0);
364  cv::Scalar lower_color_range_360 = cv::Scalar(h_min_ / 2, s_min_, v_min_, 0);
365  cv::Scalar upper_color_range_360 = cv::Scalar(360 / 2, s_max_, v_max_, 0);
366  cv::Mat output_image_0, output_image_360;
367  cv::inRange(hsv_image, lower_color_range_0, upper_color_range_0, output_image_0);
368  cv::inRange(hsv_image, lower_color_range_360, upper_color_range_360, output_image_360);
369  output_image = output_image_0 | output_image_360;
370  }
371  }
372 
373 public:
374  virtual void onInit() // NOLINT(modernize-use-override)
375  {
376  h_max_ = 360;
377  h_min_ = 0;
378  s_max_ = 256;
379  s_min_ = 0;
380  v_max_ = 256;
381  v_min_ = 0;
382 
383  ColorFilterNodelet::onInit();
384  }
385 };
386 
387 } // namespace opencv_apps
388 
389 namespace color_filter
390 {
392 {
393 public:
394  virtual void onInit() // NOLINT(modernize-use-override)
395  {
396  ROS_WARN("DeprecationWarning: Nodelet rgb_color_filter/rgb_color_filter is deprecated, "
397  "and renamed to opencv_apps/rgb_color_filter.");
399  }
400 };
402 {
403 public:
404  virtual void onInit() // NOLINT(modernize-use-override)
405  {
406  ROS_WARN("DeprecationWarning: Nodelet hls_color_filter/hls_color_filter is deprecated, "
407  "and renamed to opencv_apps/hls_color_filter.");
409  }
410 };
412 {
413 public:
414  virtual void onInit() // NOLINT(modernize-use-override)
415  {
416  ROS_WARN("DeprecationWarning: Nodelet hsv_color_filter/hsv_color_filter is deprecated, "
417  "and renamed to opencv_apps/hsv_color_filter.");
419  }
420 };
421 } // namespace color_filter
422 
CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
image_transport::CameraSubscriber cam_sub_
virtual void onInit()
Initialize nodehandles nh_ and pnh_. Subclass should call this method in its onInit method...
void imageCallback(const sensor_msgs::ImageConstPtr &msg)
#define NODELET_ERROR(...)
void filter(const cv::Mat &input_image, cv::Mat &output_image)
dynamic_reconfigure::Server< Config > ReconfigureServer
f
boost::shared_ptr< ReconfigureServer > reconfigure_server_
Nodelet to automatically subscribe/unsubscribe topics according to subscription of advertised topics...
Definition: nodelet.h:70
const std::string & frameWithDefault(const std::string &frame, const std::string &image_frame)
Demo code to calculate moments.
Definition: nodelet.h:48
void subscribe()
This method is called when publisher is subscribed by other nodes. Set up subscribers in this method...
void filter(const cv::Mat &input_image, cv::Mat &output_image)
void reconfigureCallback(opencv_apps::HLSColorFilterConfig &config, uint32_t level)
#define ROS_WARN(...)
void imageCallbackWithInfo(const sensor_msgs::ImageConstPtr &msg, const sensor_msgs::CameraInfoConstPtr &cam_info)
virtual void onInit()
Initialize nodehandles nh_ and pnh_. Subclass should call this method in its onInit method...
virtual void onInit()
Initialize nodehandles nh_ and pnh_. Subclass should call this method in its onInit method...
void reconfigureCallback(opencv_apps::HSVColorFilterConfig &config, uint32_t level)
void doWork(const sensor_msgs::ImageConstPtr &image_msg, const std::string &input_frame_from_msg)
void publish(const sensor_msgs::Image &message) const
void unsubscribe()
This method is called when publisher is unsubscribed by other nodes. Shut down subscribers in this me...
virtual void onInit()
Initialize nodehandles nh_ and pnh_. Subclass should call this method in its onInit method...
boost::shared_ptr< image_transport::ImageTransport > it_
PLUGINLIB_EXPORT_CLASS(color_filter::RGBColorFilterNodelet, nodelet::Nodelet)
virtual void onInit()
Initialize nodehandles nh_ and pnh_. Subclass should call this method in its onInit method...
void reconfigureCallback(opencv_apps::RGBColorFilterConfig &config, uint32_t level)
image_transport::Publisher img_pub_
virtual void onInit()
Initialize nodehandles nh_ and pnh_. Subclass should call this method in its onInit method...
void filter(const cv::Mat &input_image, cv::Mat &output_image)
image_transport::Subscriber img_sub_
virtual void onInit()
Initialize nodehandles nh_ and pnh_. Subclass should call this method in its onInit method...
#define NODELET_DEBUG(...)
sensor_msgs::ImagePtr toImageMsg() const


opencv_apps
Author(s): Kei Okada
autogenerated on Sat Aug 22 2020 03:35:08