virtual_camera_mono.cpp
Go to the documentation of this file.
1 #include <ros/ros.h>
2 #include <dynamic_reconfigure/server.h>
9 #include <cv_bridge/cv_bridge.h>
10 #if ( CV_MAJOR_VERSION >= 4)
11 #else
12 #include <opencv/cv.hpp>
13 #include <opencv/highgui.h>
14 #endif
15 
16 #include <string>
17 #include <vector>
18 #include <boost/assign.hpp>
19 #include <boost/thread.hpp>
20 
21 #include <geometry_msgs/Polygon.h>
22 #include <geometry_msgs/PolygonStamped.h>
23 
24 #include <jsk_perception/VirtualCameraMonoConfig.h>
25 
26 
28 {
39 
40  tf::StampedTransform trans_; // transform to virtual camera
41  geometry_msgs::PolygonStamped poly_; // target polygon to transform image
43 
44 public:
45  VirtualCameraMono() : private_nh_("~"), it_(nh_), it_priv_(private_nh_), subscriber_count_(0)
46  {
48  image_transport::SubscriberStatusCallback disconnect_cb = boost::bind(&VirtualCameraMono::disconnectCb, this, _1);
49  pub_ = it_priv_.advertiseCamera("image", 1, connect_cb, disconnect_cb);
50 
51  dynamic_reconfigure::Server<jsk_perception::VirtualCameraMonoConfig>::CallbackType f =
52  boost::bind(&VirtualCameraMono::configCb, this, _1, _2);
53  srv_ = boost::make_shared<dynamic_reconfigure::Server<jsk_perception::VirtualCameraMonoConfig> >(private_nh_);
54  srv_->setCallback(f);
55 
56  private_nh_.param("frame_id", trans_.frame_id_, std::string("/elevator_inside_panel"));
57  private_nh_.param("child_frame_id", trans_.child_frame_id_, std::string("/virtual_camera_frame"));
58  ROS_INFO("VirutalCmaeraMono(%s) frame_id: %s, chid_frame_id: %s", ros::this_node::getName().c_str(), trans_.frame_id_.c_str(), trans_.child_frame_id_.c_str());
59 
60  std::vector<double> initial_pos, initial_rot;
61  if (jsk_topic_tools::readVectorParameter(private_nh_, "initial_pos", initial_pos)) {
62  trans_.setOrigin(tf::Vector3(initial_pos[0], initial_pos[1], initial_pos[2]));
63  }
64  else {
65  trans_.setOrigin(tf::Vector3(0.7, 0, 0));
66  }
67  if (jsk_topic_tools::readVectorParameter(private_nh_, "initial_rot", initial_rot)) {
68  trans_.setRotation(tf::Quaternion(initial_rot[0], initial_rot[1], initial_rot[2], initial_rot[3]));
69  }
70  else {
71  trans_.setRotation(tf::Quaternion(0.707, 0, 0, -0.707) * tf::Quaternion(0, 0.707, 0, -0.707));
72  }
73  ROS_INFO(" initia_pos : %f %f %f", trans_.getOrigin().getX(), trans_.getOrigin().getY(), trans_.getOrigin().getZ());
74  ROS_INFO(" initia_rot : %f %f %f %f", trans_.getRotation().getX(), trans_.getRotation().getY(), trans_.getRotation().getZ(), trans_.getRotation().getW());
75 
76  poly_.header.frame_id = trans_.frame_id_;
77  geometry_msgs::Point32 pt;
78  pt.x=0, pt.y=1, pt.z=0; poly_.polygon.points.push_back(pt);
79  pt.x=0, pt.y=-1, pt.z=0; poly_.polygon.points.push_back(pt);
80  pt.x=0, pt.y=-1, pt.z=-1; poly_.polygon.points.push_back(pt);
81  pt.x=0, pt.y=1, pt.z=-1; poly_.polygon.points.push_back(pt);
82 
83  // parameter subscriber
84  sub_trans_ = nh_.subscribe<geometry_msgs::TransformStamped>("view_point", 1, &VirtualCameraMono::transCb, this);
85  sub_poly_ = nh_.subscribe<geometry_msgs::PolygonStamped>("target_polygon", 1, &VirtualCameraMono::polyCb, this);
86 
87  }
88 
89  void configCb(const jsk_perception::VirtualCameraMonoConfig &config, uint32_t level)
90  {
91  boost::mutex::scoped_lock(mutex_);
92  switch (config.interpolation_method) {
93  case 0:
94  interpolation_method_ = cv::INTER_NEAREST;
95  break;
96  case 1:
97  interpolation_method_ = cv::INTER_LINEAR;
98  break;
99  case 2:
100  interpolation_method_ = cv::INTER_AREA;
101  break;
102  case 3:
103  interpolation_method_ = cv::INTER_CUBIC;
104  break;
105  case 4:
106  interpolation_method_ = cv::INTER_LANCZOS4;
107  break;
108  default:
109  ROS_ERROR("Invalid interpolation method: %d", config.interpolation_method);
110  break;
111  }
112  }
113 
115  {
116  if (subscriber_count_ == 0){
117  subscribe();
118  }
119  subscriber_count_++;
120  ROS_DEBUG("connected new node. current subscriber: %d", subscriber_count_);
121  }
122 
124  {
125  subscriber_count_--;
126  if (subscriber_count_ == 0) {
127  unsubscribe();
128  }
129  ROS_DEBUG("disconnected node. current subscriber: %d", subscriber_count_);
130  }
131 
132  void subscribe()
133  {
134  ROS_INFO("Subscribing to image topic");
135  sub_ = it_.subscribeCamera("image", 1, &VirtualCameraMono::imageCb, this);
136  ros::V_string names = boost::assign::list_of("image");
138  }
139 
140  void unsubscribe()
141  {
142  ROS_INFO("Unsubscibing from image topic");
143  sub_.shutdown();
144  }
145 
146  void imageCb(const sensor_msgs::ImageConstPtr& image_msg,
147  const sensor_msgs::CameraInfoConstPtr& info_msg)
148  {
149  cv_bridge::CvImagePtr cv_ptr;
150  cv::Mat image;
151  try {
152  cv_ptr = cv_bridge::toCvCopy(image_msg, "bgr8");
153  image = cv_ptr->image;
154  }
155  catch (cv_bridge::Exception& ex) {
156  ROS_ERROR("[virtual_camera_mono] Failed to convert image");
157  return;
158  }
159 
160  cam_model_.fromCameraInfo(info_msg);
161 
162  trans_.stamp_ = ros::Time::now();
163  tf_broadcaster_.sendTransform(trans_);
164 
165  //
166  ROS_DEBUG("transform image.");
167  cv::Mat outimage = image.clone();
168  if (TransformImage(image, outimage, trans_, poly_, cam_model_)) {
169  ROS_DEBUG("publish image and transform.");
170  sensor_msgs::CameraInfo virtual_info = *info_msg;
171  cv_ptr->image = outimage;
172  sensor_msgs::Image::Ptr img_msg = cv_ptr->toImageMsg();
173  img_msg->header.stamp = trans_.stamp_;
174  virtual_info.header.stamp = trans_.stamp_;
175  img_msg->header.frame_id = trans_.child_frame_id_;
176  virtual_info.header.frame_id = trans_.child_frame_id_;
177  pub_.publish(*img_msg, virtual_info);
178  }
179  }
180 
181  // subscribe target polygon
182  void polyCb(const geometry_msgs::PolygonStampedConstPtr& poly) { poly_ = *poly; }
183 
184  // subscribe virtual camera pose
185  void transCb(const geometry_msgs::TransformStampedConstPtr& tf)
186  {
187  trans_.frame_id_ = tf->header.frame_id;
188  trans_.child_frame_id_ = tf->child_frame_id;
189  trans_.setOrigin(tf::Vector3(tf->transform.translation.x,
190  tf->transform.translation.y,
191  tf->transform.translation.z));
192  trans_.setRotation(tf::Quaternion(tf->transform.rotation.x, tf->transform.rotation.y,
193  tf->transform.rotation.z, tf->transform.rotation.w));
194  }
195 
196  // poly is plane only
197  bool TransformImage(cv::Mat src, cv::Mat dest,
198  tf::StampedTransform& trans, geometry_msgs::PolygonStamped& poly,
200  {
201  try {
202  // transform polygon to camera coordinate and virtual camera coordinate
203  std::vector<tf::Point> target_poly, target_poly_translated;
204  for(std::vector<geometry_msgs::Point32>::iterator pit=poly.polygon.points.begin(); pit != poly.polygon.points.end(); pit++) {
205  geometry_msgs::PointStamped point, cpoint, vpoint;
206  point.point.x = pit->x, point.point.y = pit->y, point.point.z = pit->z;
207  point.header = poly.header;
208  tf_listener_.transformPoint(cam_model_.tfFrame(), point, cpoint);
209  tf_listener_.transformPoint(trans.frame_id_, point, vpoint);
210 
211  tf::Vector3 vpt_vec = trans.inverse() * tf::Vector3(vpoint.point.x, vpoint.point.y, vpoint.point.z);
212 
213  // push
214  target_poly.push_back(tf::Point(cpoint.point.x, cpoint.point.y, cpoint.point.z));
215  target_poly_translated.push_back(tf::Point(vpt_vec.x(),vpt_vec.y(),vpt_vec.z()));
216  }
217 
218  // warp from (cpoint in camera) to (vpoint in virtual camera)
219  cv::Point2f src_pnt[4], dst_pnt[4];
220  for(int i = 0; i < 4; i++) {
221  cv::Point3d xyz(target_poly[i].x(),target_poly[i].y(),target_poly[i].z());
222  cv::Point3d xyz_trans(target_poly_translated[i].x(),
223  target_poly_translated[i].y(),
224  target_poly_translated[i].z());
225  cv::Point2d uv,uv_trans;
226  uv = cam_model_.project3dToPixel(xyz);
227  src_pnt[i] = cv::Point (uv.x, uv.y);
228  uv_trans = cam_model_.project3dToPixel(xyz_trans);
229  dst_pnt[i] = cv::Point (uv_trans.x, uv_trans.y);
230  }
231 
232  cv::Mat map_matrix = cv::getPerspectiveTransform (src_pnt, dst_pnt);
233  cv::warpPerspective (src, dest, map_matrix, dest.size(), interpolation_method_);
234  }
235  catch (tf::TransformException e) {
236  ROS_WARN_THROTTLE(10, "[virtual_camera_mono] failed to transform image: %s", e.what());
237  return false;
238  }
239  return true;
240  }
241 };
242 
243 int main(int argc, char **argv)
244 {
245  ros::init(argc, argv, "virtual_camera_mono");
246 
247  VirtualCameraMono vcam;
248 
249  ros::spin();
250 }
251 
tf::StampedTransform trans_
f
image_transport::ImageTransport it_priv_
TFSIMD_FORCE_INLINE void setRotation(const Quaternion &q)
void publish(const sensor_msgs::Image &image, const sensor_msgs::CameraInfo &info) const
#define ROS_WARN_THROTTLE(rate,...)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
image_transport::CameraSubscriber sub_
CameraSubscriber subscribeCamera(const std::string &base_topic, uint32_t queue_size, const CameraSubscriber::Callback &callback, const ros::VoidPtr &tracked_object=ros::VoidPtr(), const TransportHints &transport_hints=TransportHints())
int main(int argc, char **argv)
void disconnectCb(const image_transport::SingleSubscriberPublisher &)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
boost::function< void(const SingleSubscriberPublisher &)> SubscriberStatusCallback
ROSCPP_DECL const std::string & getName()
TFSIMD_FORCE_INLINE const tfScalar & getY() const
void transformPoint(const std::string &target_frame, const geometry_msgs::PointStamped &stamped_in, geometry_msgs::PointStamped &stamped_out) const
TFSIMD_FORCE_INLINE const tfScalar & getW() const
void transCb(const geometry_msgs::TransformStampedConstPtr &tf)
TFSIMD_FORCE_INLINE const tfScalar & getZ() const
ROSCPP_DECL void spin(Spinner &spinner)
geometry_msgs::PolygonStamped poly_
bool readVectorParameter(ros::NodeHandle &nh, const std::string &param_name, std::vector< double > &result)
void connectCb(const image_transport::SingleSubscriberPublisher &)
TFSIMD_FORCE_INLINE const tfScalar & x() const
void imageCb(const sensor_msgs::ImageConstPtr &image_msg, const sensor_msgs::CameraInfoConstPtr &info_msg)
bool TransformImage(cv::Mat src, cv::Mat dest, tf::StampedTransform &trans, geometry_msgs::PolygonStamped &poly, image_geometry::PinholeCameraModel &cam_model_)
image_geometry::PinholeCameraModel cam_model_
std::string child_frame_id_
CameraPublisher advertiseCamera(const std::string &base_topic, uint32_t queue_size, bool latch=false)
void configCb(const jsk_perception::VirtualCameraMonoConfig &config, uint32_t level)
std::vector< std::string > V_string
TFSIMD_FORCE_INLINE const tfScalar & z() const
#define ROS_INFO(...)
bool fromCameraInfo(const sensor_msgs::CameraInfo &msg)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
bool warnNoRemap(const std::vector< std::string > names)
CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
TFSIMD_FORCE_INLINE const tfScalar & y() const
void sendTransform(const StampedTransform &transform)
ros::Subscriber sub_trans_
Transform inverse() const
x
y
tf::TransformListener tf_listener_
image_transport::CameraPublisher pub_
TFSIMD_FORCE_INLINE Vector3 & getOrigin()
tf::TransformBroadcaster tf_broadcaster_
Quaternion getRotation() const
void polyCb(const geometry_msgs::PolygonStampedConstPtr &poly)
TFSIMD_FORCE_INLINE const tfScalar & getX() const
static Time now()
boost::shared_ptr< dynamic_reconfigure::Server< jsk_perception::VirtualCameraMonoConfig > > srv_
cv::Point2d project3dToPixel(const cv::Point3d &xyz) const
ros::NodeHandle private_nh_
#define ROS_ERROR(...)
TFSIMD_FORCE_INLINE void setOrigin(const Vector3 &origin)
std::string frame_id_
image_transport::ImageTransport it_
#define ROS_DEBUG(...)
ros::Subscriber sub_poly_
z


jsk_perception
Author(s): Manabu Saito, Ryohei Ueda
autogenerated on Mon May 3 2021 03:03:27