map_keyframe_based.cpp
Go to the documentation of this file.
00001 /*
00002  *  This file is part of ucl_drone 2016.
00003  *  For more information, refer to the corresponding header file.
00004  *
00005  *  \author Arnaud Jacques & Alexandre Leclere
00006  *  \date 2016
00007  *
00008  */
00009 
00010 #include <ucl_drone/map/map_keyframe_based.h>
00011 
00012 Map::Map()
00013   : visualizer(new pcl::visualization::PCLVisualizer("3D visualizer"))
00014   , cloud(new pcl::PointCloud< pcl::PointXYZRGBSIFT >())
00015 {
00016   cv::initModule_nonfree();  // initialize OpenCV SIFT and SURF
00017 
00018   // initialize default status boolean
00019   this->processedImgReceived = false;
00020   this->tracking_lost = false;
00021   this->pending_reset = false;
00022 
00023   // get launch parameters
00024   ros::param::get("~do_search", this->do_search);
00025   ros::param::get("~stop_if_lost", this->stop_if_lost);
00026 
00027   // define some threshold used later
00028   // better if defined in the launch file
00029   threshold_lost = 10;
00030   threshold_new_keyframe = 50;
00031   threshold_new_keyframe_percentage = 0.25;
00032 
00033   // initialize an Empty reference keyframe
00034   reference_keyframe = new KeyFrame();
00035 
00036   // Subsribers
00037 
00038   processed_image_channel_in = nh.resolveName("processed_image");
00039   processed_image_sub = nh.subscribe(processed_image_channel_in, 1, &Map::processedImageCb,
00040                                      this);  // carefull!!! size of queue is 1
00041 
00042   reset_pose_channel = nh.resolveName("reset_pose");
00043   reset_pose_sub = nh.subscribe(reset_pose_channel, 1, &Map::resetPoseCb, this);
00044 
00045   end_reset_pose_channel = nh.resolveName("end_reset_pose");
00046   end_reset_pose_sub = nh.subscribe(end_reset_pose_channel, 1, &Map::endResetPoseCb, this);
00047 
00048   // Publishers
00049 
00050   pose_PnP_channel = nh.resolveName("pose_visual");
00051   pose_PnP_pub = nh.advertise< ucl_drone::Pose3D >(pose_PnP_channel, 1);
00052 
00053   pose_correction_channel = nh.resolveName("pose_visual_correction");
00054   pose_correction_pub = nh.advertise< ucl_drone::Pose3D >(pose_correction_channel, 1);
00055 
00056   target_channel_out = nh.resolveName("ucl_drone/target_detected");
00057   target_pub = nh.advertise< ucl_drone::TargetDetected >(target_channel_out, 1);
00058 
00059   // initialize the map and the visualizer
00060   pcl::visualization::PointCloudColorHandlerCustom< pcl::PointXYZRGBSIFT > single_color(cloud, 0,
00061                                                                                         255, 0);
00062   visualizer->setBackgroundColor(0, 0.1, 0.3);
00063   visualizer->addPointCloud< pcl::PointXYZRGBSIFT >(cloud, single_color, "SIFT_cloud");
00064   visualizer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3,
00065                                                "SIFT_cloud");
00066   visualizer->addCoordinateSystem(1.0);  // red: x, green: y, blue: z
00067 
00068   // get camera parameters in launch file
00069   if (!Read::CamMatrixParams("cam_matrix"))
00070   {
00071     ROS_ERROR("cam_matrix not properly transmitted");
00072   }
00073   if (!Read::ImgSizeParams("img_size"))
00074   {
00075     ROS_ERROR("img_size not properly transmitted");
00076   }
00077 
00078   this->camera_matrix_K =
00079       (cv::Mat_< double >(3, 3) << Read::focal_length_x(), 0, Read::img_center_x(), 0,
00080        Read::focal_length_y(), Read::img_center_y(), 0, 0, 1);
00081 
00082   // initialize empty opencv vectors
00083   this->tvec = cv::Mat::zeros(3, 1, CV_64FC1);
00084   this->rvec = cv::Mat::zeros(3, 1, CV_64FC1);
00085 
00086   this->init_planes();
00087 
00088   ROS_DEBUG("simple_map initialized");
00089 }
00090 
00091 Map::~Map()
00092 {
00093 }
00094 
00095 void Map::resetPoseCb(const std_msgs::Empty& msg)
00096 {
00097   pending_reset = true;
00098   KeyFrame::resetList();  // remove all keyframes
00099   this->cloud = boost::shared_ptr< pcl::PointCloud< pcl::PointXYZRGBSIFT > >(
00100       new pcl::PointCloud< pcl::PointXYZRGBSIFT >);  // empty the cloud
00101   processed_image_sub.shutdown();                    // stop receiving new visual information
00102   // update visualizer
00103   this->visualizer->updatePointCloud< pcl::PointXYZRGBSIFT >(this->cloud, "SIFT_cloud");
00104   // reset
00105   this->previous_frame = Frame();
00106   this->tvec = cv::Mat::zeros(3, 1, CV_64FC1);
00107   this->rvec = cv::Mat::zeros(3, 1, CV_64FC1);
00108   processed_image_sub = nh.subscribe(processed_image_channel_in, 3, &Map::processedImageCb, this);
00109 }
00110 
00111 void Map::endResetPoseCb(const std_msgs::Empty& msg)
00112 {
00113   pending_reset = false;
00114 }
00115 
00116 void Map::processedImageCb(const ucl_drone::ProcessedImageMsg::ConstPtr processed_image_in)
00117 {
00118   TIC(callback);
00119   if (pending_reset)
00120     return;
00121   this->processedImgReceived = true;
00122   this->lastProcessedImgReceived = processed_image_in;
00123   Frame current_frame(processed_image_in);
00124 
00125 #ifdef DEBUG_PROJECTION  // the cloud is re-initialized at each new message and alawys centered at
00126                          // the drone pose
00127   this->cloud = boost::shared_ptr< pcl::PointCloud< pcl::PointXYZRGBSIFT > >(
00128       new pcl::PointCloud< pcl::PointXYZRGBSIFT >);
00129   current_frame.msg.pose.x = 0;
00130   current_frame.msg.pose.y = 0;
00131 #endif
00132 
00133   if (this->cloud->size() != 0)  // IF THE MAP IS NOT EMPTY
00134   {
00135     TIC(doPnP);
00136     std::vector< int > inliers;
00137     bool PnP_success = this->doPnP(current_frame, PnP_pose, inliers, reference_keyframe);
00138     TOC(doPnP, "doPnP");
00139 
00140     // filter out bad PnP estimation not yet treated: case where PnP thinks he has a good pose
00141     // etimation while he actually has found the bad clone configuration (symmetry in ground plane:
00142     // like a mirror effect), resulting in negative altitude and bad (uninterpretable?) other
00143     // meausures
00144     if (abs(PnP_pose.z - current_frame.msg.pose.z) > 0.8)  // treshold in cm
00145     {
00146       ROS_INFO("TRACKING LOST ! (PnP found bad symmetric clone? jump of: %f)",
00147                fabs(PnP_pose.z - current_frame.msg.pose.z));
00148       PnP_success = false;
00149     }
00150 
00151     if (PnP_success)  // if the visual pose is performed
00152     {
00153       TIC(publish);
00154       this->publishPoseVisual(current_frame.msg.pose, PnP_pose);
00155       TOC(publish, "publish");
00156       current_frame.pose_visual_msg = PnP_pose;  // correction of the pose associated to the frame
00157 
00158       // ROS_DEBUG("PnP_pose:  x=%+2.6f y=%+2.6f z=%+2.6f rotX=%+2.6f rotY=%+2.6f rotZ=%+2.6f",
00159       //           PnP_pose.x, PnP_pose.y, PnP_pose.z, PnP_pose.rotX, PnP_pose.rotY,
00160       //           PnP_pose.rotZ);
00161       // ROS_DEBUG("trad_pose: x=%+2.6f y=%+2.6f z=%+2.6f rotX=%+2.6f rotY=%+2.6f rotZ=%+2.6f",
00162       //             current_frame.msg.pose.x, current_frame.msg.pose.y, current_frame.msg.pose.z,
00163       //             current_frame.msg.pose.rotX, current_frame.msg.pose.rotY,
00164       //             current_frame.msg.pose.rotZ);
00165     }
00166 
00167     // if a new keyframe is needed (because the current one does not match enough, search among
00168     // previous ones, or create a new one)
00169     if (this->newKeyFrameNeeded(inliers.size()))
00170     {
00171       ROS_DEBUG("new keyframe needed");
00172       int keyframe_ID = -1;
00173 
00174       ucl_drone::Pose3D pose;  // pose used locally to attach to new keyframe
00175       if (!PnP_success)        // && !this->stop_if_lost)
00176       {
00177         pose = current_frame.msg.pose;  // sensor based pose of current frame
00178       }
00179       else
00180       {
00181         pose = PnP_pose;                    // PnP pose of the current frame
00182         pose.z = current_frame.msg.pose.z;  // in theory, absolute (because ultrasonic sensor)
00183         // and more precise than PnP, so use this one to map. In practice: Kalman filtered on board
00184         // (firmware), so, good meausure (not drifted) but not absolute!!! causes bad errors in map.
00185         // We want to avoid this, so if PnP available, use it!
00186         pose.rotX = current_frame.msg.pose.rotX;  // idem
00187         pose.rotY = current_frame.msg.pose.rotY;  // idem
00188       }
00189 
00190       bool search_success = false;
00191       if (do_search)
00192       {
00193         TIC(search);
00194         search_success = closestKeyFrame(pose, keyframe_ID, current_frame);
00195         TOC(search, "search");
00196       }
00197 
00198       if (search_success)
00199       {
00200         reference_keyframe = KeyFrame::getKeyFrame(keyframe_ID);
00201       }
00202       else
00203       {
00204         reference_keyframe = new KeyFrame(pose);
00205 
00206         // add new keyframe to the map
00207         std::vector< cv::Point3f > points_out;  // points after 2D projection
00208         TIC(projection);
00209         projection_2D(current_frame.imgPoints, pose, points_out);
00210         TOC(projection, "projection");
00211         pcl::PointCloud< pcl::PointXYZRGBSIFT >::Ptr pointcloud(
00212             new pcl::PointCloud< pcl::PointXYZRGBSIFT >);
00213         current_frame.convertToPcl(points_out, reference_keyframe->getID(), pointcloud);
00214         reference_keyframe->addPoints(pointcloud);
00215 
00216         *(this->cloud) += *pointcloud;
00217 
00218         this->visualizer->updatePointCloud< pcl::PointXYZRGBSIFT >(this->cloud, "SIFT_cloud");
00219       }
00220       TOC(callback, "callback");
00221       return;
00222     }
00223   }
00224   else  // IF THE MAP IS EMPTY
00225   {
00226     ROS_DEBUG("MAP INITIALIZATION");
00227     reference_keyframe = new KeyFrame(current_frame.msg.pose);
00228 
00229     std::vector< cv::Point3f > points_out;  // points after 2D projection
00230     projection_2D(current_frame.imgPoints, current_frame.msg.pose, points_out,
00231                   false);  // to change for flying
00232     pcl::PointCloud< pcl::PointXYZRGBSIFT >::Ptr pointcloud(
00233         new pcl::PointCloud< pcl::PointXYZRGBSIFT >);
00234     current_frame.convertToPcl(points_out, reference_keyframe->getID(), pointcloud);
00235     reference_keyframe->addPoints(pointcloud);
00236     *(this->cloud) = *pointcloud;
00237     // PnP_pose.z = 0.73;
00238     PnP_pose.header.stamp =
00239         processed_image_in->pose.header.stamp;  // needed for rqt_plot // ros::Time::now();  //
00240     this->publishPoseVisual(current_frame.msg.pose, PnP_pose);
00241     ROS_DEBUG("MAP INITIALIZATION : rotZ = %f", current_frame.msg.pose.rotZ);
00242     this->visualizer->updatePointCloud< pcl::PointXYZRGBSIFT >(this->cloud, "SIFT_cloud");
00243   }
00244 
00245   ROS_DEBUG("Present keyframe id = %d", reference_keyframe->getID());
00246   previous_frame = current_frame;
00247 
00248   TOC(callback, "callback");
00249 }
00250 
00251 void Map::publishPoseVisual(ucl_drone::Pose3D poseFrame, ucl_drone::Pose3D posePnP)
00252 {
00253   ucl_drone::Pose3D pose_correction;
00254   pose_correction.header.stamp = ros::Time::now();
00255   pose_correction.x = poseFrame.x - posePnP.x;
00256   pose_correction.y = poseFrame.y - posePnP.y;
00257   pose_correction.z = poseFrame.z - posePnP.z;
00258   pose_correction.rotX = poseFrame.rotX - posePnP.rotX;
00259   pose_correction.rotY = poseFrame.rotY - posePnP.rotY;
00260   pose_correction.rotZ = poseFrame.rotZ - posePnP.rotZ;
00261   pose_PnP_pub.publish(PnP_pose);
00262   pose_correction_pub.publish(pose_correction);
00263 }
00264 
00265 bool Map::doPnP(Frame current_frame, ucl_drone::Pose3D& PnP_pose, std::vector< int >& inliers,
00266                 KeyFrame* ref_keyframe)
00267 {
00268   std::vector< std::vector< int > > idx_matching_points;
00269   std::vector< cv::Point3f > ref_keyframe_matching_points;
00270   std::vector< cv::Point2f > frame_matching_points;
00271 
00272   TIC(matchWithFrame);
00273   ref_keyframe->matchWithFrame(current_frame, idx_matching_points, ref_keyframe_matching_points,
00274                                frame_matching_points);
00275   if (ref_keyframe == reference_keyframe)
00276     TOC(matchWithFrame, "matchWithFrame");
00277 
00278   if (ref_keyframe_matching_points.size() < threshold_lost)
00279   {
00280     if (ref_keyframe == reference_keyframe)
00281       ROS_INFO("TRACKING LOST ! (Not enough matching points: %d)",
00282                ref_keyframe_matching_points.size());
00283     return false;
00284   }
00285 
00286   cv::Mat_< double > tcam, cam2world, world2drone, distCoeffs;
00287 
00288   distCoeffs = (cv::Mat_< double >(1, 5) << 0, 0, 0, 0, 0);
00289 
00290   TIC(solvePnPRansac);
00291   // solve with P3P
00292   cv::solvePnPRansac(ref_keyframe_matching_points, frame_matching_points, this->camera_matrix_K,
00293                      distCoeffs, rvec, tvec, true, 2500, 2, 2 * threshold_new_keyframe, inliers,
00294                      CV_P3P);  // alternatives: CV_EPNP and CV_ITERATIVE
00295   TOC(solvePnPRansac, "solvePnPRansac");
00296 
00297   // ROS_DEBUG("rvec: %+2.6f, %+2.6f, %+2.6f", rvec.at< double >(0, 0), rvec.at< double >(1, 0),
00298   //           rvec.at< double >(2, 0));
00299 
00300   if (inliers.size() < threshold_lost)
00301   {
00302     if (ref_keyframe == reference_keyframe)
00303       ROS_INFO("TRACKING LOST ! (Not enough inliers)");
00304     return false;
00305   }
00306 
00307   if (ref_keyframe == reference_keyframe)
00308   {
00309     // select only inliers
00310     std::vector< cv::Point3f > inliers_ref_keyframe_matching_points;
00311     std::vector< cv::Point2f > inliers_frame_matching_points;
00312 
00313     for (int j = 0; j < inliers.size(); j++)
00314     {
00315       int i = inliers[j];
00316 
00317       inliers_ref_keyframe_matching_points.push_back(ref_keyframe_matching_points[i]);
00318       inliers_frame_matching_points.push_back(frame_matching_points[i]);
00319     }
00320 
00321     // solve with PnP n>3
00322     cv::solvePnP(inliers_ref_keyframe_matching_points, inliers_frame_matching_points,
00323                  this->camera_matrix_K, distCoeffs, rvec, tvec, true, CV_EPNP);
00324   }
00325 
00326   cv::Rodrigues(rvec, cam2world);
00327 
00328   if (fabs(determinant(cam2world)) - 1 > 1e-07)
00329   {
00330     ROS_DEBUG("TRACKING LOST ! (Determinant of rotation matrix)");
00331     return false;
00332   }
00333 
00334   // equivalent to rollPitchYawToRotationMatrix(PI, 0, -PI / 2);
00335   cv::Mat_< double > drone2cam =
00336       (cv::Mat_< double >(3, 3) << 0.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, -1.0);
00337 
00338   tcam = -cam2world.t() * tvec;
00339   PnP_pose.x = tcam(0);
00340   PnP_pose.y = tcam(1);
00341   PnP_pose.z = tcam(2);
00342 
00343   cv::Mat_< double > world2cam = cam2world.t();
00344   cv::Mat_< double > cam2drone = drone2cam.t();
00345   world2drone = world2cam * cam2drone;
00346 
00347   tf::Matrix3x3(world2drone(0, 0), world2drone(0, 1), world2drone(0, 2), world2drone(1, 0),
00348                 world2drone(1, 1), world2drone(1, 2), world2drone(2, 0), world2drone(2, 1),
00349                 world2drone(2, 2))
00350       .getRPY(PnP_pose.rotX, PnP_pose.rotY, PnP_pose.rotZ);
00351 
00352   PnP_pose.xvel = 0.0;
00353   PnP_pose.yvel = 0.0;
00354   PnP_pose.zvel = 0.0;
00355   PnP_pose.rotXvel = 0.0;
00356   PnP_pose.rotYvel = 0.0;
00357   PnP_pose.rotZvel = 0.0;
00358 
00359   PnP_pose.header.stamp = current_frame.msg.pose.header.stamp;  // needed for rqt_plot
00360 
00361   ROS_DEBUG("# img:%4d, keyframe%d:%4d, match:%4d, inliers:%4d", current_frame.imgPoints.size(),
00362             ref_keyframe->getID(), ref_keyframe->cloud->points.size(),
00363             ref_keyframe_matching_points.size(), inliers.size());
00364 
00365   return true;
00366 }
00367 
00369 void Map::targetDetectedPublisher()
00370 {
00371   if (processedImgReceived && target_pub.getNumSubscribers() > 0)
00372   {
00373     if (lastProcessedImgReceived->target_detected)
00374     {
00375       ROS_DEBUG("TARGET IS DETECTED");
00376 
00377       ucl_drone::TargetDetected msg;
00378       msg.pose = lastProcessedImgReceived->pose;
00379       msg.img_point.x = lastProcessedImgReceived->target_points[4].x;
00380       msg.img_point.y = lastProcessedImgReceived->target_points[4].y;
00381       msg.img_point.z = 0;
00382       std::vector< cv::Point2f > target_center(1);
00383       target_center[0].x = lastProcessedImgReceived->target_points[4].x;
00384       target_center[0].y = lastProcessedImgReceived->target_points[4].y;
00385       std::vector< cv::Point3f > world_coord;
00386       projection_2D(target_center, msg.pose, world_coord);
00387       msg.world_point.x = world_coord[0].x;
00388       msg.world_point.y = world_coord[0].y;
00389       msg.world_point.z = world_coord[0].z;
00390       target_pub.publish(msg);
00391     }
00392   }
00393 }
00394 
00395 void Map::init_planes()
00396 {
00397   float thres = 0.95;
00398   cv::Mat top_left = (cv::Mat_< double >(3, 1) << -Read::img_center_x() / Read::focal_length_x(),
00399                       -Read::img_center_y() / Read::focal_length_y(), thres);
00400   cv::Mat top_right = (cv::Mat_< double >(3, 1)
00401                            << (Read::img_width() - Read::img_center_x()) / Read::focal_length_x(),
00402                        -Read::img_center_y() / Read::focal_length_y(), thres);
00403   cv::Mat bottom_right =
00404       (cv::Mat_< double >(3, 1) << (Read::img_width() - Read::img_center_x()) /
00405                                        Read::focal_length_x(),
00406        (Read::img_height() - Read::img_center_y()) / Read::focal_length_y(), thres);
00407   cv::Mat bottom_left =
00408       (cv::Mat_< double >(3, 1) << -Read::img_center_x() / Read::focal_length_x(),
00409        (Read::img_height() - Read::img_center_y()) / Read::focal_length_y(), thres);
00410   cam_plane_top = top_left.cross(top_right);
00411   cam_plane_right = top_right.cross(bottom_right);
00412   cam_plane_bottom = bottom_right.cross(bottom_left);
00413   cam_plane_left = bottom_left.cross(top_left);
00414   ROS_DEBUG("MAP: planes initilized");
00415 }
00416 
00417 bool customLess(std::vector< int > a, std::vector< int > b)
00418 {
00419   return a[1] > b[1];
00420 }
00421 
00422 bool Map::closestKeyFrame(const ucl_drone::Pose3D& pose, int& keyframe_ID, Frame current_frame)
00423 {
00424   std::vector< std::vector< int > > keyframes_ID;
00425   TIC(getVisibleKeyFrames)
00426   this->getVisibleKeyFrames(pose, keyframes_ID);
00427   TOC(getVisibleKeyFrames, "getVisibleKeyFrames")
00428 
00429   int best_keyframe = -1;
00430   int best_keyframe_inlier_size = 0;
00431   std::vector< int > inliers;
00432   ucl_drone::Pose3D PnP_pose;
00433   KeyFrame* reference_keyframe_candidate;
00434 
00435   for (int i = 0; i < keyframes_ID.size(); i++)
00436   {
00437     // check if enough points for PnP
00438     if (keyframes_ID[i][1] > threshold_lost)
00439     {
00440       // ROS_DEBUG("keyframe #%d: enough points for PnP (i=%d)", keyframes_ID[i][0], i);
00441       // PnP number of inliers test
00442       reference_keyframe_candidate = KeyFrame::getKeyFrame(keyframes_ID[i][0]);
00443       bool PnP_success =
00444           this->doPnP(current_frame, PnP_pose, inliers, reference_keyframe_candidate);
00445 
00446       // filter out bad PnP estimation not yet treated: case where PnP thinks he has a good pose
00447       // estimation while he actually has found the bad clone configuration (symmetry in ground
00448       // plane:
00449       // like a mirror effect), resulting in negative altitude and bad (uninterpretable?) other
00450       // meausures
00451       if (abs(PnP_pose.z - current_frame.msg.pose.z) > 0.5)  // treshold in m
00452       {
00453         PnP_success = false;
00454       }
00455 
00456       if (PnP_success)
00457       {
00458         // PnP number of inliers test
00459         if (inliers.size() > best_keyframe_inlier_size &&
00460             !this->newKeyFrameNeeded(inliers.size(), reference_keyframe_candidate))
00461         {
00462           best_keyframe = keyframes_ID[i][0];
00463           best_keyframe_inlier_size = inliers.size();
00464         }
00465         if (inliers.size() > 1.1 * threshold_new_keyframe)
00466         {
00467           break;
00468         }
00469       }
00470     }
00471     else
00472     {
00473       break;  // because keyframes_ID is sorted in decreasing order with respect to
00474               // number of visible points (keyframes_ID[i][1])
00475     }
00476   }
00477 
00478   // ROS_DEBUG("best_keyframe = %d", best_keyframe);
00479   if (best_keyframe == -1)
00480   {
00481     return false;
00482   }
00483   keyframe_ID = best_keyframe;
00484   return true;
00485 }
00486 
00487 void Map::getVisibleKeyFrames(const ucl_drone::Pose3D& pose,
00488                               std::vector< std::vector< int > >& keyframes_ID)
00489 {
00490   std::vector< int > idx;
00491   this->getVisiblePoints(pose, idx);
00492   int j;
00493   for (unsigned i = 0; i < idx.size(); ++i)
00494   {
00495     int id = cloud->points[idx[i]].keyframe_ID;
00496     for (j = 0; j < keyframes_ID.size(); j++)
00497     {
00498       if (id == keyframes_ID[j][0])
00499       {
00500         keyframes_ID[j][1]++;
00501         break;
00502       }
00503     }
00504     if (j == keyframes_ID.size())
00505     {
00506       std::vector< int > vec(2);
00507       vec[0] = id;
00508       vec[1] = 1;
00509       keyframes_ID.push_back(vec);
00510     }
00511   }
00512 
00513   std::sort(keyframes_ID.begin(), keyframes_ID.end(), customLess);
00514 
00515   // ROS_DEBUG("Visible Keyframes:");
00516   // for (j = 0; j < keyframes_ID.size(); j++)
00517   // {
00518   //   ROS_DEBUG("id %d containing %d points", keyframes_ID[j][0], keyframes_ID[j][1]);
00519   // }
00520 }
00521 
00522 void Map::getVisiblePoints(const ucl_drone::Pose3D& pose, std::vector< int >& idx)
00523 {
00524   double yaw = -pose.rotZ;
00525   double pitch = -pose.rotY;
00526   double roll = -pose.rotX;
00527 
00528   cv::Mat world2drone = rollPitchYawToRotationMatrix(roll, pitch, yaw);
00529   // cv::Mat drone2cam = rollPitchYawToRotationMatrix(PI, 0, -PI / 2);
00530   cv::Mat_< double > drone2cam =
00531       (cv::Mat_< double >(3, 3) << 0.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, -1.0);
00532   cv::Mat world2cam = drone2cam * world2drone;
00533 
00534   // ROS_DEBUG("TRANSFO READY");
00535 
00536   cv::Mat world_plane_top = world2cam.t() * cam_plane_top;
00537   cv::Mat world_plane_right = world2cam.t() * cam_plane_right;
00538   cv::Mat world_plane_bottom = world2cam.t() * cam_plane_bottom;
00539   cv::Mat world_plane_left = world2cam.t() * cam_plane_left;
00540   cv::Mat translation = (cv::Mat_< double >(3, 1) << pose.x, pose.y, pose.z);
00541   double d_top = -translation.dot(world_plane_top);
00542   double d_right = -translation.dot(world_plane_right);
00543   double d_bottom = -translation.dot(world_plane_bottom);
00544   double d_left = -translation.dot(world_plane_left);
00545 
00546   // ROS_DEBUG("WORLD PLANES READY");
00547 
00548   for (unsigned i = 0; i < cloud->points.size(); ++i)
00549   {
00550     cv::Mat point =
00551         (cv::Mat_< double >(3, 1) << cloud->points[i].x, cloud->points[i].y, cloud->points[i].z);
00552 
00553     double t_top = point.dot(world_plane_top) + d_top;
00554     double t_right = point.dot(world_plane_right) + d_right;
00555     double t_bottom = point.dot(world_plane_bottom) + d_bottom;
00556     double t_left = point.dot(world_plane_left) + d_left;
00557 
00558     if (t_top >= 0 && t_right >= 0 && t_bottom >= 0 && t_left >= 0)
00559     {
00560       idx.push_back(i);
00561     }
00562   }
00563 }
00564 
00565 void Map::getDescriptors(const ucl_drone::Pose3D& pose, cv::Mat& descriptors,
00566                          std::vector< int >& idx, bool only_visible)
00567 {
00568   // only_visible = false;
00569   if (!only_visible)  // get all points descriptors
00570   {
00571     descriptors = cv::Mat_< float >(cloud->points.size(), DESCRIPTOR_SIZE);
00572     for (unsigned i = 0; i < cloud->points.size(); ++i)
00573     {
00574       for (unsigned j = 0; j < DESCRIPTOR_SIZE; ++j)
00575       {
00576         descriptors.at< float >(i, j) = cloud->points[i].descriptor[j];
00577       }
00578       idx.push_back(i);
00579     }
00580   }
00581   if (only_visible)  // get only points visible from pose
00582                      // It doesn't take into account obstacles
00583   {
00584     ROS_DEBUG("GET_DESCRIPTORS, pose:pos(%f, %f, %f) rot(%f, %f, %f)", pose.x, pose.y, pose.z,
00585               pose.rotX, pose.rotY, pose.rotZ);
00586 
00587     this->getVisiblePoints(pose, idx);
00588     this->getDescriptors(idx, descriptors);
00589 
00590     ROS_DEBUG(" %d POINTS VISIBLE", idx.size());
00591   }
00592 }
00593 
00594 void Map::getDescriptors(const std::vector< int >& idx, cv::Mat& descriptors)
00595 {
00596   descriptors = cv::Mat_< float >(idx.size(), DESCRIPTOR_SIZE);
00597   for (unsigned i = 0; i < idx.size(); ++i)
00598   {
00599     for (unsigned j = 0; j < DESCRIPTOR_SIZE; ++j)
00600     {
00601       descriptors.at< float >(i, j) = cloud->points[idx[i]].descriptor[j];
00602     }
00603   }
00604 }
00605 
00606 bool Map::newKeyFrameNeeded(int number_of_common_keypoints)
00607 {
00608   return newKeyFrameNeeded(number_of_common_keypoints, this->reference_keyframe);
00609 }
00610 
00611 bool Map::newKeyFrameNeeded(int number_of_common_keypoints, KeyFrame* reference_keyframe_candidate)
00612 {
00613   return (number_of_common_keypoints < threshold_new_keyframe ||
00614           number_of_common_keypoints <
00615               threshold_new_keyframe_percentage * reference_keyframe_candidate->size());
00616 }
00617 
00618 void cloud_debug(pcl::PointCloud< pcl::PointXYZRGBSIFT >::ConstPtr cloud)
00619 {
00620   for (size_t i = 0; i < cloud->points.size(); ++i)
00621   {
00622     ROS_DEBUG("points[%d] = (%f, %f, %f)", i, cloud->points[i].x, cloud->points[i].y,
00623               cloud->points[i].z);
00624   }
00625 }
00626 
00627 int main(int argc, char** argv)
00628 {
00629   ros::init(argc, argv, "simple_map");
00630   ROS_INFO_STREAM("simple map started!");
00631 
00632   // if (ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Debug))
00633   // {
00634   //   ros::console::notifyLoggerLevelsChanged();
00635   // }
00636 
00637   Map map;
00638   ros::Time t = ros::Time::now() + ros::Duration(13);
00639   while (ros::Time::now() < t)
00640   {
00641     map.visualizer->spinOnce(100);
00642   }
00643 
00644   ros::Rate r(3);
00645 
00646   int visualizer_count = 0;
00647 
00648   while (ros::ok())
00649   {
00650     TIC(cloud);
00651     map.visualizer->spinOnce(10);
00652     TOC(cloud, "cloud");
00653 
00654     TIC(target);
00655     map.targetDetectedPublisher();
00656     TOC(target, "target");
00657 
00658     ros::spinOnce();
00659     r.sleep();
00660   }
00661   return 0;
00662 }


ucl_drone
Author(s): dronesinma
autogenerated on Sat Jun 8 2019 20:51:53