26#include <unordered_map>
41const int OBSTACLE_MINIMUM_NUM_POINTS = 50;
50 ADEBUG <<
"NCut destructor done";
54 if (!Configure(param)) {
55 AERROR <<
"failed to load ncut config.";
60 if (!_classifier->init()) {
61 AERROR <<
"failed to init FrameClassifierPipeline.";
67bool NCut::Configure(
const NCutParam &ncut_param_) {
83 AINFO <<
"NCut Parameters" << ncut_param_.DebugString();
89 double start_t = omp_get_wtime();
92 _segment_pids.clear();
93 _segment_labels.clear();
94 _segment_bbox.clear();
95 _outlier_pids.clear();
96 _cluster_points.clear();
97 _cluster_bounding_box.clear();
98 _cluster_skeleton_points.clear();
99 _cluster_skeleton_features.clear();
100 std::vector<int> pids(cloud->size());
101 for (
size_t i = 0; i < cloud->size(); ++i) {
102 pids[i] =
static_cast<int>(i);
105 AINFO <<
"cloud obstacle size in ncut segment is " << _cloud_obstacles->size();
107 ADEBUG <<
"segment enter ... input cloud size " << cloud->size();
113 SuperPixelsFloodFill(cloud, _grid_radius, _super_pixel_cell_size, &_cluster_points);
116 ADEBUG <<
"super pixels " << _cluster_points.size();
117 AINFO <<
"super pixels done " << omp_get_wtime() - start_t;
118 start_t = omp_get_wtime();
122 PrecomputeAllSkeletonAndBbox();
124 AINFO <<
"precompute skeleton and bbox done " << omp_get_wtime() - start_t;
125 start_t = omp_get_wtime();
128 std::vector<std::vector<int>> segment_clusters;
129 std::vector<std::string> segment_labels;
130 NormalizedCut(_ncuts_stop_threshold,
true, &segment_clusters, &segment_labels);
132 AINFO <<
"normalized_cut done, #segments " << segment_clusters.size() <<
", time: " << omp_get_wtime() - start_t;
133 start_t = omp_get_wtime();
136 for (
size_t i = 0; i < segment_clusters.size(); ++i) {
137 std::vector<int> pids;
138 GetClustersPids(segment_clusters[i], &pids);
139 if (pids.size() > 0) {
140 _segment_pids.push_back(pids);
141 _segment_labels.push_back(segment_labels[i]);
143 GetComponentBoundingBox(segment_clusters[i], &box);
144 _segment_bbox.push_back(box);
149void NCut::SuperPixelsFloodFill(
153 std::vector<std::vector<int>> *super_pixels) {
155 std::vector<int> num_cells_per_components;
156 ff_grid.GetSegments(cloud, super_pixels, &num_cells_per_components);
159void NCut::PrecomputeAllSkeletonAndBbox() {
160 const int num_clusters =
static_cast<int>(_cluster_points.size());
161 _cluster_skeleton_points.resize(num_clusters);
162 _cluster_skeleton_features.resize(num_clusters);
163 _cluster_bounding_box.resize(num_clusters);
164 _cluster_labels.resize(num_clusters,
"unknown");
168 _ff_feature_grid.
BuildGrid(_cloud_obstacles);
169 std::vector<gridIndex> dummy_indices;
170 BuildAverageHeightMap(_cloud_obstacles, _ff_feature_grid, &_cv_feature_map, &dummy_indices);
174 for (
int i = 0; i < num_clusters; ++i) {
175 SampleByGrid(_cluster_points[i], &_cluster_skeleton_points[i], &_cluster_skeleton_features[i]);
176 _cluster_bounding_box[i] = ComputeClusterBoundingBox(_cluster_points[i]);
179 for (
size_t i = 0; i < _cluster_points.size(); ++i) {
181 _cluster_labels[i] = GetPcLabel(pc);
185void NCut::BuildAverageHeightMap(
187 const FloodFill &ff_map,
188 cv::Mat *cv_height_map_in,
189 std::vector<gridIndex> *point_pixel_indices_in) {
190 cv::Mat &cv_height_map = *cv_height_map_in;
191 std::vector<gridIndex> &point_pixel_indices = *point_pixel_indices_in;
192 const int num_points =
static_cast<int>(cloud->size());
193 cv::Mat cv_img = cv::Mat::zeros(ff_map.GetNumRows(), ff_map.GetNumCols(), CV_32F);
194 std::vector<std::vector<int>> counts;
195 counts.resize(cv_img.rows);
196 for (
size_t i = 0; i < counts.size(); ++i) {
197 counts[i].resize(cv_img.cols, 0);
199 point_pixel_indices.resize(num_points);
200 for (
int i = 0; i < num_points; ++i) {
204 if (ff_map.Pos2d(pt.x, pt.y, &irow, &jcol)) {
205 cv_img.at<
float>(irow, jcol) += pt.
z;
206 counts[irow][jcol] += 1;
207 point_pixel_indices[i].irow = irow;
208 point_pixel_indices[i].jcol = jcol;
210 point_pixel_indices[i].irow = -1;
211 point_pixel_indices[i].jcol = -1;
214 for (
int i = 0; i < cv_img.rows; ++i) {
215 for (
int j = 0; j < cv_img.cols; ++j) {
216 if (counts[i][j] > 0) {
217 cv_img.at<
float>(i, j) /=
static_cast<float>(counts[i][j]);
221 cv::Mat cv_height_map_copy;
222 cv::GaussianBlur(cv_img, cv_height_map_copy, cv::Size(3, 3), 0, 0);
223 cv::normalize(cv_height_map_copy, cv_height_map, 0, 255, cv::NORM_MINMAX, CV_8UC1);
226void NCut::SampleByGrid(
227 const std::vector<int> &point_gids,
228 MatrixXf *skeleton_coords_in,
229 MatrixXf *skeleton_feature_in) {
230 MatrixXf &skeleton_coords = *skeleton_coords_in;
231 MatrixXf &skeleton_feature = *skeleton_feature_in;
232 FloodFill sampler(_grid_radius, _skeleton_cell_size);
234 sampler.BuildGrid(pc);
235 std::unordered_map<int, std::pair<base::PointF, float>> centroids;
236 const std::vector<int> &point_idx = sampler.GetPointIdxInGrid();
237 std::unordered_map<int, std::pair<base::PointF, float>>::iterator it;
238 for (
size_t i = 0; i < point_idx.size(); ++i) {
239 it = centroids.find(point_idx[i]);
240 if (it != centroids.end()) {
241 it->second.first.x += (*pc)[i].x;
242 it->second.first.y += (*pc)[i].y;
243 it->second.first.z += (*pc)[i].z;
244 it->second.second += 1.f;
246 centroids[point_idx[i]] = std::make_pair((*pc)[i], 1.f);
249 int num_skeletons =
static_cast<int>(centroids.size());
250 skeleton_coords.resize(num_skeletons, 3);
252 for (it = centroids.begin(); it != centroids.end(); ++it) {
253 skeleton_coords.coeffRef(p, 0) = it->second.first.x / it->second.second;
254 skeleton_coords.coeffRef(p, 1) = it->second.first.y / it->second.second;
255 skeleton_coords.coeffRef(p, 2) = it->second.first.z / it->second.second;
258 GetPatchFeature(skeleton_coords, &skeleton_feature);
261void NCut::GetPatchFeature(
const MatrixXf &points, MatrixXf *features_in) {
262 MatrixXf &features = *features_in;
263 const int num_points =
static_cast<int>(points.rows());
264 const int dim = _patch_size * _patch_size;
265 features.resize(num_points, dim);
266 for (
int i = 0; i < num_points; ++i) {
270 _ff_feature_grid.
Pos2d(points.coeffRef(i, 0), points.coeffRef(i, 1), &irow, &jcol);
272 cv::Point2f pt(
static_cast<float>(irow),
static_cast<float>(jcol));
273 cv::getRectSubPix(_cv_feature_map, cv::Size(_patch_size, _patch_size), pt, patch);
276 assert(dim == patch.rows * patch.cols);
278 for (
int r = 0; r < patch.rows; ++r) {
279 for (
int c = 0; c < patch.cols; ++c) {
280 float val = patch.at<
float>(r, c);
281 features.coeffRef(i, p++) =
static_cast<float>((std::isnan(val) || std::isinf(val)) ? 1.e-50 : val);
288NCut::NcutBoundingBox NCut::ComputeClusterBoundingBox(
const std::vector<int> &point_gids) {
290 float x_max = -std::numeric_limits<float>::max();
291 float y_max = -std::numeric_limits<float>::max();
292 float z_max = -std::numeric_limits<float>::max();
293 float x_min = std::numeric_limits<float>::max();
294 float y_min = std::numeric_limits<float>::max();
295 float z_min = std::numeric_limits<float>::max();
296 for (
size_t j = 0; j < point_gids.size(); ++j) {
297 int pid = point_gids[j];
298 x_min = std::min(x_min, (*_cloud_obstacles)[pid].x);
299 x_max = std::max(x_max, (*_cloud_obstacles)[pid].x);
300 y_min = std::min(y_min, (*_cloud_obstacles)[pid].y);
301 y_max = std::max(y_max, (*_cloud_obstacles)[pid].y);
302 z_min = std::min(z_min, (*_cloud_obstacles)[pid].z);
303 z_max = std::max(z_max, (*_cloud_obstacles)[pid].z);
306 std::get<0>(box) = x_min;
307 std::get<1>(box) = x_max;
308 std::get<2>(box) = y_min;
309 std::get<3>(box) = y_max;
310 std::get<4>(box) = z_min;
311 std::get<5>(box) = z_max;
316 if (cloud->size() < OBSTACLE_MINIMUM_NUM_POINTS) {
324 label = _classifier->GetLabel(rot_cloud);
326 if (label ==
"background") {
332void NCut::NormalizedCut(
333 float ncuts_threshold,
335 std::vector<std::vector<int>> *segment_clusters_in,
336 std::vector<std::string> *segment_labels_in) {
337 std::vector<std::vector<int>> &segment_clusters = *segment_clusters_in;
338 std::vector<std::string> &segment_labels = *segment_labels_in;
339 const int num_clusters =
static_cast<int>(_cluster_points.size());
340 if (num_clusters < 1) {
343 if (num_clusters == 1) {
344 std::vector<int> tmp(1, 0);
345 segment_clusters.push_back(tmp);
346 segment_labels.push_back(_cluster_labels[0]);
350 LOG_DEBUG <<
"\n+++++++++++++++++++++++++++++ input " << num_clusters <<
" clusters +++++++++++++++++++++++++++\n";
354 ComputeSkeletonWeights(&weights);
355 std::vector<int> *curr =
new std::vector<int>(num_clusters);
356 for (
int i = 0; i < num_clusters; ++i) {
359 std::stack<std::vector<int> *> job_stack;
360 job_stack.push(curr);
361 while (!job_stack.empty()) {
362 curr = job_stack.top();
365 AINFO <<
"curr size " << curr->size();
368 std::string seg_label;
369 if (curr->size() == 1) {
370 segment_clusters.push_back(*curr);
371 segment_labels.push_back(_cluster_labels[(*curr)[0]]);
372 }
else if (use_classifier && IsMovableObstacle(*curr, &seg_label)) {
373 segment_clusters.push_back(*curr);
374 segment_labels.push_back(seg_label);
376 std::cout <<
"cluster: ";
377 for (
size_t i = 0; i < curr->size(); ++i) {
378 std::cout << (*curr)[i] <<
" ";
380 std::cout <<
" as a segment (" << seg_label <<
")" << std::endl;
383 std::vector<int> *seg1 =
new std::vector<int>();
384 std::vector<int> *seg2 =
new std::vector<int>();
385 MatrixXf my_weights(curr->size(), curr->size());
386 for (
size_t i = 0; i < curr->size(); ++i) {
387 const int ci = curr->at(i);
388 for (
size_t j = 0; j < curr->size(); ++j) {
389 const int cj = curr->at(j);
390 my_weights.coeffRef(i, j) = weights.coeffRef(ci, cj);
393 double cost = GetMinNcuts(my_weights, curr, seg1, seg2);
395 AINFO <<
"N cut cost is " << cost <<
", seg1 size " << seg1->size() <<
", seg2 size " << seg2->size();
396 if (curr->size() < 50) {
397 std::cout <<
"seg1: ";
398 for (
size_t i = 0; i < seg1->size(); ++i) {
399 std::cout << (*seg1)[i] <<
" ";
401 std::cout << std::endl;
402 std::cout <<
"seg2: ";
403 for (
size_t i = 0; i < seg2->size(); ++i) {
404 std::cout << (*seg2)[i] <<
" ";
406 std::cout << std::endl;
410 if (cost > ncuts_threshold || 0 == seg1->size() || 0 == seg2->size()) {
411 std::vector<int> buffer;
412 for (
size_t i = 0; i < curr->size(); ++i) {
413 const int cid = (*curr)[i];
414 if (_cluster_labels[cid] !=
"unknown") {
416 std::cout <<
"cluster: " << cid <<
" as a segment (hit, " << _cluster_labels[cid] <<
")"
419 std::vector<int> tmp(1, cid);
420 segment_clusters.push_back(tmp);
421 segment_labels.push_back(_cluster_labels[cid]);
423 buffer.push_back(cid);
426 if (buffer.size() > 0) {
427 segment_clusters.push_back(buffer);
428 segment_labels.push_back(
"unknown");
431 std::cout <<
"cluster: ";
432 for (
size_t i = 0; i < buffer.size(); ++i) {
433 std::cout << buffer[i] <<
" ";
435 std::cout <<
" as a segment (hit, unknown)" << std::endl;
440 job_stack.push(seg1);
441 job_stack.push(seg2);
445 LOG_DEBUG <<
"============================================================="
451 std::cout <<
"graph cut return segments: " << std::endl;
452 for (
size_t i = 0; i < segment_clusters.size(); ++i) {
453 std::cout <<
"seg " << i <<
": ";
454 for (
size_t j = 0; j < segment_clusters[i].size(); ++j) {
455 std::cout << segment_clusters[i][j] <<
" ";
457 std::cout <<
": " << segment_labels[i] << std::endl;
459 LOG_DEBUG <<
"normalized_cut: " << segment_clusters.size() <<
" segments from " << _cluster_points.size()
465void NCut::ComputeSkeletonWeights(Eigen::MatrixXf *weights_in) {
466 Eigen::MatrixXf &weights = *weights_in;
467 const int num_clusters =
static_cast<int>(_cluster_points.size());
468 const double hs2 = _sigma_space * _sigma_space;
469 const double hf2 = _sigma_feature * _sigma_feature;
470 const double radius2 = _connect_radius * _connect_radius;
471 weights.resize(num_clusters, num_clusters);
472 for (
int i = 0; i < num_clusters; ++i) {
473 weights.coeffRef(i, i) = 1.f;
474 for (
int j = i + 1; j < num_clusters; ++j) {
475 float dist_point = std::numeric_limits<float>::max();
476 float dist_feature = std::numeric_limits<float>::max();
477 ComputeSquaredSkeletonDistance(
478 _cluster_skeleton_points[i],
479 _cluster_skeleton_features[i],
480 _cluster_skeleton_points[j],
481 _cluster_skeleton_features[j],
484 if (dist_point > radius2) {
485 weights.coeffRef(i, j) = 0.f;
486 weights.coeffRef(j, i) = 0.f;
488 weights.coeffRef(i, j) =
static_cast<float>(exp(-dist_point / hs2) * exp(-dist_feature / hf2));
489 weights.coeffRef(j, i) = weights.coeffRef(i, j);
495float NCut::GetMinNcuts(
496 const Eigen::MatrixXf &in_weights,
497 const std::vector<int> *in_clusters,
498 std::vector<int> *seg1,
499 std::vector<int> *seg2) {
501 const int num_clusters =
static_cast<int>(in_weights.rows());
502 seg1->resize(num_clusters);
503 seg2->resize(num_clusters);
505 Eigen::MatrixXf eigenvectors;
506 LaplacianDecomposition(in_weights, &eigenvectors);
514 const float minval = eigenvectors.col(1).minCoeff();
515 const float maxval = eigenvectors.col(1).maxCoeff();
516 const float increment =
static_cast<float>((maxval - minval) / (
static_cast<float>(_num_cuts) + 1.0f));
519 float opt_split = 0.0;
520 float opt_cost = std::numeric_limits<float>::max();
521 for (
int i = 0; i < _num_cuts; ++i) {
525 float split =
static_cast<float>(minval +
static_cast<float>(i + 1) * increment);
526 for (
int j = 0; j < num_clusters; ++j) {
527 if (eigenvectors.coeffRef(j, 1) > split) {
528 (*seg1)[num_seg1++] = j;
530 (*seg2)[num_seg2++] = j;
537 for (
int j = 0; j < num_seg1; ++j) {
538 assoc1 += in_weights.row(seg1->at(j)).sum();
540 for (
int j = 0; j < num_seg2; ++j) {
541 assoc2 += in_weights.row(seg2->at(j)).sum();
543 for (
int j = 0; j < num_seg1; ++j) {
544 for (
int t = 0; t < num_seg2; ++t) {
545 cut += in_weights.coeffRef(seg1->at(j), seg2->at(t));
548 float cost =
static_cast<float>(cut / assoc1 + cut / assoc2);
550 LOG_DEBUG <<
"seg1: " << num_seg1 <<
", seg2: " << num_seg2 <<
", split " << split <<
", cut " << cut
551 <<
", assoc1 " << assoc1 <<
", assoc2 " << assoc2 <<
", cost " << cost;
554 if (cost < opt_cost) {
562 for (
int i = 0; i < num_clusters; ++i) {
563 if (eigenvectors.coeffRef(i, 1) > opt_split) {
564 (*seg1)[num_seg1++] = in_clusters->at(i);
566 (*seg2)[num_seg2++] = in_clusters->at(i);
569 seg1->resize(num_seg1);
570 seg2->resize(num_seg2);
574void NCut::LaplacianDecomposition(
const Eigen::MatrixXf &weights, Eigen::MatrixXf *eigenvectors_in) {
578 Eigen::MatrixXf &eigenvectors = *eigenvectors_in;
580 Eigen::VectorXf diag(weights.rows());
581 for (
int i = 0; i < weights.rows(); ++i) {
582 diag.coeffRef(i) = weights.row(i).sum();
585 Eigen::MatrixXf
laplacian(weights.rows(), weights.cols());
586 for (
int i = 0; i <
laplacian.rows(); ++i) {
587 for (
int j = 0; j <
laplacian.cols(); ++j) {
589 laplacian.coeffRef(i, j) = diag.coeffRef(i) - weights.coeffRef(i, j);
591 laplacian.coeffRef(i, j) = 0.f - weights.coeffRef(i, j);
599 Eigen::VectorXf diag_halfinv(weights.rows());
600 for (
int i = 0; i < weights.rows(); ++i) {
601 diag_halfinv.coeffRef(i) =
static_cast<float>(1.0 / std::sqrt(diag.coeffRef(i)));
604 for (
int i = 0; i <
laplacian.rows(); ++i) {
605 laplacian.row(i) *= diag_halfinv.coeffRef(i);
607 for (
int j = 0; j <
laplacian.cols(); ++j) {
608 laplacian.col(j) *= diag_halfinv.coeffRef(j);
612 for (
int i = 0; i <
laplacian.rows(); ++i) {
619 Eigen::EigenSolver<MatrixXf> eig_solver(
laplacian);
625 std::vector<std::pair<float, int>> eigval(
laplacian.rows());
626 for (
size_t i = 0; i < eigval.size(); ++i) {
627 eigval[i] = std::make_pair(eig_solver.eigenvalues()[i].real(), i);
629 std::sort(eigval.begin(), eigval.end(), std::less<std::pair<float, int>>());
631 eigenvectors.resize(weights.rows(), weights.cols());
632 for (
int i = 0; i < eigenvectors.cols(); ++i) {
633 eigenvectors.col(i) = eig_solver.eigenvectors().col(eigval[i].second).real();
635 for (
int i = 0; i < eigenvectors.rows(); ++i) {
636 eigenvectors.row(i) *= diag_halfinv.coeffRef(i);
640bool NCut::ComputeSquaredSkeletonDistance(
641 const Eigen::MatrixXf &in1_points,
642 const Eigen::MatrixXf &in1_features,
643 const Eigen::MatrixXf &in2_points,
644 const Eigen::MatrixXf &in2_features,
646 float *dist_feature) {
647 if (!((in1_points.rows() == in1_features.rows()) && (in2_points.rows() == in2_features.rows()))) {
650 const int num1 =
static_cast<int>(in1_points.rows());
651 const int num2 =
static_cast<int>(in2_points.rows());
652 const int dim =
static_cast<int>(in1_features.cols());
655 float min_dist = std::numeric_limits<float>::max();
656 for (
int i = 0; i < num1; ++i) {
657 for (
int j = 0; j < num2; ++j) {
658 const float diff_x = in1_points.coeffRef(i, 0) - in2_points.coeffRef(j, 0);
659 const float diff_y = in1_points.coeffRef(i, 1) - in2_points.coeffRef(j, 1);
660 const float diff_z = in1_points.coeffRef(i, 2) - in2_points.coeffRef(j, 2);
661 float dist = diff_x * diff_x + diff_y * diff_y + diff_z * diff_z;
662 if (dist < min_dist) {
669 *dist_point = min_dist;
671 for (
int i = 0; i < dim; ++i) {
672 float diff = in1_features.coeffRef(min_index1, i) - in2_features.coeffRef(min_index2, i);
678bool NCut::IsMovableObstacle(
const std::vector<int> &cluster_ids, std::string *label) {
680 GetComponentBoundingBox(cluster_ids, &box);
681 float dummy_length = GetBboxLength(box);
682 float dummy_width = GetBboxWidth(box);
683 float length = std::max(dummy_length, dummy_width);
684 float width = std::min(dummy_length, dummy_width);
685 if (IsPotentialPedestrianSize(length, width) || IsPotentialBicyclistSize(length, width)
686 || IsPotentialCarSize(length, width)) {
687 *label = GetClustersLabel(cluster_ids);
688 if (*label !=
"unknown" || *label !=
"background") {
695std::string NCut::GetClustersLabel(
const std::vector<int> &cluster_ids) {
696 std::vector<int> point_ids;
697 GetClustersPids(cluster_ids, &point_ids);
699 return GetPcLabel(cloud);
702void NCut::GetClustersPids(
const std::vector<int> &cids, std::vector<int> *pids_in) {
703 std::vector<int> &pids = *pids_in;
705 for (
size_t i = 0; i < cids.size(); ++i) {
706 num_points +=
static_cast<int>(_cluster_points[cids[i]].size());
708 pids.resize(num_points, -1);
710 for (
size_t i = 0; i < cids.size(); ++i) {
711 const std::vector<int> &curr_pids = _cluster_points[cids[i]];
712 memcpy(pids.data() + offset, curr_pids.data(),
sizeof(
int) * curr_pids.size());
713 offset +=
static_cast<int>(curr_pids.size());
717int NCut::GetComponentBoundingBox(
const std::vector<int> &cluster_ids, NcutBoundingBox *box_in) {
718 NcutBoundingBox &box = *box_in;
719 if (cluster_ids.empty()) {
722 int cid = cluster_ids[0];
723 float x_min = std::get<0>(_cluster_bounding_box[cid]);
724 float x_max = std::get<1>(_cluster_bounding_box[cid]);
725 float y_min = std::get<2>(_cluster_bounding_box[cid]);
726 float y_max = std::get<3>(_cluster_bounding_box[cid]);
727 float z_min = std::get<4>(_cluster_bounding_box[cid]);
728 float z_max = std::get<5>(_cluster_bounding_box[cid]);
729 int num_points =
static_cast<int>(_cluster_points[cid].size());
730 for (
size_t i = 1; i < cluster_ids.size(); ++i) {
731 cid = cluster_ids[i];
732 x_min = std::min(x_min, std::get<0>(_cluster_bounding_box[cid]));
733 x_max = std::max(x_max, std::get<1>(_cluster_bounding_box[cid]));
734 y_min = std::min(y_min, std::get<2>(_cluster_bounding_box[cid]));
735 y_max = std::max(y_max, std::get<3>(_cluster_bounding_box[cid]));
736 z_min = std::min(y_min, std::get<4>(_cluster_bounding_box[cid]));
737 z_max = std::max(y_max, std::get<5>(_cluster_bounding_box[cid]));
738 num_points +=
static_cast<int>(_cluster_points[cid].size());
740 std::get<0>(box) = x_min;
741 std::get<1>(box) = x_max;
742 std::get<2>(box) = y_min;
743 std::get<3>(box) = y_max;
744 std::get<4>(box) = z_min;
745 std::get<5>(box) = z_max;
750 if (cloud->size() < OBSTACLE_MINIMUM_NUM_POINTS) {
753 float x_max = -std::numeric_limits<float>::max();
754 float y_max = -std::numeric_limits<float>::max();
755 float x_min = std::numeric_limits<float>::max();
756 float y_min = std::numeric_limits<float>::max();
757 for (
size_t i = 0; i < cloud->size(); ++i) {
759 x_min = std::min(x_min, pt.
x);
760 x_max = std::max(x_max, pt.
x);
761 y_min = std::min(y_min, pt.
y);
762 y_max = std::max(y_max, pt.
y);
764 float dummy_length = x_max - x_min;
765 float dummy_width = y_max - y_min;
766 float length = std::max(dummy_length, dummy_width);
767 float width = std::min(dummy_length, dummy_width);
768 std::string label =
"unknown";
769 bool is_candidate =
false;
770 if (only_check_pedestrian) {
771 if (IsPotentialPedestrianSize(length, width) || IsPotentialBicyclistSize(length, width)) {
775 if (IsPotentialPedestrianSize(length, width) || IsPotentialBicyclistSize(length, width)
776 || IsPotentialCarSize(length, width)) {
781 label = GetPcLabel(cloud);
787 float x_max = -std::numeric_limits<float>::max();
788 float y_max = -std::numeric_limits<float>::max();
789 float z_max = -std::numeric_limits<float>::max();
790 float x_min = std::numeric_limits<float>::max();
791 float y_min = std::numeric_limits<float>::max();
792 float z_min = std::numeric_limits<float>::max();
793 for (
size_t i = 0; i < cloud->size(); ++i) {
795 x_min = std::min(x_min, pt.
x);
796 x_max = std::max(x_max, pt.
x);
797 y_min = std::min(y_min, pt.
y);
798 y_max = std::max(y_max, pt.
y);
799 z_min = std::min(z_min, pt.
z);
800 z_max = std::max(z_max, pt.
z);
802 *length = (x_max - x_min);
803 *width = (y_max - y_min);
804 *height = (z_max - z_min);
void SetGridRadius(float grid_radius)
Set the grid radius
bool Pos2d(float x, float y, int *irow, int *jcol) const
Get row and col position
void SetCellSize(float cell_size)
Set the cell size
void BuildGrid(base::PointFCloudConstPtr cloud)
Build grid based on point cloud
std::string GetPcRoughLabel(const base::PointFCloudPtr &cloud, bool only_check_pedestrian)
Get the label of point cloud
void GetSegmentRoughSize(const base::PointFCloudPtr &cloud, float *length, float *width, float *height)
Get the segment size
bool Init(const NCutParam ¶m)
Init Ncut according to parameters
void Segment(base::PointFCloudConstPtr cloud)
Segmen main entrance
bool GetProtoFromFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the file specified by the file_name as a representation of protobufs,...
std::string GetAbsolutePath(const std::string &prefix, const std::string &relative_path)
Get absolute path by concatenating prefix and relative_path.
uint32_t width
Width of point cloud
AttributePointCloud< PointF > PointFCloud
std::shared_ptr< PointFCloud > PointFCloudPtr
std::shared_ptr< const PointFCloud > PointFCloudConstPtr
double OrientCloud(const PointFCloud &pc, PointFCloud *pc_out, bool demean)
float diff(Image< float > *I, int x1, int y1, int x2, int y2)
Dissimilarity measure between pixels
Image< float > * laplacian(Image< float > *src)
Compute laplacian
optional float ncuts_enable_classifier_threshold
optional uint32 felzenszwalb_min_size
optional float overlap_factor
optional float sigma_feature
optional float connect_radius
optional float grid_radius
optional float super_pixel_cell_size
optional float sigma_space
optional float felzenszwalb_k
optional float skeleton_cell_size
optional float felzenszwalb_sigma
optional uint32 patch_size
optional float ncuts_stop_threshold