00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <ros/ros.h>
00037 #include <rospack/rospack.h>
00038 #include <opencv/highgui.h>
00039 #include <cv_bridge/cv_bridge.h>
00040 #include <opencv/cv.hpp>
00041 #include <posedetection_msgs/Feature0DDetect.h>
00042 #include <posedetection_msgs/ImageFeature0D.h>
00043 #include <posedetection_msgs/ObjectDetection.h>
00044 #include <posedetection_msgs/Object6DPose.h>
00045 #include <geometry_msgs/PoseStamped.h>
00046 #include <geometry_msgs/Pose.h>
00047 #include <geometry_msgs/Quaternion.h>
00048 #include <sensor_msgs/image_encodings.h>
00049 #include <image_transport/image_transport.h>
00050 #include <image_geometry/pinhole_camera_model.h>
00051 #include <tf/tf.h>
00052 #include <boost/shared_ptr.hpp>
00053 #include <boost/foreach.hpp>
00054 #include <boost/filesystem.hpp>
00055 #include <vector>
00056 #include <sstream>
00057 #include <iostream>
00058 #include <dynamic_reconfigure/server.h>
00059 #include <jsk_perception/point_pose_extractorConfig.h>
00060 #include <jsk_perception/SetTemplate.h>
00061 #include <jsk_topic_tools/log_utils.h>
00062 namespace enc = sensor_msgs::image_encodings;
00063
00064 bool _first_sample_change;
00065
00066 void features2keypoint (posedetection_msgs::Feature0D features,
00067 std::vector<cv::KeyPoint>& keypoints,
00068 cv::Mat& descriptors){
00069 keypoints.resize(features.scales.size());
00070 descriptors.create(features.scales.size(),features.descriptor_dim,CV_32FC1);
00071 std::vector<cv::KeyPoint>::iterator keypoint_it = keypoints.begin();
00072 for ( int i=0; keypoint_it != keypoints.end(); ++keypoint_it, ++i ) {
00073 *keypoint_it = cv::KeyPoint(cv::Point2f(features.positions[i*2+0],
00074 features.positions[i*2+1]),
00075 features.descriptor_dim,
00076 features.orientations[i],
00077 0,
00078 features.scales[i]
00079 );
00080 for (int j = 0; j < features.descriptor_dim; j++){
00081 descriptors.at<float>(i,j) =
00082 features.descriptors[i*features.descriptor_dim+j];
00083 }
00084 }
00085 }
00086
00087
00088 class Matching_Template
00089 {
00090 public:
00091 std::string _matching_frame;
00092 cv::Mat _template_img;
00093 std::vector<cv::KeyPoint> _template_keypoints;
00094 cv::Mat _template_descriptors;
00095 int _original_width_size;
00096 int _original_height_size;
00097 double _template_width;
00098 double _template_height;
00099 tf::Transform _relativepose;
00100 cv::Mat _affine_matrix;
00101 std::string _window_name;
00102
00103 double _reprojection_threshold;
00104
00105 double _distanceratio_threshold;
00106 std::vector<cv::Point2d> _correspondances;
00107 cv::Mat _previous_stack_img;
00108
00109 Matching_Template(){
00110 }
00111 Matching_Template(cv::Mat img,
00112 std::string matching_frame,
00113 int original_width_size,
00114 int original_height_size,
00115 double template_width,
00116 double template_height,
00117 tf::Transform relativepose,
00118 cv::Mat affine_matrix,
00119 double reprojection_threshold,
00120 double distanceratio_threshold,
00121 std::string window_name,
00122 bool autosize){
00123
00124 _template_img = img.clone();
00125 _matching_frame = matching_frame;
00126 _original_width_size = original_width_size;
00127 _original_height_size = original_height_size;
00128 _template_width = template_width;
00129 _template_height = template_height;
00130 _relativepose = relativepose;
00131 _affine_matrix = affine_matrix;
00132 _window_name = window_name;
00133 _reprojection_threshold = reprojection_threshold;
00134 _distanceratio_threshold = distanceratio_threshold;
00135 _template_keypoints.clear();
00136 _correspondances.clear();
00137
00138 }
00139
00140
00141 virtual ~Matching_Template(){
00142 std::cerr << "delete " << _window_name << std::endl;
00143 }
00144
00145
00146 std::string get_window_name(){
00147 return _window_name;
00148 }
00149
00150 std::vector<cv::Point2d>* correspondances(){
00151 return &_correspondances;
00152 }
00153
00154 bool check_template (){
00155 if (_template_img.empty() && _template_keypoints.size() == 0 &&
00156 _template_descriptors.empty()){
00157 return false;
00158 }
00159 else {
00160 return true;
00161 }
00162 }
00163
00164
00165 int set_template(ros::ServiceClient client){
00166 posedetection_msgs::Feature0DDetect srv;
00167
00168 if ( _template_img.empty()) {
00169 ROS_ERROR ("template picture is empty.");
00170 return -1;
00171 }
00172 ROS_INFO_STREAM("read template image and call " << client.getService() << " service");
00173 cv_bridge::CvImage cv_img;
00174 cv_img.image = cv::Mat(_template_img);
00175 cv_img.encoding = std::string("bgr8");
00176 srv.request.image = *(cv_img.toImageMsg());
00177 if (client.call(srv)) {
00178 ROS_INFO_STREAM("get features with " << srv.response.features.scales.size() << " descriptoins");
00179 features2keypoint (srv.response.features, _template_keypoints, _template_descriptors);
00180
00181
00182 cv::Mat M_inv;
00183 cv::Mat dst;
00184 cv::invert(_affine_matrix, M_inv);
00185
00186
00187
00188
00189
00190 for (int i = 0; i < (int)_template_keypoints.size(); i++){
00191 cv::Point2f pt;
00192 cv::Mat pt_mat(cv::Size(1,1), CV_32FC2, &pt);
00193 cv::Mat pt_src_mat(cv::Size(1,1), CV_32FC2, &_template_keypoints.at(i).pt);
00194 cv::perspectiveTransform (pt_src_mat, pt_mat, M_inv);
00195 _template_keypoints.at(i).pt = pt_mat.at<cv::Point2f>(0,0);
00196 }
00197
00198
00199 return 0;
00200 } else {
00201 ROS_ERROR("Failed to call service Feature0DDetect");
00202 return 1;
00203 }
00204 }
00205
00206
00207 double log_fac( int n )
00208 {
00209 static std::vector<double> slog_table;
00210 int osize = slog_table.size();
00211 if(osize <= n){
00212 slog_table.resize(n+1);
00213 if(osize == 0){
00214 slog_table[0] = -1;
00215 slog_table[1] = log(1.0);
00216 osize = 2;
00217 }
00218 for(int i = osize; i <= n; i++ ){
00219 slog_table[i] = slog_table[i-1] + log(i);
00220 }
00221 }
00222 return slog_table[n];
00223 }
00224
00225 int min_inlier( int n, int m, double p_badsupp, double p_badxform )
00226 {
00227 double pi, sum;
00228 int i, j;
00229 double lp_badsupp = log( p_badsupp );
00230 double lp_badsupp1 = log( 1.0 - p_badsupp );
00231 for( j = m+1; j <= n; j++ ){
00232 sum = 0;
00233 for( i = j; i <= n; i++ ){
00234 pi = (i-m) * lp_badsupp + (n-i+m) * lp_badsupp1 +
00235 log_fac( n - m ) - log_fac( i - m ) - log_fac( n - i );
00236 sum += exp( pi );
00237 }
00238 if( sum < p_badxform )
00239 break;
00240 }
00241 return j;
00242 }
00243
00244
00245 bool estimate_od (ros::ServiceClient client, cv::Mat src_img,
00246 std::vector<cv::KeyPoint> sourceimg_keypoints,
00247 image_geometry::PinholeCameraModel pcam,
00248 double err_thr, cv::Mat &stack_img,
00249 cv::flann::Index* ft, posedetection_msgs::Object6DPose* o6p){
00250
00251 if ( _template_keypoints.size()== 0 &&
00252 _template_descriptors.empty() ){
00253 set_template(client);
00254 }
00255 if ( _template_keypoints.size()== 0 &&
00256 _template_descriptors.empty() ) {
00257 ROS_ERROR ("Template image was not set.");
00258 return false;
00259 }
00260
00261 cv::Size stack_size = cv::Size(MAX(src_img.cols,_template_img.cols),
00262 src_img.rows+_template_img.rows);
00263 stack_img = cv::Mat(stack_size,CV_8UC3);
00264 stack_img = cv::Scalar(0);
00265 cv::Mat stack_img_tmp(stack_img,cv::Rect(0,0,_template_img.cols,_template_img.rows));
00266 cv::add(stack_img_tmp, _template_img, stack_img_tmp);
00267 cv::Mat stack_img_src(stack_img,cv::Rect(0,_template_img.rows,src_img.cols,src_img.rows));
00268 cv::add(stack_img_src, src_img, stack_img_src);
00269 _previous_stack_img = stack_img.clone();
00270
00271
00272 cv::Mat m_indices(_template_descriptors.rows, 2, CV_32S);
00273 cv::Mat m_dists(_template_descriptors.rows, 2, CV_32F);
00274 ft->knnSearch(_template_descriptors, m_indices, m_dists, 2, cv::flann::SearchParams(-1) );
00275
00276
00277 std::vector<cv::Point2f> pt1, pt2;
00278 std::vector<int> queryIdxs,trainIdxs;
00279 for ( unsigned int j = 0; j < _template_keypoints.size(); j++ ) {
00280 if ( m_dists.at<float>(j,0) < m_dists.at<float>(j,1) * _distanceratio_threshold) {
00281 queryIdxs.push_back(j);
00282 trainIdxs.push_back(m_indices.at<int>(j,0));
00283 }
00284 }
00285 if ( queryIdxs.size() == 0 ) {
00286 ROS_WARN_STREAM("could not find matched points with distanceratio(" <<_distanceratio_threshold << ")");
00287 } else {
00288 cv::KeyPoint::convert(_template_keypoints,pt1,queryIdxs);
00289 cv::KeyPoint::convert(sourceimg_keypoints,pt2,trainIdxs);
00290 }
00291
00292 ROS_INFO ("Found %d total matches among %d template keypoints", (int)pt2.size(), (int)_template_keypoints.size());
00293
00294 cv::Mat H;
00295 std::vector<uchar> mask((int)pt2.size());
00296
00297 if ( pt1.size() > 4 ) {
00298
00299 H = cv::findHomography(cv::Mat(pt1), cv::Mat(pt2), mask, CV_RANSAC, _reprojection_threshold);
00300 }
00301
00302
00303 for (int j = 0; j < (int)pt1.size(); j++){
00304 cv::Point2f pt, pt_orig;
00305 cv::Mat pt_mat(cv::Size(1,1), CV_32FC2, &pt);
00306 cv::Mat pt_src_mat(cv::Size(1,1), CV_32FC2, &pt1.at(j));
00307 cv::perspectiveTransform (pt_src_mat, pt_mat, _affine_matrix);
00308 pt_orig = pt_mat.at<cv::Point2f>(0,0);
00309 if ( mask.at(j)){
00310 cv::line(stack_img, pt_orig, pt2.at(j)+cv::Point2f(0,_template_img.rows),
00311 CV_RGB(0,255,0), 1,8,0);
00312 }
00313 else {
00314 cv::line(stack_img, pt_orig, pt2.at(j)+cv::Point2f(0,_template_img.rows),
00315 CV_RGB(255,0,255), 1,8,0);
00316 }
00317 }
00318 int inlier_sum = 0;
00319 for (int k=0; k < (int)mask.size(); k++){
00320 inlier_sum += (int)mask.at(k);
00321 }
00322
00323 double text_scale = 1.5;
00324 {
00325 int fontFace = 0, thickness = 0, baseLine;
00326 int x, y;
00327 cv::Size text_size;
00328 std::string text;
00329
00330 text = "inlier: " + boost::lexical_cast<std::string>((int)inlier_sum) + " / " + boost::lexical_cast<std::string>((int)pt2.size());
00331 text_size = cv::getTextSize(text, fontFace, text_scale, thickness, &baseLine);
00332 x = stack_img.size().width - text_size.width;
00333 y = text_size.height + thickness + 10;
00334 cv::putText (stack_img, text, cv::Point(x, y),
00335 fontFace, text_scale, CV_RGB(0, 255, 0),
00336 thickness, 8, false);
00337
00338 text = "template: " + boost::lexical_cast<std::string>((int)_template_keypoints.size());
00339 text_size = cv::getTextSize(text, fontFace, text_scale, thickness, &baseLine);
00340 x = stack_img.size().width - text_size.width;
00341 y += text_size.height + thickness + 10;
00342 cv::putText (stack_img, text, cv::Point(x, y),
00343 fontFace, text_scale, CV_RGB(0, 255, 0),
00344 thickness, 8, false);
00345 }
00346
00347
00348 ROS_INFO(" _correspondances.size: %d", (int)_correspondances.size());
00349 for (int j = 0; j < (int)_correspondances.size(); j++){
00350 cv::circle(stack_img, cv::Point2f(_correspondances.at(j).x, _correspondances.at(j).y + _template_img.size().height),
00351 8, CV_RGB(255,0,0), -1);
00352 }
00353
00354 ROS_INFO(" inlier_sum:%d min_lier:%d", inlier_sum, min_inlier((int)pt2.size(), 4, 0.10, 0.01));
00355 if ((cv::countNonZero( H ) == 0) || (inlier_sum < min_inlier((int)pt2.size(), 4, 0.10, 0.01))){
00356 ROS_INFO(" inlier_sum < min_lier return-from estimate-od");
00357 if( _window_name != "" )
00358 cv::imshow(_window_name, stack_img);
00359 return false;
00360 }
00361
00362 std::string _type;
00363 char chr[20];
00364
00365
00366 sprintf(chr, "%d", (int)pt2.size());
00367 _type = _matching_frame + "_" + std::string(chr);
00368
00369 sprintf(chr, "%d", inlier_sum);
00370 _type = _type + "_" + std::string(chr);
00371
00372 cv::Point2f corners2d[4] = {cv::Point2f(0,0),
00373 cv::Point2f(_original_width_size,0),
00374 cv::Point2f(_original_width_size,_original_height_size),
00375 cv::Point2f(0,_original_height_size)};
00376 cv::Mat corners2d_mat (cv::Size(4, 1), CV_32FC2, corners2d);
00377 cv::Point3f corners3d[4] = {cv::Point3f(0,0,0),
00378 cv::Point3f(0,_template_width,0),
00379 cv::Point3f(_template_height,_template_width,0),
00380 cv::Point3f(_template_height,0,0)};
00381 cv::Mat corners3d_mat (cv::Size(4, 1), CV_32FC3, corners3d);
00382
00383 cv::Mat corners2d_mat_trans;
00384
00385 cv::perspectiveTransform (corners2d_mat, corners2d_mat_trans, H);
00386
00387 double fR3[3], fT3[3];
00388 cv::Mat rvec(3, 1, CV_64FC1, fR3);
00389 cv::Mat tvec(3, 1, CV_64FC1, fT3);
00390 cv::Mat zero_distortion_mat = cv::Mat::zeros(4, 1, CV_64FC1);
00391
00392 cv::solvePnP (corners3d_mat, corners2d_mat_trans,
00393 pcam.intrinsicMatrix(),
00394 zero_distortion_mat,
00395 rvec, tvec);
00396
00397 tf::Transform checktf, resulttf;
00398
00399 checktf.setOrigin( tf::Vector3(fT3[0], fT3[1], fT3[2] ) );
00400
00401 double rx = fR3[0], ry = fR3[1], rz = fR3[2];
00402 tf::Quaternion quat;
00403 double angle = cv::norm(rvec);
00404 quat.setRotation(tf::Vector3(rx/angle, ry/angle, rz/angle), angle);
00405 checktf.setRotation( quat );
00406
00407 resulttf = checktf * _relativepose;
00408
00409 ROS_INFO( " tx: (%0.2lf,%0.2lf,%0.2lf) rx: (%0.2lf,%0.2lf,%0.2lf)",
00410 resulttf.getOrigin().getX(),
00411 resulttf.getOrigin().getY(),
00412 resulttf.getOrigin().getZ(),
00413 resulttf.getRotation().getAxis().x() * resulttf.getRotation().getAngle(),
00414 resulttf.getRotation().getAxis().y() * resulttf.getRotation().getAngle(),
00415 resulttf.getRotation().getAxis().z() * resulttf.getRotation().getAngle());
00416
00417 o6p->pose.position.x = resulttf.getOrigin().getX();
00418 o6p->pose.position.y = resulttf.getOrigin().getY();
00419 o6p->pose.position.z = resulttf.getOrigin().getZ();
00420 o6p->pose.orientation.w = resulttf.getRotation().w();
00421 o6p->pose.orientation.x = resulttf.getRotation().x();
00422 o6p->pose.orientation.y = resulttf.getRotation().y();
00423 o6p->pose.orientation.z = resulttf.getRotation().z();
00424 o6p->type = _matching_frame;
00425
00426
00427 std::vector<cv::Point2f> projected_top;
00428 {
00429 tf::Vector3 coords[8] = {tf::Vector3(0,0,0),
00430 tf::Vector3(0, _template_width, 0),
00431 tf::Vector3(_template_height, _template_width,0),
00432 tf::Vector3(_template_height, 0, 0),
00433 tf::Vector3(0, 0, -0.03),
00434 tf::Vector3(0, _template_width, -0.03),
00435 tf::Vector3(_template_height, _template_width, -0.03),
00436 tf::Vector3(_template_height, 0, -0.03)};
00437
00438 projected_top = std::vector<cv::Point2f>(8);
00439
00440 for(int i=0; i<8; i++) {
00441 coords[i] = checktf * coords[i];
00442 cv::Point3f pt(coords[i].getX(), coords[i].getY(), coords[i].getZ());
00443 projected_top[i] = pcam.project3dToPixel(pt);
00444 }
00445 }
00446
00447 {
00448 float max_x, max_y, min_x, min_y;
00449 max_x = max_y = -1e9;
00450 min_x = min_y = 1e9;
00451 for (int j = 0; j < 4; j++){
00452 cv::Point2f pt = corners2d_mat_trans.at<cv::Point2f>(0,j);
00453 max_x = std::max(max_x, pt.x), max_y = std::max(max_y, pt.y);
00454 min_x = std::min(min_x, pt.x), min_y = std::min(min_y, pt.y);
00455 }
00456 if((max_x - min_x) < 30 || (max_y - min_y) < 30 ||
00457 src_img.rows < (max_x - min_x)/2 || src_img.cols < (max_y - min_y)/2){
00458 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);
00459 return false;
00460 }
00461 }
00462
00463 double err_sum = 0;
00464 bool err_success = true;
00465 for (int j = 0; j < 4; j++){
00466 double err = sqrt(pow((corners2d_mat_trans.at<cv::Point2f>(0,j).x - projected_top.at(j).x), 2) +
00467 pow((corners2d_mat_trans.at<cv::Point2f>(0,j).y - projected_top.at(j).y), 2));
00468 err_sum += err;
00469 }
00470 if (err_sum > err_thr){
00471 ROS_INFO(" err_sum:%f > err_thr:%f return-from estimate-od", err_sum, err_thr);
00472 err_success = false;
00473 } else {
00474 o6p->reliability = 1.0 - (err_sum / err_thr);
00475 }
00476
00477 for (int j = 0; j < corners2d_mat_trans.cols; j++){
00478 cv::Point2f p1(corners2d_mat_trans.at<cv::Point2f>(0,j).x,
00479 corners2d_mat_trans.at<cv::Point2f>(0,j).y+_template_img.rows);
00480 cv::Point2f p2(corners2d_mat_trans.at<cv::Point2f>(0,(j+1)%corners2d_mat_trans.cols).x,
00481 corners2d_mat_trans.at<cv::Point2f>(0,(j+1)%corners2d_mat_trans.cols).y+_template_img.rows);
00482 cv::line (stack_img, p1, p2, CV_RGB(255, 0, 0),
00483 (err_success?4:1),
00484 CV_AA, 0);
00485 }
00486
00487
00488 if(projected_top.size() == 8) {
00489 int cnt = 8;
00490 std::vector<cv::Point2f> ps(cnt);
00491 for(int i=0; i<cnt; i++)
00492 ps[i] = cv::Point2f(projected_top[i].x,
00493 projected_top[i].y+_template_img.rows);
00494
00495 int draw_width = ( err_success ? 3 : 1);
00496 for(int i=0; i<4; i++) {
00497 cv::line (stack_img, ps[i], ps[(i+1)%4], CV_RGB(0, 0, 255), draw_width, CV_AA, 0);
00498 cv::line (stack_img, ps[i+4], ps[(i+1)%4+4], CV_RGB(0, 0, 255), draw_width, CV_AA, 0);
00499 cv::line (stack_img, ps[i], ps[i+4], CV_RGB(0, 0, 255), draw_width, CV_AA, 0);
00500 }
00501 }
00502
00503
00504 if ( err_success )
00505 {
00506 tf::Vector3 coords[4] = { tf::Vector3(0,0,0),
00507 tf::Vector3(0.05,0,0),
00508 tf::Vector3(0,0.05,0),
00509 tf::Vector3(0,0,0.05)};
00510 std::vector<cv::Point2f> ps(4);
00511
00512 for(int i=0; i<4; i++) {
00513 coords[i] = resulttf * coords[i];
00514 cv::Point3f pt(coords[i].getX(), coords[i].getY(), coords[i].getZ());
00515 ps[i] = pcam.project3dToPixel(pt);
00516 ps[i].y += _template_img.rows;
00517 }
00518
00519 cv::line (stack_img, ps[0], ps[1], CV_RGB(255, 0, 0), 3, CV_AA, 0);
00520 cv::line (stack_img, ps[0], ps[2], CV_RGB(0, 255, 0), 3, CV_AA, 0);
00521 cv::line (stack_img, ps[0], ps[3], CV_RGB(0, 0, 255), 3, CV_AA, 0);
00522 }
00523
00524
00525 {
00526 std::string text;
00527 int x, y;
00528 text = "error: " + boost::lexical_cast<std::string>(err_sum);
00529 x = stack_img.size().width - 16*17*text_scale;
00530 y = _template_img.size().height - (16 + 2)*text_scale*6;
00531 cv::putText (stack_img, text, cv::Point(x, y),
00532 0, text_scale, CV_RGB(0, 255, 0),
00533 2, 8, false);
00534 ROS_INFO(" %s < %f (threshold)", text.c_str(), err_thr );
00535 }
00536
00537 if( _window_name != "" )
00538 cv::imshow(_window_name, stack_img);
00539
00540 return err_success;
00541 }
00542 };
00543
00544
00545 class PointPoseExtractor
00546 {
00547 ros::NodeHandle _n;
00548 image_transport::ImageTransport it;
00549 ros::Subscriber _sub;
00550 ros::ServiceServer _server;
00551 ros::ServiceClient _client;
00552 ros::Publisher _pub, _pub_agg, _pub_pose;
00553 image_transport::Publisher _debug_pub;
00554 double _reprojection_threshold;
00555 double _distanceratio_threshold;
00556 double _th_step;
00557 double _phi_step;
00558 bool _autosize;
00559 double _err_thr;
00560 static std::vector<Matching_Template *> _templates;
00561 image_geometry::PinholeCameraModel pcam;
00562 bool pnod;
00563 bool _initialized;
00564 bool _viewer;
00565
00566 public:
00567 PointPoseExtractor() : it(ros::NodeHandle("~")) {
00568
00569
00570 _client = _n.serviceClient<posedetection_msgs::Feature0DDetect>("Feature0DDetect");
00571 _pub = _n.advertise<posedetection_msgs::ObjectDetection>("ObjectDetection", 10);
00572 _pub_agg = _n.advertise<posedetection_msgs::ObjectDetection>("ObjectDetection_agg", 10);
00573 _pub_pose = _n.advertise<geometry_msgs::PoseStamped>("object_pose", 10);
00574 _debug_pub = it.advertise("debug_image", 1);
00575 _server = _n.advertiseService("SetTemplate", &PointPoseExtractor::settemplate_cb, this);
00576 _initialized = false;
00577 }
00578
00579 virtual ~PointPoseExtractor(){
00580 _sub.shutdown();
00581 _client.shutdown();
00582 _pub.shutdown();
00583 _pub_agg.shutdown();
00584 }
00585
00586 static void make_template_from_mousecb(Matching_Template *mt){
00587 cv::Mat H;
00588 cv::Mat tmp_template, tmp_warp_template;
00589 std::vector<cv::Point2f>pt1, pt2;
00590 double width, height;
00591 std::string filename;
00592 std::cout << "input template's [width]" << std::endl;
00593 std::cin >> width;
00594 std::cout << "input template's [height]" << std::endl;
00595 std::cin >> height;
00596 std::cout << "input template's [filename]" << std::endl;
00597 std::cin >> filename;
00598
00599 for (int i = 0; i < 4; i++){
00600 pt1.push_back(cv::Point2d((int)mt->_correspondances.at(i).x,
00601 (int)mt->_correspondances.at(i).y + mt->_template_img.size().height));
00602 }
00603 cv::Rect rect = cv::boundingRect(cv::Mat(pt1));
00604 double scale = std::max(width, height) / 500.0;
00605 int iwidth = width / scale, iheight = height / scale;
00606 pt2.push_back(cv::Point2d(0,0));
00607 pt2.push_back(cv::Point2d(iwidth,0));
00608 pt2.push_back(cv::Point2d(iwidth,iheight));
00609 pt2.push_back(cv::Point2d(0, iheight));
00610 H = cv::findHomography(cv::Mat(pt1), cv::Mat(pt2));
00611
00612 cv::getRectSubPix(mt->_previous_stack_img, rect.size(),
00613 cv::Point2f((rect.tl().x + rect.br().x)/2.0,(rect.tl().y + rect.br().y)/2.0),
00614 tmp_template);
00615 cv::warpPerspective(mt->_previous_stack_img, tmp_warp_template, H, cv::Size(iwidth, iheight));
00616
00617 try {
00618 cv::imwrite(filename,tmp_template);
00619 boost::filesystem::path fname(filename);
00620 std::stringstream ss;
00621 ss << fname.stem() << "_wrap" << fname.extension();
00622 cv::imwrite(ss.str(),tmp_warp_template);
00623 }catch (cv::Exception e) {
00624 std::cerr << e.what() << std::endl;
00625 }
00626
00627 for (int i = 0; i < (int)pt1.size(); i++){
00628 pt2.push_back(cv::Point2d((int)pt1.at(i).x - rect.x,
00629 (int)pt1.at(i).y - rect.y - mt->_template_img.size().height));
00630 }
00631
00632
00633
00634
00635
00636
00637 cv::Mat M = (cv::Mat_<double>(3,3) << 1,0,0, 0,1,0, 0,0,1);
00638 std::string window_name = "sample" + boost::lexical_cast<std::string>((int)_templates.size());
00639
00640 Matching_Template* tmplt =
00641 new Matching_Template (tmp_warp_template, "sample",
00642 tmp_warp_template.size().width, tmp_warp_template.size().height,
00643 width, height,
00644 tf::Transform(tf::Quaternion(0, 0, 0, 1), tf::Vector3(0, 0, 0)),
00645 M,
00646 mt->_reprojection_threshold,
00647 mt->_distanceratio_threshold,
00648 _first_sample_change ? window_name : mt->_window_name,
00649 cv::getWindowProperty(mt->_window_name, CV_WND_PROP_AUTOSIZE));
00650
00651 mt->_correspondances.clear();
00652 _templates.push_back(tmplt);
00653 cv::namedWindow(_first_sample_change ? window_name : mt->_window_name,
00654 cv::getWindowProperty(mt->_window_name, CV_WND_PROP_AUTOSIZE));
00655 cvSetMouseCallback (_first_sample_change ? window_name.c_str() : mt->_window_name.c_str(),
00656 &cvmousecb, static_cast<void *>(_templates.back()));
00657 _first_sample_change = true;
00658 }
00659
00660 static void cvmousecb (int event, int x, int y, int flags, void* param){
00661 Matching_Template *mt = (Matching_Template*)param;
00662
00663 switch (event){
00664 case CV_EVENT_LBUTTONUP: {
00665 cv::Point2d pt(x,y - (int)mt->_template_img.size().height);
00666 ROS_INFO("add correspondence (%d, %d)", (int)pt.x, (int)pt.y);
00667 mt->_correspondances.push_back(pt);
00668 if ((int)mt->_correspondances.size() >= 4){
00669 make_template_from_mousecb(mt);
00670 mt->_correspondances.clear();
00671 ROS_INFO("reset");
00672 }
00673 break;
00674 }
00675 case CV_EVENT_RBUTTONUP: {
00676 mt->_correspondances.clear();
00677 ROS_INFO("reset");
00678 break;
00679 }
00680 }
00681 }
00682
00683
00684 void initialize () {
00685 std::string matching_frame;
00686 std::string _pose_str;
00687 double template_width;
00688 double template_height;
00689 std::string template_filename;
00690 std::string window_name;
00691 ros::NodeHandle local_nh("~");
00692
00693 local_nh.param("child_frame_id", matching_frame, std::string("matching"));
00694 local_nh.param("object_width", template_width, 0.06);
00695 local_nh.param("object_height", template_height, 0.0739);
00696 local_nh.param("relative_pose", _pose_str, std::string("0 0 0 0 0 0 1"));
00697 std::string default_template_file_name;
00698 try {
00699 #ifdef ROSPACK_EXPORT
00700 rospack::ROSPack rp;
00701 rospack::Package *p = rp.get_pkg("jsk_perception");
00702 if (p!=NULL) default_template_file_name = p->path + std::string("/sample/opencv-logo2.png");
00703 #else
00704 rospack::Rospack rp;
00705 std::vector<std::string> search_path;
00706 rp.getSearchPathFromEnv(search_path);
00707 rp.crawl(search_path, 1);
00708 std::string path;
00709 if (rp.find("jsk_perception",path)==true) default_template_file_name = path + std::string("/sample/opencv-logo2.png");
00710 #endif
00711 } catch (std::runtime_error &e) {
00712 }
00713 local_nh.param("template_filename", template_filename, default_template_file_name);
00714 local_nh.param("reprojection_threshold", _reprojection_threshold, 3.0);
00715 local_nh.param("distanceratio_threshold", _distanceratio_threshold, 0.49);
00716 local_nh.param("error_threshold", _err_thr, 50.0);
00717 local_nh.param("theta_step", _th_step, 5.0);
00718 local_nh.param("phi_step", _phi_step, 5.0);
00719 local_nh.param("viewer_window", _viewer, true);
00720 local_nh.param("window_name", window_name, std::string("sample1"));
00721 local_nh.param("autosize", _autosize, false);
00722 local_nh.param("publish_null_object_detection", pnod, false);
00723
00724 _first_sample_change = false;
00725
00726
00727 cv::Mat template_img;
00728 template_img = cv::imread (template_filename, 1);
00729 if ( template_img.empty()) {
00730 ROS_ERROR ("template picture <%s> cannot read. template picture is not found or uses unsuported format.", template_filename.c_str());
00731 return;
00732 }
00733
00734
00735 std::vector<double> rv(7);
00736 std::istringstream iss(_pose_str);
00737 tf::Transform transform;
00738 for(int i=0; i<6; i++)
00739 iss >> rv[i];
00740
00741 if (iss.eof()) {
00742 transform = tf::Transform(tf::createQuaternionFromRPY(rv[3], rv[4], rv[5]),
00743 tf::Vector3(rv[0], rv[1], rv[2]));
00744 } else {
00745 iss >> rv[6];
00746 transform = tf::Transform(tf::Quaternion(rv[3], rv[4], rv[5], rv[6]),
00747 tf::Vector3(rv[0], rv[1], rv[2]));
00748 }
00749
00750
00751 add_new_template(template_img, window_name, transform,
00752 template_width, template_height, _th_step, _phi_step);
00753
00754 }
00755
00756
00757 cv::Mat make_homography(cv::Mat src, cv::Mat rvec, cv::Mat tvec,
00758 double template_width, double template_height, cv::Size &size){
00759
00760 cv::Point3f coner[4] = {cv::Point3f(-(template_width/2.0), -(template_height/2.0),0),
00761 cv::Point3f(template_width/2.0,-(template_height/2.0),0),
00762 cv::Point3f(template_width/2.0,template_height/2.0,0),
00763 cv::Point3f(-(template_width/2.0),template_height/2.0,0)};
00764 cv::Mat coner_mat (cv::Size(4, 1), CV_32FC3, coner);
00765 std::vector<cv::Point2f> coner_img_points;
00766
00767 cv::Mat zero_distortion_mat = cv::Mat::zeros(4, 1, CV_64FC1);
00768 cv::projectPoints(coner_mat, rvec, tvec,
00769 pcam.intrinsicMatrix(),
00770 zero_distortion_mat,
00771 coner_img_points);
00772 float x_min = 10000, x_max = 0;
00773 float y_min = 10000, y_max = 0;
00774 for (int i = 0; i < (int)coner_img_points.size(); i++){
00775 x_min = std::min(x_min, coner_img_points.at(i).x);
00776 x_max = std::max(x_max, coner_img_points.at(i).x);
00777 y_min = std::min(y_min, coner_img_points.at(i).y);
00778 y_max = std::max(y_max, coner_img_points.at(i).y);
00779 }
00780
00781 std::vector<cv::Point2f> coner_img_points_trans;
00782 for (int i = 0; i < (int)coner_img_points.size(); i++){
00783 cv::Point2f pt_tmp(coner_img_points.at(i).x - x_min,
00784 coner_img_points.at(i).y - y_min);
00785 coner_img_points_trans.push_back(pt_tmp);
00786 }
00787
00788 cv::Point2f template_points[4] = {cv::Point2f(0,0),
00789 cv::Point2f(src.size().width,0),
00790 cv::Point2f(src.size().width,src.size().height),
00791 cv::Point2f(0,src.size().height)};
00792 cv::Mat template_points_mat (cv::Size(4, 1), CV_32FC2, template_points);
00793
00794 size = cv::Size(x_max - x_min, y_max - y_min);
00795 return cv::findHomography(template_points_mat, cv::Mat(coner_img_points_trans), 0, 3);
00796 }
00797
00798
00799 int make_warped_images (cv::Mat src, std::vector<cv::Mat> &imgs,
00800 std::vector<cv:: Mat> &Mvec,
00801 double template_width, double template_height,
00802 double th_step, double phi_step){
00803
00804 std::vector<cv::Size> sizevec;
00805
00806 for (int i = (int)((-3.14/4.0)/th_step); i*th_step < 3.14/4.0; i++){
00807 for (int j = (int)((-3.14/4.0)/phi_step); j*phi_step < 3.14/4.0; j++){
00808 double fR3[3], fT3[3];
00809 cv::Mat rvec(3, 1, CV_64FC1, fR3);
00810 cv::Mat tvec(3, 1, CV_64FC1, fT3);
00811
00812 tf::Quaternion quat;
00813 quat.setEuler(0, th_step*i, phi_step*j);
00814 fR3[0] = quat.getAxis().x() * quat.getAngle();
00815 fR3[1] = quat.getAxis().y() * quat.getAngle();
00816 fR3[2] = quat.getAxis().z() * quat.getAngle();
00817 fT3[0] = 0;
00818 fT3[1] = 0;
00819 fT3[2] = 0.5;
00820
00821 cv::Mat M;
00822 cv::Size size;
00823 M = make_homography(src, rvec, tvec, template_width, template_height, size);
00824 Mvec.push_back(M);
00825 sizevec.push_back(size);
00826 }
00827 }
00828
00829 for (int i = 0; i < (int)Mvec.size(); i++){
00830 cv::Mat dst;
00831 cv::warpPerspective(src, dst, Mvec.at(i), sizevec.at(i),
00832 CV_INTER_LINEAR, IPL_BORDER_CONSTANT, 0);
00833 imgs.push_back(dst);
00834 }
00835 return 0;
00836 }
00837
00838 bool add_new_template(cv::Mat img, std::string typestr, tf::Transform relative_pose,
00839 double template_width, double template_height,
00840 double theta_step=5.0, double phi_step=5.0)
00841 {
00842 std::vector<cv::Mat> imgs;
00843 std::vector<cv::Mat> Mvec;
00844 make_warped_images(img, imgs, Mvec,
00845 template_width, template_height, theta_step, phi_step);
00846
00847 for (int i = 0; i < (int)imgs.size(); i++){
00848 std::string type = typestr;
00849 if(imgs.size() > 1) {
00850 char chr[20];
00851 sprintf(chr, "%d", i);
00852 type += "_" + std::string(chr);
00853 }
00854
00855 Matching_Template * tmplt =
00856 new Matching_Template(imgs.at(i), type,
00857 img.size().width, img.size().height,
00858 template_width, template_height,
00859 relative_pose, Mvec.at(i),
00860 _reprojection_threshold,
00861 _distanceratio_threshold,
00862 (_viewer ? type : ""), _autosize);
00863 _templates.push_back(tmplt);
00864 if( _viewer )
00865 {
00866 cv::namedWindow(type, _autosize ? CV_WINDOW_AUTOSIZE : 0);
00867 cvSetMouseCallback (type.c_str(), &cvmousecb, static_cast<void *>(_templates.back()));
00868 }
00869 }
00870 return true;
00871 }
00872
00873 bool settemplate_cb (jsk_perception::SetTemplate::Request &req,
00874 jsk_perception::SetTemplate::Response &res){
00875 cv_bridge::CvImagePtr cv_ptr;
00876 cv_ptr = cv_bridge::toCvCopy(req.image, enc::BGR8);
00877 cv::Mat img(cv_ptr->image);
00878
00879 tf::Transform transform(tf::Quaternion(req.relativepose.orientation.x,
00880 req.relativepose.orientation.y,
00881 req.relativepose.orientation.z,
00882 req.relativepose.orientation.w),
00883 tf::Vector3(req.relativepose.position.x,
00884 req.relativepose.position.y,
00885 req.relativepose.position.z));
00886
00887
00888 add_new_template(img, req.type, transform,
00889 req.dimx, req.dimy, 1.0, 1.0);
00890 return true;
00891 }
00892
00893
00894 void imagefeature_cb (const posedetection_msgs::ImageFeature0DConstPtr& msg){
00895 std::vector<cv::KeyPoint> sourceimg_keypoints;
00896 cv::Mat sourceimg_descriptors;
00897 std::vector<posedetection_msgs::Object6DPose> vo6p;
00898 posedetection_msgs::ObjectDetection od;
00899
00900 cv_bridge::CvImagePtr cv_ptr;
00901 cv_ptr = cv_bridge::toCvCopy(msg->image, enc::BGR8);
00902 cv::Mat src_img(cv_ptr->image);
00903
00904
00905 features2keypoint (msg->features, sourceimg_keypoints, sourceimg_descriptors);
00906 pcam.fromCameraInfo(msg->info);
00907 if ( cv::countNonZero(pcam.intrinsicMatrix()) == 0 ) {
00908 ROS_FATAL("intrinsic matrix is zero, your camera info looks invalid");
00909 }
00910 if ( !_initialized ) {
00911
00912 initialize();
00913 std::cerr << "initialize templates done" << std::endl;
00914 _initialized = true;
00915 }
00916
00917 if ( sourceimg_keypoints.size () < 2 ) {
00918 ROS_INFO ("The number of keypoints in source image is less than 2");
00919 }
00920 else {
00921
00922 cv::flann::Index *ft = new cv::flann::Index(sourceimg_descriptors, cv::flann::KDTreeIndexParams(1));
00923
00924
00925 ROS_INFO("_templates size: %d", (int)_templates.size());
00926 for (int i = 0; i < (int)_templates.size(); i++){
00927 posedetection_msgs::Object6DPose o6p;
00928
00929 cv::Mat debug_img;
00930 if (_templates.at(i)->estimate_od(_client, src_img, sourceimg_keypoints, pcam, _err_thr, debug_img, ft, &o6p))
00931 vo6p.push_back(o6p);
00932
00933
00934 cv_bridge::CvImage out_msg;
00935 out_msg.header = msg->image.header;
00936 out_msg.encoding = "bgr8";
00937 out_msg.image = debug_img;
00938 _debug_pub.publish(out_msg.toImageMsg());
00939 }
00940 delete ft;
00941 if (((int)vo6p.size() != 0) || pnod) {
00942 od.header.stamp = msg->image.header.stamp;
00943 od.header.frame_id = msg->image.header.frame_id;
00944 od.objects = vo6p;
00945 _pub.publish(od);
00946 _pub_agg.publish(od);
00947
00948 geometry_msgs::PoseStamped pose_msg;
00949 pose_msg.header = od.header;
00950 pose_msg.pose = od.objects[0].pose;
00951 _pub_pose.publish(pose_msg);
00952 }
00953 }
00954
00955
00956
00957 cv::waitKey( 10 );
00958 }
00959
00960
00961
00962
00963 void check_subscribers()
00964 {
00965 if(_pub.getNumSubscribers() == 0 && _initialized) {
00966 if(_sub)
00967 _sub.shutdown();
00968 static int i = 0;
00969 if ( i++ % 100 == 0 ) {
00970 ROS_INFO("wait for subscriberes ... %s", _pub.getTopic().c_str());
00971 }
00972 } else {
00973 if(!_sub)
00974 _sub = _n.subscribe("ImageFeature0D", 1,
00975 &PointPoseExtractor::imagefeature_cb, this);
00976 }
00977 }
00978
00979
00980 void dyn_conf_callback(jsk_perception::point_pose_extractorConfig &config,
00981 uint32_t level) {
00982 std::cout << "id = " << config.template_id << std::endl;
00983 std::cout << "lvl = " << level << std::endl;
00984 if((int)_templates.size() <= config.template_id) {
00985 ROS_WARN("template_id is invalid");
00986 config.template_id = 0;
00987 if(_templates.size() != 0)
00988 config.frame_id = _templates[0]->_matching_frame;
00989 } else {
00990 Matching_Template* tmpl = _templates[config.template_id];
00991 if(config.frame_id == tmpl->_matching_frame) {
00992 ROS_WARN("update params");
00993 tmpl->_reprojection_threshold = config.reprojection_threshold;
00994 tmpl->_distanceratio_threshold = config.distanceratio_threshold;
00995 _err_thr = config.error_threshold;
00996 } else {
00997 ROS_WARN("get params");
00998 config.frame_id = tmpl->_matching_frame;
00999 config.reprojection_threshold = tmpl->_reprojection_threshold;
01000 config.distanceratio_threshold = tmpl->_distanceratio_threshold;
01001 config.error_threshold = _err_thr;
01002 }
01003 }
01004 }
01005
01006 };
01007
01008
01009 std::vector<Matching_Template *> PointPoseExtractor::_templates;
01010
01011 int main (int argc, char **argv){
01012 ros::init (argc, argv, "PointPoseExtractor");
01013
01014 PointPoseExtractor matcher;
01015
01016 dynamic_reconfigure::Server<jsk_perception::point_pose_extractorConfig> server;
01017 dynamic_reconfigure::Server<jsk_perception::point_pose_extractorConfig>::CallbackType f;
01018 f = boost::bind(&PointPoseExtractor::dyn_conf_callback, &matcher, _1, _2);
01019 server.setCallback(f);
01020
01021 ros::Rate r(10);
01022 while(ros::ok()) {
01023 ros::spinOnce();
01024 matcher.check_subscribers();
01025 r.sleep();
01026 }
01027
01028 return 0;
01029 }