00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00041 #include <opencv2/opencv.hpp>
00042 #include <cv_bridge/cv_bridge.h>
00043 #include <sensor_msgs/image_encodings.h>
00044 #include <sensor_msgs/CameraInfo.h>
00045 #include <dynamic_reconfigure/server.h>
00046
00047 #include <image_transport/image_transport.h>
00048 #include <image_transport/subscriber_filter.h>
00049
00050 #include <message_filters/subscriber.h>
00051 #include <message_filters/synchronizer.h>
00052 #include <message_filters/sync_policies/exact_time.h>
00053 #include <message_filters/sync_policies/approximate_time.h>
00054
00055 #include "opencv_apps/AddingImagesConfig.h"
00056 #include "opencv_apps/nodelet.h"
00057
00058 namespace adding_images {
00059 class AddingImagesNodelet : public opencv_apps::Nodelet {
00060 private:
00061 boost::shared_ptr<image_transport::ImageTransport> it_;
00062
00063 typedef message_filters::sync_policies::ExactTime<
00064 sensor_msgs::Image, sensor_msgs::Image, sensor_msgs::CameraInfo> SyncPolicyWithCameraInfo;
00065 typedef message_filters::sync_policies::ApproximateTime<
00066 sensor_msgs::Image, sensor_msgs::Image, sensor_msgs::CameraInfo> ApproxSyncPolicyWithCameraInfo;
00067 typedef message_filters::sync_policies::ExactTime<
00068 sensor_msgs::Image, sensor_msgs::Image> SyncPolicy;
00069 typedef message_filters::sync_policies::ApproximateTime<
00070 sensor_msgs::Image, sensor_msgs::Image> ApproxSyncPolicy;
00071
00073
00075 typedef adding_images::AddingImagesConfig Config;
00076 typedef dynamic_reconfigure::Server<Config> ReconfigureServer;
00077 Config config_;
00078 boost::shared_ptr<ReconfigureServer> reconfigure_server_;
00079
00080 bool debug_view_;
00081 ros::Time prev_stamp_;
00082
00083 std::string window_name_;
00084
00085 image_transport::SubscriberFilter sub_image1_, sub_image2_;
00086 image_transport::Publisher img_pub_;
00087 message_filters::Subscriber<sensor_msgs::CameraInfo> sub_camera_info_;
00088 boost::shared_ptr<message_filters::Synchronizer<SyncPolicyWithCameraInfo> > sync_with_info_;
00089 boost::shared_ptr<message_filters::Synchronizer<ApproxSyncPolicyWithCameraInfo> > async_with_info_;
00090 boost::shared_ptr<message_filters::Synchronizer<SyncPolicy> > sync_;
00091 boost::shared_ptr<message_filters::Synchronizer<ApproxSyncPolicy> > async_;
00092 boost::mutex mutex_;
00093
00094 bool approximate_sync_;
00095 double alpha_;
00096 double beta_;
00097 double gamma_;
00098
00099 void imageCallbackWithInfo(
00100 const sensor_msgs::ImageConstPtr& msg1,
00101 const sensor_msgs::ImageConstPtr& msg2,
00102 const sensor_msgs::CameraInfoConstPtr& cam_info) {
00103 do_work(msg1, msg2, cam_info->header.frame_id);
00104 }
00105
00106 void imageCallback(const sensor_msgs::ImageConstPtr& msg1,
00107 const sensor_msgs::ImageConstPtr& msg2) {
00108 do_work(msg1, msg2, msg1->header.frame_id);
00109 }
00110
00111 void subscribe() {
00112 NODELET_DEBUG("Subscribing to image topic.");
00113 sub_image1_.subscribe(*it_, "image1", 3);
00114 sub_image2_.subscribe(*it_, "image2", 3);
00115 sub_camera_info_.subscribe(*nh_, "camera_info", 3);
00116 if (config_.use_camera_info) {
00117 if (approximate_sync_) {
00118 async_with_info_ = boost::make_shared<
00119 message_filters::Synchronizer<ApproxSyncPolicyWithCameraInfo> >(100);
00120 async_with_info_->connectInput(sub_image1_, sub_image2_, sub_camera_info_);
00121 async_with_info_->registerCallback(boost::bind(
00122 &AddingImagesNodelet::imageCallbackWithInfo, this, _1, _2, _3));
00123 } else {
00124 sync_with_info_ =
00125 boost::make_shared<message_filters::Synchronizer<SyncPolicyWithCameraInfo> >(100);
00126 sync_with_info_->connectInput(sub_image1_, sub_image2_, sub_camera_info_);
00127 sync_with_info_->registerCallback(boost::bind(
00128 &AddingImagesNodelet::imageCallbackWithInfo, this, _1, _2, _3));
00129 }
00130 } else {
00131 if (approximate_sync_) {
00132 async_ = boost::make_shared<
00133 message_filters::Synchronizer<ApproxSyncPolicy> >(100);
00134 async_->connectInput(sub_image1_, sub_image2_);
00135 async_->registerCallback(
00136 boost::bind(&AddingImagesNodelet::imageCallback, this, _1, _2));
00137 } else {
00138 sync_ =
00139 boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
00140 sync_->connectInput(sub_image1_, sub_image2_);
00141 sync_->registerCallback(
00142 boost::bind(&AddingImagesNodelet::imageCallback, this, _1, _2));
00143 }
00144 }
00145 }
00146
00147 void unsubscribe() {
00148 NODELET_DEBUG("Unsubscribing from image topic.");
00149 sub_image1_.unsubscribe();
00150 sub_image2_.unsubscribe();
00151 sub_camera_info_.unsubscribe();
00152 }
00153
00154 void reconfigureCallback(Config& config, uint32_t level) {
00155 boost::mutex::scoped_lock lock(mutex_);
00156 config_ = config;
00157 alpha_ = config.alpha;
00158 if ( config.auto_beta ) {
00159 beta_ = 1.0 - alpha_;
00160 config.beta = beta_;
00161 } else {
00162 beta_ = config.beta;
00163 }
00164 gamma_ = config.gamma;
00165 }
00166
00167 void do_work(const sensor_msgs::Image::ConstPtr& image_msg1,
00168 const sensor_msgs::Image::ConstPtr& image_msg2,
00169 const std::string input_frame_from_msg) {
00170 boost::mutex::scoped_lock lock(mutex_);
00171
00172 try {
00173 cv::Mat image1 =
00174 cv_bridge::toCvShare(image_msg1, image_msg1->encoding)->image;
00175 cv::Mat image2 =
00176 cv_bridge::toCvShare(image_msg2, image_msg1->encoding)->image;
00177 if (cv_bridge::getCvType(image_msg1->encoding) != cv_bridge::getCvType(image_msg2->encoding)) {
00178 NODELET_ERROR("Encoding of input images must be same type: %s, %s",
00179 image_msg1->encoding.c_str(), image_msg2->encoding.c_str());
00180 return;
00181 }
00182
00183 cv::Mat result_image;
00184 cv::addWeighted(image1, alpha_, image2, beta_, gamma_, result_image);
00185
00186 sensor_msgs::ImagePtr image_msg3 = cv_bridge::CvImage(image_msg1->header,
00187 image_msg1->encoding,
00188 result_image).toImageMsg();
00189 if (debug_view_) {
00190 cv::namedWindow(window_name_, cv::WINDOW_AUTOSIZE);
00191 #ifdef CV_BRIDGE_CVT_COLOR_FOR_DISPLAY_IS_NOT_SUPPORTED
00192 cv::imshow(window_name_, result_image);
00193 #else
00194 #ifdef CV_BRIDGE_CVT_COLOR_FOR_DISPLAY_OPTION_IS_NOT_SUPPORTED
00195 cv::imshow(window_name_, cv_bridge::cvtColorForDisplay(cv_bridge::toCvShare(image_msg3, image_msg3->encoding))->image);
00196 #else
00197 cv_bridge::CvtColorForDisplayOptions options;
00198 if (sensor_msgs::image_encodings::bitDepth(image_msg1->encoding) == 32 ||
00199 sensor_msgs::image_encodings::bitDepth(image_msg1->encoding) == 64) {
00200
00201 options.do_dynamic_scaling = true;
00202 }
00203 cv::imshow(window_name_, cv_bridge::cvtColorForDisplay(cv_bridge::toCvShare(image_msg3), "", options)->image);
00204 #endif
00205 #endif
00206 int c = cv::waitKey(1);
00207 }
00208 img_pub_.publish(image_msg3);
00209
00210 } catch (cv::Exception& e) {
00211 NODELET_ERROR("Image processing error: %s %s %s %i", e.err.c_str(),
00212 e.func.c_str(), e.file.c_str(), e.line);
00213 }
00214
00215 prev_stamp_ = image_msg1->header.stamp;
00216 }
00217
00218 public:
00219 virtual void onInit() {
00220 Nodelet::onInit();
00221 it_ = boost::shared_ptr<image_transport::ImageTransport>(
00222 new image_transport::ImageTransport(*nh_));
00223
00224 pnh_->param("debug_view", debug_view_, false);
00225 if (debug_view_) {
00226 always_subscribe_ = true;
00227 }
00228 prev_stamp_ = ros::Time(0, 0);
00229
00230 window_name_ = "AddingImages Demo";
00232
00234 reconfigure_server_ =
00235 boost::make_shared<dynamic_reconfigure::Server<Config> >(*pnh_);
00236 dynamic_reconfigure::Server<Config>::CallbackType f =
00237 boost::bind(&AddingImagesNodelet::reconfigureCallback, this, _1, _2);
00238 reconfigure_server_->setCallback(f);
00239
00240 pnh_->param("approximate_sync", approximate_sync_, true);
00241 img_pub_ = advertiseImage(*pnh_, "image", 1);
00242 onInitPostProcess();
00243 }
00244 };
00245 }
00246
00247 #include <pluginlib/class_list_macros.h>
00248 PLUGINLIB_EXPORT_CLASS(adding_images::AddingImagesNodelet, nodelet::Nodelet);