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 <image_geometry/pinhole_camera_model.h>
00007 #include <cv_bridge/CvBridge.h>
00008
00009 namespace image_proc {
00010
00011 class RectifyNodelet : public nodelet::Nodelet
00012 {
00013 boost::shared_ptr<image_transport::ImageTransport> it_;
00014 image_transport::CameraSubscriber sub_camera_;
00015 image_transport::Publisher pub_rect_;
00016 boost::shared_ptr<AdvertisementChecker> check_inputs_;
00017 image_geometry::PinholeCameraModel model_;
00018 int interpolation_;
00019 int queue_size_;
00020
00021 virtual void onInit();
00022
00023 void connectCb();
00024
00025 void imageCb(const sensor_msgs::ImageConstPtr& image_msg,
00026 const sensor_msgs::CameraInfoConstPtr& info_msg);
00027
00028 public:
00029 RectifyNodelet() : interpolation_(CV_INTER_LINEAR) {}
00030 };
00031
00032 void RectifyNodelet::onInit()
00033 {
00034 ros::NodeHandle &nh = getNodeHandle();
00035 ros::NodeHandle &private_nh = getPrivateNodeHandle();
00036 it_.reset(new image_transport::ImageTransport(nh));
00037
00038
00039 private_nh.param("queue_size", queue_size_, 5);
00040
00041
00042 image_transport::SubscriberStatusCallback connect_cb = boost::bind(&RectifyNodelet::connectCb, this);
00043 pub_rect_ = it_->advertise("image_rect", 1, connect_cb, connect_cb);
00044
00045
00046 const std::vector<std::string>& argv = getMyArgv();
00047 bool do_input_checks = std::find(argv.begin(), argv.end(),
00048 "--no-input-checks") == argv.end();
00049
00050
00051 if (do_input_checks)
00052 {
00053 ros::V_string topics;
00054 topics.push_back("image_mono");
00055 topics.push_back("camera_info");
00056 check_inputs_.reset( new AdvertisementChecker(nh, getName()) );
00057 check_inputs_->start(topics, 60.0);
00058 }
00059 }
00060
00061
00062 void RectifyNodelet::connectCb()
00063 {
00064 if (pub_rect_.getNumSubscribers() == 0)
00065 sub_camera_.shutdown();
00066 else if (!sub_camera_)
00067 sub_camera_ = it_->subscribeCamera("image_mono", queue_size_, &RectifyNodelet::imageCb, this);
00068 }
00069
00070 void RectifyNodelet::imageCb(const sensor_msgs::ImageConstPtr& image_msg,
00071 const sensor_msgs::CameraInfoConstPtr& info_msg)
00072 {
00073
00074 if (info_msg->K[0] == 0.0) {
00075 NODELET_ERROR_THROTTLE(30, "Rectified topic '%s' requested but camera publishing '%s' "
00076 "is uncalibrated", pub_rect_.getTopic().c_str(),
00077 sub_camera_.getInfoTopic().c_str());
00078 return;
00079 }
00080
00081
00082 if (info_msg->D.empty() || info_msg->D[0] == 0.0)
00083 {
00084 pub_rect_.publish(image_msg);
00085 return;
00086 }
00087
00088
00089 model_.fromCameraInfo(info_msg);
00090
00091
00092 sensor_msgs::ImagePtr rect_msg = boost::make_shared<sensor_msgs::Image>();
00093 rect_msg->header = image_msg->header;
00094 rect_msg->height = image_msg->height;
00095 rect_msg->width = image_msg->width;
00096 rect_msg->encoding = image_msg->encoding;
00097 rect_msg->step = image_msg->step;
00098 rect_msg->data.resize(rect_msg->height * rect_msg->step);
00099
00100
00101 sensor_msgs::CvBridge image_bridge, rect_bridge;
00102 const cv::Mat image = image_bridge.imgMsgToCv(image_msg);
00103 cv::Mat rect = rect_bridge.imgMsgToCv(rect_msg);
00104
00105
00106 model_.rectifyImage(image, rect, interpolation_);
00107 pub_rect_.publish(rect_msg);
00108 }
00109
00110 }
00111
00112
00113 #include <pluginlib/class_list_macros.h>
00114 PLUGINLIB_DECLARE_CLASS(image_proc, rectify, image_proc::RectifyNodelet, nodelet::Nodelet)