00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <ucl_drone/map/simple_map.h>
00012
00013 #if EXTRACTOR_TYPE == TYPE_ORB
00014 Map::Map()
00015 : visualizer(new pcl::visualization::PCLVisualizer("3D visualizer"))
00016 , cloud(new pcl::PointCloud< pcl::PointXYZRGBSIFT >())
00017 , matcher(new cv::flann::LshIndexParams(20, 10, 2))
00018 #else
00019 Map::Map()
00020 : visualizer(new pcl::visualization::PCLVisualizer("3D visualizer"))
00021 , cloud(new pcl::PointCloud< pcl::PointXYZRGBSIFT >())
00022 #endif
00023 {
00024 cv::initModule_nonfree();
00025 this->processedImgReceived = false;
00026 this->tracking_lost = false;
00027 this->pending_reset = false;
00028
00029 processed_image_channel_in = nh.resolveName("processed_image");
00030 processed_image_sub =
00031 nh.subscribe(processed_image_channel_in, 3, &Map::processedImageCb,
00032 this);
00033
00034
00035
00036 reset_channel = nh.resolveName("reset_pose");
00037 reset_sub = nh.subscribe(reset_channel, 1, &Map::resetCb, this);
00038
00039
00040 target_channel_out = nh.resolveName("ucl_drone/target_detected");
00041 target_pub = nh.advertise< ucl_drone::TargetDetected >(target_channel_out, 1);
00042
00043
00044 pcl::visualization::PointCloudColorHandlerCustom< pcl::PointXYZRGBSIFT > single_color(cloud, 255,
00045 0, 0);
00046 visualizer->setBackgroundColor(0, 0.1, 0.3);
00047
00048 visualizer->addPointCloud< pcl::PointXYZRGBSIFT >(cloud, single_color, "SIFT_cloud");
00049 visualizer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3,
00050 "SIFT_cloud");
00051 visualizer->addCoordinateSystem(1.0);
00052 visualizer->initCameraParameters();
00053
00054
00055
00056
00057
00058
00059 if (!Read::CamMatrixParams("cam_matrix"))
00060 {
00061 ROS_ERROR("cam_matrix not properly transmitted");
00062 }
00063 if (!Read::ImgSizeParams("img_size"))
00064 {
00065 ROS_ERROR("img_size not properly transmitted");
00066 }
00067
00068 this->camera_matrix_K =
00069 (cv::Mat_< double >(3, 3) << Read::focal_length_x(), 0, Read::img_center_x(), 0,
00070 Read::focal_length_y(), Read::img_center_y(), 0, 0, 1);
00071
00072 ROS_DEBUG("simple_map initialized");
00073
00074 pose_PnP_channel = nh.resolveName("pose_visual");
00075 pose_PnP_pub = nh.advertise< ucl_drone::Pose3D >(pose_PnP_channel, 1);
00076
00077 this->tvec = cv::Mat::zeros(3, 1, CV_64FC1);
00078 this->rvec = cv::Mat::zeros(3, 1, CV_64FC1);
00079
00080 this->init_planes();
00081 }
00082
00083 Map::~Map()
00084 {
00085 }
00086
00087 void Map::resetCb(const std_msgs::Empty msg)
00088 {
00089 pending_reset = true;
00090 this->cloud = boost::shared_ptr< pcl::PointCloud< pcl::PointXYZRGBSIFT > >(
00091 new pcl::PointCloud< pcl::PointXYZRGBSIFT >);
00092 processed_image_sub.shutdown();
00093 this->visualizer->updatePointCloud< pcl::PointXYZRGBSIFT >(this->cloud, "SIFT_cloud");
00094 this->previous_frame = Frame();
00095 this->tvec = cv::Mat::zeros(3, 1, CV_64FC1);
00096 this->rvec = cv::Mat::zeros(3, 1, CV_64FC1);
00097 ros::Rate r(1 / 5.0);
00098 r.sleep();
00099 processed_image_sub = nh.subscribe(processed_image_channel_in, 3, &Map::processedImageCb, this);
00100 }
00101
00102 void Map::processedImageCb(const ucl_drone::ProcessedImageMsg::ConstPtr processed_image_in)
00103 {
00104 if (pending_reset)
00105 return;
00106
00107 this->processedImgReceived = true;
00108 this->lastProcessedImgReceived = processed_image_in;
00109 Frame current_frame(processed_image_in);
00110
00111 #ifdef DEBUG_PROJECTION
00112 this->cloud = boost::shared_ptr< pcl::PointCloud< pcl::PointXYZRGBSIFT > >(
00113 new pcl::PointCloud< pcl::PointXYZRGBSIFT >);
00114 current_frame.msg.pose.x = 0;
00115 current_frame.msg.pose.y = 0;
00116 #endif
00117
00118 if (this->cloud->size() != 0)
00119 {
00120 std::vector< std::vector< int > > idx_matching_points;
00121 std::vector< int > idx_unknown_points;
00122 std::vector< cv::Point3f > map_matching_points;
00123 std::vector< cv::Point2f > frame_matching_points;
00124 std::vector< cv::Point2f > frame_unknown_points;
00125
00126 this->matchWithFrame(current_frame, idx_matching_points, idx_unknown_points,
00127 map_matching_points, frame_matching_points, frame_unknown_points);
00128
00129 tracking_lost = false;
00130
00131 ucl_drone::Pose3D mixed_pose;
00132 if (map_matching_points.size() > 7)
00133 {
00134 cv::Mat_< double > tcam, cam2world, world2drone, distCoeffs;
00135 std::vector< int > inliers;
00136
00137 distCoeffs = (cv::Mat_< double >(1, 5) << 0, 0, 0, 0, 0);
00138
00139 cv::solvePnPRansac(map_matching_points, frame_matching_points, this->camera_matrix_K,
00140 distCoeffs, rvec, tvec, true, 3000, 2, 300, inliers,
00141 CV_P3P);
00142
00143 ROS_DEBUG("# img:%4d, map:%4d, match:%4d, inliers::%4d", current_frame.imgPoints.size(),
00144 this->cloud->points.size(), map_matching_points.size(), inliers.size());
00145
00146
00147
00148
00149 if (inliers.size() < 7 || inliers.size() < map_matching_points.size() / 10.0)
00150 {
00151 ROS_DEBUG("TRACKING LOST ! (not enough inliers)");
00152 tracking_lost = true;
00153 return;
00154 }
00155
00156
00157
00158
00159
00160
00161
00162 cv::Rodrigues(rvec, cam2world);
00163
00164 if (fabs(determinant(cam2world)) - 1 > 1e-07)
00165 {
00166 ROS_DEBUG("TRACKING LOST ! (determinant of rotation matrix)");
00167 tracking_lost = true;
00168 return;
00169 }
00170
00171
00172 cv::Mat_< double > drone2cam =
00173 (cv::Mat_< double >(3, 3) << 0.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0,
00174 -1.0);
00175
00176
00177 tcam = -cam2world.t() * tvec;
00178 PnP_pose.x = tcam(0);
00179 PnP_pose.y = tcam(1);
00180 PnP_pose.z = tcam(2);
00181
00182 cv::Mat_< double > world2cam = cam2world.t();
00183 cv::Mat_< double > cam2drone = drone2cam.t();
00184 world2drone =
00185 world2cam * cam2drone;
00186
00187
00188 tf::Matrix3x3(world2drone(0, 0), world2drone(0, 1), world2drone(0, 2), world2drone(1, 0),
00189 world2drone(1, 1), world2drone(1, 2), world2drone(2, 0), world2drone(2, 1),
00190 world2drone(2, 2))
00191 .getRPY(PnP_pose.rotX, PnP_pose.rotY, PnP_pose.rotZ);
00192
00193 PnP_pose.xvel = 0.0;
00194 PnP_pose.yvel = 0.0;
00195 PnP_pose.zvel = 0.0;
00196 PnP_pose.rotXvel = 0.0;
00197 PnP_pose.rotYvel = 0.0;
00198 PnP_pose.rotZvel = 0.0;
00199
00200 PnP_pose.header.stamp = processed_image_in->pose.header.stamp;
00201 pose_PnP_pub.publish(PnP_pose);
00202 current_frame.pose_visual_msg = PnP_pose;
00203
00204 ROS_DEBUG("PnP_pose: x=%+2.6f y=%+2.6f z=%+2.6f rotX=%+2.6f rotY=%+2.6f rotZ=%+2.6f",
00205 PnP_pose.x, PnP_pose.y, PnP_pose.z, PnP_pose.rotX, PnP_pose.rotY, PnP_pose.rotZ);
00206 ROS_DEBUG("trad_pose: x=%+2.6f y=%+2.6f z=%+2.6f rotX=%+2.6f rotY=%+2.6f rotZ=%+2.6f",
00207 current_frame.msg.pose.x, current_frame.msg.pose.y, current_frame.msg.pose.z,
00208 current_frame.msg.pose.rotX, current_frame.msg.pose.rotY,
00209 current_frame.msg.pose.rotZ);
00210
00211 mixed_pose = current_frame.msg.pose;
00212 mixed_pose.x = PnP_pose.x;
00213 mixed_pose.y = PnP_pose.y;
00214 mixed_pose.z = PnP_pose.z;
00215
00216
00217 mixed_pose.rotZ = PnP_pose.rotZ;
00218
00219 std::vector< cv::Point3f > points_out;
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 ROS_DEBUG("update inliers");
00258 projection_2D(frame_matching_points, mixed_pose, points_out);
00259 for (int i = 0; i < inliers.size(); i++)
00260 {
00261 int count = this->cloud->points[idx_matching_points[inliers[i]][0]].view_count;
00262 if (count <= 5)
00263 {
00264 double alpha = 1.0 / (count + 1.0);
00265 double beta = count / (count + 1.0);
00266
00267 this->cloud->points[idx_matching_points[inliers[i]][0]].x =
00268 beta * this->cloud->points[idx_matching_points[inliers[i]][0]].x +
00269 alpha * points_out[inliers[i]].x;
00270 this->cloud->points[idx_matching_points[inliers[i]][0]].y =
00271 beta * this->cloud->points[idx_matching_points[inliers[i]][0]].y +
00272 alpha * points_out[inliers[i]].y;
00273 this->cloud->points[idx_matching_points[inliers[i]][0]].z =
00274 beta * this->cloud->points[idx_matching_points[inliers[i]][0]].z +
00275 alpha * points_out[inliers[i]].z;
00276 }
00277 this->cloud->points[idx_matching_points[inliers[i]][0]].view_count += 1;
00278 }
00279
00280 if (frame_unknown_points.size() <= 200 &&
00281 2 * frame_unknown_points.size() <= frame_matching_points.size())
00282
00283 {
00284 ROS_DEBUG("NOT ENOUGH TO ADD !");
00285 return;
00286 }
00287 else
00288 {
00289 projection_2D(frame_unknown_points, mixed_pose, points_out);
00290
00291
00292
00293 pcl::PointCloud< pcl::PointXYZRGBSIFT >::Ptr pointcloud(
00294 new pcl::PointCloud< pcl::PointXYZRGBSIFT >);
00295 current_frame.convertToPcl(idx_unknown_points, points_out, pointcloud);
00296
00297 *(this->cloud) += *pointcloud;
00298 }
00299 this->visualizer->updatePointCloud< pcl::PointXYZRGBSIFT >(this->cloud, "SIFT_cloud");
00300
00301 }
00302 else
00303 {
00304 ROS_DEBUG("TRACKING LOST ! (not enough matching points)");
00305 tracking_lost = true;
00306 }
00307 }
00308 else
00309 {
00310 ROS_DEBUG("MAP INITIALIZATION");
00311 std::vector< cv::Point3f > points_out;
00312 projection_2D(current_frame.imgPoints, current_frame.msg.pose, points_out,
00313 true);
00314 pcl::PointCloud< pcl::PointXYZRGBSIFT >::Ptr pointcloud(
00315 new pcl::PointCloud< pcl::PointXYZRGBSIFT >);
00316 current_frame.convertToPcl(points_out, pointcloud);
00317 *(this->cloud) = *pointcloud;
00318 PnP_pose.z = 0.76;
00319 PnP_pose.header.stamp = processed_image_in->pose.header.stamp;
00320 pose_PnP_pub.publish(PnP_pose);
00321 this->visualizer->updatePointCloud< pcl::PointXYZRGBSIFT >(this->cloud, "SIFT_cloud");
00322 }
00323
00324 previous_frame = current_frame;
00325 }
00326
00328 void Map::targetDetectedPublisher()
00329 {
00330 if (processedImgReceived && target_pub.getNumSubscribers() > 0)
00331 {
00332 ROS_DEBUG("signal sent ImageProcessor::targetDetectedPublisher");
00333
00334 if (lastProcessedImgReceived->target_detected)
00335 {
00336 ROS_DEBUG("TARGET IS DETECTED");
00337
00338 ucl_drone::TargetDetected msg;
00339 msg.pose = lastProcessedImgReceived->pose;
00340
00341 msg.img_point.x = lastProcessedImgReceived->target_points[4].x;
00342 msg.img_point.y = lastProcessedImgReceived->target_points[4].y;
00343 msg.img_point.z = 0;
00344 std::vector< cv::Point2f > target_center(1);
00345 target_center[0].x = lastProcessedImgReceived->target_points[4].x;
00346 target_center[0].y = lastProcessedImgReceived->target_points[4].y;
00347 std::vector< cv::Point3f > world_coord;
00348 projection_2D(target_center, msg.pose, world_coord);
00349 msg.world_point.x = world_coord[0].x;
00350 msg.world_point.y = world_coord[0].y;
00351 msg.world_point.z = world_coord[0].z;
00352 target_pub.publish(msg);
00353 }
00354 }
00355 }
00356
00357 void Map::init_planes()
00358 {
00359 float thres = 0.9;
00360 cv::Mat top_left = (cv::Mat_< double >(3, 1) << -Read::img_center_x() / Read::focal_length_x(),
00361 -Read::img_center_y() / Read::focal_length_y(), thres);
00362 cv::Mat top_right = (cv::Mat_< double >(3, 1)
00363 << (Read::img_width() - Read::img_center_x()) / Read::focal_length_x(),
00364 -Read::img_center_y() / Read::focal_length_y(), thres);
00365 cv::Mat bottom_right =
00366 (cv::Mat_< double >(3, 1) << (Read::img_width() - Read::img_center_x()) /
00367 Read::focal_length_x(),
00368 (Read::img_height() - Read::img_center_y()) / Read::focal_length_y(), thres);
00369 cv::Mat bottom_left =
00370 (cv::Mat_< double >(3, 1) << -Read::img_center_x() / Read::focal_length_x(),
00371 (Read::img_height() - Read::img_center_y()) / Read::focal_length_y(), thres);
00372 cam_plane_top = top_left.cross(top_right);
00373 cam_plane_right = top_right.cross(bottom_right);
00374 cam_plane_bottom = bottom_right.cross(bottom_left);
00375 cam_plane_left = bottom_left.cross(top_left);
00376 ROS_DEBUG("MAp: planes initilized");
00377 }
00378
00380 void Map::getDescriptors(ucl_drone::Pose3D pose, cv::Mat& descriptors, std::vector< int >& idx,
00381 bool only_visible)
00382 {
00383
00384 if (!only_visible)
00385 {
00386 descriptors = cv::Mat_< float >(cloud->points.size(), DESCRIPTOR_SIZE);
00387 for (unsigned i = 0; i < cloud->points.size(); ++i)
00388 {
00389 cloud->points[i].x;
00390 cloud->points[i].y;
00391 cloud->points[i].z;
00392 for (unsigned j = 0; j < DESCRIPTOR_SIZE; ++j)
00393 {
00394 descriptors.at< float >(i, j) = cloud->points[i].descriptor[j];
00395 }
00396 idx.push_back(i);
00397 }
00398 }
00399 if (only_visible)
00400
00401 {
00402 ROS_DEBUG("GET_DESCRIPTORS, pose:pos(%f, %f, %f) rot(%f, %f, %f)", pose.x, pose.y, pose.z,
00403 pose.rotX, pose.rotY, pose.rotZ);
00404 double yaw = -pose.rotZ;
00405 double pitch = pose.rotY;
00406 double roll = pose.rotX;
00407
00408 cv::Mat world2drone = rollPitchYawToRotationMatrix(roll, pitch, yaw);
00409
00410 cv::Mat_< double > drone2cam =
00411 (cv::Mat_< double >(3, 3) << 0.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, -1.0);
00412 cv::Mat world2cam = drone2cam * world2drone;
00413
00414 ROS_DEBUG("TRANSFO READY");
00415
00416 cv::Mat world_plane_top = world2cam.t() * cam_plane_top;
00417 cv::Mat world_plane_right = world2cam.t() * cam_plane_right;
00418 cv::Mat world_plane_bottom = world2cam.t() * cam_plane_bottom;
00419 cv::Mat world_plane_left = world2cam.t() * cam_plane_left;
00420 cv::Mat translation = (cv::Mat_< double >(3, 1) << pose.x, pose.y, pose.z);
00421 double d_top = -translation.dot(world_plane_top);
00422 double d_right = -translation.dot(world_plane_right);
00423 double d_bottom = -translation.dot(world_plane_bottom);
00424 double d_left = -translation.dot(world_plane_left);
00425
00426 ROS_DEBUG("WORLD PLANES READY");
00427
00428 for (unsigned i = 0; i < cloud->points.size(); ++i)
00429 {
00430 cv::Mat point =
00431 (cv::Mat_< double >(3, 1) << cloud->points[i].x, cloud->points[i].y, cloud->points[i].z);
00432
00433 double t_top = point.dot(world_plane_top) + d_top;
00434 double t_right = point.dot(world_plane_right) + d_right;
00435 double t_bottom = point.dot(world_plane_bottom) + d_bottom;
00436 double t_left = point.dot(world_plane_left) + d_left;
00437
00438 if (t_top >= 0 && t_right >= 0 && t_bottom >= 0 && t_left >= 0)
00439 {
00440 idx.push_back(i);
00441 }
00442 }
00443 ROS_DEBUG(" %d POINTS VISIBLE", idx.size());
00444 descriptors = cv::Mat_< float >(idx.size(), DESCRIPTOR_SIZE);
00445 for (unsigned i = 0; i < idx.size(); ++i)
00446 {
00447 for (unsigned j = 0; j < DESCRIPTOR_SIZE; ++j)
00448 {
00449 descriptors.at< float >(i, j) = cloud->points[idx[i]].descriptor[j];
00450 }
00451 }
00452 }
00453 }
00454
00462 void Map::matchWithFrame(Frame& frame, std::vector< std::vector< int > >& idx_matching_points,
00463 std::vector< int >& idx_unknown_points,
00464 std::vector< cv::Point3f >& map_matching_points,
00465 std::vector< cv::Point2f >& frame_matching_points,
00466 std::vector< cv::Point2f >& frame_unknown_points)
00467 {
00468 bool use_ratio_test = false;
00469
00470 if (frame.descriptors.rows == 0)
00471 {
00472 return;
00473 }
00474
00475 std::vector< int > idx;
00476 cv::Mat map_descriptors;
00477 std::vector< int > map_idx;
00478 bool only_visible = !tracking_lost;
00479 this->getDescriptors(frame.msg.pose, map_descriptors, map_idx, only_visible);
00480 if (map_descriptors.rows == 0)
00481 {
00482 idx_unknown_points.resize(frame.imgPoints.size());
00483 frame_unknown_points.resize(frame.imgPoints.size());
00484 for (unsigned k = 0; k < frame.imgPoints.size(); k++)
00485 {
00486 idx_unknown_points[k] = k;
00487 frame_unknown_points[k] = frame.imgPoints[k];
00488 }
00489 return;
00490 }
00491 else
00492 {
00493
00494 if (use_ratio_test)
00495 {
00496 std::vector< std::vector< cv::DMatch > > knn_matches;
00497 matcher.knnMatch(frame.descriptors, map_descriptors, knn_matches, 2);
00498
00499
00500 for (unsigned k = 0; k < knn_matches.size(); k++)
00501 {
00502 if (knn_matches[k][0].distance / knn_matches[k][1].distance < 0.9)
00503 {
00504 if (knn_matches[k][0].distance < DIST_THRESHOLD)
00505 {
00506 std::vector< int > v(2);
00507 v[0] = map_idx[knn_matches[k][0].trainIdx];
00508 v[1] = knn_matches[k][0].queryIdx;
00509 idx_matching_points.push_back(v);
00510
00511 cv::Point3f map_point;
00512 pcl::PointXYZRGBSIFT pcl_point =
00513 this->cloud->points[map_idx[knn_matches[k][0].trainIdx]];
00514 map_point.x = pcl_point.x;
00515 map_point.y = pcl_point.y;
00516 map_point.z = pcl_point.z;
00517 map_matching_points.push_back(map_point);
00518 frame_matching_points.push_back(frame.imgPoints[knn_matches[k][0].queryIdx]);
00519 }
00520 else
00521 {
00522 idx_unknown_points.push_back(knn_matches[k][0].queryIdx);
00523 frame_unknown_points.push_back(frame.imgPoints[knn_matches[k][0].queryIdx]);
00524 }
00525 }
00526 }
00527 }
00528 else
00529 {
00530 std::vector< cv::DMatch > simple_matches;
00531 matcher.match(frame.descriptors, map_descriptors, simple_matches);
00532
00533
00534 for (unsigned k = 0; k < simple_matches.size(); k++)
00535 {
00536 if (simple_matches[k].distance < DIST_THRESHOLD)
00537 {
00538 std::vector< int > v(2);
00539 v[0] = map_idx[simple_matches[k].trainIdx];
00540 v[1] = simple_matches[k].queryIdx;
00541 idx_matching_points.push_back(v);
00542
00543 cv::Point3f map_point;
00544 pcl::PointXYZRGBSIFT pcl_point = this->cloud->points[map_idx[simple_matches[k].trainIdx]];
00545 map_point.x = pcl_point.x;
00546 map_point.y = pcl_point.y;
00547 map_point.z = pcl_point.z;
00548 map_matching_points.push_back(map_point);
00549 frame_matching_points.push_back(frame.imgPoints[simple_matches[k].queryIdx]);
00550 }
00551 else
00552 {
00553 idx_unknown_points.push_back(simple_matches[k].queryIdx);
00554 frame_unknown_points.push_back(frame.imgPoints[simple_matches[k].queryIdx]);
00555 }
00556 }
00557 }
00558 }
00559 }
00560
00561 void cloud_debug(pcl::PointCloud< pcl::PointXYZRGBSIFT >::ConstPtr cloud)
00562 {
00563 for (size_t i = 0; i < cloud->points.size(); ++i)
00564 {
00565 ROS_DEBUG("points[%d] = (%f, %f, %f)", i, cloud->points[i].x, cloud->points[i].y,
00566 cloud->points[i].z);
00567 }
00568 }
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584 int main(int argc, char** argv)
00585 {
00586 ros::init(argc, argv, "simple_map");
00587 ROS_INFO_STREAM("simple map started!");
00588
00589
00590
00591
00592
00593
00594 Map map;
00595
00596 ros::Rate r(12);
00597
00598 int visualizer_count = 0;
00599
00600
00601
00602 while (ros::ok())
00603 {
00604
00605
00606
00607
00608 map.visualizer->spinOnce(100);
00609
00610
00611
00612
00613 map.targetDetectedPublisher();
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626 if (map.pending_reset)
00627 {
00628 ros::Time t = ros::Time::now() + ros::Duration(1);
00629 while (ros::Time::now() < t)
00630 {
00631 ros::spinOnce();
00632 }
00633 map.pending_reset = false;
00634 }
00635
00636 ros::spinOnce();
00637 r.sleep();
00638 }
00639
00640 return 0;
00641 }