00001 #include <ros/ros.h>
00002 #include <nodelet/nodelet.h>
00003 #include <image_transport/image_transport.h>
00004 #include <sensor_msgs/image_encodings.h>
00005 #include <dynamic_reconfigure/server.h>
00006 #include <image_proc/DebayerConfig.h>
00007
00008 #include <opencv2/imgproc/imgproc.hpp>
00009
00010 #include "edge_aware.h"
00011 #include "yuv422.h"
00012
00013 #include <boost/make_shared.hpp>
00014
00015 namespace image_proc {
00016
00017 namespace enc = sensor_msgs::image_encodings;
00018
00019 class DebayerNodelet : public nodelet::Nodelet
00020 {
00021
00022 boost::shared_ptr<image_transport::ImageTransport> it_;
00023 image_transport::Subscriber sub_raw_;
00024
00025 boost::mutex connect_mutex_;
00026 image_transport::Publisher pub_mono_;
00027 image_transport::Publisher pub_color_;
00028
00029
00030 boost::recursive_mutex config_mutex_;
00031 typedef image_proc::DebayerConfig Config;
00032 typedef dynamic_reconfigure::Server<Config> ReconfigureServer;
00033 boost::shared_ptr<ReconfigureServer> reconfigure_server_;
00034 Config config_;
00035
00036 virtual void onInit();
00037
00038 void connectCb();
00039
00040 void imageCb(const sensor_msgs::ImageConstPtr& raw_msg);
00041
00042 void configCb(Config &config, uint32_t level);
00043 };
00044
00045 void DebayerNodelet::onInit()
00046 {
00047 ros::NodeHandle &nh = getNodeHandle();
00048 ros::NodeHandle &private_nh = getPrivateNodeHandle();
00049 it_.reset(new image_transport::ImageTransport(nh));
00050
00051
00052 reconfigure_server_.reset(new ReconfigureServer(config_mutex_, private_nh));
00053 ReconfigureServer::CallbackType f = boost::bind(&DebayerNodelet::configCb, this, _1, _2);
00054 reconfigure_server_->setCallback(f);
00055
00056
00057 typedef image_transport::SubscriberStatusCallback ConnectCB;
00058 ConnectCB connect_cb = boost::bind(&DebayerNodelet::connectCb, this);
00059
00060 boost::lock_guard<boost::mutex> lock(connect_mutex_);
00061 pub_mono_ = it_->advertise("image_mono", 1, connect_cb, connect_cb);
00062 pub_color_ = it_->advertise("image_color", 1, connect_cb, connect_cb);
00063 }
00064
00065
00066 void DebayerNodelet::connectCb()
00067 {
00068 boost::lock_guard<boost::mutex> lock(connect_mutex_);
00069 if (pub_mono_.getNumSubscribers() == 0 && pub_color_.getNumSubscribers() == 0)
00070 sub_raw_.shutdown();
00071 else if (!sub_raw_)
00072 {
00073 image_transport::TransportHints hints("raw", ros::TransportHints(), getPrivateNodeHandle());
00074 sub_raw_ = it_->subscribe("image_raw", 1, &DebayerNodelet::imageCb, this, hints);
00075 }
00076 }
00077
00078 void DebayerNodelet::imageCb(const sensor_msgs::ImageConstPtr& raw_msg)
00079 {
00082
00083 if (enc::isMono(raw_msg->encoding))
00084 {
00085
00086 pub_mono_.publish(raw_msg);
00087 pub_color_.publish(raw_msg);
00088
00089
00090 if (pub_color_.getNumSubscribers() > 0)
00091 {
00092 NODELET_WARN_THROTTLE(30,
00093 "Color topic '%s' requested, but raw image data from topic '%s' is grayscale",
00094 pub_color_.getTopic().c_str(), sub_raw_.getTopic().c_str());
00095 }
00096 }
00097 else if (enc::isColor(raw_msg->encoding))
00098 {
00099 pub_color_.publish(raw_msg);
00100
00101
00102 if (pub_mono_.getNumSubscribers() > 0)
00103 {
00104 int bit_depth = enc::bitDepth(raw_msg->encoding);
00105 int num_channels = enc::numChannels(raw_msg->encoding);
00106 int code = -1;
00107 if (raw_msg->encoding == enc::BGR8 ||
00108 raw_msg->encoding == enc::BGR16)
00109 code = CV_BGR2GRAY;
00110 else if (raw_msg->encoding == enc::RGB8 ||
00111 raw_msg->encoding == enc::RGB16)
00112 code = CV_RGB2GRAY;
00113 else if (raw_msg->encoding == enc::BGRA8 ||
00114 raw_msg->encoding == enc::BGRA16)
00115 code = CV_BGRA2GRAY;
00116 else if (raw_msg->encoding == enc::RGBA8 ||
00117 raw_msg->encoding == enc::RGBA16)
00118 code = CV_RGBA2GRAY;
00119
00120 sensor_msgs::ImagePtr gray_msg = boost::make_shared<sensor_msgs::Image>();
00121 gray_msg->header = raw_msg->header;
00122 gray_msg->height = raw_msg->height;
00123 gray_msg->width = raw_msg->width;
00124 gray_msg->encoding = bit_depth == 8 ? enc::MONO8 : enc::MONO16;
00125 gray_msg->step = gray_msg->width * (bit_depth / 8);
00126 gray_msg->data.resize(gray_msg->height * gray_msg->step);
00127
00128 int type = bit_depth == 8 ? CV_8U : CV_16U;
00129 const cv::Mat color(raw_msg->height, raw_msg->width, CV_MAKETYPE(type, num_channels),
00130 const_cast<uint8_t*>(&raw_msg->data[0]), raw_msg->step);
00131 cv::Mat gray(gray_msg->height, gray_msg->width, CV_MAKETYPE(type, 1),
00132 &gray_msg->data[0], gray_msg->step);
00133 cv::cvtColor(color, gray, code);
00134
00135 pub_mono_.publish(gray_msg);
00136 }
00137 }
00138 else if (enc::isBayer(raw_msg->encoding)) {
00139 int bit_depth = enc::bitDepth(raw_msg->encoding);
00140 int type = bit_depth == 8 ? CV_8U : CV_16U;
00141 const cv::Mat bayer(raw_msg->height, raw_msg->width, CV_MAKETYPE(type, 1),
00142 const_cast<uint8_t*>(&raw_msg->data[0]), raw_msg->step);
00143
00144 if (pub_mono_.getNumSubscribers() > 0)
00145 {
00146 int code = -1;
00147 if (raw_msg->encoding == enc::BAYER_RGGB8 ||
00148 raw_msg->encoding == enc::BAYER_RGGB16)
00149 code = CV_BayerBG2GRAY;
00150 else if (raw_msg->encoding == enc::BAYER_BGGR8 ||
00151 raw_msg->encoding == enc::BAYER_BGGR16)
00152 code = CV_BayerRG2GRAY;
00153 else if (raw_msg->encoding == enc::BAYER_GBRG8 ||
00154 raw_msg->encoding == enc::BAYER_GBRG16)
00155 code = CV_BayerGR2GRAY;
00156 else if (raw_msg->encoding == enc::BAYER_GRBG8 ||
00157 raw_msg->encoding == enc::BAYER_GRBG16)
00158 code = CV_BayerGB2GRAY;
00159
00160 sensor_msgs::ImagePtr gray_msg = boost::make_shared<sensor_msgs::Image>();
00161 gray_msg->header = raw_msg->header;
00162 gray_msg->height = raw_msg->height;
00163 gray_msg->width = raw_msg->width;
00164 gray_msg->encoding = bit_depth == 8 ? enc::MONO8 : enc::MONO16;
00165 gray_msg->step = gray_msg->width * (bit_depth / 8);
00166 gray_msg->data.resize(gray_msg->height * gray_msg->step);
00167
00168 cv::Mat gray(gray_msg->height, gray_msg->width, CV_MAKETYPE(type, 1),
00169 &gray_msg->data[0], gray_msg->step);
00170 cv::cvtColor(bayer, gray, code);
00171
00172 pub_mono_.publish(gray_msg);
00173 }
00174
00175 if (pub_color_.getNumSubscribers() > 0)
00176 {
00177 sensor_msgs::ImagePtr color_msg = boost::make_shared<sensor_msgs::Image>();
00178 color_msg->header = raw_msg->header;
00179 color_msg->height = raw_msg->height;
00180 color_msg->width = raw_msg->width;
00181 color_msg->encoding = bit_depth == 8? enc::BGR8 : enc::BGR16;
00182 color_msg->step = color_msg->width * 3 * (bit_depth / 8);
00183 color_msg->data.resize(color_msg->height * color_msg->step);
00184
00185 cv::Mat color(color_msg->height, color_msg->width, CV_MAKETYPE(type, 3),
00186 &color_msg->data[0], color_msg->step);
00187
00188 int algorithm;
00189 {
00190 boost::lock_guard<boost::recursive_mutex> lock(config_mutex_);
00191 algorithm = config_.debayer;
00192 }
00193
00194 if (algorithm == Debayer_EdgeAware ||
00195 algorithm == Debayer_EdgeAwareWeighted)
00196 {
00197
00198 if (raw_msg->encoding != enc::BAYER_GRBG8)
00199 {
00200 NODELET_WARN_THROTTLE(30, "Edge aware algorithms currently only support GRBG8 Bayer. "
00201 "Falling back to bilinear interpolation.");
00202 algorithm = Debayer_Bilinear;
00203 }
00204 else
00205 {
00206 if (algorithm == Debayer_EdgeAware)
00207 debayerEdgeAware(bayer, color);
00208 else
00209 debayerEdgeAwareWeighted(bayer, color);
00210 }
00211 }
00212 if (algorithm == Debayer_Bilinear ||
00213 algorithm == Debayer_VNG)
00214 {
00215 int code = -1;
00216 if (raw_msg->encoding == enc::BAYER_RGGB8 ||
00217 raw_msg->encoding == enc::BAYER_RGGB16)
00218 code = CV_BayerBG2BGR;
00219 else if (raw_msg->encoding == enc::BAYER_BGGR8 ||
00220 raw_msg->encoding == enc::BAYER_BGGR16)
00221 code = CV_BayerRG2BGR;
00222 else if (raw_msg->encoding == enc::BAYER_GBRG8 ||
00223 raw_msg->encoding == enc::BAYER_GBRG16)
00224 code = CV_BayerGR2BGR;
00225 else if (raw_msg->encoding == enc::BAYER_GRBG8 ||
00226 raw_msg->encoding == enc::BAYER_GRBG16)
00227 code = CV_BayerGB2BGR;
00228
00229 if (algorithm == Debayer_VNG)
00230 code += CV_BayerBG2BGR_VNG - CV_BayerBG2BGR;
00231
00232 cv::cvtColor(bayer, color, code);
00233 }
00234
00235 pub_color_.publish(color_msg);
00236 }
00237 }
00238 else if (raw_msg->encoding == enc::YUV422)
00239 {
00240 const cv::Mat yuv(raw_msg->height, raw_msg->width, CV_8UC2,
00241 const_cast<uint8_t*>(&raw_msg->data[0]), raw_msg->step);
00242
00243 if (pub_mono_.getNumSubscribers() > 0)
00244 {
00245 sensor_msgs::ImagePtr gray_msg = boost::make_shared<sensor_msgs::Image>();
00246 gray_msg->header = raw_msg->header;
00247 gray_msg->height = raw_msg->height;
00248 gray_msg->width = raw_msg->width;
00249 gray_msg->encoding = enc::MONO8;
00250 gray_msg->step = gray_msg->width;
00251 gray_msg->data.resize(gray_msg->height * gray_msg->step);
00252
00253 cv::Mat gray(gray_msg->height, gray_msg->width, CV_8UC1,
00254 &gray_msg->data[0], gray_msg->step);
00255 yuv422ToGray(yuv, gray);
00256
00257 pub_mono_.publish(gray_msg);
00258 }
00259
00260 if (pub_color_.getNumSubscribers() > 0)
00261 {
00262 sensor_msgs::ImagePtr color_msg = boost::make_shared<sensor_msgs::Image>();
00263 color_msg->header = raw_msg->header;
00264 color_msg->height = raw_msg->height;
00265 color_msg->width = raw_msg->width;
00266 color_msg->encoding = enc::BGR8;
00267 color_msg->step = color_msg->width * 3;
00268 color_msg->data.resize(color_msg->height * color_msg->step);
00269
00270 cv::Mat color(color_msg->height, color_msg->width, CV_8UC3,
00271 &color_msg->data[0], color_msg->step);
00272 yuv422ToColor(yuv, color);
00273
00274 pub_color_.publish(color_msg);
00275 }
00276 }
00277 else if (raw_msg->encoding == enc::TYPE_8UC3)
00278 {
00279
00280 NODELET_ERROR_THROTTLE(10,
00281 "Raw image topic '%s' has ambiguous encoding '8UC3'. The "
00282 "source should set the encoding to 'bgr8' or 'rgb8'.",
00283 sub_raw_.getTopic().c_str());
00284 }
00285 else
00286 {
00287 NODELET_ERROR_THROTTLE(10, "Raw image topic '%s' has unsupported encoding '%s'",
00288 sub_raw_.getTopic().c_str(), raw_msg->encoding.c_str());
00289 }
00290 }
00291
00292 void DebayerNodelet::configCb(Config &config, uint32_t level)
00293 {
00294 config_ = config;
00295 }
00296
00297 }
00298
00299
00300 #include <pluginlib/class_list_macros.h>
00301 PLUGINLIB_DECLARE_CLASS(image_proc, debayer, image_proc::DebayerNodelet, nodelet::Nodelet)