00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <cob_image_flip/image_flip.h>
00022 #include <geometry_msgs/TransformStamped.h>
00023
00024 namespace cob_image_flip
00025 {
00026 ImageFlip::ImageFlip(ros::NodeHandle nh)
00027 : node_handle_(nh), img_sub_counter_(0), pc_sub_counter_(0), disparity_sub_counter_(0), transform_listener_(nh), it_(0), last_rotation_angle_(0), last_rotation_factor_(0)
00028 {
00029
00030 ROS_DEBUG_STREAM("\n--------------------------\nImage Flip Parameters:\n--------------------------");
00031 node_handle_.param("rotation_mode", rotation_mode_, 0);
00032 ROS_DEBUG_STREAM("rotation_mode = " << rotation_mode_);
00033 if (rotation_mode_ == FIXED_ANGLE)
00034 {
00035
00036 node_handle_.param("rotation_angle", rotation_angle_, 0.);
00037 ROS_DEBUG_STREAM("rotation_angle = " << rotation_angle_);
00038 }
00039 else if (rotation_mode_ == AUTOMATIC_GRAVITY_DIRECTION || rotation_mode_ == AUTOMATIC_GRAVITY_DIRECTION_90)
00040 {
00041
00042 node_handle_.param("reference_frame", reference_frame_, std::string(""));
00043 ROS_DEBUG_STREAM("reference_frame = " << reference_frame_);
00044 }
00045 else
00046 {
00047 ROS_ERROR("Unsupported value for parameter 'rotation_mode'. Exiting the cob_image_flip.");
00048 exit(1);
00049 }
00050 node_handle_.param("flip_color_image", flip_color_image_, false);
00051 ROS_DEBUG_STREAM("flip_color_image = " << flip_color_image_);
00052 node_handle_.param("flip_pointcloud", flip_pointcloud_, false);
00053 ROS_DEBUG_STREAM("flip_pointcloud = " << flip_pointcloud_);
00054 node_handle_.param("flip_disparity_image", flip_disparity_image_, false);
00055 ROS_DEBUG_STREAM("flip_disparity_image = " << flip_disparity_image_);
00056 node_handle_.param("display_warnings", display_warnings_, false);
00057 ROS_DEBUG_STREAM("display_warnings = " << display_warnings_);
00058
00059 if (flip_color_image_ == true)
00060 {
00061 it_ = new image_transport::ImageTransport(node_handle_);
00062 color_camera_image_sub_.registerCallback(boost::bind(&ImageFlip::imageCallback, this, _1));
00063 color_camera_image_pub_ = it_->advertise("colorimage_out", 1, boost::bind(&ImageFlip::imgConnectCB, this, _1), boost::bind(&ImageFlip::imgDisconnectCB, this, _1));
00064 color_camera_image_2d_transform_pub_ = node_handle_.advertise<cob_perception_msgs::Float64ArrayStamped>("colorimage_inplane_transform", 1,false);
00065 }
00066
00067
00068 if (flip_pointcloud_ == true)
00069 {
00070 point_cloud_pub_ = node_handle_.advertise<sensor_msgs::PointCloud2>("pointcloud_out", 1, boost::bind(&ImageFlip::pcConnectCB, this, _1), boost::bind(&ImageFlip::pcDisconnectCB, this, _1));
00071 point_cloud_2d_transform_pub_ = node_handle_.advertise<cob_perception_msgs::Float64ArrayStamped>("pointcloud_inplane_transform", 1,false);
00072 }
00073
00074 if (flip_disparity_image_ == true)
00075 {
00076 disparity_image_pub_ = node_handle_.advertise<stereo_msgs::DisparityImage>("disparityimage_out", 1, boost::bind(&ImageFlip::disparityConnectCB, this, _1), boost::bind(&ImageFlip::disparityDisconnectCB, this, _1));
00077 disparity_image_2d_transform_pub_ = node_handle_.advertise<cob_perception_msgs::Float64ArrayStamped>("disparityimage_inplane_transform", 1,false);
00078 }
00079
00080 ROS_DEBUG_STREAM("ImageFlip initialized.");
00081 }
00082
00083 ImageFlip::~ImageFlip()
00084 {
00085 if (it_ != 0)
00086 delete it_;
00087 }
00088
00089
00090 double ImageFlip::determineRotationAngle(const std::string& camera_frame_id, const ros::Time& time)
00091 {
00092 double rotation_angle = 0.;
00093 if (rotation_mode_ == FIXED_ANGLE)
00094 {
00095 rotation_angle = rotation_angle_;
00096 }
00097 else if (rotation_mode_ == AUTOMATIC_GRAVITY_DIRECTION || rotation_mode_ == AUTOMATIC_GRAVITY_DIRECTION_90)
00098 {
00099
00100 try
00101 {
00102
00103 tf::Stamped<tf::Vector3> x_axis_camera(tf::Vector3(1, 0, 0), time , camera_frame_id), x_axis_ref;
00104 tf::Stamped<tf::Vector3> y_axis_camera(tf::Vector3(0, 1, 0), x_axis_camera.stamp_, camera_frame_id), y_axis_ref;
00105 transform_listener_.waitForTransform(reference_frame_, camera_frame_id, x_axis_camera.stamp_, ros::Duration(0.2));
00106 transform_listener_.transformVector(reference_frame_, x_axis_camera, x_axis_ref);
00107 transform_listener_.transformVector(reference_frame_, y_axis_camera, y_axis_ref);
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 if (x_axis_ref.z()!=0)
00118 {
00119
00120 const double a = y_axis_ref.z()/x_axis_ref.z();
00121 tf::Vector3 x_axis_target(y_axis_ref.x()-x_axis_ref.x()*a,y_axis_ref.y()-x_axis_ref.y()*a, 0);
00122 x_axis_target.normalize();
00123
00124 tf::Vector3 z_axis_target = x_axis_ref.cross(y_axis_ref);
00125 tf::Vector3 y_axis_target = z_axis_target.cross(x_axis_target);
00126 y_axis_target.normalize();
00127
00128
00129
00130
00131
00132
00133
00134 int factor = (y_axis_target.z()<0. ? 1 : -1);
00135 if (factor != last_rotation_factor_ && fabs(y_axis_target.z()) < 0.01)
00136 factor = last_rotation_factor_;
00137 last_rotation_factor_ = factor;
00138 x_axis_target *= factor;
00139
00140
00141
00142
00143 tf::Vector3 rot_axis_x = x_axis_ref.cross(x_axis_target);
00144 double rot_sin = ((rot_axis_x.dot(z_axis_target)) >= 0 ? 1 : -1) * rot_axis_x.length();
00145 double rot_cos = x_axis_ref.dot(x_axis_target);
00146 rotation_angle = -180./CV_PI * atan2(rot_sin, rot_cos);
00147
00148
00149 }
00150 if (rotation_mode_ == AUTOMATIC_GRAVITY_DIRECTION_90)
00151 rotation_angle = 90. * cvRound(rotation_angle*1./90.);
00152 last_rotation_angle_ = rotation_angle;
00153
00154
00155
00156
00157
00158
00159
00160 }
00161 catch (tf2::TransformException& ex)
00162 {
00163 if (display_warnings_ == true)
00164 ROS_DEBUG("%s",ex.what());
00165 rotation_angle = last_rotation_angle_;
00166 }
00167 }
00168 else
00169 {
00170 if (display_warnings_)
00171 ROS_WARN("ImageFlip::imageCallback: Unsupported rotation mode.");
00172 }
00173
00174 return rotation_angle;
00175 }
00176
00177
00178 bool ImageFlip::convertImageMessageToMat(const sensor_msgs::Image::ConstPtr& image_msg, cv_bridge::CvImageConstPtr& image_ptr, cv::Mat& image)
00179 {
00180 try
00181 {
00182 image_ptr = cv_bridge::toCvShare(image_msg, image_msg->encoding);
00183 }
00184 catch (cv_bridge::Exception& e)
00185 {
00186 ROS_ERROR("ImageFlip::convertColorImageMessageToMat: cv_bridge exception: %s", e.what());
00187 return false;
00188 }
00189 image = image_ptr->image;
00190
00191 return true;
00192 }
00193
00194
00195 void ImageFlip::imageCallback(const sensor_msgs::ImageConstPtr& color_image_msg)
00196 {
00197
00198 cv_bridge::CvImageConstPtr color_image_ptr;
00199 cv::Mat color_image;
00200 if (convertImageMessageToMat(color_image_msg, color_image_ptr, color_image) == false)
00201 return;
00202 cv::Mat color_image_turned;
00203 cv::Mat rot_mat = cv::Mat::zeros(2,3,CV_64FC1);
00204
00205
00206 double rotation_angle = determineRotationAngle(color_image_msg->header.frame_id, color_image_msg->header.stamp);
00207
00208
00209
00210 if (rotation_angle==0. || rotation_angle==360. || rotation_angle==-360.)
00211 {
00212 color_image_turned = color_image;
00213 rot_mat.at<double>(0,0) = 1.;
00214 rot_mat.at<double>(1,1) = 1.;
00215 }
00216 else if (rotation_angle==90. || rotation_angle==-270.)
00217 {
00218
00219 color_image_turned.create(color_image.cols, color_image.rows, color_image.type());
00220 if (color_image.type() != CV_8UC3)
00221 {
00222 ROS_ERROR("ImageFlip::imageCallback: Error: The image format of the color image is not CV_8UC3.\n");
00223 return;
00224 }
00225 for (int v = 0; v < color_image_turned.rows; v++)
00226 for (int u = 0; u < color_image_turned.cols; u++)
00227 color_image_turned.at<cv::Vec3b>(v,u) = color_image.at<cv::Vec3b>(color_image.rows-1-u,v);
00228 rot_mat.at<double>(0,1) = -1.;
00229 rot_mat.at<double>(0,2) = color_image.rows;
00230 rot_mat.at<double>(1,0) = 1.;
00231 }
00232 else if (rotation_angle==270. || rotation_angle==-90.)
00233 {
00234
00235 color_image_turned.create(color_image.cols, color_image.rows, color_image.type());
00236 if (color_image.type() != CV_8UC3)
00237 {
00238 std::cout << "ImageFlip::imageCallback: Error: The image format of the color image is not CV_8UC3.\n";
00239 return;
00240 }
00241 for (int v = 0; v < color_image_turned.rows; v++)
00242 for (int u = 0; u < color_image_turned.cols; u++)
00243 color_image_turned.at<cv::Vec3b>(v,u) = color_image.at<cv::Vec3b>(u,color_image.cols-1-v);
00244 rot_mat.at<double>(0,1) = 1.;
00245 rot_mat.at<double>(1,0) = -1.;
00246 rot_mat.at<double>(1,2) = color_image.cols;
00247 }
00248 else if (rotation_angle==180 || rotation_angle==-180)
00249 {
00250
00251 color_image_turned.create(color_image.rows, color_image.cols, color_image.type());
00252 if (color_image.type() != CV_8UC3)
00253 {
00254 std::cout << "ImageFlip::imageCallback: Error: The image format of the color image is not CV_8UC3.\n";
00255 return;
00256 }
00257 for (int v = 0; v < color_image.rows; v++)
00258 {
00259 uchar* src = color_image.ptr(v);
00260 uchar* dst = color_image_turned.ptr(color_image.rows - v - 1) + 3 * (color_image.cols - 1);
00261 for (int u = 0; u < color_image.cols; u++)
00262 {
00263 for (int k = 0; k < 3; k++)
00264 {
00265 *dst = *src;
00266 src++;
00267 dst++;
00268 }
00269 dst -= 6;
00270 }
00271 }
00272 rot_mat.at<double>(0,0) = -1.;
00273 rot_mat.at<double>(0,2) = color_image.cols;
00274 rot_mat.at<double>(1,1) = -1.;
00275 rot_mat.at<double>(1,2) = color_image.rows;
00276 }
00277 else
00278 {
00279
00280 bool switch_aspect_ratio = !(fabs(sin(rotation_angle*CV_PI/180.)) < 0.707106781);
00281 if (switch_aspect_ratio==false)
00282 color_image_turned.create(color_image.rows, color_image.cols, color_image.type());
00283 else
00284 color_image_turned.create(color_image.cols, color_image.rows, color_image.type());
00285 if (color_image.type() != CV_8UC3)
00286 {
00287 ROS_ERROR("ImageFlip::imageCallback: Error: The image format of the color image is not CV_8UC3.\n");
00288 return;
00289 }
00290
00291 cv::Point center = cv::Point(color_image.cols/2, color_image.rows/2);
00292 rot_mat = cv::getRotationMatrix2D(center, -rotation_angle, 1.0);
00293 if (switch_aspect_ratio==true)
00294 {
00295 rot_mat.at<double>(0,2) += 0.5*(color_image_turned.cols-color_image.cols);
00296 rot_mat.at<double>(1,2) += 0.5*(color_image_turned.rows-color_image.rows);
00297 }
00298 cv::warpAffine(color_image, color_image_turned, rot_mat, color_image_turned.size());
00299 }
00300
00301
00302 cv_bridge::CvImage cv_ptr;
00303 cv_ptr.image = color_image_turned;
00304 cv_ptr.encoding = color_image_msg->encoding;
00305 sensor_msgs::Image::Ptr color_image_turned_msg = cv_ptr.toImageMsg();
00306 color_image_turned_msg->header = color_image_msg->header;
00307 color_camera_image_pub_.publish(color_image_turned_msg);
00308
00309
00310
00311 cv::Mat rot33 = cv::Mat::eye(3,3,CV_64FC1);
00312 for (int r=0; r<2; ++r)
00313 for (int c=0; c<3; ++c)
00314 rot33.at<double>(r,c) = rot_mat.at<double>(r,c);
00315 cv::Mat rot33_inv = rot33.inv();
00316 cob_perception_msgs::Float64ArrayStamped rot33_inv_msg;
00317 rot33_inv_msg.header = color_image_msg->header;
00318 rot33_inv_msg.data.resize(9);
00319 for (int r=0; r<3; ++r)
00320 for (int c=0; c<3; ++c)
00321 rot33_inv_msg.data[r*3+c] = rot33_inv.at<double>(r,c);
00322 color_camera_image_2d_transform_pub_.publish(rot33_inv_msg);
00323 }
00324
00325 void ImageFlip::imgConnectCB(const image_transport::SingleSubscriberPublisher& pub)
00326 {
00327 img_sub_counter_++;
00328 if (img_sub_counter_ == 1)
00329 {
00330 ROS_DEBUG("ImageFlip::imgConnectCB: Connecting image callback.");
00331 color_camera_image_sub_.subscribe(*it_, "colorimage_in", 1);
00332 }
00333 }
00334
00335 void ImageFlip::imgDisconnectCB(const image_transport::SingleSubscriberPublisher& pub)
00336 {
00337 img_sub_counter_--;
00338 if (img_sub_counter_ == 0)
00339 {
00340 ROS_DEBUG("ImageFlip::imgDisconnectCB: Disconnecting image callback.");
00341 color_camera_image_sub_.unsubscribe();
00342 }
00343 }
00344
00345
00346 void ImageFlip::pcCallback(const sensor_msgs::PointCloud2::ConstPtr& point_cloud_msg)
00347 {
00348
00349 double rotation_angle = determineRotationAngle(point_cloud_msg->header.frame_id, point_cloud_msg->header.stamp);
00350 cv::Mat rot_mat = cv::Mat::zeros(2,3,CV_64FC1);
00351
00352
00353 const int element_size = point_cloud_msg->point_step;
00354 const int row_size = point_cloud_msg->row_step;
00355 sensor_msgs::PointCloud2::Ptr point_cloud_out_msg = boost::shared_ptr<sensor_msgs::PointCloud2>(new sensor_msgs::PointCloud2);
00356 point_cloud_out_msg->fields = point_cloud_msg->fields;
00357 point_cloud_out_msg->header = point_cloud_msg->header;
00358 point_cloud_out_msg->height = point_cloud_msg->height;
00359 point_cloud_out_msg->width = point_cloud_msg->width;
00360 point_cloud_out_msg->point_step = point_cloud_msg->point_step;
00361 point_cloud_out_msg->row_step = point_cloud_msg->row_step;
00362 point_cloud_out_msg->is_bigendian = point_cloud_msg->is_bigendian;
00363 point_cloud_out_msg->is_dense = point_cloud_msg->is_dense;
00364 point_cloud_out_msg->data.resize(point_cloud_out_msg->height * point_cloud_out_msg->width * element_size);
00365
00366
00367
00368 if (rotation_angle==0. || rotation_angle==360. || rotation_angle==-360.)
00369 {
00370 memcpy(&(point_cloud_out_msg->data[0]), &(point_cloud_msg->data[0]), point_cloud_msg->height*point_cloud_msg->width*element_size);
00371 rot_mat.at<double>(0,0) = 1.;
00372 rot_mat.at<double>(1,1) = 1.;
00373 }
00374 else if (rotation_angle==90. || rotation_angle==-270.)
00375 {
00376
00377 point_cloud_out_msg->height = point_cloud_msg->width;
00378 point_cloud_out_msg->width = point_cloud_msg->height;
00379 const int row_size_out = point_cloud_msg->height*element_size;
00380 point_cloud_out_msg->row_step = row_size_out;
00381 for (int v = 0; v < point_cloud_out_msg->height; v++)
00382 for (int u = 0; u < point_cloud_out_msg->width; u++)
00383 memcpy(&(point_cloud_out_msg->data[v*row_size_out+u*element_size]), &(point_cloud_msg->data[(point_cloud_msg->height-1-u)*row_size+v*element_size]), element_size);
00384 rot_mat.at<double>(0,1) = -1.;
00385 rot_mat.at<double>(0,2) = point_cloud_msg->height;
00386 rot_mat.at<double>(1,0) = 1.;
00387 }
00388 else if (rotation_angle==270. || rotation_angle==-90.)
00389 {
00390
00391 point_cloud_out_msg->height = point_cloud_msg->width;
00392 point_cloud_out_msg->width = point_cloud_msg->height;
00393 const int row_size_out = point_cloud_msg->height*element_size;
00394 point_cloud_out_msg->row_step = row_size_out;
00395 for (int v = 0; v < point_cloud_out_msg->height; v++)
00396 for (int u = 0; u < point_cloud_out_msg->width; u++)
00397 memcpy(&(point_cloud_out_msg->data[v*row_size_out+u*element_size]), &(point_cloud_msg->data[u*row_size+(point_cloud_msg->width-1-v)*element_size]), element_size);
00398 rot_mat.at<double>(0,1) = 1.;
00399 rot_mat.at<double>(1,0) = -1.;
00400 rot_mat.at<double>(1,2) = point_cloud_msg->width;
00401 }
00402 else if (rotation_angle==180 || rotation_angle==-180)
00403 {
00404
00405 for (int v = 0; v < point_cloud_out_msg->height; v++)
00406 for (int u = 0; u < point_cloud_out_msg->width; u++)
00407 memcpy(&(point_cloud_out_msg->data[v*row_size+u*element_size]), &(point_cloud_msg->data[(point_cloud_msg->height-1-v)*row_size+(point_cloud_msg->width-1-u)*element_size]), element_size);
00408 rot_mat.at<double>(0,0) = -1.;
00409 rot_mat.at<double>(0,2) = point_cloud_msg->width;
00410 rot_mat.at<double>(1,1) = -1.;
00411 rot_mat.at<double>(1,2) = point_cloud_msg->height;
00412 }
00413 else
00414 {
00415
00416 int row_size_out = row_size;
00417
00418 bool switch_aspect_ratio = !(fabs(sin(rotation_angle*CV_PI/180.)) < 0.707106781);
00419 if (switch_aspect_ratio==true)
00420 {
00421 point_cloud_out_msg->height = point_cloud_msg->width;
00422 point_cloud_out_msg->width = point_cloud_msg->height;
00423 row_size_out = point_cloud_msg->height*element_size;
00424 point_cloud_out_msg->row_step = row_size_out;
00425 }
00426
00427
00428 cv::Point center = cv::Point(point_cloud_msg->width/2, point_cloud_msg->height/2);
00429 rot_mat = cv::getRotationMatrix2D(center, -rotation_angle, 1.0);
00430 if (switch_aspect_ratio==true)
00431 {
00432 rot_mat.at<double>(0,2) += 0.5*((double)point_cloud_out_msg->width - (double)point_cloud_msg->width);
00433 rot_mat.at<double>(1,2) += 0.5*((double)point_cloud_out_msg->height - (double)point_cloud_msg->height);
00434 }
00435 cv::Mat rot_mat_inv = rot_mat.clone();
00436 rot_mat_inv.at<double>(0,1) = rot_mat.at<double>(1,0);
00437 rot_mat_inv.at<double>(1,0) = rot_mat.at<double>(0,1);
00438 rot_mat_inv.at<double>(0,2) = -rot_mat.at<double>(0,2)*rot_mat.at<double>(0,0) - rot_mat.at<double>(1,2)*rot_mat.at<double>(1,0);
00439 rot_mat_inv.at<double>(1,2) = -rot_mat.at<double>(1,2)*rot_mat.at<double>(0,0) + rot_mat.at<double>(0,2)*rot_mat.at<double>(1,0);
00440
00441
00442 std::vector<uchar> zero_element(element_size, 0);
00443 for (size_t i=0; i<point_cloud_msg->fields.size(); ++i)
00444 {
00445 if (point_cloud_msg->fields[i].name.compare("x") == 0 || point_cloud_msg->fields[i].name.compare("y") == 0 || point_cloud_msg->fields[i].name.compare("z") == 0)
00446 {
00447 float* val = (float*)&(zero_element[point_cloud_msg->fields[i].offset]);
00448 *val = std::numeric_limits<float>::quiet_NaN();
00449 }
00450 if (point_cloud_msg->fields[i].name.compare("rgb") == 0)
00451 {
00452 float* val = (float*)&(zero_element[point_cloud_msg->fields[i].offset]);
00453 int vali = 0;
00454 *val = *(float*)(&vali);
00455 }
00456 }
00457
00458
00459 for (int v = 0; v < point_cloud_out_msg->height; v++)
00460 {
00461 for (int u = 0; u < point_cloud_out_msg->width; u++)
00462 {
00463 int src_u = rot_mat_inv.at<double>(0,0)*u + rot_mat_inv.at<double>(0,1)*v + rot_mat_inv.at<double>(0,2);
00464 int src_v = rot_mat_inv.at<double>(1,0)*u + rot_mat_inv.at<double>(1,1)*v + rot_mat_inv.at<double>(1,2);
00465 if (src_u < 0 || src_u > point_cloud_msg->width-1 || src_v < 0 || src_v > point_cloud_msg->height-1)
00466 memcpy(&(point_cloud_out_msg->data[v*row_size_out+u*element_size]), &(zero_element[0]), element_size);
00467 else
00468 memcpy(&(point_cloud_out_msg->data[v*row_size_out+u*element_size]), &(point_cloud_msg->data[src_v*row_size+src_u*element_size]), element_size);
00469 }
00470 }
00471 }
00472
00473
00474 point_cloud_pub_.publish(point_cloud_out_msg);
00475
00476
00477
00478 cv::Mat rot33 = cv::Mat::eye(3,3,CV_64FC1);
00479 for (int r=0; r<2; ++r)
00480 for (int c=0; c<3; ++c)
00481 rot33.at<double>(r,c) = rot_mat.at<double>(r,c);
00482 cv::Mat rot33_inv = rot33.inv();
00483 cob_perception_msgs::Float64ArrayStamped rot33_inv_msg;
00484 rot33_inv_msg.header = point_cloud_msg->header;
00485 rot33_inv_msg.data.resize(9);
00486 for (int r=0; r<3; ++r)
00487 for (int c=0; c<3; ++c)
00488 rot33_inv_msg.data[r*3+c] = rot33_inv.at<double>(r,c);
00489 point_cloud_2d_transform_pub_.publish(rot33_inv_msg);
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557 }
00558
00559 void ImageFlip::pcConnectCB(const ros::SingleSubscriberPublisher& pub)
00560 {
00561 pc_sub_counter_++;
00562 if (pc_sub_counter_ == 1)
00563 {
00564 ROS_DEBUG("ImageFlip::pcConnectCB: Connecting point cloud callback.");
00565 point_cloud_sub_ = node_handle_.subscribe<sensor_msgs::PointCloud2>("pointcloud_in", 1, &ImageFlip::pcCallback, this);
00566 }
00567 }
00568
00569 void ImageFlip::pcDisconnectCB(const ros::SingleSubscriberPublisher& pub)
00570 {
00571 pc_sub_counter_--;
00572 if (pc_sub_counter_ == 0)
00573 {
00574 ROS_DEBUG("ImageFlip::pcDisconnectCB: Disconnecting point cloud callback.");
00575 point_cloud_sub_.shutdown();
00576 }
00577 }
00578
00579 void void_delete_image_msg(const sensor_msgs::Image*)
00580 {
00581 return;
00582 }
00583
00584 void ImageFlip::disparityCallback(const stereo_msgs::DisparityImage::ConstPtr& disparity_image_msg)
00585 {
00586
00587 cv_bridge::CvImageConstPtr disparity_image_ptr;
00588 cv::Mat disparity_image;
00589 sensor_msgs::ImageConstPtr disparity_image_constptr = boost::shared_ptr<const sensor_msgs::Image>(&disparity_image_msg->image, void_delete_image_msg);
00590 if (convertImageMessageToMat(disparity_image_constptr, disparity_image_ptr, disparity_image) == false)
00591 return;
00592 cv::Mat disparity_image_turned;
00593 cv::Mat rot_mat = cv::Mat::zeros(2,3,CV_64FC1);
00594
00595
00596 double rotation_angle = determineRotationAngle(disparity_image_msg->header.frame_id, disparity_image_msg->header.stamp);
00597
00598
00599
00600 if (rotation_angle==0. || rotation_angle==360. || rotation_angle==-360.)
00601 {
00602 disparity_image_turned = disparity_image;
00603 rot_mat.at<double>(0,0) = 1.;
00604 rot_mat.at<double>(1,1) = 1.;
00605 }
00606 else if (rotation_angle==90. || rotation_angle==-270.)
00607 {
00608
00609 disparity_image_turned.create(disparity_image.cols, disparity_image.rows, disparity_image.type());
00610 if (disparity_image.type() != CV_32FC1)
00611 {
00612 ROS_ERROR("ImageFlip::imageCallback: Error: The image format of the disparity image is not CV_32FC1.\n");
00613 return;
00614 }
00615 for (int v = 0; v < disparity_image_turned.rows; v++)
00616 for (int u = 0; u < disparity_image_turned.cols; u++)
00617 disparity_image_turned.at<float>(v,u) = disparity_image.at<float>(disparity_image.rows-1-u,v);
00618 rot_mat.at<double>(0,1) = -1.;
00619 rot_mat.at<double>(0,2) = disparity_image.rows;
00620 rot_mat.at<double>(1,0) = 1.;
00621 }
00622 else if (rotation_angle==270. || rotation_angle==-90.)
00623 {
00624
00625 disparity_image_turned.create(disparity_image.cols, disparity_image.rows, disparity_image.type());
00626 if (disparity_image.type() != CV_32FC1)
00627 {
00628 std::cout << "ImageFlip::imageCallback: Error: The image format of the color image is not CV_32FC1.\n";
00629 return;
00630 }
00631 for (int v = 0; v < disparity_image_turned.rows; v++)
00632 for (int u = 0; u < disparity_image_turned.cols; u++)
00633 disparity_image_turned.at<float>(v,u) = disparity_image.at<float>(u,disparity_image.cols-1-v);
00634 rot_mat.at<double>(0,1) = 1.;
00635 rot_mat.at<double>(1,0) = -1.;
00636 rot_mat.at<double>(1,2) = disparity_image.cols;
00637 }
00638 else if (rotation_angle==180 || rotation_angle==-180)
00639 {
00640
00641 disparity_image_turned.create(disparity_image.rows, disparity_image.cols, disparity_image.type());
00642 if (disparity_image.type() != CV_32FC1)
00643 {
00644 std::cout << "ImageFlip::imageCallback: Error: The image format of the color image is not CV_32FC1.\n";
00645 return;
00646 }
00647 for (int v = 0; v < disparity_image.rows; v++)
00648 {
00649 float* src = (float*)disparity_image.ptr(v);
00650 float* dst = (float*)disparity_image_turned.ptr(disparity_image.rows - v - 1) + (disparity_image.cols - 1);
00651 for (int u = 0; u < disparity_image.cols; u++)
00652 {
00653 *dst = *src;
00654 src++;
00655 dst--;
00656 }
00657 }
00658 rot_mat.at<double>(0,0) = -1.;
00659 rot_mat.at<double>(0,2) = disparity_image.cols;
00660 rot_mat.at<double>(1,1) = -1.;
00661 rot_mat.at<double>(1,2) = disparity_image.rows;
00662 }
00663 else
00664 {
00665
00666 bool switch_aspect_ratio = !(fabs(sin(rotation_angle*CV_PI/180.)) < 0.707106781);
00667 if (switch_aspect_ratio==false)
00668 disparity_image_turned.create(disparity_image.rows, disparity_image.cols, disparity_image.type());
00669 else
00670 disparity_image_turned.create(disparity_image.cols, disparity_image.rows, disparity_image.type());
00671 if (disparity_image.type() != CV_32FC1)
00672 {
00673 ROS_ERROR("ImageFlip::imageCallback: Error: The image format of the color image is not CV_32FC1.\n");
00674 return;
00675 }
00676
00677 cv::Point center = cv::Point(disparity_image.cols/2, disparity_image.rows/2);
00678 rot_mat = cv::getRotationMatrix2D(center, -rotation_angle, 1.0);
00679 if (switch_aspect_ratio==true)
00680 {
00681 rot_mat.at<double>(0,2) += 0.5*(disparity_image_turned.cols-disparity_image.cols);
00682 rot_mat.at<double>(1,2) += 0.5*(disparity_image_turned.rows-disparity_image.rows);
00683 }
00684 cv::warpAffine(disparity_image, disparity_image_turned, rot_mat, disparity_image_turned.size());
00685 }
00686
00687
00688 cv_bridge::CvImage cv_ptr;
00689 cv_ptr.image = disparity_image_turned;
00690 cv_ptr.encoding = disparity_image_msg->image.encoding;
00691 stereo_msgs::DisparityImage::Ptr disparity_image_turned_msg(new stereo_msgs::DisparityImage);
00692 sensor_msgs::ImagePtr disparity_image_turned_msg_image = cv_ptr.toImageMsg();
00693 disparity_image_turned_msg_image->header = disparity_image_msg->image.header;
00694 disparity_image_turned_msg->image = *disparity_image_turned_msg_image;
00695 disparity_image_turned_msg->header = disparity_image_msg->header;
00696 disparity_image_pub_.publish(disparity_image_turned_msg);
00697
00698
00699
00700 cv::Mat rot33 = cv::Mat::eye(3,3,CV_64FC1);
00701 for (int r=0; r<2; ++r)
00702 for (int c=0; c<3; ++c)
00703 rot33.at<double>(r,c) = rot_mat.at<double>(r,c);
00704 cv::Mat rot33_inv = rot33.inv();
00705 cob_perception_msgs::Float64ArrayStamped rot33_inv_msg;
00706 rot33_inv_msg.header = disparity_image_msg->header;
00707 rot33_inv_msg.data.resize(9);
00708 for (int r=0; r<3; ++r)
00709 for (int c=0; c<3; ++c)
00710 rot33_inv_msg.data[r*3+c] = rot33_inv.at<double>(r,c);
00711 disparity_image_2d_transform_pub_.publish(rot33_inv_msg);
00712 }
00713
00714
00715 void ImageFlip::disparityConnectCB(const ros::SingleSubscriberPublisher& pub)
00716 {
00717 disparity_sub_counter_++;
00718 if (disparity_sub_counter_ == 1)
00719 {
00720 ROS_DEBUG("ImageFlip::disparityConnectCB: Connecting disparity callback.");
00721 disparity_image_sub_ = node_handle_.subscribe<stereo_msgs::DisparityImage>("disparityimage_in", 1, &ImageFlip::disparityCallback, this);
00722 }
00723 }
00724
00725 void ImageFlip::disparityDisconnectCB(const ros::SingleSubscriberPublisher& pub)
00726 {
00727 disparity_sub_counter_--;
00728 if (disparity_sub_counter_ == 0)
00729 {
00730 ROS_DEBUG("ImageFlip::disparityDisconnectCB: Disconnecting disparity callback.");
00731 disparity_image_sub_.shutdown();
00732 }
00733 }
00734
00735
00736 }