00001
00002 #include <hrl_head_registration/head_registration.h>
00003
00004 #define USE_COLOR_MODEL
00005
00006 void extractSkinPC(const PCRGB::Ptr& pc_in, PCRGB::Ptr& pc_out, double thresh)
00007 {
00008 uint8_t r, g, b;
00009 double skin_like, h, s, l;
00010 for(uint32_t i=0;i<pc_in->size();i++) {
00011 if(PT_IS_NOT_NAN(pc_in, i)) {
00012 extractRGB(pc_in->points[i].rgb, r, g, b);
00013 skin_like = skin_likelihood(r, g, b);
00014 if(skin_like > thresh)
00015 COPY_PT_INTO_CLOUD(pc_in, pc_out, i);
00016 }
00017 }
00018 }
00019
00020 int32_t findClosestPoint(const PCRGB::Ptr& pc, uint32_t u, uint32_t v)
00021 {
00022 if(PT_IS_NOT_NAN(pc, v*640 + u))
00023 return v*640 + u;
00024 for(uint32_t i=1;i<5;i++) {
00025 for(uint32_t j=1;j<5;j++) {
00026 if(PT_IS_NOT_NAN(pc, v*640 + u + i))
00027 return v*640 + u + i;
00028 if(PT_IS_NOT_NAN(pc, v*640 + u - i))
00029 return v*640 + u + i;
00030 if(PT_IS_NOT_NAN(pc, v*640 + u + j*640))
00031 return v*640 + u + i;
00032 if(PT_IS_NOT_NAN(pc, v*640 + u - j*640))
00033 return v*640 + u + i;
00034 }
00035 }
00036 return -1;
00037 }
00038
00039 void generateColorModel(const PCRGB::Ptr& pc_in, Eigen::Vector3d& mean, Eigen::Matrix3d& cov)
00040 {
00041 Eigen::MatrixXd X(3, pc_in->size());
00042 for(uint32_t i=0;i<pc_in->size();i++)
00043 extractHSL(pc_in->points[i].rgb, X(0,i), X(1,i), X(2,i));
00044 mean = X.rowwise().sum() / pc_in->size();
00045 cov = X * X.transpose() / pc_in->size() - mean * mean.transpose();
00046 }
00047
00048 bool extractPCFromColorModel(const PCRGB::Ptr& pc_in, PCRGB::Ptr& pc_out,
00049 Eigen::Vector3d& mean, Eigen::Matrix3d& cov, double std_devs)
00050 {
00051 double hue_weight;
00052 ros::param::param<double>("~hue_weight", hue_weight, 1.0);
00053 printf("%f\n", hue_weight);
00054
00055 Eigen::Vector3d x, x_m;
00056 Eigen::Matrix3d cov_inv = cov.inverse();
00057 for(uint32_t i=0;i<pc_in->size();i++) {
00058 extractHSL(pc_in->points[i].rgb, x(0), x(1), x(2));
00059 x_m = x - mean;
00060 x_m(0) *= hue_weight;
00061 double dist = std::sqrt(x_m.transpose() * cov_inv * x_m);
00062 if(dist <= std_devs)
00063 pc_out->points.push_back(pc_in->points[i]);
00064 }
00065 }
00066
00067 void sphereTrim(const PCRGB::Ptr& pc_in, PCRGB::Ptr& pc_out, uint32_t ind, double radius)
00068 {
00069 KDTree::Ptr kd_tree(new pcl::KdTreeFLANN<PRGB> ());
00070 kd_tree->setInputCloud(pc_in);
00071 vector<int> inds;
00072 vector<float> dists;
00073 kd_tree->radiusSearch(*pc_in, ind, radius, inds, dists);
00074 for(uint32_t j=0;j<inds.size();j++)
00075 COPY_PT_INTO_CLOUD(pc_in, pc_out, inds[j]);
00076 }
00077
00078 namespace pcl {
00079
00080 class ColorPointRepresentation : public PointRepresentation<PRGB> {
00081 public:
00082 ColorPointRepresentation(float h_mult = 0.0005, float s_mult = 0.0005, float l_mult = 0.0005) {
00083 nr_dimensions_ = 6;
00084 alpha_.resize(6);
00085 alpha_[0] = 1; alpha_[1] = 1; alpha_[2] = 1;
00086 alpha_[3] = h_mult; alpha_[4] = s_mult; alpha_[5] = l_mult;
00087 }
00088 virtual void copyToFloatArray(const PRGB& p, float* out) const {
00089 double h, s, l;
00090 extractHSL(p.rgb, h, s, l);
00091 out[0] = p.x; out[1] = p.y; out[2] = p.z;
00092 out[3] = h; out[4] = s; out[5] = l;
00093 }
00094
00095
00096
00097
00098
00099
00100 };
00101 }
00102
00103 void computeICPRegistration(const PCRGB::Ptr& target_pc, const PCRGB::Ptr& source_pc,
00104 Eigen::Affine3d& tf_mat, int max_iters, double color_weight)
00105 {
00106 double icp_trans_eps, icp_max_corresp;
00107 ros::param::param<double>("~icp_max_corresp", icp_max_corresp, 0.1);
00108 ros::param::param<double>("~icp_trans_eps", icp_trans_eps, 1e-6);
00109 pcl::IterativeClosestPoint<PRGB, PRGB> icp;
00110 PCRGB::Ptr aligned_pc(new PCRGB());
00111 boost::shared_ptr<pcl::PointRepresentation<PRGB> const>
00112 pt_rep(new pcl::ColorPointRepresentation(color_weight, color_weight, color_weight));
00113 icp.setPointRepresentation(pt_rep);
00114 icp.setInputTarget(target_pc);
00115 icp.setInputCloud(source_pc);
00116 icp.setTransformationEpsilon(icp_trans_eps);
00117 icp.setMaxCorrespondenceDistance(icp_max_corresp);
00118 icp.setMaximumIterations(max_iters);
00119 icp.align(*aligned_pc);
00120 tf_mat = icp.getFinalTransformation().cast<double>();
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 #if 0
00143 vector<PCRGB::Ptr> pcs;
00144 vector<string> pc_topics;
00145 aligned_pc->header.frame_id = "/openni_rgb_optical_frame";
00146 source_pc->header.frame_id = "/openni_rgb_optical_frame";
00147 target_pc->header.frame_id = "/openni_rgb_optical_frame";
00148 pcs.push_back(aligned_pc);
00149 pcs.push_back(source_pc);
00150 pcs.push_back(target_pc);
00151 pc_topics.push_back("/aligned_pc");
00152 pc_topics.push_back("/source_pc");
00153 pc_topics.push_back("/target_pc");
00154 pubLoop(pcs, pc_topics, 5.0, 5);
00155 #endif
00156 }
00157
00158 void extractFace(const PCRGB::Ptr& input_pc, PCRGB::Ptr& out_pc, int u_click, int v_click)
00159 {
00160 double trim_radius, skin_thresh;
00161 ros::param::param<double>("~trim_radius", trim_radius, 0.12);
00162 ros::param::param<double>("~skin_thresh", skin_thresh, 0.8);
00163
00164 PCRGB::Ptr trimmed_pc(new PCRGB());
00165 int32_t closest_ind = findClosestPoint(input_pc, u_click, v_click);
00166 if(closest_ind < 0)
00167 return;
00168 sphereTrim(input_pc, trimmed_pc, closest_ind, trim_radius);
00169 extractSkinPC(trimmed_pc, out_pc, skin_thresh);
00170 }
00171
00172 void extractFaceColorModel(const PCRGB::Ptr& input_pc, PCRGB::Ptr& out_pc, int u_click, int v_click)
00173 {
00174 double trim_radius, model_radius, color_std_thresh;
00175 ros::param::param<double>("~trim_radius", trim_radius, 0.12);
00176 ros::param::param<double>("~model_radius", model_radius, 0.02);
00177 ros::param::param<double>("~color_std_thresh", color_std_thresh, 1.5);
00178
00179 int32_t closest_ind = findClosestPoint(input_pc, u_click, v_click);
00180 if(closest_ind < 0)
00181 return;
00182
00183 PCRGB::Ptr model_pc(new PCRGB());
00184 sphereTrim(input_pc, model_pc, closest_ind, model_radius);
00185 Eigen::Vector3d mean_color;
00186 Eigen::Matrix3d cov_color;
00187 generateColorModel(model_pc, mean_color, cov_color);
00188
00189 PCRGB::Ptr trimmed_pc(new PCRGB());
00190 sphereTrim(input_pc, trimmed_pc, closest_ind, trim_radius);
00191 extractPCFromColorModel(trimmed_pc, out_pc, mean_color, cov_color, color_std_thresh);
00192 }
00193
00194 bool findFaceRegistration(const PCRGB::Ptr& template_pc, const PCRGB::Ptr& input_pc,
00195 int u_click, int v_click, Eigen::Affine3d& tf_mat)
00196 {
00197 double color_weight;
00198 int max_iters;
00199 ros::param::param<double>("~color_weight", color_weight, 0.0);
00200 ros::param::param<int>("~max_iters", max_iters, 200);
00201 PCRGB::Ptr skin_pc(new PCRGB());
00202
00203 #ifdef USE_COLOR_MODEL
00204 extractFaceColorModel(input_pc, skin_pc, u_click, v_click);
00205 #else
00206 extractFace(input_pc, skin_pc, u_click, v_click);
00207 #endif
00208 if(skin_pc->size() == 0)
00209 return false;
00210 computeICPRegistration(template_pc, skin_pc, tf_mat, max_iters, color_weight);
00211
00212 return true;
00213 }
00214
00215 int main(int argc, char **argv)
00216 {
00217 ros::init(argc, argv, "head_registration");
00218 ros::NodeHandle nh;
00219
00220 #if 0
00221 PCRGB::Ptr input_pc, template_pc;
00222 readPCBag(argv[1], template_pc);
00223 readPCBag(argv[2], input_pc);
00224 int u, v;
00225 FILE* file = fopen(argv[3], "r");
00226 fscanf(file, "%d,%d\n", &u, &v);
00227 fclose(file);
00228
00229 Eigen::Affine3d tf_mat;
00230 findFaceRegistration(template_pc, input_pc, u, v, tf_mat);
00231
00232 PCRGB::Ptr tf_pc(new PCRGB());
00233 transformPC(*input_pc, *tf_pc, tf_mat);
00234 tf_pc->header.frame_id = "/base_link";
00235 pubLoop(tf_pc, "test", 5);
00236 return 0;
00237 #endif
00238
00239 #if 1
00240 PCRGB::Ptr input_pc(new PCRGB()), face_extract_pc(new PCRGB());
00241 readPCBag(argv[1], input_pc);
00242 int u, v;
00243 FILE* file = fopen(argv[2], "r");
00244 fscanf(file, "%d,%d\n", &u, &v);
00245 fclose(file);
00246 Eigen::Affine3d tf_mat;
00247 extractFaceColorModel(input_pc, face_extract_pc, u, v);
00248 face_extract_pc->header.frame_id = "/base_link";
00249 pubLoop(face_extract_pc, "/test", 5);
00250 #endif
00251
00252 }