00001 #include <limits>
00002 #include <opencv/cv.h>
00003 #include <opencv2/imgproc/imgproc.hpp>
00004 #include <opencv2/highgui/highgui.hpp>
00005
00006 #include <hrl_phri_2011/PHRIPointCloudCapture.h>
00007 #include <hrl_phri_2011/pcl_features.h>
00008 #include <hrl_phri_2011/utils.h>
00009
00010 typedef hrl_phri_2011::PHRIPointCloudCapture PCC;
00011 typedef map<string, Eigen::Affine3d, less<string>,
00012 Eigen::aligned_allocator<std::pair<const string, Eigen::Affine3d> > > map_str_t3d;
00013
00014 void findOverlaps(const PCRGB::Ptr& target_pc, const PCRGB::Ptr& source_pc,
00015 pcl::IndicesPtr& target_inds_list, pcl::IndicesPtr& source_inds_list,
00016 double icp_radius=0.03, bool use_rgb=false, double color_weight=0.001)
00017 {
00018 KDTree::Ptr kd_tree(new pcl::KdTreeFLANN<PRGB> ());
00019 kd_tree->setInputCloud(target_pc);
00020 if(use_rgb){
00021 boost::shared_ptr<pcl::DefaultPointRepresentation<PRGB> const>
00022 pt_rep(new pcl::DefaultPointRepresentation<PRGB>(color_weight, color_weight, color_weight));
00023 kd_tree->setPointRepresentation(pt_rep);
00024 }
00025 vector<bool> target_inds(target_pc->points.size(), false);
00026 vector<bool> source_inds(source_pc->points.size(), false);
00027 for(uint32_t i=0;i<source_pc->points.size();i++) {
00028 vector<int> inds;
00029 vector<float> dists;
00030 kd_tree->radiusSearch(*source_pc, i, icp_radius, inds, dists);
00031 for(uint32_t j=0;j<inds.size();j++)
00032 target_inds[inds[j]] = true;
00033 if(inds.size() > 0)
00034 source_inds[i] = true;
00035 }
00036 for(uint32_t i=0;i<target_pc->points.size();i++)
00037 if(target_inds[i])
00038 target_inds_list->push_back(i);
00039 for(uint32_t i=0;i<source_pc->points.size();i++)
00040 if(source_inds[i])
00041 source_inds_list->push_back(i);
00042 }
00043
00044 void findTransformFromOverlapICP(const PCRGB::Ptr& target_pc, const PCRGB::Ptr& source_pc,
00045 Eigen::Affine3d& tf_mat)
00046 {
00047 int icp_iters, use_rgb;
00048 double color_weight, icp_radius;
00049 ros::param::param<int>("~icp_iters", icp_iters, 10);
00050 ros::param::param<double>("~color_weight", color_weight, 0.0005);
00051 ros::param::param<double>("~icp_radius", icp_radius, 0.05);
00052 ros::param::param<int>("~use_rgb", use_rgb, 1);
00053 ROS_INFO("PS %d %f %f", icp_iters, color_weight, icp_radius);
00054
00055 pcl::IndicesPtr target_inds_list(new vector<int>()), source_inds_list(new vector<int>());
00056 findOverlaps(target_pc, source_pc, target_inds_list, source_inds_list, icp_radius, use_rgb, color_weight);
00057 ROS_INFO("INDS %d %d", target_inds_list->size(), source_inds_list->size());
00058 PCRGB::Ptr target_pc_ol(new PCRGB());
00059 PCRGB::Ptr source_pc_ol(new PCRGB());
00060 extractIndices(target_pc, target_inds_list, target_pc_ol);
00061 extractIndices(source_pc, source_inds_list, source_pc_ol);
00062 ROS_INFO("PC COUNT %d %d", target_pc_ol->points.size(), source_pc_ol->points.size());
00063 computeICPRegistration(target_pc_ol, source_pc_ol, tf_mat, icp_iters, color_weight);
00064 }
00065
00066 void erodePC(const PCRGB::Ptr& target_pc, const vector<int>& inds, PCRGB::Ptr& eroded_pc)
00067 {
00068 cv::Mat pc_img = cv::Mat::zeros(640, 480, CV_32F);
00069 cv::Mat pc_img_eroded = cv::Mat::zeros(640, 480, CV_32F);
00070 for(uint32_t i=0;i<inds.size();i++)
00071 if(target_pc->points[i].x == target_pc->points[i].x &&
00072 target_pc->points[i].y == target_pc->points[i].y &&
00073 target_pc->points[i].z == target_pc->points[i].z) {
00074 pc_img.at<uint8_t>(inds[i] % 640, inds[i] / 640) = 1.0;
00075 }
00076
00077 IplImage pc_img_ipl = pc_img, pc_img_eroded_ipl = pc_img_eroded;
00078 int num_erode;
00079 ros::NodeHandle nh_priv("~");
00080 nh_priv.param<int>("num_erode", num_erode, 2);
00081 if(num_erode > 0)
00082 cvErode(&pc_img_ipl, &pc_img_eroded_ipl, NULL, num_erode);
00083 else
00084 pc_img_eroded_ipl = pc_img_ipl;
00085 pcl::IndicesPtr inds_erode(new vector<int>());
00086 for(uint32_t i=0;i<inds.size();i++)
00087 if(pc_img_eroded.at<uint8_t>(inds[i] % 640, inds[i] / 640) == 1.0)
00088 inds_erode->push_back(i);
00089
00090 pcl::ExtractIndices<PRGB> extract_inds;
00091 extract_inds.setInputCloud(target_pc);
00092 extract_inds.setIndices(inds_erode);
00093 extract_inds.filter(*eroded_pc);
00094 }
00095
00096 void extractPCs(const vector<PCC::Ptr> & captures, vector<PCRGB::Ptr>& pc_list)
00097 {
00098 double z_cutoff;
00099 ros::param::param<double>("~z_cutoff", z_cutoff, -0.2);
00100 BOOST_FOREACH(PCC::Ptr pcc, captures) {
00101 map_str_t3d cap_poses;
00102 for(uint32_t i=0;i<pcc->frame_names.size();i++)
00103 tf::poseMsgToEigen(pcc->saved_frames[i].pose, cap_poses[pcc->frame_names[i]]);
00104
00105 PCRGB pc_raw, pc_trans, pc_filtered;
00106 pcl::fromROSMsg(pcc->pc_capture, pc_raw);
00107 std::vector<int> inds;
00108
00109 Eigen::Affine3d pc_tf(cap_poses["/head_center"].inverse() * cap_poses["/openni_rgb_optical_frame"]);
00110 transformPC(pc_raw, pc_trans, pc_tf);
00111
00112 for(size_t i=0;i<pc_trans.points.size();i++) {
00113 const PRGB p = pc_trans.points[i];
00114 PRGB new_p;
00115 if(p.x == p.x && p.y == p.y && p.z == p.z &&
00116 p.x > -0.22 && p.x < 0.22 && p.y > -0.15 && p.y < 0.15 && p.z > z_cutoff && p.z < 0.25) {
00117 new_p.x = p.x; new_p.y = p.y; new_p.z = p.z; new_p.rgb = p.rgb;
00118 inds.push_back(i);
00119 pc_filtered.points.push_back(new_p);
00120 } else {
00121 new_p.x = numeric_limits<float>::quiet_NaN();
00122 new_p.y = numeric_limits<float>::quiet_NaN();
00123 new_p.z = numeric_limits<float>::quiet_NaN();
00124 }
00125 }
00126
00127
00128
00129 PCRGB::Ptr pc_eroded(new PCRGB());
00130 erodePC(pc_filtered.makeShared(), inds, pc_eroded);
00131
00132
00133
00134 pc_list.push_back(pc_eroded);
00135 }
00136 }
00137
00138 void concatRegisteredPC(PCRGB::Ptr& target_pc, const PCRGB::Ptr& source_pc, double keep_radius)
00139 {
00140 PCRGB::Ptr source_tf_pc(new PCRGB()), source_filtered_pc(new PCRGB());
00141 Eigen::Affine3d tf_mat;
00142 findTransformFromOverlapICP(target_pc, source_pc, tf_mat);
00143 transformPC(*source_pc, *source_tf_pc, tf_mat);
00144
00145 pcl::IndicesPtr target_inds_list(new vector<int>()), source_inds_list(new vector<int>());
00146 findOverlaps(target_pc, source_tf_pc, target_inds_list, source_inds_list, keep_radius);
00147 pcl::ExtractIndices<PRGB> extract_inds;
00148 extract_inds.setNegative(true);
00149 extract_inds.setInputCloud(source_tf_pc);
00150 extract_inds.setIndices(source_inds_list);
00151 extract_inds.filter(*source_filtered_pc);
00152 target_pc->operator+=(*source_filtered_pc);
00153 }
00154
00155 void stitchPCs(std::vector<PCC::Ptr> &captures, double keep_radius)
00156 {
00157 vector<PCRGB::Ptr> pc_list;
00158 extractPCs(captures, pc_list);
00159 int num_pc = (int) pc_list.size();
00160 PCRGB::Ptr pc_combo(new PCRGB());
00161 pc_combo->operator+=(*pc_list[0]);
00162 ROS_INFO("Begin Stitching");
00163 for(int i=1;i<=num_pc/2-1;i++) {
00164 concatRegisteredPC(pc_combo, pc_list[i], keep_radius);
00165 ROS_INFO("Stitched cloud %d", i);
00166 }
00167 for(int i=num_pc-1;i>=num_pc/2;i--) {
00168 concatRegisteredPC(pc_combo, pc_list[i], keep_radius);
00169 ROS_INFO("Stitched cloud %d", i);
00170 }
00171 pc_combo->header.frame_id = "/head_center";
00172 ROS_INFO("Publishing PC to topic /stitched_head");
00173 pubLoop(*pc_combo, "/stitched_head");
00174 }
00175
00176 void displayRawPCs(std::vector<PCC::Ptr> &captures)
00177 {
00178 vector<PCRGB::Ptr> pc_list;
00179 extractPCs(captures, pc_list);
00180 PCRGB pc_combo;
00181 BOOST_FOREACH(PCRGB::Ptr const pc, pc_list) {
00182 pc_combo += *pc;
00183 }
00184 pc_combo.header.frame_id = "/head_center";
00185 pubLoop(pc_combo, "/stitched_head");
00186 }
00187
00188 int main(int argc, char **argv)
00189 {
00190 ros::init(argc, argv, "pc_head_stitcher");
00191
00192
00193 rosbag::Bag bag;
00194 bag.open(std::string(argv[1]), rosbag::bagmode::Read);
00195 rosbag::View view(bag, rosbag::TopicQuery("/point_cloud_captures"));
00196 std::vector<PCC::Ptr> captures;
00197 BOOST_FOREACH(rosbag::MessageInstance const m, view) {
00198 captures.push_back(m.instantiate<PCC>());
00199 }
00200 double keep_radius;
00201 ros::NodeHandle nh_priv("~");
00202 nh_priv.param<double>("keep_radius", keep_radius, 0.01);
00203
00204 if(argc == 2)
00205 stitchPCs(captures, keep_radius);
00206 if(argc == 3 && argv[2][0] == 'd')
00207 displayRawPCs(captures);
00208
00209 return 0;
00210 }