00001 #include <ros/ros.h>
00002 #include <nodelet/nodelet.h>
00003 #include <image_transport/image_transport.h>
00004 #include <image_proc/advertisement_checker.h>
00005
00006 #include <sensor_msgs/image_encodings.h>
00007 #include <opencv2/imgproc/imgproc.hpp>
00008
00009 #include <boost/make_shared.hpp>
00010
00011 namespace image_proc {
00012
00013 namespace enc = sensor_msgs::image_encodings;
00014
00015 class DebayerNodelet : public nodelet::Nodelet
00016 {
00017 boost::shared_ptr<image_transport::ImageTransport> it_;
00018 image_transport::Subscriber sub_raw_;
00019 image_transport::Publisher pub_mono_;
00020 image_transport::Publisher pub_color_;
00021 boost::shared_ptr<AdvertisementChecker> check_inputs_;
00022
00023 virtual void onInit();
00024
00025 void connectCb();
00026
00027 void imageCb(const sensor_msgs::ImageConstPtr& raw_msg);
00028 };
00029
00030 void DebayerNodelet::onInit()
00031 {
00032 ros::NodeHandle &nh = getNodeHandle();
00033 it_.reset(new image_transport::ImageTransport(nh));
00034
00035
00036 typedef image_transport::SubscriberStatusCallback ConnectCB;
00037 ConnectCB connect_cb = boost::bind(&DebayerNodelet::connectCb, this);
00038 pub_mono_ = it_->advertise("image_mono", 1, connect_cb, connect_cb);
00039 pub_color_ = it_->advertise("image_color", 1, connect_cb, connect_cb);
00040
00041
00042 const std::vector<std::string>& argv = getMyArgv();
00043 bool do_input_checks = std::find(argv.begin(), argv.end(),
00044 "--no-input-checks") == argv.end();
00045
00046
00047 if (do_input_checks)
00048 {
00049 ros::V_string topics;
00050 topics.push_back("image_raw");
00051 check_inputs_.reset( new AdvertisementChecker(nh, getName()) );
00052 check_inputs_->start(topics, 60.0);
00053 }
00054 }
00055
00056
00057 void DebayerNodelet::connectCb()
00058 {
00059 if (pub_mono_.getNumSubscribers() == 0 && pub_color_.getNumSubscribers() == 0)
00060 sub_raw_.shutdown();
00061 else if (!sub_raw_)
00062 sub_raw_ = it_->subscribe("image_raw", 1, &DebayerNodelet::imageCb, this);
00063 }
00064
00065 void DebayerNodelet::imageCb(const sensor_msgs::ImageConstPtr& raw_msg)
00066 {
00067
00068 if (raw_msg->encoding == enc::MONO8 || raw_msg->encoding == enc::MONO16)
00069 {
00070
00071 if (pub_color_.getNumSubscribers() > 0)
00072 {
00073 NODELET_WARN_THROTTLE(30,
00074 "Color topic '%s' requested, but raw image data from topic '%s' is grayscale",
00075 pub_color_.getTopic().c_str(), sub_raw_.getTopic().c_str());
00076 }
00077 pub_mono_.publish(raw_msg);
00078 pub_color_.publish(raw_msg);
00079 return;
00080 }
00081
00082
00083 if (raw_msg->encoding == enc::TYPE_8UC3) {
00084 NODELET_ERROR_THROTTLE(30,
00085 "Raw image topic '%s' has ambiguous encoding '8UC3'. The "
00086 "source should set the encoding to 'bgr8' or 'rgb8'.",
00087 sub_raw_.getTopic().c_str());
00088 return;
00089 }
00090
00091 sensor_msgs::ImageConstPtr color_msg = raw_msg;
00092
00093
00095 if (raw_msg->encoding.find("bayer") != std::string::npos) {
00096
00097 int code = 0;
00098 if (raw_msg->encoding == enc::BAYER_RGGB8)
00099 code = CV_BayerBG2BGR;
00100 else if (raw_msg->encoding == enc::BAYER_BGGR8)
00101 code = CV_BayerRG2BGR;
00102 else if (raw_msg->encoding == enc::BAYER_GBRG8)
00103 code = CV_BayerGR2BGR;
00104 else if (raw_msg->encoding == enc::BAYER_GRBG8)
00105 code = CV_BayerGB2BGR;
00106 else {
00107 NODELET_ERROR_THROTTLE(30, "Raw image topic '%s' has unsupported encoding '%s'",
00108 sub_raw_.getTopic().c_str(), raw_msg->encoding.c_str());
00109 return;
00110 }
00111
00112
00113 sensor_msgs::ImagePtr out_color = boost::make_shared<sensor_msgs::Image>();
00114 out_color->header = raw_msg->header;
00115 out_color->height = raw_msg->height;
00116 out_color->width = raw_msg->width;
00117 out_color->encoding = enc::BGR8;
00118 out_color->step = out_color->width * 3;
00119 out_color->data.resize(out_color->height * out_color->step);
00120
00121
00122 const cv::Mat bayer(raw_msg->height, raw_msg->width, CV_8UC1,
00123 const_cast<uint8_t*>(&raw_msg->data[0]), raw_msg->step);
00124 cv::Mat color(out_color->height, out_color->width, CV_8UC3,
00125 &out_color->data[0], out_color->step);
00126
00127
00128 cv::cvtColor(bayer, color, code);
00129 color_msg = out_color;
00130 }
00131
00132 else if (raw_msg->encoding != enc::RGB8 && raw_msg->encoding != enc::BGR8)
00133 {
00134 NODELET_ERROR_THROTTLE(30, "Raw image topic '%s' has unsupported encoding '%s'",
00135 sub_raw_.getTopic().c_str(), raw_msg->encoding.c_str());
00136 return;
00137 }
00138
00139 pub_color_.publish(color_msg);
00140
00141
00142 if (pub_mono_.getNumSubscribers() > 0)
00143 {
00144 sensor_msgs::ImagePtr gray_msg = boost::make_shared<sensor_msgs::Image>();
00145 gray_msg->header = raw_msg->header;
00146 gray_msg->height = raw_msg->height;
00147 gray_msg->width = raw_msg->width;
00148 gray_msg->encoding = enc::MONO8;
00149 gray_msg->step = gray_msg->width;
00150 gray_msg->data.resize(gray_msg->height * gray_msg->step);
00151
00152 const cv::Mat color(color_msg->height, color_msg->width, CV_8UC3,
00153 const_cast<uint8_t*>(&color_msg->data[0]), color_msg->step);
00154 cv::Mat gray(gray_msg->height, gray_msg->width, CV_8UC1,
00155 &gray_msg->data[0], gray_msg->step);
00156 int code = (color_msg->encoding == enc::BGR8) ? CV_BGR2GRAY : CV_RGB2GRAY;
00157 cv::cvtColor(color, gray, code);
00158
00159 pub_mono_.publish(gray_msg);
00160 }
00161 }
00162
00163 }
00164
00165
00166 #include <pluginlib/class_list_macros.h>
00167 PLUGINLIB_DECLARE_CLASS(image_proc, debayer, image_proc::DebayerNodelet, nodelet::Nodelet)