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));