fiducial_detect.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Austin Hendrix
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  *
30  * Author: Austin Hendrix <namniart@gmail.com>
31  */
32 
33 #include <assert.h>
34 #include <sys/time.h>
35 #include <unistd.h>
36 
37 #include <cv_bridge/cv_bridge.h>
39 #include <ros/ros.h>
41 #include <tf/transform_datatypes.h>
44 #include <tf2_ros/buffer.h>
47 #include <visualization_msgs/Marker.h>
48 
49 #include <list>
50 #include <string>
51 
53 #include "fiducial_lib/File.hpp"
54 
55 #include "fiducial_pose/rosrpp.h"
56 
57 #include "fiducial_msgs/Fiducial.h"
58 #include "fiducial_msgs/FiducialArray.h"
59 #include "fiducial_msgs/FiducialTransform.h"
60 #include "fiducial_msgs/FiducialTransformArray.h"
61 
63 private:
66  fiducial_msgs::FiducialTransformArray fiducialTransformArray;
67  fiducial_msgs::FiducialArray fiducialVertexArray;
68 
72  int frameNum;
74 
76 
77 
78  // the last frame we saw on the camera header
79  std::string last_camera_frame;
80 
83 
84  // if set, we publish the images that contain fiducials
86 
87  // pose estimtion params
89  double fiducial_len;
91 
93 
94  const double scale;
95 
97  std::string data_directory;
98  std::string log_file;
99 
100 
101  static void fiducial_announce(void *t, int id, int direction,
102  double world_diagonal, double x0, double y0,
103  double x1, double y1, double x2, double y2,
104  double x3, double y3);
105 
106  void fiducial_cb(int id, int direction, double world_diagonal, double x0,
107  double y0, double x1, double y1, double x2, double y2,
108  double x3, double y3);
109 
110  void imageCallback(const sensor_msgs::ImageConstPtr &msg);
111  void processImage(const sensor_msgs::ImageConstPtr &msg);
112  void camInfoCallback(const sensor_msgs::CameraInfo::ConstPtr &msg);
113 
114  boost::thread *update_thread;
115 
116 public:
118  ~FiducialsNode();
119 };
120 
122  if (update_thread) {
123  update_thread->join();
124  delete update_thread;
125  update_thread = NULL;
126  }
127 }
128 
129 void FiducialsNode::fiducial_announce(void *t, int id, int direction,
130  double world_diagonal, double x0,
131  double y0, double x1, double y1,
132  double x2, double y2, double x3,
133  double y3) {
134  FiducialsNode *ths = (FiducialsNode *)t;
135  ths->fiducial_cb(id, direction, world_diagonal, x0, y0, x1, y1, x2, y2, x3,
136  y3);
137 }
138 
139 void FiducialsNode::fiducial_cb(int id, int direction, double world_diagonal,
140  double x0, double y0, double x1, double y1,
141  double x2, double y2, double x3, double y3) {
142  fiducial_msgs::Fiducial fid;
143 
144  ROS_INFO(
145  "fiducial: id=%d dir=%d diag=%f (%.2f,%.2f), (%.2f,%.2f), (%.2f,%.2f), "
146  "(%.2f,%.2f)",
147  id, direction, world_diagonal, x0, y0, x1, y1, x2, y2, x3, y3);
148 
149  fid.direction = direction;
150  fid.fiducial_id = id;
151  fid.x0 = x0;
152  fid.y0 = y0;
153  fid.x1 = x1;
154  fid.y1 = y1;
155  fid.x2 = x2;
156  fid.y2 = y2;
157  fid.x3 = x3;
158  fid.y3 = y3;
159 
160  fiducialVertexArray.fiducials.push_back(fid);
161 
162  if (estimate_pose) {
163  if (!haveCamInfo && frameNum < 5) {
164  return;
165  }
166  fiducial_msgs::FiducialTransform ft;
167  geometry_msgs::Transform trans;
168  ft.transform = trans;
169  if (pose_est->fiducialCallback(&fid, &ft)) {
170  fiducialTransformArray.transforms.push_back(ft);
171  }
172  }
173 }
174 
176  const sensor_msgs::CameraInfo::ConstPtr &msg) {
177  if (msg->K != boost::array<double, 9>({0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0})) {
178  if (pose_est) {
180  }
181 
182  haveCamInfo = true;
183  last_camera_frame = msg->header.frame_id;
184  }
185  else {
186  ROS_WARN("%s", "CameraInfo message has invalid intrinsics, K matrix is all zeros");
187  }
188 }
189 
190 void FiducialsNode::imageCallback(const sensor_msgs::ImageConstPtr &msg) {
191  if (!processing_image) {
192  processing_image = true;
193  if (update_thread) {
194  update_thread->join();
195  delete update_thread;
196  update_thread = NULL;
197  }
198  processing_image = true;
199  update_thread = new boost::thread(
200  boost::bind(&FiducialsNode::processImage, this, msg));
201  } else {
202  ROS_INFO("Dropping image");
203  }
204 }
205 
206 void FiducialsNode::processImage(const sensor_msgs::ImageConstPtr &msg) {
207  processing_image = true;
208  frameNum++;
209 
210  last_image_seq = msg->header.seq;
211  last_image_time = msg->header.stamp;
212  ROS_INFO("Got image seq %d", last_image_seq);
213 
214  fiducialTransformArray.transforms.clear();
215  fiducialTransformArray.header.stamp = msg->header.stamp;
216  fiducialTransformArray.header.frame_id = last_camera_frame;
217  fiducialTransformArray.image_seq = msg->header.seq;
218 
219  fiducialVertexArray.fiducials.clear();
220  fiducialVertexArray.header.stamp = msg->header.stamp;
221  fiducialVertexArray.header.frame_id = last_camera_frame;
222  fiducialVertexArray.image_seq = msg->header.seq;
223 
224  try {
227  IplImage *image = new IplImage(cv_img->image);
228  if (fiducials == NULL) {
229  ROS_INFO("Got first image! Setting up Fiducials library");
230  // Load up *fiducials_create*:
231  Fiducials_Create fiducials_create =
233 
234  fiducials_create->fiducials_path = data_directory.c_str();
235  fiducials_create->announce_object = (Memory) this;
236  fiducials_create->log_file_name = log_file.c_str();
237  fiducials_create->fiducial_announce_routine = fiducial_announce;
238 
239  // Create *fiducials* object using first image:
240  fiducials = Fiducials__create(image, fiducials_create);
241  }
244 
247 
248  ROS_INFO("Processed image");
249  if (publish_images) {
250  for (unsigned i = 0; i < fiducialVertexArray.fiducials.size(); i++) {
251  fiducial_msgs::Fiducial &fid = fiducialVertexArray.fiducials[i];
252  cvLine(image, cvPoint(fid.x0, fid.y0), cvPoint(fid.x1, fid.y1),
253  CV_RGB(255, 0, 0), 3);
254  cvLine(image, cvPoint(fid.x1, fid.y1), cvPoint(fid.x2, fid.y2),
255  CV_RGB(255, 0, 0), 3);
256  cvLine(image, cvPoint(fid.x2, fid.y2), cvPoint(fid.x3, fid.y3),
257  CV_RGB(255, 0, 0), 3);
258  cvLine(image, cvPoint(fid.x3, fid.y3), cvPoint(fid.x0, fid.y0),
259  CV_RGB(255, 0, 0), 3);
260  }
261  image_pub.publish(msg);
262  }
263 
264  fiducialVertexArray.fiducials.clear();
265  fiducialTransformArray.transforms.clear();
266 
267  } catch (cv_bridge::Exception &e) {
268  ROS_ERROR("cv_bridge exception: %s", e.what());
269  }
270 
271  ROS_INFO("Finished processing image seq %d", last_image_seq);
272  processing_image = false;
273 }
274 
276  frameNum = 0;
277  haveCamInfo = false;
278  processing_image = false;
279  update_thread = NULL;
280 
281  nh.param<std::string>("data_directory", data_directory, ".");
282  nh.param<std::string>("log_file", log_file, "fiducials.log.txt");
283 
284  nh.param<bool>("publish_images", publish_images, false);
285  nh.param<bool>("estimate_pose", estimate_pose, true);
286 
287  nh.param<double>("fiducial_len", fiducial_len, 0.146);
288  nh.param<bool>("undistort_points", undistort_points, false);
289 
290  image_transport::ImageTransport img_transport(nh);
291 
292  if (publish_images) {
293  image_pub = img_transport.advertise("fiducial_images", 1);
294  }
295 
296  vertices_pub = nh.advertise<fiducial_msgs::FiducialArray>("/fiducial_vertices", 1);
297 
298  if (estimate_pose) {
299  pose_pub = nh.advertise<fiducial_msgs::FiducialTransformArray>(
300  "/fiducial_transforms", 1);
301  pose_est = new RosRpp(fiducial_len, undistort_points);
302  } else {
303  pose_est = NULL;
304  }
305 
306  fiducials = NULL;
307 
308  img_sub = img_transport.subscribe("/camera", 1,
310 
311  caminfo_sub =
312  nh.subscribe("/camera_info", 1, &FiducialsNode::camInfoCallback, this);
313 
314  ROS_INFO("Fiducials Localization ready");
315 }
316 
317 int main(int argc, char **argv) {
318  ros::init(argc, argv, "fiducial_detect");
319  ros::NodeHandle nh("~");
320 
321  FiducialsNode node(nh);
322 
323  ros::spin();
324 
325  return 0;
326 }
CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
ros::Subscriber caminfo_sub
image_transport::Subscriber img_sub
const double scale
void publish(const boost::shared_ptr< M > &message) const
std::string log_file
void imageCallback(const sensor_msgs::ImageConstPtr &msg)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
Fiducials_Fiducial_Announce_Routine fiducial_announce_routine
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
std::string data_directory
String_Const fiducials_path
bool fiducialCallback(fiducial_msgs::Fiducial *fiducial, fiducial_msgs::FiducialTransform *transform)
#define ROS_WARN(...)
ROSCPP_DECL void spin(Spinner &spinner)
fiducial_msgs::FiducialTransformArray fiducialTransformArray
std::string last_camera_frame
void processImage(const sensor_msgs::ImageConstPtr &msg)
static void fiducial_announce(void *t, int id, int direction, double world_diagonal, double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3)
boost::thread * update_thread
void publish(const sensor_msgs::Image &message) const
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
ros::Publisher pose_pub
Fiducials Fiducials__create(CV_Image original_image, Fiducials_Create fiducials_create)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
Fiducials fiducials
FiducialsNode(ros::NodeHandle &nh)
ros::Time last_image_time
Fiducials_Create Fiducials_Create__one_and_only(void)
fiducial_msgs::FiducialArray fiducialVertexArray
Fiducials_Results Fiducials__process(Fiducials fiducials)
void * Memory
void fiducial_cb(int id, int direction, double world_diagonal, double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3)
image_transport::Publisher image_pub
void camInfoCallback(const sensor_msgs::CameraInfo::ConstPtr &msg)
int main(int argc, char **argv)
void camInfoCallback(const sensor_msgs::CameraInfo::ConstPtr &msg)
String_Const log_file_name
#define ROS_ERROR(...)
ros::Publisher vertices_pub
void Fiducials__image_set(Fiducials fiducials, CV_Image image)


fiducial_detect
Author(s): Austin Hendrix
autogenerated on Thu Dec 28 2017 04:07:00