point_pose_extractor.cpp
Go to the documentation of this file.
1 // -*- mode: c++ -*-
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2015, JSK Lab
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/o2r other materials provided
17  * with the distribution.
18  * * Neither the name of the JSK Lab nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 
36 #include <ros/ros.h>
37 #include <rospack/rospack.h>
38 #include <cv_bridge/cv_bridge.h>
39 #if ( CV_MAJOR_VERSION >= 4)
40 #include <opencv2/opencv.hpp>
41 #include <opencv2/highgui/highgui_c.h>
42 #include <opencv2/calib3d/calib3d_c.h>
43 #else
44 #include <opencv/highgui.h>
45 #include <opencv/cv.hpp>
46 #endif
47 #include <posedetection_msgs/Feature0DDetect.h>
48 #include <posedetection_msgs/ImageFeature0D.h>
49 #include <posedetection_msgs/ObjectDetection.h>
50 #include <posedetection_msgs/Object6DPose.h>
51 #include <geometry_msgs/PoseStamped.h>
52 #include <geometry_msgs/Pose.h>
53 #include <geometry_msgs/Quaternion.h>
57 #include <tf/tf.h>
58 #include <boost/shared_ptr.hpp>
59 #include <boost/foreach.hpp>
60 #include <boost/filesystem.hpp>
61 #include <vector>
62 #include <sstream>
63 #include <iostream>
64 #include <dynamic_reconfigure/server.h>
65 #include <jsk_perception/point_pose_extractorConfig.h>
66 #include <jsk_perception/SetTemplate.h>
69 
71 
72 void features2keypoint (posedetection_msgs::Feature0D features,
73  std::vector<cv::KeyPoint>& keypoints,
74  cv::Mat& descriptors){
75  keypoints.resize(features.scales.size());
76  descriptors.create(features.scales.size(),features.descriptor_dim,CV_32FC1);
77  std::vector<cv::KeyPoint>::iterator keypoint_it = keypoints.begin();
78  for ( int i=0; keypoint_it != keypoints.end(); ++keypoint_it, ++i ) {
79  *keypoint_it = cv::KeyPoint(cv::Point2f(features.positions[i*2+0],
80  features.positions[i*2+1]),
81  features.descriptor_dim, // size
82  features.orientations[i], //angle
83  0, // resonse
84  features.scales[i] // octave
85  );
86  for (int j = 0; j < features.descriptor_dim; j++){
87  descriptors.at<float>(i,j) =
88  features.descriptors[i*features.descriptor_dim+j];
89  }
90  }
91 }
92 
93 
95 {
96 public:
97  std::string _matching_frame;
98  cv::Mat _template_img;
99  std::vector<cv::KeyPoint> _template_keypoints;
103  double _template_width; // width of template [m]
104  double _template_height; // height of template [m]
106  cv::Mat _affine_matrix;
107  std::string _window_name;
108  // The maximum allowed reprojection error to treat a point pair as an inlier
110  // threshold on squared ratio of distances between NN and 2nd NN
112  std::vector<cv::Point2d> _correspondances;
114 
116  }
118  std::string matching_frame,
119  int original_width_size,
120  int original_height_size,
121  double template_width,
122  double template_height,
123  tf::Transform relativepose,
124  cv::Mat affine_matrix,
125  double reprojection_threshold,
126  double distanceratio_threshold,
127  std::string window_name,
128  bool autosize){
129 
130  _template_img = img.clone();
131  _matching_frame = matching_frame;
132  _original_width_size = original_width_size;
133  _original_height_size = original_height_size;
134  _template_width = template_width;
135  _template_height = template_height;
136  _relativepose = relativepose;
137  _affine_matrix = affine_matrix;
138  _window_name = window_name;
139  _reprojection_threshold = reprojection_threshold;
140  _distanceratio_threshold = distanceratio_threshold;
141  _template_keypoints.clear();
142  _correspondances.clear();
143  // cv::namedWindow(_window_name, autosize ? CV_WINDOW_AUTOSIZE : 0);
144  }
145 
146 
148  std::cerr << "delete " << _window_name << std::endl;
149  }
150 
151 
152  std::string get_window_name(){
153  return _window_name;
154  }
155 
156  std::vector<cv::Point2d>* correspondances(){
157  return &_correspondances;
158  }
159 
160  bool check_template (){
161  if (_template_img.empty() && _template_keypoints.size() == 0 &&
162  _template_descriptors.empty()){
163  return false;
164  }
165  else {
166  return true;
167  }
168  }
169 
170 
172  posedetection_msgs::Feature0DDetect srv;
173 
174  if ( _template_img.empty()) {
175  ROS_ERROR ("template picture is empty.");
176  return -1;
177  }
178  ROS_INFO_STREAM("read template image and call " << client.getService() << " service");
179  cv_bridge::CvImage cv_img;
180  cv_img.image = cv::Mat(_template_img);
181  cv_img.encoding = std::string("bgr8");
182  srv.request.image = *(cv_img.toImageMsg());
183  if (client.call(srv)) {
184  ROS_INFO_STREAM("get features with " << srv.response.features.scales.size() << " descriptoins");
185  features2keypoint (srv.response.features, _template_keypoints, _template_descriptors);
186 
187  // inverse affine translation
188  cv::Mat M_inv;
189  cv::Mat dst;
190  cv::invert(_affine_matrix, M_inv);
191  // cv::drawKeypoints (tmp, _template_keypoints, dst, cv::Scalar::all(1), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
192  // cv::drawKeypoints (tmp, _template_keypoints, dst);
193  // cv::warpPerspective(_template_img, dst, M_inv,
194  // cv::Size(_original_width_size, _original_height_size),
195  // CV_INTER_LINEAR, IPL_BORDER_CONSTANT, 0);
196  for (int i = 0; i < (int)_template_keypoints.size(); i++){
197  cv::Point2f pt;
198  cv::Mat pt_mat(cv::Size(1,1), CV_32FC2, &pt);
199  cv::Mat pt_src_mat(cv::Size(1,1), CV_32FC2, &_template_keypoints.at(i).pt);
200  cv::perspectiveTransform (pt_src_mat, pt_mat, M_inv);
201  _template_keypoints.at(i).pt = pt_mat.at<cv::Point2f>(0,0);
202  }
203  // cvSetMouseCallback (_window_name.c_str(), &PointPoseExtractor::cvmousecb, this);
204  // _template_img = dst;
205  return 0;
206  } else {
207  ROS_ERROR("Failed to call service Feature0DDetect");
208  return 1;
209  }
210  }
211 
212 
213  double log_fac( int n )
214  {
215  static std::vector<double> slog_table;
216  int osize = slog_table.size();
217  if(osize <= n){
218  slog_table.resize(n+1);
219  if(osize == 0){
220  slog_table[0] = -1;
221  slog_table[1] = log(1.0);
222  osize = 2;
223  }
224  for(int i = osize; i <= n; i++ ){
225  slog_table[i] = slog_table[i-1] + log(i);
226  }
227  }
228  return slog_table[n];
229  }
230 
231  int min_inlier( int n, int m, double p_badsupp, double p_badxform )
232  {
233  double pi, sum;
234  int i, j;
235  double lp_badsupp = log( p_badsupp );
236  double lp_badsupp1 = log( 1.0 - p_badsupp );
237  for( j = m+1; j <= n; j++ ){
238  sum = 0;
239  for( i = j; i <= n; i++ ){
240  pi = (i-m) * lp_badsupp + (n-i+m) * lp_badsupp1 +
241  log_fac( n - m ) - log_fac( i - m ) - log_fac( n - i );
242  sum += exp( pi );
243  }
244  if( sum < p_badxform )
245  break;
246  }
247  return j;
248  }
249 
250 
251  bool estimate_od (ros::ServiceClient client, cv::Mat src_img,
252  std::vector<cv::KeyPoint> sourceimg_keypoints,
254  double err_thr, cv::Mat &stack_img,
255  cv::flann::Index* ft, posedetection_msgs::Object6DPose* o6p){
256 
257  if ( _template_keypoints.size()== 0 &&
258  _template_descriptors.empty() ){
259  set_template(client);
260  }
261  if ( _template_keypoints.size()== 0 &&
262  _template_descriptors.empty() ) {
263  ROS_ERROR ("Template image was not set.");
264  return false;
265  }
266  // stacked image
267  cv::Size stack_size = cv::Size(MAX(src_img.cols,_template_img.cols),
268  src_img.rows+_template_img.rows);
269  stack_img = cv::Mat(stack_size,CV_8UC3);
270  stack_img = cv::Scalar(0);
271  cv::Mat stack_img_tmp(stack_img,cv::Rect(0,0,_template_img.cols,_template_img.rows));
272  cv::add(stack_img_tmp, _template_img, stack_img_tmp);
273  cv::Mat stack_img_src(stack_img,cv::Rect(0,_template_img.rows,src_img.cols,src_img.rows));
274  cv::add(stack_img_src, src_img, stack_img_src);
275  _previous_stack_img = stack_img.clone();
276 
277  // matching
278  cv::Mat m_indices(_template_descriptors.rows, 2, CV_32S);
279  cv::Mat m_dists(_template_descriptors.rows, 2, CV_32F);
280  ft->knnSearch(_template_descriptors, m_indices, m_dists, 2, cv::flann::SearchParams(-1) );
281 
282  // matched points
283  std::vector<cv::Point2f> pt1, pt2;
284  std::vector<int> queryIdxs,trainIdxs;
285  for ( unsigned int j = 0; j < _template_keypoints.size(); j++ ) {
286  if ( m_dists.at<float>(j,0) < m_dists.at<float>(j,1) * _distanceratio_threshold) {
287  queryIdxs.push_back(j);
288  trainIdxs.push_back(m_indices.at<int>(j,0));
289  }
290  }
291  if ( queryIdxs.size() == 0 ) {
292  ROS_WARN_STREAM("could not find matched points with distanceratio(" <<_distanceratio_threshold << ")");
293  } else {
294  cv::KeyPoint::convert(_template_keypoints,pt1,queryIdxs);
295  cv::KeyPoint::convert(sourceimg_keypoints,pt2,trainIdxs);
296  }
297 
298  ROS_INFO ("Found %d total matches among %d template keypoints", (int)pt2.size(), (int)_template_keypoints.size());
299 
300  cv::Mat H;
301  std::vector<uchar> mask((int)pt2.size());
302 
303  if ( pt1.size() > 4 ) {
304  // ToDO for curve face
305  H = cv::findHomography(cv::Mat(pt1), cv::Mat(pt2), mask, CV_RANSAC, _reprojection_threshold);
306  }
307 
308  // draw line
309  for (int j = 0; j < (int)pt1.size(); j++){
310  cv::Point2f pt, pt_orig;
311  cv::Mat pt_mat(cv::Size(1,1), CV_32FC2, &pt);
312  cv::Mat pt_src_mat(cv::Size(1,1), CV_32FC2, &pt1.at(j));
313  cv::perspectiveTransform (pt_src_mat, pt_mat, _affine_matrix);
314  pt_orig = pt_mat.at<cv::Point2f>(0,0);
315  if ( mask.at(j)){
316  cv::line(stack_img, pt_orig, pt2.at(j)+cv::Point2f(0,_template_img.rows),
317  CV_RGB(0,255,0), 1,8,0);
318  }
319  else {
320  cv::line(stack_img, pt_orig, pt2.at(j)+cv::Point2f(0,_template_img.rows),
321  CV_RGB(255,0,255), 1,8,0);
322  }
323  }
324  int inlier_sum = 0;
325  for (int k=0; k < (int)mask.size(); k++){
326  inlier_sum += (int)mask.at(k);
327  }
328 
329  double text_scale = 1.5;
330  {
331  int fontFace = 0, thickness = 0, baseLine;
332  int x, y;
333  cv::Size text_size;
334  std::string text;
335 
336  text = "inlier: " + boost::lexical_cast<std::string>((int)inlier_sum) + " / " + boost::lexical_cast<std::string>((int)pt2.size());
337  text_size = cv::getTextSize(text, fontFace, text_scale, thickness, &baseLine);
338  x = stack_img.size().width - text_size.width;
339  y = text_size.height + thickness + 10; // 10pt pading
340  cv::putText (stack_img, text, cv::Point(x, y),
341  fontFace, text_scale, CV_RGB(0, 255, 0),
342  thickness, 8, false);
343 
344  text = "template: " + boost::lexical_cast<std::string>((int)_template_keypoints.size());
345  text_size = cv::getTextSize(text, fontFace, text_scale, thickness, &baseLine);
346  x = stack_img.size().width - text_size.width;
347  y += text_size.height + thickness + 10; // 10pt pading
348  cv::putText (stack_img, text, cv::Point(x, y),
349  fontFace, text_scale, CV_RGB(0, 255, 0),
350  thickness, 8, false);
351  }
352 
353  // draw correspondances
354  ROS_INFO(" _correspondances.size: %d", (int)_correspondances.size());
355  for (int j = 0; j < (int)_correspondances.size(); j++){
356  cv::circle(stack_img, cv::Point2f(_correspondances.at(j).x, _correspondances.at(j).y + _template_img.size().height),
357  8, CV_RGB(255,0,0), -1);
358  }
359 
360  ROS_INFO(" inlier_sum:%d min_lier:%d", inlier_sum, min_inlier((int)pt2.size(), 4, 0.10, 0.01));
361  if ((cv::countNonZero( H ) == 0) || (inlier_sum < min_inlier((int)pt2.size(), 4, 0.10, 0.01))){
362  ROS_INFO(" inlier_sum < min_lier return-from estimate-od");
363  if( _window_name != "" )
364  cv::imshow(_window_name, stack_img);
365  return false;
366  }
367 
368  std::string _type;
369  char chr[20];
370 
371  // number of match points
372  sprintf(chr, "%d", (int)pt2.size());
373  _type = _matching_frame + "_" + std::string(chr);
374 
375  sprintf(chr, "%d", inlier_sum);
376  _type = _type + "_" + std::string(chr);
377 
378  cv::Point2f corners2d[4] = {cv::Point2f(0,0),
379  cv::Point2f(_original_width_size,0),
380  cv::Point2f(_original_width_size,_original_height_size),
381  cv::Point2f(0,_original_height_size)};
382  cv::Mat corners2d_mat (cv::Size(4, 1), CV_32FC2, corners2d);
383  cv::Point3f corners3d[4] = {cv::Point3f(0,0,0),
384  cv::Point3f(0,_template_width,0),
385  cv::Point3f(_template_height,_template_width,0),
386  cv::Point3f(_template_height,0,0)};
387  cv::Mat corners3d_mat (cv::Size(4, 1), CV_32FC3, corners3d);
388 
389  cv::Mat corners2d_mat_trans;
390 
391  cv::perspectiveTransform (corners2d_mat, corners2d_mat_trans, H);
392 
393  double fR3[3], fT3[3];
394  cv::Mat rvec(3, 1, CV_64FC1, fR3);
395  cv::Mat tvec(3, 1, CV_64FC1, fT3);
396  cv::Mat zero_distortion_mat = cv::Mat::zeros(4, 1, CV_64FC1);
397 
398  cv::solvePnP (corners3d_mat, corners2d_mat_trans,
399  pcam.intrinsicMatrix(),
400  zero_distortion_mat,//if unrectified: pcam.distortionCoeffs()
401  rvec, tvec);
402 
403  tf::Transform checktf, resulttf;
404 
405  checktf.setOrigin( tf::Vector3(fT3[0], fT3[1], fT3[2] ) );
406 
407  double rx = fR3[0], ry = fR3[1], rz = fR3[2];
408  tf::Quaternion quat;
409  double angle = cv::norm(rvec);
410  quat.setRotation(tf::Vector3(rx/angle, ry/angle, rz/angle), angle);
411  checktf.setRotation( quat );
412 
413  resulttf = checktf * _relativepose;
414 
415  ROS_INFO( " tx: (%0.2lf,%0.2lf,%0.2lf) rx: (%0.2lf,%0.2lf,%0.2lf)",
416  resulttf.getOrigin().getX(),
417  resulttf.getOrigin().getY(),
418  resulttf.getOrigin().getZ(),
419  resulttf.getRotation().getAxis().x() * resulttf.getRotation().getAngle(),
420  resulttf.getRotation().getAxis().y() * resulttf.getRotation().getAngle(),
421  resulttf.getRotation().getAxis().z() * resulttf.getRotation().getAngle());
422 
423  o6p->pose.position.x = resulttf.getOrigin().getX();
424  o6p->pose.position.y = resulttf.getOrigin().getY();
425  o6p->pose.position.z = resulttf.getOrigin().getZ();
426  o6p->pose.orientation.w = resulttf.getRotation().w();
427  o6p->pose.orientation.x = resulttf.getRotation().x();
428  o6p->pose.orientation.y = resulttf.getRotation().y();
429  o6p->pose.orientation.z = resulttf.getRotation().z();
430  o6p->type = _matching_frame; // _type
431 
432  // draw 3d cube model
433  std::vector<cv::Point2f> projected_top;
434  {
435  tf::Vector3 coords[8] = {tf::Vector3(0,0,0),
436  tf::Vector3(0, _template_width, 0),
437  tf::Vector3(_template_height, _template_width,0),
438  tf::Vector3(_template_height, 0, 0),
439  tf::Vector3(0, 0, -0.03),
440  tf::Vector3(0, _template_width, -0.03),
441  tf::Vector3(_template_height, _template_width, -0.03),
442  tf::Vector3(_template_height, 0, -0.03)};
443 
444  projected_top = std::vector<cv::Point2f>(8);
445 
446  for(int i=0; i<8; i++) {
447  coords[i] = checktf * coords[i];
448  cv::Point3f pt(coords[i].getX(), coords[i].getY(), coords[i].getZ());
449  projected_top[i] = pcam.project3dToPixel(pt);
450  }
451  }
452 
453  { // check if the matched region does not too big or too small
454  float max_x, max_y, min_x, min_y;
455  max_x = max_y = -1e9;
456  min_x = min_y = 1e9;
457  for (int j = 0; j < 4; j++){
458  cv::Point2f pt = corners2d_mat_trans.at<cv::Point2f>(0,j);
459  max_x = std::max(max_x, pt.x), max_y = std::max(max_y, pt.y);
460  min_x = std::min(min_x, pt.x), min_y = std::min(min_y, pt.y);
461  }
462  if((max_x - min_x) < 30 || (max_y - min_y) < 30 ||
463  src_img.rows < (max_x - min_x)/2 || src_img.cols < (max_y - min_y)/2){
464  ROS_INFO(" matched region is too big or small (2< && <30) width:%f height:%f return-from estimate-od", max_x - min_x, max_y - min_y);
465  return false;
466  }
467  }
468 
469  double err_sum = 0;
470  bool err_success = true;
471  for (int j = 0; j < 4; j++){
472  double err = sqrt(pow((corners2d_mat_trans.at<cv::Point2f>(0,j).x - projected_top.at(j).x), 2) +
473  pow((corners2d_mat_trans.at<cv::Point2f>(0,j).y - projected_top.at(j).y), 2));
474  err_sum += err;
475  }
476  if (err_sum > err_thr){
477  ROS_INFO(" err_sum:%f > err_thr:%f return-from estimate-od", err_sum, err_thr);
478  err_success = false;
479  } else {
480  o6p->reliability = 1.0 - (err_sum / err_thr);
481  }
482  // draw lines around the detected object
483  for (int j = 0; j < corners2d_mat_trans.cols; j++){
484  cv::Point2f p1(corners2d_mat_trans.at<cv::Point2f>(0,j).x,
485  corners2d_mat_trans.at<cv::Point2f>(0,j).y+_template_img.rows);
486  cv::Point2f p2(corners2d_mat_trans.at<cv::Point2f>(0,(j+1)%corners2d_mat_trans.cols).x,
487  corners2d_mat_trans.at<cv::Point2f>(0,(j+1)%corners2d_mat_trans.cols).y+_template_img.rows);
488  cv::line (stack_img, p1, p2, CV_RGB(255, 0, 0),
489  (err_success?4:1), // width
490  CV_AA, 0);
491  }
492 
493  // draw 3d cube model
494  if(projected_top.size() == 8) { // verify, the size is 8
495  int cnt = 8;
496  std::vector<cv::Point2f> ps(cnt);
497  for(int i=0; i<cnt; i++)
498  ps[i] = cv::Point2f(projected_top[i].x,
499  projected_top[i].y+_template_img.rows);
500 
501  int draw_width = ( err_success ? 3 : 1);
502  for(int i=0; i<4; i++) {
503  cv::line (stack_img, ps[i], ps[(i+1)%4], CV_RGB(0, 0, 255), draw_width, CV_AA, 0);
504  cv::line (stack_img, ps[i+4], ps[(i+1)%4+4], CV_RGB(0, 0, 255), draw_width, CV_AA, 0);
505  cv::line (stack_img, ps[i], ps[i+4], CV_RGB(0, 0, 255), draw_width, CV_AA, 0);
506  }
507  }
508 
509  // draw coords
510  if ( err_success )
511  {
512  tf::Vector3 coords[4] = { tf::Vector3(0,0,0),
513  tf::Vector3(0.05,0,0),
514  tf::Vector3(0,0.05,0),
515  tf::Vector3(0,0,0.05)};
516  std::vector<cv::Point2f> ps(4);
517 
518  for(int i=0; i<4; i++) {
519  coords[i] = resulttf * coords[i];
520  cv::Point3f pt(coords[i].getX(), coords[i].getY(), coords[i].getZ());
521  ps[i] = pcam.project3dToPixel(pt);
522  ps[i].y += _template_img.rows; // draw on camera image
523  }
524 
525  cv::line (stack_img, ps[0], ps[1], CV_RGB(255, 0, 0), 3, CV_AA, 0);
526  cv::line (stack_img, ps[0], ps[2], CV_RGB(0, 255, 0), 3, CV_AA, 0);
527  cv::line (stack_img, ps[0], ps[3], CV_RGB(0, 0, 255), 3, CV_AA, 0);
528  }
529 
530  // write text on image
531  {
532  std::string text;
533  int x, y;
534  text = "error: " + boost::lexical_cast<std::string>(err_sum);
535  x = stack_img.size().width - 16*17*text_scale; // 16pt * 17
536  y = _template_img.size().height - (16 + 2)*text_scale*6;
537  cv::putText (stack_img, text, cv::Point(x, y),
538  0, text_scale, CV_RGB(0, 255, 0),
539  2, 8, false);
540  ROS_INFO(" %s < %f (threshold)", text.c_str(), err_thr );
541  }
542  // for debug window
543  if( _window_name != "" )
544  cv::imshow(_window_name, stack_img);
545 
546  return err_success;
547  }
548 }; // the end of difinition of class Matching_Template
549 
550 
552 {
558  ros::Publisher _pub, _pub_agg, _pub_pose;
562  double _th_step;
563  double _phi_step;
564  bool _autosize;
565  double _err_thr;
566  static std::vector<Matching_Template *> _templates;
568  bool pnod;
570  bool _viewer;
571 
572 public:
573  PointPoseExtractor() : it(ros::NodeHandle("~")) {
574  // _sub = _n.subscribe("ImageFeature0D", 1,
575  // &PointPoseExtractor::imagefeature_cb, this);
576  _client = _n.serviceClient<posedetection_msgs::Feature0DDetect>("Feature0DDetect");
577  _pub = _n.advertise<posedetection_msgs::ObjectDetection>("ObjectDetection", 10);
578  _pub_agg = _n.advertise<posedetection_msgs::ObjectDetection>("ObjectDetection_agg", 10);
579  _pub_pose = _n.advertise<geometry_msgs::PoseStamped>("object_pose", 10);
580  _debug_pub = it.advertise("debug_image", 1);
581  _server = _n.advertiseService("SetTemplate", &PointPoseExtractor::settemplate_cb, this);
582  _initialized = false;
583  }
584 
586  _sub.shutdown();
587  _client.shutdown();
588  _pub.shutdown();
589  _pub_agg.shutdown();
590  }
591 
593  cv::Mat H;
594  cv::Mat tmp_template, tmp_warp_template;
595  std::vector<cv::Point2f>pt1, pt2;
596  double width, height;
597  std::string filename;
598  std::cout << "input template's [width]" << std::endl;
599  std::cin >> width;
600  std::cout << "input template's [height]" << std::endl;
601  std::cin >> height;
602  std::cout << "input template's [filename]" << std::endl;
603  std::cin >> filename;
604 
605  for (int i = 0; i < 4; i++){
606  pt1.push_back(cv::Point2d((int)mt->_correspondances.at(i).x,
607  (int)mt->_correspondances.at(i).y + mt->_template_img.size().height));
608  }
609  cv::Rect rect = cv::boundingRect(cv::Mat(pt1));
610  double scale = std::max(width, height) / 500.0;
611  int iwidth = width / scale, iheight = height / scale;
612  pt2.push_back(cv::Point2d(0,0));
613  pt2.push_back(cv::Point2d(iwidth,0));
614  pt2.push_back(cv::Point2d(iwidth,iheight));
615  pt2.push_back(cv::Point2d(0, iheight));
616  H = cv::findHomography(cv::Mat(pt1), cv::Mat(pt2));
617 
618  cv::getRectSubPix(mt->_previous_stack_img, rect.size(),
619  cv::Point2f((rect.tl().x + rect.br().x)/2.0,(rect.tl().y + rect.br().y)/2.0),
620  tmp_template);
621  cv::warpPerspective(mt->_previous_stack_img, tmp_warp_template, H, cv::Size(iwidth, iheight));
622 
623  try {
624  cv::imwrite(filename,tmp_template);
625  boost::filesystem::path fname(filename);
626  std::stringstream ss;
627  ss << fname.stem() << "_wrap" << fname.extension();
628  cv::imwrite(ss.str(),tmp_warp_template);
629  }catch (cv::Exception e) {
630  std::cerr << e.what() << std::endl;
631  }
632 
633  for (int i = 0; i < (int)pt1.size(); i++){
634  pt2.push_back(cv::Point2d((int)pt1.at(i).x - rect.x,
635  (int)pt1.at(i).y - rect.y - mt->_template_img.size().height));
636  }
637  // cv::Mat mask_img = cv::Mat::zeros(tmp_template.size(), CV_8UC3);
638  // cv::fillConvexPoly(mask_img, pt2.begin(), (int)pt2.size(), CV_RGB(255, 255, 255));
639 
640  // cv::namedWindow("hoge", 1);
641  // cv::imshow("hoge", mask_img);
642 
643  cv::Mat M = (cv::Mat_<double>(3,3) << 1,0,0, 0,1,0, 0,0,1);
644  std::string window_name = "sample" + boost::lexical_cast<std::string>((int)_templates.size());
645 
646  Matching_Template* tmplt =
647  new Matching_Template (tmp_warp_template, "sample",
648  tmp_warp_template.size().width, tmp_warp_template.size().height,
649  width, height,
650  tf::Transform(tf::Quaternion(0, 0, 0, 1), tf::Vector3(0, 0, 0)),
651  M,
654  _first_sample_change ? window_name : mt->_window_name,
655  cv::getWindowProperty(mt->_window_name, CV_WND_PROP_AUTOSIZE));
656 
657  mt->_correspondances.clear();
658  _templates.push_back(tmplt);
659  cv::namedWindow(_first_sample_change ? window_name : mt->_window_name,
660  cv::getWindowProperty(mt->_window_name, CV_WND_PROP_AUTOSIZE));
661  cvSetMouseCallback (_first_sample_change ? window_name.c_str() : mt->_window_name.c_str(),
662  &cvmousecb, static_cast<void *>(_templates.back()));
663  _first_sample_change = true;
664  }
665 
666  static void cvmousecb (int event, int x, int y, int flags, void* param){
667  Matching_Template *mt = (Matching_Template*)param;
668  // std::cerr << "mousecb_ -> " << mt << std::endl;
669  switch (event){
670  case CV_EVENT_LBUTTONUP: {
671  cv::Point2d pt(x,y - (int)mt->_template_img.size().height);
672  ROS_INFO("add correspondence (%d, %d)", (int)pt.x, (int)pt.y);
673  mt->_correspondances.push_back(pt);
674  if ((int)mt->_correspondances.size() >= 4){
675  make_template_from_mousecb(mt);
676  mt->_correspondances.clear();
677  ROS_INFO("reset");
678  }
679  break;
680  }
681  case CV_EVENT_RBUTTONUP: {
682  mt->_correspondances.clear();
683  ROS_INFO("reset");
684  break;
685  }
686  }
687  }
688 
689 
690  void initialize () {
691  std::string matching_frame;
692  std::string _pose_str;
693  double template_width;
694  double template_height;
695  std::string template_filename;
696  std::string window_name;
697  ros::NodeHandle local_nh("~");
698 
699  local_nh.param("child_frame_id", matching_frame, std::string("matching"));
700  local_nh.param("object_width", template_width, 0.06);
701  local_nh.param("object_height", template_height, 0.0739);
702  local_nh.param("relative_pose", _pose_str, std::string("0 0 0 0 0 0 1"));
703  std::string default_template_file_name;
704  try {
705 #ifdef ROSPACK_EXPORT
707  rospack::Package *p = rp.get_pkg("jsk_perception");
708  if (p!=NULL) default_template_file_name = p->path + std::string("/sample/opencv-logo2.png");
709 #else
710  rospack::Rospack rp;
711  std::vector<std::string> search_path;
712  rp.getSearchPathFromEnv(search_path);
713  rp.crawl(search_path, 1);
714  std::string path;
715  if (rp.find("jsk_perception",path)==true) default_template_file_name = path + std::string("/sample/opencv-logo2.png");
716 #endif
717  } catch (std::runtime_error &e) {
718  }
719  local_nh.param("template_filename", template_filename, default_template_file_name);
720  local_nh.param("reprojection_threshold", _reprojection_threshold, 3.0);
721  local_nh.param("distanceratio_threshold", _distanceratio_threshold, 0.49);
722  local_nh.param("error_threshold", _err_thr, 50.0);
723  local_nh.param("theta_step", _th_step, 5.0);
724  local_nh.param("phi_step", _phi_step, 5.0);
725  local_nh.param("viewer_window", _viewer, true);
726  local_nh.param("window_name", window_name, std::string("sample1"));
727  local_nh.param("autosize", _autosize, false);
728  local_nh.param("publish_null_object_detection", pnod, false);
729 
730  _first_sample_change = false;
731 
732  // make one template
733  cv::Mat template_img;
734  template_img = cv::imread (template_filename, 1);
735  if ( template_img.empty()) {
736  ROS_ERROR ("template picture <%s> cannot read. template picture is not found or uses unsuported format.", template_filename.c_str());
737  return;
738  }
739 
740  // relative pose
741  std::vector<double> rv(7);
742  std::istringstream iss(_pose_str);
744  for(int i=0; i<6; i++)
745  iss >> rv[i];
746 
747  if (iss.eof()) { // use rpy expression
748  transform = tf::Transform(tf::createQuaternionFromRPY(rv[3], rv[4], rv[5]),
749  tf::Vector3(rv[0], rv[1], rv[2]));
750  } else { // use quaternion expression
751  iss >> rv[6];
752  transform = tf::Transform(tf::Quaternion(rv[3], rv[4], rv[5], rv[6]),
753  tf::Vector3(rv[0], rv[1], rv[2]));
754  }
755 
756  // add the image to template list
757  add_new_template(template_img, window_name, transform,
758  template_width, template_height, _th_step, _phi_step);
759 
760  } // initialize
761 
762 
763  cv::Mat make_homography(cv::Mat src, cv::Mat rvec, cv::Mat tvec,
764  double template_width, double template_height, cv::Size &size){
765 
766  cv::Point3f coner[4] = {cv::Point3f(-(template_width/2.0), -(template_height/2.0),0),
767  cv::Point3f(template_width/2.0,-(template_height/2.0),0),
768  cv::Point3f(template_width/2.0,template_height/2.0,0),
769  cv::Point3f(-(template_width/2.0),template_height/2.0,0)};
770  cv::Mat coner_mat (cv::Size(4, 1), CV_32FC3, coner);
771  std::vector<cv::Point2f> coner_img_points;
772 
773  cv::Mat zero_distortion_mat = cv::Mat::zeros(4, 1, CV_64FC1);
774  cv::projectPoints(coner_mat, rvec, tvec,
775  pcam.intrinsicMatrix(),
776  zero_distortion_mat, // pcam.distortionCoeffs(),
777  coner_img_points);
778  float x_min = 10000, x_max = 0;
779  float y_min = 10000, y_max = 0;
780  for (int i = 0; i < (int)coner_img_points.size(); i++){
781  x_min = std::min(x_min, coner_img_points.at(i).x);
782  x_max = std::max(x_max, coner_img_points.at(i).x);
783  y_min = std::min(y_min, coner_img_points.at(i).y);
784  y_max = std::max(y_max, coner_img_points.at(i).y);
785  }
786 
787  std::vector<cv::Point2f> coner_img_points_trans;
788  for (int i = 0; i < (int)coner_img_points.size(); i++){
789  cv::Point2f pt_tmp(coner_img_points.at(i).x - x_min,
790  coner_img_points.at(i).y - y_min);
791  coner_img_points_trans.push_back(pt_tmp);
792  }
793 
794  cv::Point2f template_points[4] = {cv::Point2f(0,0),
795  cv::Point2f(src.size().width,0),
796  cv::Point2f(src.size().width,src.size().height),
797  cv::Point2f(0,src.size().height)};
798  cv::Mat template_points_mat (cv::Size(4, 1), CV_32FC2, template_points);
799 
800  size = cv::Size(x_max - x_min, y_max - y_min);
801  return cv::findHomography(template_points_mat, cv::Mat(coner_img_points_trans), 0, 3);
802  }
803 
804 
805  int make_warped_images (cv::Mat src, std::vector<cv::Mat> &imgs,
806  std::vector<cv:: Mat> &Mvec,
807  double template_width, double template_height,
808  double th_step, double phi_step){
809 
810  std::vector<cv::Size> sizevec;
811 
812  for (int i = (int)((-3.14/4.0)/th_step); i*th_step < 3.14/4.0; i++){
813  for (int j = (int)((-3.14/4.0)/phi_step); j*phi_step < 3.14/4.0; j++){
814  double fR3[3], fT3[3];
815  cv::Mat rvec(3, 1, CV_64FC1, fR3);
816  cv::Mat tvec(3, 1, CV_64FC1, fT3);
817 
818  tf::Quaternion quat;
819  quat.setEuler(0, th_step*i, phi_step*j);
820  fR3[0] = quat.getAxis().x() * quat.getAngle();
821  fR3[1] = quat.getAxis().y() * quat.getAngle();
822  fR3[2] = quat.getAxis().z() * quat.getAngle();
823  fT3[0] = 0;
824  fT3[1] = 0;
825  fT3[2] = 0.5;
826 
827  cv::Mat M;
828  cv::Size size;
829  M = make_homography(src, rvec, tvec, template_width, template_height, size);
830  Mvec.push_back(M);
831  sizevec.push_back(size);
832  }
833  }
834 
835  for (int i = 0; i < (int)Mvec.size(); i++){
836  cv::Mat dst;
837  cv::warpPerspective(src, dst, Mvec.at(i), sizevec.at(i),
838  CV_INTER_LINEAR, IPL_BORDER_CONSTANT, 0);
839  imgs.push_back(dst);
840  }
841  return 0;
842  }
843 
844  bool add_new_template(cv::Mat img, std::string typestr, tf::Transform relative_pose,
845  double template_width, double template_height,
846  double theta_step=5.0, double phi_step=5.0)
847  {
848  std::vector<cv::Mat> imgs;
849  std::vector<cv::Mat> Mvec;
850  make_warped_images(img, imgs, Mvec,
851  template_width, template_height, theta_step, phi_step);
852 
853  for (int i = 0; i < (int)imgs.size(); i++){
854  std::string type = typestr;
855  if(imgs.size() > 1) {
856  char chr[20];
857  sprintf(chr, "%d", i);
858  type += "_" + std::string(chr);
859  }
860 
861  Matching_Template * tmplt =
862  new Matching_Template(imgs.at(i), type,
863  img.size().width, img.size().height,
864  template_width, template_height,
865  relative_pose, Mvec.at(i),
868  (_viewer ? type : ""), _autosize);
869  _templates.push_back(tmplt);
870  if( _viewer )
871  {
872  cv::namedWindow(type, _autosize ? CV_WINDOW_AUTOSIZE : 0);
873  cvSetMouseCallback (type.c_str(), &cvmousecb, static_cast<void *>(_templates.back()));
874  }
875  }
876  return true;
877  }
878 
879  bool settemplate_cb (jsk_perception::SetTemplate::Request &req,
880  jsk_perception::SetTemplate::Response &res){
881  cv_bridge::CvImagePtr cv_ptr;
882  cv_ptr = cv_bridge::toCvCopy(req.image, enc::BGR8);
883  cv::Mat img(cv_ptr->image);
884 
885  tf::Transform transform(tf::Quaternion(req.relativepose.orientation.x,
886  req.relativepose.orientation.y,
887  req.relativepose.orientation.z,
888  req.relativepose.orientation.w),
889  tf::Vector3(req.relativepose.position.x,
890  req.relativepose.position.y,
891  req.relativepose.position.z));
892 
893  // add the image to template list
894  add_new_template(img, req.type, transform,
895  req.dimx, req.dimy, 1.0, 1.0);
896  return true;
897  }
898 
899 
900  void imagefeature_cb (const posedetection_msgs::ImageFeature0DConstPtr& msg){
901  std::vector<cv::KeyPoint> sourceimg_keypoints;
902  cv::Mat sourceimg_descriptors;
903  std::vector<posedetection_msgs::Object6DPose> vo6p;
904  posedetection_msgs::ObjectDetection od;
905 
906  cv_bridge::CvImagePtr cv_ptr;
907  cv_ptr = cv_bridge::toCvCopy(msg->image, enc::BGR8);
908  cv::Mat src_img(cv_ptr->image);
909 
910  // from ros messages to keypoint and pin hole camera model
911  features2keypoint (msg->features, sourceimg_keypoints, sourceimg_descriptors);
912  pcam.fromCameraInfo(msg->info);
913  if ( cv::countNonZero(pcam.intrinsicMatrix()) == 0 ) {
914  ROS_FATAL("intrinsic matrix is zero, your camera info looks invalid");
915  }
916  if ( !_initialized ) {
917  // make template images from camera info
918  initialize();
919  std::cerr << "initialize templates done" << std::endl;
920  _initialized = true;
921  }
922 
923  if ( sourceimg_keypoints.size () < 2 ) {
924  ROS_INFO ("The number of keypoints in source image is less than 2");
925  }
926  else {
927  // make KDTree
928  cv::flann::Index *ft = new cv::flann::Index(sourceimg_descriptors, cv::flann::KDTreeIndexParams(1));
929 
930  // matching and detect object
931  ROS_INFO("_templates size: %d", (int)_templates.size());
932  for (int i = 0; i < (int)_templates.size(); i++){
933  posedetection_msgs::Object6DPose o6p;
934 
935  cv::Mat debug_img;
936  if (_templates.at(i)->estimate_od(_client, src_img, sourceimg_keypoints, pcam, _err_thr, debug_img, ft, &o6p))
937  vo6p.push_back(o6p);
938 
939  // for debug Image topic
940  cv_bridge::CvImage out_msg;
941  out_msg.header = msg->image.header;
942  out_msg.encoding = "bgr8";
943  out_msg.image = debug_img;
944  _debug_pub.publish(out_msg.toImageMsg());
945  }
946  delete ft;
947  if (((int)vo6p.size() != 0) || pnod) {
948  od.header.stamp = msg->image.header.stamp;
949  od.header.frame_id = msg->image.header.frame_id;
950  od.objects = vo6p;
951  _pub.publish(od);
952  _pub_agg.publish(od);
953  // Publish result as geometry_msgs/PoseStamped. But it can only contain one object
954  geometry_msgs::PoseStamped pose_msg;
955  pose_msg.header = od.header;
956  pose_msg.pose = od.objects[0].pose;
957  _pub_pose.publish(pose_msg);
958  }
959  }
960  // BOOST_FOREACH(Matching_Template* mt, _templates) {
961  // std::cerr << "templates_ -> " << mt << std::endl;
962  // }
963  cv::waitKey( 10 );
964  }
965 
966  /* if there are subscribers of the output topic -> do work
967  else if -> unregister all topics this node subscribing
968  */
970  {
971  if(_pub.getNumSubscribers() == 0 && _initialized) {
972  if(_sub)
973  _sub.shutdown();
974  static int i = 0;
975  if ( i++ % 100 == 0 ) {
976  ROS_INFO("wait for subscriberes ... %s", _pub.getTopic().c_str());
977  }
978  } else {
979  if(!_sub)
980  _sub = _n.subscribe("ImageFeature0D", 1,
982  }
983  }
984 
985  /* callback for dynamic reconfigure */
986  void dyn_conf_callback(jsk_perception::point_pose_extractorConfig &config,
987  uint32_t level) {
988  std::cout << "id = " << config.template_id << std::endl;
989  std::cout << "lvl = " << level << std::endl;
990  if((int)_templates.size() <= config.template_id) {
991  ROS_WARN("template_id is invalid");
992  config.template_id = 0;
993  if(_templates.size() != 0)
994  config.frame_id = _templates[0]->_matching_frame;
995  } else {
996  Matching_Template* tmpl = _templates[config.template_id];
997  if(config.frame_id == tmpl->_matching_frame) {
998  ROS_WARN("update params");
999  tmpl->_reprojection_threshold = config.reprojection_threshold;
1000  tmpl->_distanceratio_threshold = config.distanceratio_threshold;
1001  _err_thr = config.error_threshold;
1002  } else {
1003  ROS_WARN("get params");
1004  config.frame_id = tmpl->_matching_frame;
1005  config.reprojection_threshold = tmpl->_reprojection_threshold;
1006  config.distanceratio_threshold = tmpl->_distanceratio_threshold;
1007  config.error_threshold = _err_thr;
1008  }
1009  }
1010  }
1011 
1012 }; // the end of definition of class PointPoseExtractor
1013 
1014 
1015 std::vector<Matching_Template *> PointPoseExtractor::_templates;
1016 
1017 int main (int argc, char **argv){
1018  ros::init (argc, argv, "PointPoseExtractor");
1019 
1020  PointPoseExtractor matcher;
1021 
1022  dynamic_reconfigure::Server<jsk_perception::point_pose_extractorConfig> server;
1023  dynamic_reconfigure::Server<jsk_perception::point_pose_extractorConfig>::CallbackType f;
1024  f = boost::bind(&PointPoseExtractor::dyn_conf_callback, &matcher, _1, _2);
1025  server.setCallback(f);
1026 
1027  ros::Rate r(10); // 10 hz
1028  while(ros::ok()) {
1029  ros::spinOnce();
1030  matcher.check_subscribers();
1031  r.sleep();
1032  }
1033 
1034  return 0;
1035 }
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
rospack::Rospack rp
const cv::Matx33d & intrinsicMatrix() const
f
ros::ServiceClient _client
static tf::Quaternion createQuaternionFromRPY(double roll, double pitch, double yaw)
#define ROS_FATAL(...)
tfScalar getAngle() const
path
void features2keypoint(posedetection_msgs::Feature0D features, std::vector< cv::KeyPoint > &keypoints, cv::Mat &descriptors)
void publish(const boost::shared_ptr< M > &message) const
ros::ServiceServer _server
def err(line_no, msg)
TFSIMD_FORCE_INLINE const tfScalar & getX() const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
INLINE Rall1d< T, V, S > log(const Rall1d< T, V, S > &arg)
ROSCONSOLE_DECL void initialize()
def convert(filename_in, filename_out, ffmpeg_executable="ffmpeg")
void dyn_conf_callback(jsk_perception::point_pose_extractorConfig &config, uint32_t level)
static std::vector< Matching_Template * > _templates
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
std::string encoding
Publisher advertise(const std::string &base_topic, uint32_t queue_size, bool latch=false)
bool call(MReq &req, MRes &res)
width
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
double y_min
server
Matching_Template(cv::Mat img, std::string matching_frame, int original_width_size, int original_height_size, double template_width, double template_height, tf::Transform relativepose, cv::Mat affine_matrix, double reprojection_threshold, double distanceratio_threshold, std::string window_name, bool autosize)
#define ROS_WARN(...)
int set_template(ros::ServiceClient client)
TFSIMD_FORCE_INLINE const tfScalar & x() const
int make_warped_images(cv::Mat src, std::vector< cv::Mat > &imgs, std::vector< cv::Mat > &Mvec, double template_width, double template_height, double th_step, double phi_step)
bool settemplate_cb(jsk_perception::SetTemplate::Request &req, jsk_perception::SetTemplate::Response &res)
static void make_template_from_mousecb(Matching_Template *mt)
GLfloat angle
TFSIMD_FORCE_INLINE const tfScalar & z() const
void publish(const sensor_msgs::Image &message) const
cv::Mat make_homography(cv::Mat src, cv::Mat rvec, cv::Mat tvec, double template_width, double template_height, cv::Size &size)
image_transport::ImageTransport it
int main(int argc, char **argv)
double sqrt()
image_geometry::PinholeCameraModel pcam
#define ROS_INFO(...)
bool add_new_template(cv::Mat img, std::string typestr, tf::Transform relative_pose, double template_width, double template_height, double theta_step=5.0, double phi_step=5.0)
bool fromCameraInfo(const sensor_msgs::CameraInfo &msg)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
std::vector< cv::Point2d > _correspondances
Vector3 getAxis() const
CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
ROSCPP_DECL bool ok()
TFSIMD_FORCE_INLINE const tfScalar & y() const
x
static void cvmousecb(int event, int x, int y, int flags, void *param)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
y
image_transport::Publisher _debug_pub
std::string filename
Definition: linemod.cpp:198
#define ROS_WARN_STREAM(args)
bool getSearchPathFromEnv(std::vector< std::string > &sp)
pointer MAX(context *ctx, int n, argv)
void setEuler(const tfScalar &yaw, const tfScalar &pitch, const tfScalar &roll)
bool sleep()
INLINE Rall1d< T, V, S > exp(const Rall1d< T, V, S > &arg)
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
bool _first_sample_change
uint32_t getNumSubscribers() const
#define ROS_INFO_STREAM(args)
void crawl(std::vector< std::string > search_path, bool force)
int min_inlier(int n, int m, double p_badsupp, double p_badxform)
T sum(T *pf, int length)
#define NULL
bool find(const std::string &name, std::string &path)
std::string getService()
std::vector< cv::KeyPoint > _template_keypoints
cv::Point2d project3dToPixel(const cv::Point3d &xyz) const
bool estimate_od(ros::ServiceClient client, cv::Mat src_img, std::vector< cv::KeyPoint > sourceimg_keypoints, image_geometry::PinholeCameraModel pcam, double err_thr, cv::Mat &stack_img, cv::flann::Index *ft, posedetection_msgs::Object6DPose *o6p)
std::string getTopic() const
TFSIMD_FORCE_INLINE const tfScalar & getZ() const
r
void imagefeature_cb(const posedetection_msgs::ImageFeature0DConstPtr &msg)
height
ROSCPP_DECL void spinOnce()
void setRotation(const Vector3 &axis, const tfScalar &angle)
std::vector< cv::Point2d > * correspondances()
#define ROS_ERROR(...)
TFSIMD_FORCE_INLINE void setOrigin(const Vector3 &origin)
sensor_msgs::ImagePtr toImageMsg() const
TFSIMD_FORCE_INLINE const tfScalar & getY() const
double y_max
std_msgs::Header header


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