00001
00063 #ifndef __IMPL_ORGANIZED_NORMAL_ESTIMATION_H__
00064 #define __IMPL_ORGANIZED_NORMAL_ESTIMATION_H__
00065
00066
00067 #include "cob_3d_mapping_common/label_defines.h"
00068 #include "cob_3d_features/organized_normal_estimation.h"
00069 #include <pcl/common/eigen.h>
00070
00071 template <typename PointT, typename LabelT> void
00072 cob_3d_features::OrganizedNormalEstimationHelper::computeSegmentNormal(
00073 Eigen::Vector3f& normal_out,
00074 int index,
00075 boost::shared_ptr<const pcl::PointCloud<PointT> > surface,
00076 boost::shared_ptr<const pcl::PointCloud<LabelT> > labels,
00077 int r, int steps)
00078 {
00079 const int w = surface->width, s = surface->height * surface->width;
00080 const int l_idx = labels->points[index].label;
00081
00082
00083 const int w_rem = index%w;
00084 const int x_max = std::min(2*r, r + w - w_rem - 1);
00085 const int y_min = std::max(index - r*w - r, w_rem - r);
00086 const int y_max = std::min(index + r*w - r, s - (w - w_rem) - r);
00087 Eigen::Matrix<float, 1, 9, Eigen::RowMajor> accu = Eigen::Matrix<float, 1, 9, Eigen::RowMajor>::Zero();
00088 int point_count = 0;
00089 for (int y = y_min; y <= y_max; y += steps*w)
00090 {
00091 for (int idx = y; idx < y + x_max; idx+=steps)
00092 {
00093 if (labels->points[idx].label != l_idx) { idx = idx - steps + 1; continue; }
00094 PointT const* p_idx = &(surface->points[idx]);
00095 if (pcl_isnan(p_idx->z)) { idx = idx - steps + 1; continue; }
00096
00097 accu[0] += p_idx->x * p_idx->x;
00098 accu[1] += p_idx->x * p_idx->y;
00099 accu[2] += p_idx->x * p_idx->z;
00100 accu[3] += p_idx->y * p_idx->y;
00101 accu[4] += p_idx->y * p_idx->z;
00102 accu[5] += p_idx->z * p_idx->z;
00103 accu[6] += p_idx->x;
00104 accu[7] += p_idx->y;
00105 accu[8] += p_idx->z;
00106 ++point_count;
00107 }
00108 if (point_count == 0) { y = y - steps*w + w; }
00109 }
00110
00111
00112
00113
00114
00115
00116 if (accu[0] == 0 && accu[3] == 0 && accu[5] == 0)
00117 {
00118 std::cout <<"[NormalEstimation]: null normal!" << std::endl;
00119 normal_out(0) = normal_out(1) = normal_out(2) = std::numeric_limits<float>::quiet_NaN();
00120 return;
00121 }
00122 accu /= static_cast<float>(point_count);
00123
00124 Eigen::Matrix3f cov;
00125 cov.coeffRef(0) = accu(0) - accu(6) * accu(6);
00126 cov.coeffRef(1) = cov.coeffRef(3) = accu(1) - accu(6) * accu(7);
00127 cov.coeffRef(2) = cov.coeffRef(6) = accu(2) - accu(6) * accu(8);
00128 cov.coeffRef(4) = accu(3) - accu(7) * accu(7);
00129 cov.coeffRef(5) = cov.coeffRef(7) = accu(4) - accu(7) * accu(8);
00130 cov.coeffRef(8) = accu(5) - accu(8) * accu(8);
00131 Eigen::Vector3f eigenvalues;
00132 Eigen::Matrix3f eigenvectors;
00133 pcl::eigen33(cov, eigenvectors, eigenvalues);
00134 if ( surface->points[index].getVector3fMap().dot(eigenvectors.col(0)) > 0)
00135 normal_out = eigenvectors.col(0) * (-1);
00136 else
00137 normal_out = eigenvectors.col(0);
00138 }
00139
00140 template <typename PointInT, typename PointOutT, typename LabelOutT> void
00141 cob_3d_features::OrganizedNormalEstimation<PointInT,PointOutT,LabelOutT>::recomputeSegmentNormal (
00142 PointCloudInConstPtr cloud_in,
00143 LabelCloudOutConstPtr label_in,
00144 int index,
00145 float& n_x,
00146 float& n_y,
00147 float& n_z)
00148 {
00149 Eigen::Vector3f p = cloud_in->points[index].getVector3fMap();
00150 if (pcl_isnan(p(2)))
00151 {
00152 n_x = n_y = n_z = std::numeric_limits<float>::quiet_NaN();
00153 return;
00154 }
00155
00156
00157 int idx, max_gap, gap, init_gap, n_normals = 0;
00158 int idx_x = index % cloud_in->width;
00159 int idx_y = index / cloud_in->width;
00160 int l_idx = label_in->points[index].label;
00161
00162 bool has_prev_point;
00163
00164 Eigen::Vector3f p_curr;
00165 Eigen::Vector3f p_prev(0,0,0);
00166 Eigen::Vector3f p_first(0,0,0);
00167 Eigen::Vector3f n_idx(0,0,0);
00168
00169 std::vector<std::vector<int> >::iterator it_c;
00170 std::vector<int>::iterator it_ci;
00171
00172
00173 if (idx_y >= pixel_search_radius_ && idx_y < (int)cloud_in->height - pixel_search_radius_ &&
00174 idx_x >= pixel_search_radius_ && idx_x < (int)cloud_in->width - pixel_search_radius_)
00175 {
00176 for (it_c = mask_.begin(); it_c != mask_.end(); ++it_c)
00177 {
00178 has_prev_point = false; init_gap = gap = 0; max_gap = 0.25 * (*it_c).size();
00179
00180 for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci)
00181 {
00182 idx = index + *it_ci;
00183
00184 Eigen::Vector3f p_i = cloud_in->points[idx].getVector3fMap();
00185 if ( pcl_isnan(p_i(2)) || label_in->points[idx].label != l_idx) { ++gap; continue; }
00186 if ( gap <= max_gap && has_prev_point )
00187 {
00188 p_curr = p_i - p;
00189 n_idx += (p_prev.cross(p_curr)).normalized();
00190 ++n_normals;
00191 p_prev = p_curr;
00192 }
00193 else
00194 {
00195 p_prev = p_i - p;
00196 if (!has_prev_point)
00197 {
00198 p_first = p_prev;
00199 init_gap = gap;
00200 has_prev_point = true;
00201 }
00202 }
00203 gap = 0;
00204 }
00205
00206
00207 if (gap + init_gap <= max_gap)
00208 {
00209
00210 n_idx += (p_prev.cross(p_first)).normalized();
00211 ++n_normals;
00212 }
00213 }
00214 }
00215 else
00216 {
00217 for (it_c = mask_.begin(); it_c != mask_.end(); ++it_c)
00218 {
00219 has_prev_point = false; init_gap = gap = 0; max_gap = 0.25 * (*it_c).size();
00220
00221 for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci)
00222 {
00223 idx = index + *it_ci;
00224
00225 if ( idx < 0 || idx >= (int)cloud_in->points.size() ) { continue; }
00226 int v = idx * inv_width_;
00227 if ( v < 0 || v >= (int)cloud_in->height ) { continue; }
00228 Eigen::Vector3f p_i = cloud_in->points[idx].getVector3fMap();
00229 if ( pcl_isnan(p_i(2)) || label_in->points[idx].label != l_idx) { ++gap; continue; }
00230 if ( gap <= max_gap && has_prev_point )
00231 {
00232 p_curr = p_i - p;
00233 n_idx += (p_prev.cross(p_curr)).normalized();
00234 ++n_normals;
00235 p_prev = p_curr;
00236 }
00237 else
00238 {
00239 p_prev = p_i - p;
00240 if (!has_prev_point)
00241 {
00242 p_first = p_prev;
00243 init_gap = gap;
00244 has_prev_point = true;
00245 }
00246 }
00247 gap = 0;
00248 }
00249
00250
00251 if (gap + init_gap <= max_gap)
00252 {
00253
00254 n_idx += (p_prev.cross(p_first)).normalized();
00255 ++n_normals;
00256 }
00257 }
00258 }
00259
00260 n_idx /= (float)n_normals;
00261 n_idx = n_idx.normalized();
00262 n_x = n_idx(0);
00263 n_y = n_idx(1);
00264 n_z = n_idx(2);
00265 }
00266
00267
00268 template <typename PointInT, typename PointOutT, typename LabelOutT> void
00269 cob_3d_features::OrganizedNormalEstimation<PointInT,PointOutT,LabelOutT>::computePointNormal (
00270 const PointCloudIn &cloud,
00271 int index,
00272 float &n_x,
00273 float &n_y,
00274 float &n_z,
00275 int &label_out)
00276 {
00277 Eigen::Vector3f p = cloud.points[index].getVector3fMap();
00278 if (p(2) != p(2))
00279 {
00280 n_x = n_y = n_z = std::numeric_limits<float>::quiet_NaN();
00281 label_out = I_NAN;
00282 return;
00283 }
00284
00285 int idx, max_gap, gap, init_gap, n_normals = 0;
00286 int idx_x = index % input_->width;
00287 int idx_y = index * inv_width_;
00288
00289 float distance_threshold = skip_distant_point_threshold_ * 0.003 * p(2) * p(2);
00290
00291 bool has_prev_point;
00292
00293
00294 Eigen::Vector3f p_curr;
00295 Eigen::Vector3f p_prev(0,0,0);
00296 Eigen::Vector3f p_first(0,0,0);
00297 Eigen::Vector3f n_idx(0,0,0);
00298
00299 std::vector<std::vector<int> >::iterator it_c;
00300 std::vector<int>::iterator it_ci;
00301
00302
00303
00304 if (idx_y >= pixel_search_radius_ && idx_y < (int)cloud.height - pixel_search_radius_ &&
00305 idx_x >= pixel_search_radius_ && idx_x < (int)cloud.width - pixel_search_radius_)
00306 {
00307 for (it_c = mask_.begin(); it_c != mask_.end(); ++it_c)
00308 {
00309 has_prev_point = false; init_gap = gap = 0; max_gap = 0.25 * (*it_c).size();
00310
00311 for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci)
00312 {
00313 idx = index + *it_ci;
00314 Eigen::Vector3f p_i = cloud.points[idx].getVector3fMap();
00315 if ( p_i(2) != p_i(2) || fabs(p_i(2) - p(2)) > distance_threshold ) { ++gap; continue; }
00316
00317 if ( gap <= max_gap && has_prev_point )
00318 {
00319 p_curr = p_i - p;
00320 n_idx += (p_prev.cross(p_curr)).normalized();
00321 ++n_normals;
00322 p_prev = p_curr;
00323 }
00324 else
00325 {
00326 p_prev = p_i - p;
00327 if (!has_prev_point)
00328 {
00329 p_first = p_prev;
00330 init_gap = gap;
00331 has_prev_point = true;
00332 }
00333 }
00334 gap = 0;
00335 }
00336
00337
00338 if (gap + init_gap <= max_gap)
00339 {
00340
00341 n_idx += (p_prev.cross(p_first)).normalized();
00342 ++n_normals;
00343 }
00344 }
00345 }
00346 else
00347 {
00348 for (it_c = mask_.begin(); it_c != mask_.end(); ++it_c)
00349 {
00350 has_prev_point = false; gap = 0; max_gap = 0.25 * (*it_c).size();
00351
00352 for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci)
00353 {
00354 idx = index + *it_ci;
00355
00356 if ( idx < 0 || idx >= (int)cloud.points.size() ) { ++gap; continue; }
00357 int v = idx * inv_width_;
00358 if ( v < 0 || v >= (int)cloud.height || cloud.points[idx].z != cloud.points[idx].z) { ++gap; continue; }
00359 Eigen::Vector3f p_i = cloud.points[idx].getVector3fMap();
00360 if ( fabs(p_i(2) - p(2)) > distance_threshold ) { ++gap; continue; }
00361 if ( gap <= max_gap && has_prev_point)
00362 {
00363 p_curr = p_i - p;
00364 n_idx += (p_prev.cross(p_curr)).normalized();
00365 ++n_normals;
00366 p_prev = p_curr;
00367 }
00368 else
00369 {
00370 p_prev = p_i - p;
00371 if (!has_prev_point)
00372 {
00373 p_first = p_prev;
00374 init_gap = gap;
00375 has_prev_point = true;
00376 }
00377 }
00378 gap = 0;
00379 }
00380
00381
00382 if ( gap + init_gap <= max_gap)
00383 {
00384
00385 n_idx += (p_prev.cross(p_first)).normalized();
00386 ++n_normals;
00387 }
00388 }
00389 }
00390
00391
00392
00393
00394
00395 n_idx.normalize();
00396 n_x = n_idx(0);
00397 n_y = n_idx(1);
00398 n_z = n_idx(2);
00399 }
00400
00401 template <typename PointInT, typename PointOutT, typename LabelOutT> void
00402 cob_3d_features::OrganizedNormalEstimation<PointInT,PointOutT,LabelOutT>::computeFeature (PointCloudOut &output)
00403 {
00404 if (labels_->points.size() != input_->size())
00405 {
00406 labels_->points.resize(input_->size());
00407 labels_->height = input_->height;
00408 labels_->width = input_->width;
00409 }
00410
00411 for (std::vector<int>::iterator it=indices_->begin(); it != indices_->end(); ++it)
00412 {
00413 labels_->points[*it].label = I_UNDEF;
00414 computePointNormal(*surface_, *it,
00415 output.points[*it].normal[0],
00416 output.points[*it].normal[1],
00417 output.points[*it].normal[2],
00418 labels_->points[*it].label);
00419 }
00420 }
00421
00422 #define PCL_INSTANTIATE_OrganizedNormalEstimation(T,OutT,LabelT) template class PCL_EXPORTS cob_3d_features::OrganizedNormalEstimation<T,OutT,LabelT>;
00423
00424 #endif