35 #ifndef JSK_PERCEPTION_POINT_POSE_EXTRACTOR_H_ 
   36 #define JSK_PERCEPTION_POINT_POSE_EXTRACTOR_H_ 
   38 #include <jsk_topic_tools/diagnostic_nodelet.h> 
   42 #if ( CV_MAJOR_VERSION >= 4) 
   43 #include <opencv2/opencv.hpp> 
   44 #include <opencv2/highgui/highgui_c.h> 
   45 #include <opencv2/calib3d/calib3d_c.h> 
   47 #include <opencv/highgui.h> 
   48 #include <opencv/cv.hpp> 
   50 #include <posedetection_msgs/Feature0DDetect.h> 
   51 #include <posedetection_msgs/ImageFeature0D.h> 
   52 #include <posedetection_msgs/ObjectDetection.h> 
   53 #include <posedetection_msgs/Object6DPose.h> 
   54 #include <geometry_msgs/PoseStamped.h> 
   55 #include <geometry_msgs/Pose.h> 
   56 #include <geometry_msgs/Quaternion.h> 
   62 #include <boost/shared_ptr.hpp> 
   63 #include <boost/foreach.hpp> 
   64 #include <boost/filesystem.hpp> 
   68 #include <dynamic_reconfigure/server.h> 
   69 #include <jsk_perception/point_pose_extractorConfig.h> 
   70 #include <jsk_perception/SetTemplate.h> 
   75                         std::vector<cv::KeyPoint>& keypoints,
 
   76                         cv::Mat& descriptors){
 
   77   keypoints.resize(features.scales.size());
 
   78   descriptors.create(features.scales.size(),features.descriptor_dim,CV_32FC1);
 
   79   std::vector<cv::KeyPoint>::iterator keypoint_it = keypoints.begin();
 
   80   for ( 
int i=0; keypoint_it != keypoints.end(); ++keypoint_it, ++
i ) {
 
   81     *keypoint_it = cv::KeyPoint(cv::Point2f(features.positions[
i*2+0],
 
   82                                             features.positions[
i*2+1]),
 
   83                                 features.descriptor_dim, 
 
   84                                 features.orientations[
i], 
 
   88     for (
int j = 0; j < features.descriptor_dim; j++){
 
   89       descriptors.at<
float>(
i,j) =
 
   90         features.descriptors[
i*features.descriptor_dim+j];
 
  120                     std::string matching_frame,
 
  121                     int original_width_size,
 
  122                     int original_height_size,
 
  123                     double template_width,
 
  124                     double template_height,
 
  126                     cv::Mat affine_matrix,
 
  127                     double reprojection_threshold,
 
  128                     double distanceratio_threshold,
 
  129                     std::string window_name,
 
  174     posedetection_msgs::Feature0DDetect srv;
 
  177       ROS_ERROR (
"template picture is empty.");
 
  183     cv_img.
encoding = std::string(
"bgr8");
 
  186       ROS_INFO_STREAM(
"get features with " << srv.response.features.scales.size() << 
" descriptoins");
 
  200         cv::Mat pt_mat(cv::Size(1,1), CV_32FC2, &pt);
 
  202         cv::perspectiveTransform (pt_src_mat, pt_mat, M_inv);
 
  209       ROS_ERROR(
"Failed to call service Feature0DDetect");
 
  217     static std::vector<double> slog_table;
 
  218     int osize = slog_table.size();
 
  220       slog_table.resize(
n+1);
 
  223         slog_table[1] = log(1.0);
 
  226       for(
int i = osize; 
i <= 
n; 
i++ ){
 
  227         slog_table[
i] = slog_table[
i-1] + log(
i);
 
  230     return slog_table[
n];
 
  233   int min_inlier( 
int n, 
int m, 
double p_badsupp, 
double p_badxform )
 
  237     double lp_badsupp = log( p_badsupp );
 
  238     double lp_badsupp1 = log( 1.0 - p_badsupp );
 
  239     for( j = m+1; j <= 
n; j++ ){
 
  241       for( 
i = j; 
i <= 
n; 
i++ ){
 
  242         pi = (
i-m) * lp_badsupp + (
n-
i+m) * lp_badsupp1 +
 
  246       if( 
sum < p_badxform )
 
  254                     std::vector<cv::KeyPoint> sourceimg_keypoints,
 
  256                     double err_thr, cv::Mat &stack_img,
 
  257                     cv::flann::Index* ft, posedetection_msgs::Object6DPose* o6p){
 
  265       ROS_ERROR (
"Template image was not set.");
 
  271     stack_img = cv::Mat(stack_size,CV_8UC3);
 
  272     stack_img = cv::Scalar(0);
 
  275     cv::Mat stack_img_src(stack_img,cv::Rect(0,
_template_img.rows,src_img.cols,src_img.rows));
 
  276     cv::add(stack_img_src, src_img, stack_img_src);
 
  285     std::vector<cv::Point2f> pt1, pt2;
 
  286     std::vector<int> queryIdxs,trainIdxs;
 
  289         queryIdxs.push_back(j);
 
  290         trainIdxs.push_back(m_indices.at<
int>(j,0));
 
  293     if ( queryIdxs.size() == 0 ) {
 
  303     std::vector<uchar> mask((
int)pt2.size());
 
  305     if ( pt1.size() > 4 ) {
 
  311     for (
int j = 0; j < (
int)pt1.size(); j++){
 
  312       cv::Point2f pt, pt_orig;
 
  313       cv::Mat pt_mat(cv::Size(1,1), CV_32FC2, &pt);
 
  314       cv::Mat pt_src_mat(cv::Size(1,1), CV_32FC2, &pt1.at(j));
 
  316       pt_orig = pt_mat.at<cv::Point2f>(0,0);
 
  318         cv::line(stack_img, pt_orig, pt2.at(j)+cv::Point2f(0,
_template_img.rows),
 
  319                  CV_RGB(0,255,0), 1,8,0);
 
  322         cv::line(stack_img, pt_orig, pt2.at(j)+cv::Point2f(0,
_template_img.rows),
 
  323                  CV_RGB(255,0,255), 1,8,0);
 
  327     for (
int k=0; 
k < (
int)mask.size(); 
k++){
 
  328       inlier_sum += (
int)mask.at(
k);
 
  331     double text_scale = 1.5;
 
  333       int fontFace = 0, thickness = 0, baseLine;
 
  338       text = 
"inlier: " + boost::lexical_cast<std::string>((
int)inlier_sum) + 
" / " + boost::lexical_cast<std::string>((
int)pt2.size());
 
  339       text_size = cv::getTextSize(text, fontFace, text_scale, thickness, &baseLine);
 
  340       x = stack_img.size().width - text_size.width;
 
  341       y = text_size.height + thickness + 10; 
 
  342       cv::putText (stack_img, text, cv::Point(
x, y),
 
  343                    fontFace, text_scale, CV_RGB(0, 255, 0),
 
  344                    thickness, 8, 
false);
 
  347       text_size = cv::getTextSize(text, fontFace, text_scale, thickness, &baseLine);
 
  348       x = stack_img.size().width - text_size.width;
 
  349       y += text_size.height + thickness + 10; 
 
  350       cv::putText (stack_img, text, cv::Point(
x, y),
 
  351                    fontFace, text_scale, CV_RGB(0, 255, 0),
 
  352                    thickness, 8, 
false);
 
  359                  8, CV_RGB(255,0,0), -1);
 
  362     ROS_INFO(
"    inlier_sum:%d   min_lier:%d", inlier_sum, 
min_inlier((
int)pt2.size(), 4, 0.10, 0.01));
 
  363     if ((cv::countNonZero( H ) == 0) || (inlier_sum < 
min_inlier((
int)pt2.size(), 4, 0.10, 0.01))){
 
  364       ROS_INFO(
"    inlier_sum < min_lier return-from estimate-od");
 
  374     sprintf(chr, 
"%d", (
int)pt2.size());
 
  377     sprintf(chr, 
"%d", inlier_sum);
 
  378     _type = _type + 
"_" + std::string(chr);
 
  380     cv::Point2f corners2d[4] = {cv::Point2f(0,0),
 
  384     cv::Mat corners2d_mat (cv::Size(4, 1), CV_32FC2, corners2d);
 
  385     cv::Point3f corners3d[4] = {cv::Point3f(0,0,0),
 
  389     cv::Mat corners3d_mat (cv::Size(4, 1), CV_32FC3, corners3d);
 
  391     cv::Mat corners2d_mat_trans;
 
  393     cv::perspectiveTransform (corners2d_mat, corners2d_mat_trans, H);
 
  395     double fR3[3], fT3[3];
 
  396     cv::Mat rvec(3, 1, CV_64FC1, fR3);
 
  397     cv::Mat tvec(3, 1, CV_64FC1, fT3);
 
  398     cv::Mat zero_distortion_mat = cv::Mat::zeros(4, 1, CV_64FC1);
 
  400     cv::solvePnP (corners3d_mat, corners2d_mat_trans, 
 
  407     checktf.
setOrigin( tf::Vector3(fT3[0], fT3[1], fT3[2] ) );
 
  409     double rx = fR3[0], ry = fR3[1], rz = fR3[2];
 
  411     double angle = cv::norm(rvec);
 
  417     ROS_INFO( 
"      tx: (%0.2lf,%0.2lf,%0.2lf) rx: (%0.2lf,%0.2lf,%0.2lf)",
 
  425     o6p->pose.position.x = resulttf.
getOrigin().getX();
 
  426     o6p->pose.position.y = resulttf.
getOrigin().getY();
 
  427     o6p->pose.position.z = resulttf.
getOrigin().getZ();
 
  428     o6p->pose.orientation.w = resulttf.
getRotation().w();
 
  429     o6p->pose.orientation.x = resulttf.
getRotation().x();
 
  430     o6p->pose.orientation.y = resulttf.
getRotation().y();
 
  431     o6p->pose.orientation.z = resulttf.
getRotation().z();
 
  435     std::vector<cv::Point2f> projected_top;
 
  437       tf::Vector3 coords[8] = {tf::Vector3(0,0,0),
 
  441                                tf::Vector3(0, 0, -0.03),
 
  446       projected_top = std::vector<cv::Point2f>(8);
 
  448       for(
int i=0; 
i<8; 
i++) {
 
  449         coords[
i] = checktf * coords[
i];
 
  450         cv::Point3f pt(coords[
i].getX(), coords[
i].getY(), coords[
i].getZ());
 
  456       float max_x, max_y, min_x, min_y;
 
  457       max_x = max_y = -1e9;
 
  459       for (
int j = 0; j < 4; j++){
 
  460         cv::Point2f pt = corners2d_mat_trans.at<cv::Point2f>(0,j);
 
  461         max_x = std::max(max_x, pt.x), max_y = std::max(max_y, pt.y);
 
  462         min_x = std::min(min_x, pt.x), min_y = std::min(min_y, pt.y);
 
  464       if((max_x - min_x) < 30 || (max_y - min_y) < 30 ||
 
  465          src_img.rows < (max_x - min_x)/2 || src_img.cols < (max_y - min_y)/2){
 
  466         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);
 
  472     bool err_success = 
true;
 
  473     for (
int j = 0; j < 4; j++){
 
  474       double err = 
sqrt(pow((corners2d_mat_trans.at<cv::Point2f>(0,j).x - projected_top.at(j).x), 2) +
 
  475                       pow((corners2d_mat_trans.at<cv::Point2f>(0,j).y - projected_top.at(j).y), 2));
 
  478     if (err_sum > err_thr){
 
  479       ROS_INFO(
"          err_sum:%f > err_thr:%f return-from estimate-od", err_sum, err_thr);
 
  482       o6p->reliability = 1.0 - (err_sum / err_thr);
 
  485     for (
int j = 0; j < corners2d_mat_trans.cols; j++){
 
  486       cv::Point2f p1(corners2d_mat_trans.at<cv::Point2f>(0,j).x,
 
  487                      corners2d_mat_trans.at<cv::Point2f>(0,j).y+
_template_img.rows);
 
  488       cv::Point2f p2(corners2d_mat_trans.at<cv::Point2f>(0,(j+1)%corners2d_mat_trans.cols).x,
 
  489                      corners2d_mat_trans.at<cv::Point2f>(0,(j+1)%corners2d_mat_trans.cols).y+
_template_img.rows);
 
  490       cv::line (stack_img, p1, p2, CV_RGB(255, 0, 0),
 
  496     if(projected_top.size() == 8) { 
 
  498       std::vector<cv::Point2f> ps(cnt);
 
  499       for(
int i=0; 
i<cnt; 
i++)
 
  500         ps[
i] = cv::Point2f(projected_top[
i].
x,
 
  503       int draw_width = ( err_success ? 3 : 1);
 
  504       for(
int i=0; 
i<4; 
i++) {
 
  505         cv::line (stack_img, ps[
i], ps[(
i+1)%4], CV_RGB(0, 0, 255), draw_width, CV_AA, 0);
 
  506         cv::line (stack_img, ps[
i+4], ps[(
i+1)%4+4], CV_RGB(0, 0, 255), draw_width, CV_AA, 0);
 
  507         cv::line (stack_img, ps[
i], ps[
i+4], CV_RGB(0, 0, 255), draw_width, CV_AA, 0);
 
  514       tf::Vector3 coords[4] = { tf::Vector3(0,0,0),
 
  515                                 tf::Vector3(0.05,0,0),
 
  516                                 tf::Vector3(0,0.05,0),
 
  517                                 tf::Vector3(0,0,0.05)};
 
  518       std::vector<cv::Point2f> ps(4);
 
  520       for(
int i=0; 
i<4; 
i++) {
 
  521         coords[
i] = resulttf * coords[
i];
 
  522         cv::Point3f pt(coords[
i].getX(), coords[
i].getY(), coords[
i].getZ());   
 
  527       cv::line (stack_img, ps[0], ps[1], CV_RGB(255, 0, 0), 3, CV_AA, 0);
 
  528       cv::line (stack_img, ps[0], ps[2], CV_RGB(0, 255, 0), 3, CV_AA, 0);
 
  529       cv::line (stack_img, ps[0], ps[3], CV_RGB(0, 0, 255), 3, CV_AA, 0);
 
  536       text = 
"error: " + boost::lexical_cast<std::string>(err_sum);
 
  537       x = stack_img.size().width - 16*17*text_scale; 
 
  539       cv::putText (stack_img, text, cv::Point(
x, y),
 
  540                    0, text_scale, CV_RGB(0, 255, 0),
 
  542       ROS_INFO(
"      %s < %f (threshold)", text.c_str(), err_thr );
 
  560     typedef jsk_perception::point_pose_extractorConfig 
Config;
 
  587     virtual cv::Mat 
make_homography(cv::Mat src, cv::Mat rvec, cv::Mat tvec,
 
  588                                     double template_width, 
double template_height, cv::Size &size);
 
  590                                     std::vector<cv:: Mat> &Mvec,
 
  591                                     double template_width, 
double template_height,
 
  592                                     double th_step, 
double phi_step);
 
  594                                   double template_width, 
double template_height,
 
  595                                   double theta_step, 
double phi_step);
 
  597                                  jsk_perception::SetTemplate::Response &res);
 
  598     virtual void imagefeature_cb (
const posedetection_msgs::ImageFeature0DConstPtr& msg);
 
  604     static void cvmousecb (
int event, 
int x, 
int y, 
int flags, 
void* param){
 
  609       case CV_EVENT_LBUTTONUP: {
 
  611         ROS_INFO(
"add correspondence (%d, %d)", (
int)pt.x, (
int)pt.y);
 
  620       case CV_EVENT_RBUTTONUP: {
 
  630     cv::Mat tmp_template, tmp_warp_template;
 
  631     std::vector<cv::Point2f>pt1, pt2;
 
  634     std::cout << 
"input template's [width]" << std::endl;
 
  636     std::cout << 
"input template's [height]" << std::endl;
 
  638     std::cout << 
"input template's [filename]" << std::endl;
 
  641     for (
int i = 0; 
i < 4; 
i++){
 
  645     cv::Rect rect = cv::boundingRect(cv::Mat(pt1));
 
  647     int iwidth = 
width / scale, iheight = 
height / scale;
 
  648     pt2.push_back(cv::Point2d(0,0));
 
  649     pt2.push_back(cv::Point2d(iwidth,0));
 
  650     pt2.push_back(cv::Point2d(iwidth,iheight));
 
  651     pt2.push_back(cv::Point2d(0,     iheight));
 
  652     H = cv::findHomography(cv::Mat(pt1), cv::Mat(pt2));
 
  655                       cv::Point2f((rect.tl().x + rect.br().x)/2.0,(rect.tl().y + rect.br().y)/2.0),
 
  657     cv::warpPerspective(mt->
_previous_stack_img, tmp_warp_template, H, cv::Size(iwidth, iheight));
 
  661       boost::filesystem::path fname(
filename);
 
  662       std::stringstream ss;
 
  663       ss << (fname.parent_path() / fname.stem()).c_str() << 
"_wrap" << fname.extension().c_str();
 
  664       cv::imwrite(ss.str(),tmp_warp_template);
 
  665     }
catch (cv::Exception e) {
 
  666       std::cerr << e.what()  << std::endl;
 
  669     for (
int i = 0; 
i < (
int)pt1.size(); 
i++){
 
  670       pt2.push_back(cv::Point2d((
int)pt1.at(
i).x - rect.x,
 
  679     cv::Mat M = (cv::Mat_<double>(3,3) << 1,0,0, 0,1,0, 0,0,1);
 
  680     std::string window_name = 
"sample" + boost::lexical_cast<std::string>((
int)ppe->
_templates.size());
 
  684                              tmp_warp_template.size().width, tmp_warp_template.size().height,
 
  691                              cv::getWindowProperty(mt->
_window_name, CV_WND_PROP_AUTOSIZE));
 
  696                     cv::getWindowProperty(mt->
_window_name, CV_WND_PROP_AUTOSIZE));