22 #include <geometry_msgs/TransformStamped.h> 27 : 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)
30 ROS_DEBUG_STREAM(
"\n--------------------------\nImage Flip Parameters:\n--------------------------");
47 ROS_ERROR(
"Unsupported value for parameter 'rotation_mode'. Exiting the cob_image_flip.");
92 double rotation_angle = 0.;
117 if (x_axis_ref.z()!=0)
120 const double a = y_axis_ref.z()/x_axis_ref.z();
121 tf::Vector3 x_axis_target(y_axis_ref.x()-x_axis_ref.x()*a,y_axis_ref.y()-x_axis_ref.y()*a, 0);
124 tf::Vector3 z_axis_target = x_axis_ref.cross(y_axis_ref);
134 int factor = (y_axis_target.
z()<0. ? 1 : -1);
138 x_axis_target *= factor;
143 tf::Vector3 rot_axis_x = x_axis_ref.cross(x_axis_target);
144 double rot_sin = ((rot_axis_x.
dot(z_axis_target)) >= 0 ? 1 : -1) * rot_axis_x.
length();
145 double rot_cos = x_axis_ref.dot(x_axis_target);
146 rotation_angle = -180./CV_PI * atan2(rot_sin, rot_cos);
151 rotation_angle = 90. * cvRound(rotation_angle*1./90.);
171 ROS_WARN(
"ImageFlip::imageCallback: Unsupported rotation mode.");
174 return rotation_angle;
186 ROS_ERROR(
"ImageFlip::convertColorImageMessageToMat: cv_bridge exception: %s", e.what());
189 image = image_ptr->image;
202 cv::Mat color_image_turned;
203 cv::Mat rot_mat = cv::Mat::zeros(2,3,CV_64FC1);
206 double rotation_angle =
determineRotationAngle(color_image_msg->header.frame_id, color_image_msg->header.stamp);
210 if (rotation_angle==0. || rotation_angle==360. || rotation_angle==-360.)
212 color_image_turned = color_image;
213 rot_mat.at<
double>(0,0) = 1.;
214 rot_mat.at<
double>(1,1) = 1.;
216 else if (rotation_angle==90. || rotation_angle==-270.)
219 color_image_turned.create(color_image.cols, color_image.rows, color_image.type());
220 if (color_image.type() != CV_8UC3)
222 ROS_ERROR(
"ImageFlip::imageCallback: Error: The image format of the color image is not CV_8UC3.\n");
225 for (
int v = 0; v < color_image_turned.rows; v++)
226 for (
int u = 0; u < color_image_turned.cols; u++)
227 color_image_turned.at<cv::Vec3b>(v,u) = color_image.at<cv::Vec3b>(color_image.rows-1-u,v);
228 rot_mat.at<
double>(0,1) = -1.;
229 rot_mat.at<
double>(0,2) = color_image.rows;
230 rot_mat.at<
double>(1,0) = 1.;
232 else if (rotation_angle==270. || rotation_angle==-90.)
235 color_image_turned.create(color_image.cols, color_image.rows, color_image.type());
236 if (color_image.type() != CV_8UC3)
238 std::cout <<
"ImageFlip::imageCallback: Error: The image format of the color image is not CV_8UC3.\n";
241 for (
int v = 0; v < color_image_turned.rows; v++)
242 for (
int u = 0; u < color_image_turned.cols; u++)
243 color_image_turned.at<cv::Vec3b>(v,u) = color_image.at<cv::Vec3b>(u,color_image.cols-1-v);
244 rot_mat.at<
double>(0,1) = 1.;
245 rot_mat.at<
double>(1,0) = -1.;
246 rot_mat.at<
double>(1,2) = color_image.cols;
248 else if (rotation_angle==180 || rotation_angle==-180)
251 color_image_turned.create(color_image.rows, color_image.cols, color_image.type());
252 if (color_image.type() != CV_8UC3)
254 std::cout <<
"ImageFlip::imageCallback: Error: The image format of the color image is not CV_8UC3.\n";
257 for (
int v = 0; v < color_image.rows; v++)
259 uchar* src = color_image.ptr(v);
260 uchar* dst = color_image_turned.ptr(color_image.rows - v - 1) + 3 * (color_image.cols - 1);
261 for (
int u = 0; u < color_image.cols; u++)
263 for (
int k = 0; k < 3; k++)
272 rot_mat.at<
double>(0,0) = -1.;
273 rot_mat.at<
double>(0,2) = color_image.cols;
274 rot_mat.at<
double>(1,1) = -1.;
275 rot_mat.at<
double>(1,2) = color_image.rows;
280 bool switch_aspect_ratio = !(fabs(sin(rotation_angle*CV_PI/180.)) < 0.707106781);
281 if (switch_aspect_ratio==
false)
282 color_image_turned.create(color_image.rows, color_image.cols, color_image.type());
284 color_image_turned.create(color_image.cols, color_image.rows, color_image.type());
285 if (color_image.type() != CV_8UC3)
287 ROS_ERROR(
"ImageFlip::imageCallback: Error: The image format of the color image is not CV_8UC3.\n");
291 cv::Point center = cv::Point(color_image.cols/2, color_image.rows/2);
292 rot_mat = cv::getRotationMatrix2D(center, -rotation_angle, 1.0);
293 if (switch_aspect_ratio==
true)
295 rot_mat.at<
double>(0,2) += 0.5*(color_image_turned.cols-color_image.cols);
296 rot_mat.at<
double>(1,2) += 0.5*(color_image_turned.rows-color_image.rows);
298 cv::warpAffine(color_image, color_image_turned, rot_mat, color_image_turned.size());
303 cv_ptr.
image = color_image_turned;
304 cv_ptr.encoding = color_image_msg->encoding;
305 sensor_msgs::Image::Ptr color_image_turned_msg = cv_ptr.toImageMsg();
306 color_image_turned_msg->header = color_image_msg->header;
311 cv::Mat rot33 = cv::Mat::eye(3,3,CV_64FC1);
312 for (
int r=0; r<2; ++r)
313 for (
int c=0; c<3; ++c)
314 rot33.at<
double>(r,c) = rot_mat.at<
double>(r,c);
315 cv::Mat rot33_inv = rot33.inv();
316 cob_perception_msgs::Float64ArrayStamped rot33_inv_msg;
317 rot33_inv_msg.header = color_image_msg->header;
318 rot33_inv_msg.data.resize(9);
319 for (
int r=0; r<3; ++r)
320 for (
int c=0; c<3; ++c)
321 rot33_inv_msg.data[r*3+c] = rot33_inv.at<
double>(r,c);
330 ROS_DEBUG(
"ImageFlip::imgConnectCB: Connecting image callback.");
340 ROS_DEBUG(
"ImageFlip::imgDisconnectCB: Disconnecting image callback.");
349 double rotation_angle =
determineRotationAngle(point_cloud_msg->header.frame_id, point_cloud_msg->header.stamp);
350 cv::Mat rot_mat = cv::Mat::zeros(2,3,CV_64FC1);
353 const int element_size = point_cloud_msg->point_step;
354 const int row_size = point_cloud_msg->row_step;
356 point_cloud_out_msg->fields = point_cloud_msg->fields;
357 point_cloud_out_msg->header = point_cloud_msg->header;
358 point_cloud_out_msg->height = point_cloud_msg->height;
359 point_cloud_out_msg->width = point_cloud_msg->width;
360 point_cloud_out_msg->point_step = point_cloud_msg->point_step;
361 point_cloud_out_msg->row_step = point_cloud_msg->row_step;
362 point_cloud_out_msg->is_bigendian = point_cloud_msg->is_bigendian;
363 point_cloud_out_msg->is_dense = point_cloud_msg->is_dense;
364 point_cloud_out_msg->data.resize(point_cloud_out_msg->height * point_cloud_out_msg->width * element_size);
368 if (rotation_angle==0. || rotation_angle==360. || rotation_angle==-360.)
370 memcpy(&(point_cloud_out_msg->data[0]), &(point_cloud_msg->data[0]), point_cloud_msg->height*point_cloud_msg->width*element_size);
371 rot_mat.at<
double>(0,0) = 1.;
372 rot_mat.at<
double>(1,1) = 1.;
374 else if (rotation_angle==90. || rotation_angle==-270.)
377 point_cloud_out_msg->height = point_cloud_msg->width;
378 point_cloud_out_msg->width = point_cloud_msg->height;
379 const int row_size_out = point_cloud_msg->height*element_size;
380 point_cloud_out_msg->row_step = row_size_out;
381 for (
int v = 0; v < point_cloud_out_msg->height; v++)
382 for (
int u = 0; u < point_cloud_out_msg->width; u++)
383 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);
384 rot_mat.at<
double>(0,1) = -1.;
385 rot_mat.at<
double>(0,2) = point_cloud_msg->height;
386 rot_mat.at<
double>(1,0) = 1.;
388 else if (rotation_angle==270. || rotation_angle==-90.)
391 point_cloud_out_msg->height = point_cloud_msg->width;
392 point_cloud_out_msg->width = point_cloud_msg->height;
393 const int row_size_out = point_cloud_msg->height*element_size;
394 point_cloud_out_msg->row_step = row_size_out;
395 for (
int v = 0; v < point_cloud_out_msg->height; v++)
396 for (
int u = 0; u < point_cloud_out_msg->width; u++)
397 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);
398 rot_mat.at<
double>(0,1) = 1.;
399 rot_mat.at<
double>(1,0) = -1.;
400 rot_mat.at<
double>(1,2) = point_cloud_msg->width;
402 else if (rotation_angle==180 || rotation_angle==-180)
405 for (
int v = 0; v < point_cloud_out_msg->height; v++)
406 for (
int u = 0; u < point_cloud_out_msg->width; u++)
407 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);
408 rot_mat.at<
double>(0,0) = -1.;
409 rot_mat.at<
double>(0,2) = point_cloud_msg->width;
410 rot_mat.at<
double>(1,1) = -1.;
411 rot_mat.at<
double>(1,2) = point_cloud_msg->height;
416 int row_size_out = row_size;
418 bool switch_aspect_ratio = !(fabs(sin(rotation_angle*CV_PI/180.)) < 0.707106781);
419 if (switch_aspect_ratio==
true)
421 point_cloud_out_msg->height = point_cloud_msg->width;
422 point_cloud_out_msg->width = point_cloud_msg->height;
423 row_size_out = point_cloud_msg->height*element_size;
424 point_cloud_out_msg->row_step = row_size_out;
428 cv::Point center = cv::Point(point_cloud_msg->width/2, point_cloud_msg->height/2);
429 rot_mat = cv::getRotationMatrix2D(center, -rotation_angle, 1.0);
430 if (switch_aspect_ratio==
true)
432 rot_mat.at<
double>(0,2) += 0.5*((
double)point_cloud_out_msg->width - (double)point_cloud_msg->width);
433 rot_mat.at<
double>(1,2) += 0.5*((
double)point_cloud_out_msg->height - (double)point_cloud_msg->height);
435 cv::Mat rot_mat_inv = rot_mat.clone();
436 rot_mat_inv.at<
double>(0,1) = rot_mat.at<
double>(1,0);
437 rot_mat_inv.at<
double>(1,0) = rot_mat.at<
double>(0,1);
438 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);
439 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);
442 std::vector<uchar> zero_element(element_size, 0);
443 for (
size_t i=0; i<point_cloud_msg->fields.size(); ++i)
445 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)
447 float* val = (
float*)&(zero_element[point_cloud_msg->fields[i].offset]);
448 *val = std::numeric_limits<float>::quiet_NaN();
450 if (point_cloud_msg->fields[i].name.compare(
"rgb") == 0)
452 float* val = (
float*)&(zero_element[point_cloud_msg->fields[i].offset]);
454 *val = *(
float*)(&vali);
459 for (
int v = 0; v < point_cloud_out_msg->height; v++)
461 for (
int u = 0; u < point_cloud_out_msg->width; u++)
463 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);
464 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);
465 if (src_u < 0 || src_u > point_cloud_msg->width-1 || src_v < 0 || src_v > point_cloud_msg->height-1)
466 memcpy(&(point_cloud_out_msg->data[v*row_size_out+u*element_size]), &(zero_element[0]), element_size);
468 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);
478 cv::Mat rot33 = cv::Mat::eye(3,3,CV_64FC1);
479 for (
int r=0; r<2; ++r)
480 for (
int c=0; c<3; ++c)
481 rot33.at<
double>(r,c) = rot_mat.at<
double>(r,c);
482 cv::Mat rot33_inv = rot33.inv();
483 cob_perception_msgs::Float64ArrayStamped rot33_inv_msg;
484 rot33_inv_msg.header = point_cloud_msg->header;
485 rot33_inv_msg.data.resize(9);
486 for (
int r=0; r<3; ++r)
487 for (
int c=0; c<3; ++c)
488 rot33_inv_msg.data[r*3+c] = rot33_inv.at<
double>(r,c);
564 ROS_DEBUG(
"ImageFlip::pcConnectCB: Connecting point cloud callback.");
574 ROS_DEBUG(
"ImageFlip::pcDisconnectCB: Disconnecting point cloud callback.");
588 cv::Mat disparity_image;
592 cv::Mat disparity_image_turned;
593 cv::Mat rot_mat = cv::Mat::zeros(2,3,CV_64FC1);
596 double rotation_angle =
determineRotationAngle(disparity_image_msg->header.frame_id, disparity_image_msg->header.stamp);
600 if (rotation_angle==0. || rotation_angle==360. || rotation_angle==-360.)
602 disparity_image_turned = disparity_image;
603 rot_mat.at<
double>(0,0) = 1.;
604 rot_mat.at<
double>(1,1) = 1.;
606 else if (rotation_angle==90. || rotation_angle==-270.)
609 disparity_image_turned.create(disparity_image.cols, disparity_image.rows, disparity_image.type());
610 if (disparity_image.type() != CV_32FC1)
612 ROS_ERROR(
"ImageFlip::imageCallback: Error: The image format of the disparity image is not CV_32FC1.\n");
615 for (
int v = 0; v < disparity_image_turned.rows; v++)
616 for (
int u = 0; u < disparity_image_turned.cols; u++)
617 disparity_image_turned.at<
float>(v,u) = disparity_image.at<
float>(disparity_image.rows-1-u,v);
618 rot_mat.at<
double>(0,1) = -1.;
619 rot_mat.at<
double>(0,2) = disparity_image.rows;
620 rot_mat.at<
double>(1,0) = 1.;
622 else if (rotation_angle==270. || rotation_angle==-90.)
625 disparity_image_turned.create(disparity_image.cols, disparity_image.rows, disparity_image.type());
626 if (disparity_image.type() != CV_32FC1)
628 std::cout <<
"ImageFlip::imageCallback: Error: The image format of the color image is not CV_32FC1.\n";
631 for (
int v = 0; v < disparity_image_turned.rows; v++)
632 for (
int u = 0; u < disparity_image_turned.cols; u++)
633 disparity_image_turned.at<
float>(v,u) = disparity_image.at<
float>(u,disparity_image.cols-1-v);
634 rot_mat.at<
double>(0,1) = 1.;
635 rot_mat.at<
double>(1,0) = -1.;
636 rot_mat.at<
double>(1,2) = disparity_image.cols;
638 else if (rotation_angle==180 || rotation_angle==-180)
641 disparity_image_turned.create(disparity_image.rows, disparity_image.cols, disparity_image.type());
642 if (disparity_image.type() != CV_32FC1)
644 std::cout <<
"ImageFlip::imageCallback: Error: The image format of the color image is not CV_32FC1.\n";
647 for (
int v = 0; v < disparity_image.rows; v++)
649 float* src = (
float*)disparity_image.ptr(v);
650 float* dst = (
float*)disparity_image_turned.ptr(disparity_image.rows - v - 1) + (disparity_image.cols - 1);
651 for (
int u = 0; u < disparity_image.cols; u++)
658 rot_mat.at<
double>(0,0) = -1.;
659 rot_mat.at<
double>(0,2) = disparity_image.cols;
660 rot_mat.at<
double>(1,1) = -1.;
661 rot_mat.at<
double>(1,2) = disparity_image.rows;
666 bool switch_aspect_ratio = !(fabs(sin(rotation_angle*CV_PI/180.)) < 0.707106781);
667 if (switch_aspect_ratio==
false)
668 disparity_image_turned.create(disparity_image.rows, disparity_image.cols, disparity_image.type());
670 disparity_image_turned.create(disparity_image.cols, disparity_image.rows, disparity_image.type());
671 if (disparity_image.type() != CV_32FC1)
673 ROS_ERROR(
"ImageFlip::imageCallback: Error: The image format of the color image is not CV_32FC1.\n");
677 cv::Point center = cv::Point(disparity_image.cols/2, disparity_image.rows/2);
678 rot_mat = cv::getRotationMatrix2D(center, -rotation_angle, 1.0);
679 if (switch_aspect_ratio==
true)
681 rot_mat.at<
double>(0,2) += 0.5*(disparity_image_turned.cols-disparity_image.cols);
682 rot_mat.at<
double>(1,2) += 0.5*(disparity_image_turned.rows-disparity_image.rows);
684 cv::warpAffine(disparity_image, disparity_image_turned, rot_mat, disparity_image_turned.size());
689 cv_ptr.
image = disparity_image_turned;
690 cv_ptr.encoding = disparity_image_msg->image.encoding;
691 stereo_msgs::DisparityImage::Ptr disparity_image_turned_msg(
new stereo_msgs::DisparityImage);
692 sensor_msgs::ImagePtr disparity_image_turned_msg_image = cv_ptr.toImageMsg();
693 disparity_image_turned_msg_image->header = disparity_image_msg->image.header;
694 disparity_image_turned_msg->image = *disparity_image_turned_msg_image;
695 disparity_image_turned_msg->header = disparity_image_msg->header;
700 cv::Mat rot33 = cv::Mat::eye(3,3,CV_64FC1);
701 for (
int r=0; r<2; ++r)
702 for (
int c=0; c<3; ++c)
703 rot33.at<
double>(r,c) = rot_mat.at<
double>(r,c);
704 cv::Mat rot33_inv = rot33.inv();
705 cob_perception_msgs::Float64ArrayStamped rot33_inv_msg;
706 rot33_inv_msg.header = disparity_image_msg->header;
707 rot33_inv_msg.data.resize(9);
708 for (
int r=0; r<3; ++r)
709 for (
int c=0; c<3; ++c)
710 rot33_inv_msg.data[r*3+c] = rot33_inv.at<
double>(r,c);
720 ROS_DEBUG(
"ImageFlip::disparityConnectCB: Connecting disparity callback.");
730 ROS_DEBUG(
"ImageFlip::disparityDisconnectCB: Disconnecting disparity callback.");
CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
ros::Publisher point_cloud_2d_transform_pub_
publisher for the transformation matrix for the in plane rotation and translation in the image plane...
unsigned int pc_sub_counter_
void imageCallback(const sensor_msgs::ImageConstPtr &color_image_msg)
ros::Subscriber point_cloud_sub_
point cloud input topic
void publish(const boost::shared_ptr< M > &message) const
ImageFlip(ros::NodeHandle nh)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
image_transport::Publisher color_camera_image_pub_
color camera image output topic
ros::Publisher disparity_image_pub_
disparity image output topic
Publisher advertise(const std::string &base_topic, uint32_t queue_size, bool latch=false)
void disparityConnectCB(const ros::SingleSubscriberPublisher &pub)
image_transport::ImageTransport * it_
void void_delete_image_msg(const sensor_msgs::Image *)
TFSIMD_FORCE_INLINE Vector3 cross(const Vector3 &v) const
ros::NodeHandle node_handle_
ROS node handle.
unsigned int img_sub_counter_
ros::Publisher color_camera_image_2d_transform_pub_
publisher for the transformation matrix for the in plane rotation and translation in the image plane...
ros::Publisher point_cloud_pub_
point cloud output topic
void imgDisconnectCB(const image_transport::SingleSubscriberPublisher &pub)
TFSIMD_FORCE_INLINE tfScalar dot(const Vector3 &v) const
TFSIMD_FORCE_INLINE const tfScalar & z() const
void pcConnectCB(const ros::SingleSubscriberPublisher &pub)
double last_rotation_angle_
void publish(const sensor_msgs::Image &message) const
void pcDisconnectCB(const ros::SingleSubscriberPublisher &pub)
void imgConnectCB(const image_transport::SingleSubscriberPublisher &pub)
bool flip_disparity_image_
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
image_transport::SubscriberFilter color_camera_image_sub_
color camera image input topic
double last_rotation_factor_
void disparityCallback(const stereo_msgs::DisparityImage::ConstPtr &disparity_image_msg)
void pcCallback(const sensor_msgs::PointCloud2::ConstPtr &point_cloud_msg)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
unsigned int disparity_sub_counter_
#define ROS_DEBUG_STREAM(args)
void subscribe(ImageTransport &it, const std::string &base_topic, uint32_t queue_size, const TransportHints &transport_hints=TransportHints())
ros::Subscriber disparity_image_sub_
disparity image input topic
TFSIMD_FORCE_INLINE Vector3 & normalize()
void disparityDisconnectCB(const ros::SingleSubscriberPublisher &pub)
std::string reference_frame_
tf::TransformListener transform_listener_
ros::Publisher disparity_image_2d_transform_pub_
publisher for the transformation matrix for the in plane rotation and translation in the image plane...
double determineRotationAngle(const std::string &camera_frame_id, const ros::Time &time)
TFSIMD_FORCE_INLINE tfScalar length() const
bool convertImageMessageToMat(const sensor_msgs::Image::ConstPtr &color_image_msg, cv_bridge::CvImageConstPtr &color_image_ptr, cv::Mat &color_image)