debayer.cpp
Go to the documentation of this file.
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 // Until merged into OpenCV
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   // ROS communication
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   // Dynamic reconfigure
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   // Set up dynamic reconfigure
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   // Monitor whether anyone is subscribed to the output
00057   typedef image_transport::SubscriberStatusCallback ConnectCB;
00058   ConnectCB connect_cb = boost::bind(&DebayerNodelet::connectCb, this);
00059   // Make sure we don't enter connectCb() between advertising and assigning to pub_XXX
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 // Handles (un)subscribing when clients (un)subscribe
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     // For monochrome, no processing needed!
00086     pub_mono_.publish(raw_msg);
00087     pub_color_.publish(raw_msg);
00088     
00089     // Warn if the user asked for color
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     // Convert to monochrome if needed
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         // These algorithms are not in OpenCV yet
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     // 8UC3 does not specify a color encoding. Is it BGR, RGB, HSV, XYZ, LUV...?
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 } // namespace image_proc
00298 
00299 // Register nodelet
00300 #include <pluginlib/class_list_macros.h>
00301 PLUGINLIB_DECLARE_CLASS(image_proc, debayer, image_proc::DebayerNodelet, nodelet::Nodelet)


image_proc
Author(s): Patrick Mihelich, Kurt Konolige, Jeremy Leibs
autogenerated on Fri Jan 3 2014 11:24:35