00001 #include <sstream>
00002 #include <iostream>
00003 #include <fstream>
00004 #include <tabletop_pushing/shape_features.h>
00005 #include <pcl16_ros/transforms.h>
00006 #include <pcl16/ros/conversions.h>
00007 #include <pcl16/surface/concave_hull.h>
00008 #include <pcl16/common/pca.h>
00009
00010 #include <pcl16/registration/transformation_estimation_lm.h>
00011 #include <cpl_visual_features/comp_geometry.h>
00012 #include <cpl_visual_features/helpers.h>
00013 #include <iostream>
00014
00015 #define XY_RES 0.00075
00016 #define DRAW_LR_LIMITS 1
00017
00018
00019 using namespace cpl_visual_features;
00020 using tabletop_pushing::ProtoObject;
00021 typedef tabletop_pushing::VisFeedbackPushTrackingFeedback PushTrackerState;
00022
00023 namespace tabletop_pushing
00024 {
00025
00026 inline int getHistBinIdx(int x_idx, int y_idx, int n_x_bins, int n_y_bins)
00027 {
00028 return x_idx*n_y_bins+y_idx;
00029 }
00030
00031 inline int worldLocToIdx(double val, double min_val, double max_val)
00032 {
00033 return round((val-min_val)/XY_RES);
00034 }
00035
00036 inline int objLocToIdx(double val, double min_val, double max_val)
00037 {
00038 return round((val-min_val)/XY_RES);
00039 }
00040
00041 cv::Point worldPtToImgPt(pcl16::PointXYZ world_pt, double min_x, double max_x,
00042 double min_y, double max_y)
00043 {
00044 cv::Point img_pt(worldLocToIdx(world_pt.x, min_x, max_x),
00045 worldLocToIdx(world_pt.y, min_y, max_y));
00046 return img_pt;
00047 }
00048
00049 pcl16::PointXYZ worldPointInObjectFrame(pcl16::PointXYZ world_pt, PushTrackerState& cur_state)
00050 {
00051
00052 pcl16::PointXYZ shifted_pt;
00053 shifted_pt.x = world_pt.x - cur_state.x.x;
00054 shifted_pt.y = world_pt.y - cur_state.x.y;
00055 shifted_pt.z = world_pt.z - cur_state.z;
00056 double ct = cos(cur_state.x.theta);
00057 double st = sin(cur_state.x.theta);
00058
00059 pcl16::PointXYZ obj_pt;
00060 obj_pt.x = ct*shifted_pt.x + st*shifted_pt.y;
00061 obj_pt.y = -st*shifted_pt.x + ct*shifted_pt.y;
00062 obj_pt.z = shifted_pt.z;
00063 return obj_pt;
00064 }
00065
00066 std::vector<int> getJumpIndices(XYZPointCloud& concave_hull, double alpha)
00067 {
00068 std::vector<int> jump_indices;
00069 for (int i = 0; i < concave_hull.size(); i++)
00070 {
00071 if (dist(concave_hull[i], concave_hull[(i+1)%concave_hull.size()]) > 2.0*alpha)
00072 {
00073 jump_indices.push_back(i);
00074 }
00075 }
00076 return jump_indices;
00077 }
00078
00079 XYZPointCloud getObjectBoundarySamples(ProtoObject& cur_obj, double hull_alpha)
00080 {
00081
00082
00083 XYZPointCloud footprint_cloud(cur_obj.cloud);
00084 for (int i = 0; i < footprint_cloud.size(); ++i)
00085 {
00086
00087 footprint_cloud.at(i).z = -0.3;
00088 }
00089
00090
00091 XYZPointCloud hull_cloud;
00092 pcl16::ConcaveHull<pcl16::PointXYZ> hull;
00093 hull.setDimension(2);
00094 hull.setInputCloud(footprint_cloud.makeShared());
00095 hull.setAlpha(hull_alpha);
00096 hull.reconstruct(hull_cloud);
00097 return hull_cloud;
00098 }
00099
00100 cpl_visual_features::Path compareBoundaryShapes(XYZPointCloud& hull_a, XYZPointCloud& hull_b,
00101 double& min_cost, double epsilon_cost)
00102 {
00103 Samples2f samples_a, samples_b;
00104 for (unsigned int i = 0; i < hull_a.size(); ++i)
00105 {
00106 cv::Point2f pt(hull_a[i].x, hull_a[i].y);
00107 samples_a.push_back(pt);
00108 }
00109 for (unsigned int i = 0; i < hull_b.size(); ++i)
00110 {
00111 cv::Point2f pt(hull_b[i].x, hull_b[i].y);
00112 samples_b.push_back(pt);
00113 }
00114
00115 int radius_bins = 5;
00116 int theta_bins = 12;
00117 ShapeDescriptors descriptors_a = constructDescriptors<Samples2f>(samples_a, radius_bins, theta_bins);
00118 ShapeDescriptors descriptors_b = constructDescriptors<Samples2f>(samples_b, radius_bins, theta_bins);
00119
00120 cv::Mat cost_mat = computeCostMatrix(descriptors_a, descriptors_b, epsilon_cost);
00121 cv::imshow("cost matrix", cost_mat);
00122 cpl_visual_features::Path path;
00123
00124 min_cost = getMinimumCostPath(cost_mat, path);
00125
00126 return path;
00127 }
00128
00129 void estimateTransformFromMatches(XYZPointCloud& cloud_t_0, XYZPointCloud& cloud_t_1,
00130 cpl_visual_features::Path p, Eigen::Matrix4f& transform, double max_dist)
00131 {
00132
00133 std::vector<int> source_indices;
00134 std::vector<int> target_indices;
00135
00136
00137
00138
00139
00140
00141 for (int i = 0; i < p.size(); ++i)
00142 {
00143
00144 if(i < cloud_t_0.size() && p[i] < cloud_t_1.size() &&
00145 PointCloudSegmentation::sqrDist(cloud_t_0.at(i), cloud_t_1.at(p[i])) < max_dist)
00146 {
00147 source_indices.push_back(i);
00148 target_indices.push_back(p[i]);
00149 }
00150 }
00151 ROS_INFO_STREAM("Path had " << p.size() << " matches.\tNow have " << source_indices.size() << " matches.");
00152 pcl16::registration::TransformationEstimationLM<pcl16::PointXYZ, pcl16::PointXYZ> tlm;
00153 tlm.estimateRigidTransformation(cloud_t_0, source_indices, cloud_t_1, target_indices, transform);
00154 }
00155
00156 cv::Mat visualizeObjectBoundarySamples(XYZPointCloud& hull_cloud, PushTrackerState& cur_state)
00157 {
00158 double max_y = 0.3;
00159 double min_y = -0.3;
00160 double max_x = 0.3;
00161 double min_x = -0.3;
00162 int rows = ceil((max_y-min_y)/XY_RES);
00163 int cols = ceil((max_x-min_x)/XY_RES);
00164 cv::Mat footprint(rows, cols, CV_8UC3, cv::Scalar(255,255,255));
00165
00166 for (int i = 0; i < hull_cloud.size(); ++i)
00167 {
00168 pcl16::PointXYZ obj_pt = worldPointInObjectFrame(hull_cloud[i], cur_state);
00169 int img_x = objLocToIdx(obj_pt.x, min_x, max_x);
00170 int img_y = objLocToIdx(obj_pt.y, min_y, max_y);
00171 cv::Scalar color(128, 0, 0);
00172 cv::circle(footprint, cv::Point(img_x, img_y), 1, color, 3);
00173 }
00174 return footprint;
00175 }
00176
00177 cv::Mat visualizeObjectBoundaryMatches(XYZPointCloud& hull_a, XYZPointCloud& hull_b,
00178 PushTrackerState& cur_state, cpl_visual_features::Path& path)
00179 {
00180 double max_y = 0.3;
00181 double min_y = -0.3;
00182 double max_x = 0.3;
00183 double min_x = -0.3;
00184 double max_displacement = 100;
00185 int rows = ceil((max_y-min_y)/XY_RES);
00186 int cols = ceil((max_x-min_x)/XY_RES);
00187 cv::Mat match_img(rows, cols, CV_8UC3, cv::Scalar(255,255,255));
00188
00189 cv::Scalar blue(128, 0, 0);
00190 cv::Scalar green(0, 128, 0);
00191 cv::Scalar red(0, 0, 128);
00192
00193 for (int i = 0; i < hull_a.size(); ++i)
00194 {
00195 pcl16::PointXYZ start_point_world = hull_a[i];
00196 pcl16::PointXYZ end_point_world = hull_b[path[i]];
00197
00198 pcl16::PointXYZ start_point_obj = worldPointInObjectFrame(start_point_world, cur_state);
00199 pcl16::PointXYZ end_point_obj = worldPointInObjectFrame(end_point_world, cur_state);
00200 cv::Point start_point(objLocToIdx(start_point_obj.x, min_x, max_x),
00201 objLocToIdx(start_point_obj.y, min_y, max_y));
00202 cv::Point end_point(objLocToIdx(end_point_obj.x, min_x, max_x),
00203 objLocToIdx(end_point_obj.y, min_y, max_y));
00204
00205
00206 cv::circle(match_img, start_point, 1, green, 3);
00207 cv::circle(match_img, end_point, 1, blue, 3);
00208
00209 if (end_point.x > 0 && end_point.x < match_img.rows &&
00210 end_point.y > 0 && end_point.x < match_img.cols &&
00211 std::abs(start_point.x - end_point.x) +
00212 std::abs(start_point.y - end_point.y) < max_displacement)
00213 {
00214 cv::line(match_img, start_point, end_point, red);
00215 }
00216
00217 }
00218 return match_img;
00219 }
00220
00221 cv::Mat visualizeObjectContactLocation(XYZPointCloud& hull_cloud, PushTrackerState& cur_state,
00222 pcl16::PointXYZ& contact_pt, pcl16::PointXYZ& forward_pt)
00223 {
00224 double max_y = 0.3;
00225 double min_y = -0.3;
00226 double max_x = 0.3;
00227 double min_x = -0.3;
00228
00229 cv::Mat footprint = visualizeObjectBoundarySamples(hull_cloud, cur_state);
00230 pcl16::PointXYZ contact_pt_obj = worldPointInObjectFrame(contact_pt, cur_state);
00231 int img_x = objLocToIdx(contact_pt_obj.x, min_x, max_x);
00232 int img_y = objLocToIdx(contact_pt_obj.y, min_y, max_y);
00233 pcl16::PointXYZ forward_pt_obj = worldPointInObjectFrame(forward_pt, cur_state);
00234 int img_x_1 = objLocToIdx(forward_pt_obj.x, min_x, max_x);
00235 int img_y_1 = objLocToIdx(forward_pt_obj.y, min_y, max_y);
00236 cv::Scalar color(0, 0, 128);
00237 cv::line(footprint, cv::Point(img_x, img_y), cv::Point(img_x_1, img_y_1), color, 1);
00238 cv::circle(footprint, cv::Point(img_x, img_y), 3, color, 3);
00239 cv::circle(footprint, cv::Point(img_x_1, img_y_1), 3, color, 3);
00240
00241
00242
00243
00244
00245
00246 return footprint;
00247 }
00248
00249 cv::Mat getObjectFootprint(cv::Mat obj_mask, pcl16::PointCloud<pcl16::PointXYZ>& cloud)
00250 {
00251 cv::Mat kernel(5,5,CV_8UC1, 255);
00252 cv::Mat obj_mask_target;
00253 obj_mask.copyTo(obj_mask_target);
00254
00255 cv::dilate(obj_mask, obj_mask_target, kernel);
00256 cv::erode(obj_mask_target, obj_mask, kernel);
00257
00258 double min_x = 300., max_x = -300.;
00259 double min_y = 300., max_y = -300.;
00260
00261 for (int r = 0; r < obj_mask.rows; ++r)
00262 {
00263 for (int c = 0; c < obj_mask.cols; ++c)
00264 {
00265 if (obj_mask.at<uchar>(r,c) > 0)
00266 {
00267 double x = cloud.at(c,r).x;
00268 double y = cloud.at(c,r).y;
00269 if (x < min_x) min_x = x;
00270 if (x > max_x) max_x = x;
00271 if (y < min_y) min_y = y;
00272 if (y > max_y) max_y = y;
00273 }
00274 }
00275 }
00276 int rows = ceil((max_y-min_y)/XY_RES);
00277 int cols = ceil((max_x-min_x)/XY_RES);
00278 cv::Mat footprint(rows, cols, CV_8UC1, cv::Scalar(0));
00279 for (int r = 0; r < obj_mask.rows; ++r)
00280 {
00281 for (int c = 0; c < obj_mask.cols; ++c)
00282 {
00283 if (obj_mask.at<uchar>(r,c) > 0)
00284 {
00285
00286 double x = cloud.at(c,r).x;
00287 double y = cloud.at(c,r).y;
00288 if (isnan(x) || isnan(y))
00289 continue;
00290 int img_x = worldLocToIdx(x, min_x, max_x);
00291 int img_y = worldLocToIdx(y, min_y, max_y);
00292 if (img_y > rows ||img_x > cols || img_y < 0 || img_x < 0)
00293 {
00294 ROS_WARN_STREAM("Image index out of bounds! at (" << img_y << ", " << img_x <<
00295 ", " << y << ", " << x << ")");
00296 ROS_WARN_STREAM("X extremes: (" << min_x << ", " << max_x << ")");
00297 ROS_WARN_STREAM("Y extremes: (" << min_y << ", " << max_y << ")");
00298 ROS_WARN_STREAM("image size: (" << rows << ", " << cols << ")");
00299 }
00300 footprint.at<uchar>(img_y, img_x) = 255;
00301 }
00302 }
00303 }
00304
00305 cv::dilate(footprint, footprint, kernel);
00306 cv::erode(footprint, footprint, kernel);
00307
00308 cv::erode(footprint, footprint, kernel);
00309 cv::dilate(footprint, footprint, kernel);
00310 return footprint;
00311 }
00312
00313 ShapeLocations extractObjectShapeContext(ProtoObject& cur_obj, bool use_center)
00314 {
00315 XYZPointCloud samples_pcl = getObjectBoundarySamples(cur_obj);
00316 return extractShapeContextFromSamples(samples_pcl, cur_obj, use_center);
00317 }
00318
00319 ShapeLocations extractShapeContextFromSamples(XYZPointCloud& samples_pcl, ProtoObject& cur_obj, bool use_center)
00320 {
00321 Samples2f samples;
00322 for (unsigned int i = 0; i < samples_pcl.size(); ++i)
00323 {
00324 cv::Point2f pt(samples_pcl[i].x, samples_pcl[i].y);
00325 samples.push_back(pt);
00326 }
00327 int radius_bins = 5;
00328 int theta_bins = 12;
00329 double max_radius = 0.5;
00330 cv::Point2f center(cur_obj.centroid[0], cur_obj.centroid[1]);
00331 ShapeDescriptors descriptors = constructDescriptors(samples, center, use_center, radius_bins, theta_bins, max_radius);
00332 ShapeLocations locs;
00333 for (unsigned int i = 0; i < descriptors.size(); ++i)
00334 {
00335 ShapeLocation loc(samples_pcl[i], descriptors[i]);
00336 locs.push_back(loc);
00337 }
00338
00339 return locs;
00340 }
00341
00342 cv::Mat makeHistogramImage(ShapeDescriptor histogram, int n_x_bins, int n_y_bins, int bin_width_pixels)
00343 {
00344 cv::Mat hist_img(n_x_bins*bin_width_pixels+1, n_y_bins*bin_width_pixels+1, CV_8UC1, cv::Scalar(255));
00345 int max_count = 10;
00346 for (int i = 0; i < histogram.size(); ++i)
00347 {
00348 if (histogram[i] == 0) continue;
00349 int pix_val = (1 - histogram[i]/max_count)*255;
00350 int start_x = (i%n_x_bins)*bin_width_pixels;
00351 int start_y = (i/n_x_bins)*bin_width_pixels;;
00352
00353 for (int x = start_x; x < start_x+bin_width_pixels; ++x)
00354 {
00355 for (int y = start_y; y < start_y+bin_width_pixels; ++y)
00356 {
00357 hist_img.at<uchar>(y, x) = pix_val;
00358 }
00359 }
00360 }
00361
00362 for (int i = 0; i <= n_x_bins; ++i)
00363 {
00364 int x = i*bin_width_pixels;
00365 for (int y = 0; y < hist_img.rows; ++y)
00366 {
00367 hist_img.at<uchar>(y,x) = 0;
00368 }
00369 }
00370
00371 for (int i = 0; i <= n_y_bins; ++i)
00372 {
00373 int y = i*bin_width_pixels;
00374 for (int x = 0; x < hist_img.cols; ++x)
00375 {
00376 hist_img.at<uchar>(y,x) = 0;
00377 }
00378 }
00379
00380
00381 return hist_img;
00382 }
00383 void drawSamplePoints(XYZPointCloud& hull, XYZPointCloud& samples, double alpha, pcl16::PointXYZ& center_pt,
00384 pcl16::PointXYZ& sample_pt, pcl16::PointXYZ& approach_pt,
00385 pcl16::PointXYZ e_left, pcl16::PointXYZ e_right,
00386 pcl16::PointXYZ c_left, pcl16::PointXYZ c_right,
00387 pcl16::PointXYZ i_left, pcl16::PointXYZ i_right,
00388 double x_res, double y_res, double x_range, double y_range, ProtoObject& cur_obj)
00389 {
00390 double max_y = 0.5;
00391 double min_y = -0.2;
00392 double max_x = 1.0;
00393 double min_x = 0.2;
00394
00395
00396 int rows = ceil((max_y-min_y)/XY_RES);
00397 int cols = ceil((max_x-min_x)/XY_RES);
00398 cv::Mat footprint(rows, cols, CV_8UC3, cv::Scalar(255,255,255));
00399 std::vector<int> jump_indices = getJumpIndices(hull, alpha);
00400 for (int i = 0; i < hull.size(); ++i)
00401 {
00402 int j = (i+1) % hull.size();
00403 bool is_jump = false;
00404 for (int k = 0; k < jump_indices.size(); ++k)
00405 {
00406 if (i == jump_indices[k])
00407 {
00408 is_jump = true;
00409 }
00410 }
00411 if (is_jump)
00412 {
00413 continue;
00414 }
00415 pcl16::PointXYZ obj_pt0 = hull[i];
00416 pcl16::PointXYZ obj_pt1 = hull[j];
00417 cv::Point img_pt0 = worldPtToImgPt(obj_pt0, min_x, max_x, min_y, max_y);
00418 cv::Point img_pt1 = worldPtToImgPt(obj_pt1, min_x, max_x, min_y, max_y);
00419 cv::Scalar color(0, 0, 128);
00420 cv::circle(footprint, img_pt0, 1, color, 3);
00421 cv::line(footprint, img_pt0, img_pt1, color, 1);
00422 }
00423 for (int i = 0; i < samples.size(); ++i)
00424 {
00425 cv::Point img_pt = worldPtToImgPt(samples[i], min_x, max_x, min_y, max_y);
00426 cv::Scalar color(0, 255, 0);
00427 cv::circle(footprint, img_pt, 1, color,3);
00428 cv::circle(footprint, img_pt, 3, color,3);
00429 }
00430 cv::Point img_center = worldPtToImgPt(center_pt, min_x, max_x, min_y, max_y);
00431 cv::Point img_approach_pt = worldPtToImgPt(approach_pt, min_x, max_x, min_y, max_y);
00432 cv::Point img_sample_pt = worldPtToImgPt(sample_pt, min_x, max_x, min_y, max_y);
00433 cv::Point e_left_img = worldPtToImgPt(e_left, min_x, max_x, min_y, max_y);
00434 cv::Point e_right_img = worldPtToImgPt(e_right, min_x, max_x, min_y, max_y);
00435 cv::Point c_left_img = worldPtToImgPt(c_left, min_x, max_x, min_y, max_y);
00436 cv::Point c_right_img = worldPtToImgPt(c_right, min_x, max_x, min_y, max_y);
00437 cv::Point i_left_img = worldPtToImgPt(i_left, min_x, max_x, min_y, max_y);
00438 cv::Point i_right_img = worldPtToImgPt(i_right, min_x, max_x, min_y, max_y);
00439
00440 cv::Mat footprint_hist;
00441 footprint.copyTo(footprint_hist);
00442
00443 cv::line(footprint, img_sample_pt, img_center, cv::Scalar(255,0,0), 2);
00444 cv::line(footprint, e_left_img, e_right_img, cv::Scalar(255,0,0), 2);
00445
00446
00447 cv::circle(footprint, img_center, 3, cv::Scalar(255,0,0), 2);
00448
00449
00450
00451
00452
00453
00454
00455 cv::circle(footprint, img_sample_pt, 1, cv::Scalar(255,0,255),3);
00456 cv::circle(footprint, img_sample_pt, 3, cv::Scalar(255,0,255),3);
00457
00458
00459
00460 int n_x_bins = ceil(x_range/x_res);
00461 int n_y_bins = ceil(y_range/y_res);
00462 double min_hist_x = -x_range*0.5;
00463 double min_hist_y = -y_range*0.5;
00464 std::vector<std::vector<cv::Point> > hist_corners;
00465 double center_angle = std::atan2(center_pt.y - sample_pt.y, center_pt.x - sample_pt.x);
00466 double ct = std::cos(center_angle);
00467 double st = std::sin(center_angle);
00468 for (int i = 0; i <= n_x_bins; ++i)
00469 {
00470 double local_x = min_hist_x+x_res*i;
00471 std::vector<cv::Point> hist_row;
00472 hist_corners.push_back(hist_row);
00473 for (int j = 0; j <= n_y_bins; ++j)
00474 {
00475 double local_y = min_hist_y+y_res*j;
00476
00477
00478 pcl16::PointXYZ corner_in_world;
00479 corner_in_world.x = (local_x*ct - local_y*st ) + sample_pt.x;
00480 corner_in_world.y = (local_x*st + local_y*ct ) + sample_pt.y;
00481
00482 cv::Point corner_in_img = worldPtToImgPt(corner_in_world, min_x, max_x, min_y, max_y);
00483
00484 cv::Scalar color(0,0,0);
00485 cv::circle(footprint_hist, corner_in_img, 1, color);
00486
00487 if (i > 0)
00488 {
00489 cv::line(footprint_hist, corner_in_img, hist_corners[i-1][j], color);
00490 }
00491 if (j > 0)
00492 {
00493 cv::line(footprint_hist, corner_in_img, hist_corners[i][j-1], color);
00494 }
00495 hist_corners[i].push_back(corner_in_img);
00496 }
00497 }
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524 }
00525
00526 XYZPointCloud getLocalSamplesNew(XYZPointCloud& hull, ProtoObject& cur_obj, pcl16::PointXYZ sample_pt,
00527 double sample_spread, double alpha)
00528 {
00529
00530 double radius = sample_spread / 2.0;
00531 pcl16::PointXYZ center_pt(cur_obj.centroid[0], cur_obj.centroid[1], cur_obj.centroid[2]);
00532 double center_angle = std::atan2(center_pt.y - sample_pt.y, center_pt.x - sample_pt.x);
00533 double approach_dist = 0.05;
00534 pcl16::PointXYZ approach_pt(sample_pt.x - std::cos(center_angle)*approach_dist,
00535 sample_pt.y - std::sin(center_angle)*approach_dist, 0.0);
00536 pcl16::PointXYZ e_vect(std::cos(center_angle+M_PI/2.0)*radius,
00537 std::sin(center_angle+M_PI/2.0)*radius, 0.0);
00538 pcl16::PointXYZ e_left(approach_pt.x + e_vect.x, approach_pt.y + e_vect.y, 0.0);
00539 pcl16::PointXYZ e_right(approach_pt.x - e_vect.x, approach_pt.y - e_vect.y, 0.0);
00540 pcl16::PointXYZ c_left(center_pt.x + std::cos(center_angle)*approach_dist + e_vect.x,
00541 center_pt.y + std::sin(center_angle)*approach_dist + e_vect.y, 0.0);
00542 pcl16::PointXYZ c_right(center_pt.x + std::cos(center_angle)*approach_dist - e_vect.x,
00543 center_pt.y + std::sin(center_angle)*approach_dist - e_vect.y, 0.0);
00544 std::vector<int> jump_indices = getJumpIndices(hull, alpha);
00545
00546 std::vector<int> inside_indices;
00547 for (int i = 0; i < cur_obj.cloud.size(); i++)
00548 {
00549 double dist_r = pointLineDistance2D(cur_obj.cloud[i], e_right, c_right);
00550 double dist_l = pointLineDistance2D(cur_obj.cloud[i], e_left, c_left);
00551 if (dist_r > sample_spread || dist_l > sample_spread)
00552 {
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562 }
00563 else
00564 {
00565 inside_indices.push_back(i);
00566 }
00567 }
00568
00569 std::vector<int> local_indices;
00570 for (int i = 0; i < inside_indices.size(); ++i)
00571 {
00572 const int idx = inside_indices[i];
00573
00574 double dist_l = pointLineDistance2D(cur_obj.cloud[idx], e_left, c_left);
00575 pcl16::PointXYZ e_vect_scaled(std::cos(center_angle+M_PI/2.0)*radius-dist_l,
00576 std::sin(center_angle+M_PI/2.0)*radius-dist_l, 0.0);
00577 pcl16::PointXYZ e_pt(approach_pt.x + e_vect.x, approach_pt.y + e_vect.y, 0.0);
00578
00579
00580 bool intersects = false;
00581 for (int j = 0; j < hull.size(); ++j)
00582 {
00583 bool j_is_jump = false;
00584 for (int k = 0; k < jump_indices.size(); ++k)
00585 {
00586 if (jump_indices[k] == j)
00587 {
00588 j_is_jump = true;
00589 }
00590 }
00591
00592
00593
00594
00595
00596
00597
00598 pcl16::PointXYZ intersection;
00599 if (lineSegmentIntersection2D(e_pt, cur_obj.cloud[idx], hull[j], hull[(j+1)%hull.size()], intersection))
00600 {
00601 intersects = true;
00602 }
00603 }
00604 if (!intersects)
00605 {
00606 local_indices.push_back(idx);
00607
00608 }
00609 }
00610
00611
00612 XYZPointCloud local_samples;
00613 pcl16::copyPointCloud(cur_obj.cloud, local_indices, local_samples);
00614 int min_l_idx = 0;
00615 int min_r_idx = 0;
00616
00617
00618
00619
00620 return local_samples;
00621 }
00622
00623 XYZPointCloud getLocalSamples(XYZPointCloud& hull, ProtoObject& cur_obj, pcl16::PointXYZ sample_pt,
00624 double sample_spread, double alpha)
00625 {
00626
00627 double radius = sample_spread / 2.0;
00628 pcl16::PointXYZ center_pt(cur_obj.centroid[0], cur_obj.centroid[1], cur_obj.centroid[2]);
00629 double center_angle = std::atan2(center_pt.y - sample_pt.y, center_pt.x - sample_pt.x);
00630 double approach_dist = 0.05;
00631 pcl16::PointXYZ approach_pt(sample_pt.x - std::cos(center_angle)*approach_dist,
00632 sample_pt.y - std::sin(center_angle)*approach_dist, 0.0);
00633 pcl16::PointXYZ e_vect(std::cos(center_angle+M_PI/2.0)*radius,
00634 std::sin(center_angle+M_PI/2.0)*radius, 0.0);
00635 pcl16::PointXYZ e_left(sample_pt.x + e_vect.x, sample_pt.y + e_vect.y, 0.0);
00636 pcl16::PointXYZ e_right(sample_pt.x - e_vect.x, sample_pt.y - e_vect.y, 0.0);
00637 pcl16::PointXYZ c_left(center_pt.x + std::cos(center_angle)*approach_dist + e_vect.x,
00638 center_pt.y + std::sin(center_angle)*approach_dist + e_vect.y, 0.0);
00639 pcl16::PointXYZ c_right(center_pt.x + std::cos(center_angle)*approach_dist - e_vect.x,
00640 center_pt.y + std::sin(center_angle)*approach_dist - e_vect.y, 0.0);
00641
00642
00643
00644
00645
00646
00647
00648 double min_sample_pt_dist = FLT_MAX;
00649 int sample_pt_idx = -1;
00650 std::vector<int> jump_indices;
00651 for (int i = 0; i < hull.size(); i++)
00652 {
00653
00654 double sample_pt_dist = dist(sample_pt, hull[i]);
00655 if (sample_pt_dist < min_sample_pt_dist)
00656 {
00657 min_sample_pt_dist = sample_pt_dist;
00658 sample_pt_idx = i;
00659 }
00660 if (dist(hull[i], hull[(i+1)%hull.size()]) > 2.0*alpha)
00661 {
00662 jump_indices.push_back(i);
00663
00664 }
00665 }
00666
00667
00668 pcl16::PointXYZ l_intersection;
00669 pcl16::PointXYZ r_intersection;
00670 pcl16::PointXYZ c_intersection;
00671 double min_l_dist = FLT_MAX;
00672 double min_r_dist = FLT_MAX;
00673 double min_c_dist = FLT_MAX;
00674 int min_l_idx = -1;
00675 int min_r_idx = -1;
00676 int min_c_idx = -1;
00677
00678 double min_far_l_dist = FLT_MAX;
00679 double min_far_r_dist = FLT_MAX;
00680 int far_l_idx = -1;
00681 int far_r_idx = -1;
00682
00683 for (int i = 0; i < hull.size(); i++)
00684 {
00685 int idx0 = i;
00686 int idx1 = (i+1) % hull.size();
00687
00688
00689 double far_l_dist = pointLineDistance2D(hull[idx0], e_left, c_left);
00690 if (far_l_dist < min_far_l_dist)
00691 {
00692 far_l_idx = idx0;
00693 min_far_l_dist = far_l_dist;
00694 }
00695
00696
00697 double far_r_dist = pointLineDistance2D(hull[idx0], e_right, c_right);
00698 if (far_r_dist < min_far_r_dist)
00699 {
00700 far_r_idx = idx0;
00701 min_far_r_dist = far_r_dist;
00702 }
00703
00704 bool is_jump = false;
00705 for (int j = 0; j < jump_indices.size(); ++j)
00706 {
00707 if (jump_indices[j] == idx0)
00708 {
00709 is_jump = true;
00710 }
00711 }
00712 if (is_jump)
00713 {
00714 continue;
00715 }
00716
00717 pcl16::PointXYZ intersection;
00718
00719 if (lineSegmentIntersection2D(hull[idx0], hull[idx1], e_left, c_left, intersection))
00720 {
00721 double pt_dist = dist(intersection, e_left);
00722 if (pt_dist < min_l_dist)
00723 {
00724 min_l_dist = pt_dist;
00725 min_l_idx = i;
00726 l_intersection = intersection;
00727 }
00728 }
00729
00730 if (lineSegmentIntersection2D(hull[idx0], hull[idx1], e_right, c_right, intersection))
00731 {
00732 double pt_dist = dist(intersection, e_right);
00733 if (pt_dist < min_r_dist)
00734 {
00735 min_r_dist = pt_dist;
00736 min_r_idx = i;
00737 r_intersection = intersection;
00738 }
00739 }
00740
00741 if (lineSegmentIntersection2D(hull[idx0], hull[idx1], approach_pt, center_pt, intersection))
00742 {
00743 double pt_dist = dist(intersection, approach_pt);
00744 if (pt_dist < min_c_dist)
00745 {
00746 min_c_dist = pt_dist;
00747 min_c_idx = i;
00748 c_intersection = intersection;
00749 }
00750 }
00751 }
00752
00753 double sample_pt_dist = dist(approach_pt, sample_pt);
00754
00755 if (true || min_c_idx == -1 || sample_pt_dist <= min_c_dist)
00756 {
00757 min_c_idx = sample_pt_idx;
00758 min_c_dist = sample_pt_dist;
00759 }
00760
00761 if (min_l_idx == -1)
00762 {
00763 min_l_idx = far_l_idx;
00764 min_l_dist = min_far_l_dist;
00765 }
00766
00767 if (min_r_idx == -1)
00768 {
00769 min_r_idx = far_r_idx;
00770 min_r_dist = min_far_r_dist;
00771 }
00772
00773 std::vector<int> indices;
00774
00775
00776
00777
00778
00779 int start_idx = min_l_idx < min_r_idx ? min_l_idx : min_r_idx;
00780 int end_idx = min_l_idx < min_r_idx ? min_r_idx : min_l_idx;
00781 if (min_c_idx >= start_idx && min_c_idx <= end_idx)
00782 {
00783
00784
00785 }
00786 else
00787 {
00788
00789 int tmp_idx = start_idx;
00790 start_idx = end_idx;
00791 end_idx = tmp_idx;
00792 }
00793 int start_chunk = jump_indices.size();
00794 int center_chunk = jump_indices.size();
00795 int end_chunk = jump_indices.size();
00796 for (int i = jump_indices.size()-1; i >= 0; --i)
00797 {
00798 if (start_idx <= jump_indices[i])
00799 {
00800 start_chunk = i;
00801 }
00802 if (min_c_idx <= jump_indices[i])
00803 {
00804 center_chunk = i;
00805 }
00806 if (end_idx <= jump_indices[i])
00807 {
00808 end_chunk = i;
00809 }
00810 }
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826 int cur_chunk = start_chunk;
00827
00828 for (int i = start_idx; i != end_idx; i = (i+1) % hull.size())
00829 {
00830 double dist_r = pointLineDistance2D(hull[i], e_right, c_right);
00831 double dist_l = pointLineDistance2D(hull[i], e_left, c_left);
00832
00833 if (dist_r > sample_spread || dist_l > sample_spread)
00834 {
00835 }
00836 else if (cur_chunk == start_chunk || cur_chunk == end_chunk || cur_chunk == center_chunk)
00837 {
00838 indices.push_back(i);
00839 }
00840 for (int j = 0; j < jump_indices.size(); ++j)
00841 {
00842 if(jump_indices[j] == i)
00843 {
00844 cur_chunk += 1;
00845 cur_chunk = cur_chunk % jump_indices.size();
00846 }
00847 }
00848 }
00849
00850
00851 XYZPointCloud local_samples;
00852 pcl16::copyPointCloud(hull, indices, local_samples);
00853 double x_res = 0.01, y_res=0.01, x_range=2.0*sample_spread, y_range=2.0*sample_spread;
00854 drawSamplePoints(hull, local_samples, alpha, center_pt, sample_pt, approach_pt, e_left, e_right,
00855 c_left, c_right, hull[min_l_idx], hull[min_r_idx], x_res, y_res, x_range, y_range, cur_obj);
00856 return local_samples;
00857 }
00858
00859 XYZPointCloud transformSamplesIntoSampleLocFrame(XYZPointCloud& samples, ProtoObject& cur_obj,
00860 pcl16::PointXYZ sample_pt)
00861 {
00862 XYZPointCloud samples_transformed(samples);
00863 pcl16::PointXYZ center_pt(cur_obj.centroid[0], cur_obj.centroid[1], cur_obj.centroid[2]);
00864 double center_angle = std::atan2(center_pt.y - sample_pt.y, center_pt.x - sample_pt.x);
00865 for (int i = 0; i < samples.size(); ++i)
00866 {
00867
00868 pcl16::PointXYZ demeaned(samples[i].x - sample_pt.x, samples[i].y - sample_pt.y, samples[i].z);
00869 double ct = std::cos(center_angle);
00870 double st = std::sin(center_angle);
00871 samples_transformed[i].x = ct*demeaned.x + st*demeaned.y;
00872 samples_transformed[i].y = -st*demeaned.x + ct*demeaned.y;
00873 samples_transformed[i].z = demeaned.z;
00874 }
00875 return samples_transformed;
00876 }
00877
00878 ShapeDescriptor extractPointHistogramXY(XYZPointCloud& samples, double x_res, double y_res, double x_range,
00879 double y_range)
00880 {
00881 int n_x_bins = ceil(x_range/x_res);
00882 int n_y_bins = ceil(y_range/y_res);
00883 ShapeDescriptor hist(n_y_bins*n_x_bins, 0);
00884
00885 for (int i = 0; i < samples.size(); ++i)
00886 {
00887 double x_norm = (samples[i].x+x_range*0.5)/ x_range;
00888 double y_norm = (samples[i].y+y_range*0.5)/ y_range;
00889 if (x_norm > 1.0 || x_norm < 0 || y_norm > 1.0 || y_norm <0)
00890 {
00891 continue;
00892 }
00893 int x_idx = (int)floor(x_norm*n_x_bins);
00894 int y_idx = (int)floor(y_norm*n_y_bins);
00895 int idx = getHistBinIdx(x_idx, y_idx, n_x_bins, n_y_bins);
00896 hist[idx] += 1;
00897 }
00898 std::stringstream descriptor;
00899 int feat_sum = 0;
00900 for (int i = 0; i < n_x_bins; ++i)
00901 {
00902 for (int j = 0; j < n_y_bins; ++j)
00903 {
00904 int idx = getHistBinIdx(i, j, n_x_bins, n_y_bins);
00905 descriptor << hist[idx] << " ";
00906 feat_sum += hist[idx];
00907 }
00908 descriptor << "\n";
00909 }
00910
00911
00912 return hist;
00913 }
00914
00915 void getPointRangesXY(XYZPointCloud& samples, ShapeDescriptor& sd)
00916 {
00917 double x_min = FLT_MAX;
00918 double x_max = FLT_MIN;
00919 double y_min = FLT_MAX;
00920 double y_max = FLT_MIN;
00921 for (int i = 0; i < samples.size(); ++i)
00922 {
00923 if (samples[i].x > x_max)
00924 {
00925 x_max = samples[i].x;
00926 }
00927 if (samples[i].x < x_min)
00928 {
00929 x_min = samples[i].x;
00930 }
00931 if (samples[i].y > y_max)
00932 {
00933 y_max = samples[i].y;
00934 }
00935 if (samples[i].y < y_min)
00936 {
00937 y_min = samples[i].y;
00938 }
00939 }
00940 double x_range = x_max - x_min;
00941 double y_range = y_max - y_min;
00942
00943
00944 sd.push_back(x_range);
00945 sd.push_back(y_range);
00946 }
00947
00948 void getCovarianceXYFromPoints(XYZPointCloud& pts, ShapeDescriptor& sd)
00949 {
00950 Eigen::Matrix<float, 4, 1> centroid;
00951 if(pcl16::compute3DCentroid(pts, centroid) != 0)
00952 {
00953 Eigen::Matrix3f covariance;
00954 if(pcl16::computeCovarianceMatrix(pts, centroid, covariance) != 0)
00955 {
00956 std::stringstream disp_stream;
00957 for (int i = 0; i < 2; ++i)
00958 {
00959 for (int j = i; j < 2; ++j)
00960 {
00961 sd.push_back(covariance(i,j));
00962 disp_stream << covariance(i,j) << " ";
00963 }
00964 }
00965
00966 }
00967 else
00968 {
00969 ROS_WARN_STREAM("Failed to get covariance matrix");
00970 for (int i = 0; i < 3; ++i)
00971 {
00972 sd.push_back(0);
00973 }
00974 }
00975 }
00976 else
00977 {
00978 ROS_WARN_STREAM("Failed to get centroid");
00979 for (int i = 0; i < 3; ++i)
00980 {
00981 sd.push_back(0);
00982 }
00983 }
00984 }
00985
00986 void extractPCAFeaturesXY(XYZPointCloud& samples, ShapeDescriptor& sd)
00987 {
00988 pcl16::PCA<pcl16::PointXYZ> pca;
00989 pca.setInputCloud(samples.makeShared());
00990 Eigen::Vector3f eigen_values = pca.getEigenValues();
00991 Eigen::Matrix3f eigen_vectors = pca.getEigenVectors();
00992 Eigen::Vector4f centroid = pca.getMean();
00993 double lambda0 = eigen_values(0);
00994 double lambda1 = eigen_values(1);
00995
00996
00997
00998
00999 sd.push_back(lambda0);
01000 sd.push_back(lambda1);
01001 sd.push_back(lambda0/lambda1);
01002
01003 double theta0 = atan2(eigen_vectors(1,0), eigen_vectors(0,0));
01004 double theta1 = atan2(eigen_vectors(1,1), eigen_vectors(0,1));
01005
01006 sd.push_back(theta0);
01007 sd.push_back(theta1);
01008 }
01009
01010 void extractBoundingBoxFeatures(XYZPointCloud& samples, ShapeDescriptor& sd)
01011 {
01012 std::vector<cv::Point2f> obj_pts;
01013 for (unsigned int i = 0; i < samples.size(); ++i)
01014 {
01015 obj_pts.push_back(cv::Point2f(samples[i].x, samples[i].y));
01016 }
01017 cv::RotatedRect box = cv::minAreaRect(obj_pts);
01018 double l = std::max(box.size.width, box.size.height);
01019 double w = std::min(box.size.width, box.size.height);
01020
01021 sd.push_back(l);
01022 sd.push_back(w);
01023 sd.push_back(l/w);
01024 }
01025
01026 ShapeDescriptor extractLocalShapeFeatures(XYZPointCloud& hull, ProtoObject& cur_obj,
01027 pcl16::PointXYZ sample_pt, double sample_spread, double hull_alpha,
01028 double hist_res)
01029 {
01030 XYZPointCloud local_samples = getLocalSamples(hull, cur_obj, sample_pt, sample_spread, hull_alpha);
01031
01032 XYZPointCloud transformed_pts = transformSamplesIntoSampleLocFrame(local_samples, cur_obj, sample_pt);
01033
01034
01035 ShapeDescriptor sd;
01036 #ifdef USE_RANGE_AND_VAR_FEATS
01037 getPointRangesXY(transformed_pts, sd);
01038 getCovarianceXYFromPoints(transformed_pts, sd);
01039 extractPCAFeaturesXY(transformed_pts, sd);
01040 extractBoundingBoxFeatures(transformed_pts, sd);
01041 #endif // USE_RANGE_AND_VAR_FEATS
01042
01043
01044 ShapeDescriptor histogram = extractPointHistogramXY(transformed_pts, hist_res, hist_res,
01045 sample_spread*2, sample_spread*2);
01046 sd.insert(sd.end(), histogram.begin(), histogram.end());
01047 return sd;
01048 }
01049
01050
01051
01052 ShapeDescriptor extractGlobalShapeFeatures(XYZPointCloud& hull, ProtoObject& cur_obj, pcl16::PointXYZ sample_pt,
01053 int sample_pt_idx, double sample_spread)
01054 {
01055 XYZPointCloud transformed_pts = transformSamplesIntoSampleLocFrame(cur_obj.cloud, cur_obj, sample_pt);
01056 ShapeDescriptor sd;
01057 #ifdef USE_RANGE_AND_VAR_FEATS
01058
01059 getPointRangesXY(transformed_pts, sd);
01060 getCovarianceXYFromPoints(transformed_pts, sd);
01061 extractPCAFeaturesXY(transformed_pts, sd);
01062 extractBoundingBoxFeatures(transformed_pts, sd);
01063 #endif // USE_RANGE_AND_VAR_FEATS
01064
01065
01066 ShapeLocations sc = extractShapeContextFromSamples(hull, cur_obj, true);
01067 ShapeDescriptor histogram = sc[sample_pt_idx].descriptor_;
01068 sd.insert(sd.end(), histogram.begin(), histogram.end());
01069 std::stringstream descriptor;
01070 descriptor << "";
01071 for (unsigned int i = 0; i < histogram.size(); ++i)
01072 {
01073 if (i % 5 == 0)
01074 {
01075 descriptor << "\n";
01076 }
01077 descriptor << " " << histogram[i];
01078 }
01079
01080
01081
01082 return sd;
01083 }
01084
01085 ShapeDescriptors extractLocalAndGlobalShapeFeatures(XYZPointCloud& hull, ProtoObject& cur_obj,
01086 double sample_spread, double hull_alpha,
01087 double hist_res)
01088 {
01089 ShapeDescriptors descs;
01090 for (unsigned int i = 0; i < hull.size(); ++i)
01091 {
01092 ShapeDescriptor d = extractLocalAndGlobalShapeFeatures(hull, cur_obj, hull[i], i, sample_spread, hull_alpha,
01093 hist_res);
01094 descs.push_back(d);
01095 }
01096 return descs;
01097 }
01098
01099 ShapeDescriptor extractLocalAndGlobalShapeFeatures(XYZPointCloud& hull, ProtoObject& cur_obj,
01100 pcl16::PointXYZ sample_pt, int sample_pt_idx,
01101 double sample_spread, double hull_alpha, double hist_res)
01102 {
01103
01104 ShapeDescriptor local_raw = extractLocalShapeFeatures(hull, cur_obj, sample_pt, sample_spread, hull_alpha, hist_res);
01105
01106 for (unsigned int i = 0; i < local_raw.size(); ++i)
01107 {
01108 if (local_raw[i] > 0)
01109 {
01110 local_raw[i] = 1.0;
01111 }
01112 else
01113 {
01114 local_raw[i] = 0.0;
01115 }
01116 }
01117
01118 int hist_size = std::sqrt(local_raw.size());
01119 cv::Mat local_hist(cv::Size(hist_size, hist_size), CV_64FC1, cv::Scalar(0.0));
01120 std::stringstream raw_hist;
01121 for (int r = 0; r < hist_size; ++r)
01122 {
01123 for (int c = 0; c < hist_size; ++c)
01124 {
01125 local_hist.at<double>(r,c) = local_raw[r*hist_size+c];
01126 raw_hist << " " << local_hist.at<double>(r,c);
01127 }
01128 raw_hist << "\n";
01129 }
01130
01131
01132 cv::Mat local_resize(cv::Size(6,6), CV_64FC1, cv::Scalar(0.0));
01133 cpl_visual_features::imResize(local_hist, 6./hist_size, local_resize);
01134 std::stringstream resized_hist;
01135 for (int r = 0; r < local_resize.rows; ++r)
01136 {
01137 for (int c = 0; c < local_resize.cols; ++c)
01138 {
01139 resized_hist << " " << local_resize.at<double>(r,c);
01140 }
01141 resized_hist << "\n";
01142 }
01143
01144
01145 cv::Mat local_smooth(local_resize.size(), CV_64FC1, cv::Scalar(0.0));
01146 cv::Mat g_kernel = cv::getGaussianKernel(5, 0.2, CV_64F);
01147 cv::sepFilter2D(local_resize, local_smooth, CV_64F, g_kernel, g_kernel);
01148
01149 double local_sum = 0.0;
01150 std::stringstream smooth_hist;
01151 std::stringstream smooth_hist_clip;
01152 for (int r = 0; r < local_smooth.rows; ++r)
01153 {
01154 for (int c = 0; c < local_smooth.cols; ++c)
01155 {
01156 smooth_hist << " " << local_smooth.at<double>(r,c);
01157 if(local_smooth.at<double>(r,c) < 0)
01158 {
01159 local_smooth.at<double>(r,c) = 0.0;
01160 }
01161 else
01162 {
01163 local_sum += local_smooth.at<double>(r,c);
01164 }
01165 smooth_hist_clip << " " << local_smooth.at<double>(r,c);
01166 }
01167 smooth_hist << "\n";
01168 smooth_hist_clip << "\n";
01169 }
01170
01171 ShapeDescriptor local;
01172 std::stringstream l1_hist;
01173 for (int r = 0; r < local_smooth.rows; ++r)
01174 {
01175 for (int c = 0; c < local_smooth.cols; ++c)
01176 {
01177 local_smooth.at<double>(r,c) /= local_sum;
01178 local.push_back(local_smooth.at<double>(r,c));
01179 l1_hist << " " << local_smooth.at<double>(r,c);
01180 }
01181 l1_hist << "\n";
01182 }
01183
01184
01185
01186
01187
01188
01189
01190
01191 ShapeDescriptor global = extractGlobalShapeFeatures(hull, cur_obj, sample_pt, sample_pt_idx, sample_spread);
01192
01193 double global_sum = 0.0;
01194 for (unsigned int i = 0; i < global.size(); ++i)
01195 {
01196 if (global[i] > 0)
01197 {
01198 global[i] = 1.0;
01199 global_sum += 1.0;
01200 }
01201 else
01202 {
01203 global[i] = 0.0;
01204 }
01205 }
01206
01207 for (unsigned int i = 0; i < global.size(); ++i)
01208 {
01209 global[i] /= global_sum;
01210 }
01211
01212
01213
01214 local.insert(local.end(), global.begin(), global.end());
01215
01216 return local;
01217 }
01218
01219
01227 cv::Mat computeShapeFeatureAffinityMatrix(ShapeLocations& locs, bool use_center)
01228 {
01229 cv::Mat affinity(locs.size(), locs.size(), CV_64FC1, cv::Scalar(0.0));
01230 double max_affinity = 0.0;
01231 ShapeDescriptors normalized;
01232 for (int i = 0; i < locs.size(); ++i)
01233 {
01234 ShapeDescriptor desc(locs[i].descriptor_);
01235 double feature_sum = 0;
01236 for (int j = 0; j < desc.size(); ++j)
01237 {
01238 feature_sum += desc[j];
01239 }
01240 if (feature_sum == 0) continue;
01241 for (int j = 0; j < desc.size(); ++j)
01242 {
01243 desc[j] = sqrt(desc[j]/feature_sum);
01244 }
01245 normalized.push_back(desc);
01246 }
01247
01248 for (int r = 0; r < affinity.rows; ++r)
01249 {
01250 for (int c = r; c < affinity.cols; ++c)
01251 {
01252 if (r == c)
01253 {
01254 affinity.at<double>(r,c) = 1.0;
01255 continue;
01256 }
01257 double sim_score = 1.0 - sqrt(shapeFeatureSquaredEuclideanDist(normalized[r],normalized[c]));
01258 affinity.at<double>(r,c) = sim_score;
01259 affinity.at<double>(c,r) = sim_score;
01260 if (affinity.at<double>(r,c) > max_affinity)
01261 {
01262 max_affinity = affinity.at<double>(r,c);
01263 }
01264 }
01265 }
01266 if (use_center)
01267 {
01268 cv::imshow("affinity-with-centers", affinity);
01269 }
01270 else
01271 {
01272 cv::imshow("affinity", affinity);
01273 }
01274 return affinity;
01275 }
01276
01286 double shapeFeatureChiSquareDist(ShapeDescriptor& a, ShapeDescriptor& b, double gamma)
01287 {
01288
01289
01290 double chi = 0;
01291
01292 for (unsigned int k=0; k < a.size(); k++)
01293 {
01294 const double a_plus_b = a[k] + b[k];
01295 if (a_plus_b > 0)
01296 {
01297 chi += pow(a[k] - b[k], 2) / (a_plus_b);
01298 }
01299 }
01300 chi = chi;
01301 if (gamma != 0.0)
01302 {
01303 chi = exp(-gamma*chi);
01304 }
01305 return chi;
01306 }
01307
01316 double shapeFeatureSquaredEuclideanDist(ShapeDescriptor& a, ShapeDescriptor& b)
01317 {
01318 double dist = 0;
01319 for(int k = 0; k < a.size(); ++k)
01320 {
01321 double k_dist = a[k] - b[k];
01322 dist += k_dist*k_dist;
01323 }
01324 return dist;
01325 }
01326
01327 void clusterShapeFeatures(ShapeLocations& locs, int num_clusters, std::vector<int>& cluster_ids, ShapeDescriptors& centers,
01328 double min_err_change, int max_iter, int num_retries)
01329 {
01330 cv::Mat samples(locs.size(), locs[0].descriptor_.size(), CV_64FC1);
01331 for (int r = 0; r < samples.rows; ++r)
01332 {
01333
01334 double feature_sum = 0;
01335 for (int c = 0; c < samples.cols; ++c)
01336 {
01337 samples.at<double>(r,c) = locs[r].descriptor_[c];
01338 feature_sum += samples.at<double>(r,c);
01339 }
01340 if (feature_sum == 0)
01341 {
01342 continue;
01343 }
01344 for (int c = 0; c < samples.cols; ++c)
01345 {
01346 samples.at<double>(r,c) /= feature_sum;
01347
01348 samples.at<double>(r,c) = sqrt(samples.at<double>(r,c));
01349 }
01350 }
01351 cv::TermCriteria term_crit(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, max_iter, min_err_change);
01352
01353 cv::Mat centers_cv;
01354 double slack = cv::kmeans(samples, num_clusters, cluster_ids, term_crit, num_retries, cv::KMEANS_PP_CENTERS,
01355 centers_cv);
01356 for (int r = 0; r < centers_cv.rows; ++r)
01357 {
01358 ShapeDescriptor s(centers_cv.cols, 0);
01359 for (int c = 0; c < centers_cv.cols; ++c)
01360 {
01361 s[c] = centers_cv.at<double>(r,c);
01362 }
01363 centers.push_back(s);
01364 }
01365 }
01366
01375 int closestShapeFeatureCluster(ShapeDescriptor& descriptor, ShapeDescriptors& centers, double& min_dist)
01376 {
01377 int min_idx = -1;
01378 min_dist = FLT_MAX;
01379 ShapeDescriptor normalized(descriptor);
01380 double feature_sum = 0;
01381 for (int i = 0; i < normalized.size(); ++i)
01382 {
01383 feature_sum += normalized[i];
01384 }
01385 for (int i = 0; i < normalized.size(); ++i)
01386 {
01387 normalized[i] = sqrt(normalized[i]/feature_sum);
01388 }
01389 for (int c = 0; c < centers.size(); ++c)
01390 {
01391 double c_dist = (shapeFeatureSquaredEuclideanDist(normalized, centers[c]));
01392 if (c_dist < min_dist)
01393 {
01394 min_dist = c_dist;
01395 min_idx = c;
01396 }
01397 }
01398 return min_idx;
01399 }
01400
01401 ShapeDescriptors loadSVRTrainingFeatures(std::string feature_path, int feat_length)
01402 {
01403 std::ifstream data_in(feature_path.c_str());
01404 ShapeDescriptors train_feats;
01405 while (data_in.good())
01406 {
01407 ShapeDescriptor feat(feat_length, 0.0);
01408 char c_line[4096];
01409 data_in.getline(c_line, 4096);
01410 std::stringstream line;
01411 line << c_line;
01412 int idx;
01413 double val;
01414 int num_feats = 0;
01415
01416 while (line >> idx)
01417 {
01418 if (line.peek() == ':')
01419 {
01420 line.ignore();
01421 line >> val;
01422 feat[idx-1] = val;
01423 num_feats++;
01424
01425 }
01426 if (line.peek() == ' ')
01427 {
01428 line.ignore();
01429 }
01430 }
01431
01432 if (num_feats > 0)
01433 {
01434 train_feats.push_back(feat);
01435 }
01436 }
01437 data_in.close();
01438 return train_feats;
01439 }
01440
01441 cv::Mat computeChi2Kernel(ShapeDescriptors& sds, std::string feat_path, int local_length, int global_length,
01442 double gamma_local, double gamma_global, double mixture_weight)
01443 {
01444 ShapeDescriptors train_feats = loadSVRTrainingFeatures(feat_path, local_length + global_length);
01445 cv::Mat K_local(train_feats.size(), sds.size(), CV_64FC1, cv::Scalar(0.0));
01446 cv::Mat K_global(train_feats.size(), sds.size(), CV_64FC1, cv::Scalar(0.0));
01447 for (int i = 0; i < sds.size(); ++i)
01448 {
01449 ShapeDescriptor a_local(sds[i].begin(), sds[i].begin()+local_length);
01450 ShapeDescriptor a_global(sds[i].begin()+local_length, sds[i].end());
01451 for (int j = 0; j < train_feats.size(); ++j)
01452 {
01453 ShapeDescriptor b_local(train_feats[j].begin(), train_feats[j].begin()+local_length);
01454 ShapeDescriptor b_global(train_feats[j].begin()+local_length, train_feats[j].end());
01455
01456 K_local.at<double>(j, i) = shapeFeatureChiSquareDist(a_local, b_local, gamma_local);
01457 K_global.at<double>(j, i) = shapeFeatureChiSquareDist(a_global, b_global, gamma_global);
01458 }
01459 }
01460
01461 cv::Mat K = mixture_weight * K_global + (1 - mixture_weight) * K_local;
01462 return K;
01463 }
01464
01465 };