00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #ifndef PCL_FEATURES_IMPL_USC_HPP_
00041 #define PCL_FEATURES_IMPL_USC_HPP_
00042
00043 #include <pcl/features/usc.h>
00044 #include <pcl/features/shot_lrf.h>
00045 #include <pcl/common/geometry.h>
00046 #include <pcl/common/angles.h>
00047 #include <pcl/common/utils.h>
00048
00050 template <typename PointInT, typename PointOutT, typename PointRFT> bool
00051 pcl::UniqueShapeContext<PointInT, PointOutT, PointRFT>::initCompute ()
00052 {
00053 if (!Feature<PointInT, PointOutT>::initCompute ())
00054 {
00055 PCL_ERROR ("[pcl::%s::initCompute] Init failed.\n", getClassName ().c_str ());
00056 return (false);
00057 }
00058
00059
00060 typename SHOTLocalReferenceFrameEstimation<PointInT, PointRFT>::Ptr lrf_estimator(new SHOTLocalReferenceFrameEstimation<PointInT, PointRFT>());
00061 lrf_estimator->setRadiusSearch (local_radius_);
00062 lrf_estimator->setInputCloud (input_);
00063 lrf_estimator->setIndices (indices_);
00064 if (!fake_surface_)
00065 lrf_estimator->setSearchSurface(surface_);
00066
00067 if (!FeatureWithLocalReferenceFrames<PointInT, PointRFT>::initLocalReferenceFrames (indices_->size (), lrf_estimator))
00068 {
00069 PCL_ERROR ("[pcl::%s::initCompute] Init failed.\n", getClassName ().c_str ());
00070 return (false);
00071 }
00072
00073 if (search_radius_< min_radius_)
00074 {
00075 PCL_ERROR ("[pcl::%s::initCompute] search_radius_ must be GREATER than min_radius_.\n", getClassName ().c_str ());
00076 return (false);
00077 }
00078
00079
00080 descriptor_length_ = elevation_bins_ * azimuth_bins_ * radius_bins_;
00081
00082
00083 float azimuth_interval = 360.0f / static_cast<float> (azimuth_bins_);
00084 float elevation_interval = 180.0f / static_cast<float> (elevation_bins_);
00085
00086
00087 radii_interval_.clear ();
00088 phi_divisions_.clear ();
00089 theta_divisions_.clear ();
00090 volume_lut_.clear ();
00091
00092
00093 radii_interval_.resize (radius_bins_ + 1);
00094 for (size_t j = 0; j < radius_bins_ + 1; j++)
00095 radii_interval_[j] = static_cast<float> (exp (log (min_radius_) + ((static_cast<float> (j) / static_cast<float> (radius_bins_)) * log (search_radius_/min_radius_))));
00096
00097
00098 theta_divisions_.resize (elevation_bins_+1);
00099 for (size_t k = 0; k < elevation_bins_+1; k++)
00100 theta_divisions_[k] = static_cast<float> (k) * elevation_interval;
00101
00102
00103 phi_divisions_.resize (azimuth_bins_+1);
00104 for (size_t l = 0; l < azimuth_bins_+1; l++)
00105 phi_divisions_[l] = static_cast<float> (l) * azimuth_interval;
00106
00107
00108
00109
00110 float integr_phi = pcl::deg2rad (phi_divisions_[1]) - pcl::deg2rad (phi_divisions_[0]);
00111
00112 float e = 1.0f / 3.0f;
00113
00114 volume_lut_.resize (radius_bins_ * elevation_bins_ * azimuth_bins_);
00115
00116 for (size_t j = 0; j < radius_bins_; j++)
00117 {
00118
00119 float integr_r = (radii_interval_[j+1]*radii_interval_[j+1]*radii_interval_[j+1] / 3) - (radii_interval_[j]*radii_interval_[j]*radii_interval_[j]/ 3);
00120
00121 for (size_t k = 0; k < elevation_bins_; k++)
00122 {
00123
00124 float integr_theta = cosf (deg2rad (theta_divisions_[k])) - cosf (deg2rad (theta_divisions_[k+1]));
00125
00126 float V = integr_phi * integr_theta * integr_r;
00127
00128
00129
00130
00131
00132 for (size_t l = 0; l < azimuth_bins_; l++)
00133
00134
00135 volume_lut_[(l*elevation_bins_*radius_bins_) + k*radius_bins_ + j] = 1.0f / powf (V, e);
00136 }
00137 }
00138 return (true);
00139 }
00140
00142 template <typename PointInT, typename PointOutT, typename PointRFT> void
00143 pcl::UniqueShapeContext<PointInT, PointOutT, PointRFT>::computePointDescriptor (size_t index, std::vector<float> &desc)
00144 {
00145 pcl::Vector3fMapConst origin = input_->points[(*indices_)[index]].getVector3fMap ();
00146
00147 const Eigen::Vector3f& x_axis = frames_->points[index].x_axis.getNormalVector3fMap ();
00148
00149 const Eigen::Vector3f& normal = frames_->points[index].z_axis.getNormalVector3fMap ();
00150
00151
00152 std::vector<int> nn_indices;
00153 std::vector<float> nn_dists;
00154 const size_t neighb_cnt = searchForNeighbors ((*indices_)[index], search_radius_, nn_indices, nn_dists);
00155
00156 for (size_t ne = 0; ne < neighb_cnt; ne++)
00157 {
00158 if (pcl::utils::equal(nn_dists[ne], 0.0f))
00159 continue;
00160
00161 Eigen::Vector3f neighbour = surface_->points[nn_indices[ne]].getVector3fMap ();
00162
00163
00164
00165
00166 float r = sqrt (nn_dists[ne]);
00167
00168
00169 Eigen::Vector3f proj;
00170 pcl::geometry::project (neighbour, origin, normal, proj);
00171 proj -= origin;
00172
00173
00174 proj.normalize ();
00175
00176
00177 Eigen::Vector3f cross = x_axis.cross (proj);
00178 float phi = rad2deg (std::atan2 (cross.norm (), x_axis.dot (proj)));
00179 phi = cross.dot (normal) < 0.f ? (360.0f - phi) : phi;
00181 Eigen::Vector3f no = neighbour - origin;
00182 no.normalize ();
00183 float theta = normal.dot (no);
00184 theta = pcl::rad2deg (acosf (std::min (1.0f, std::max (-1.0f, theta))));
00185
00187 size_t j = 0;
00188 size_t k = 0;
00189 size_t l = 0;
00190
00192 for (size_t rad = 1; rad < radius_bins_ + 1; rad++)
00193 {
00194 if (r <= radii_interval_[rad])
00195 {
00196 j = rad - 1;
00197 break;
00198 }
00199 }
00200
00201 for (size_t ang = 1; ang < elevation_bins_ + 1; ang++)
00202 {
00203 if (theta <= theta_divisions_[ang])
00204 {
00205 k = ang - 1;
00206 break;
00207 }
00208 }
00209
00210 for (size_t ang = 1; ang < azimuth_bins_ + 1; ang++)
00211 {
00212 if (phi <= phi_divisions_[ang])
00213 {
00214 l = ang - 1;
00215 break;
00216 }
00217 }
00218
00220 std::vector<int> neighbour_indices;
00221 std::vector<float> neighbour_didtances;
00222 float point_density = static_cast<float> (searchForNeighbors (*surface_, nn_indices[ne], point_density_radius_, neighbour_indices, neighbour_didtances));
00224 float w = (1.0f / point_density) * volume_lut_[(l*elevation_bins_*radius_bins_) +
00225 (k*radius_bins_) +
00226 j];
00227
00228 assert (w >= 0.0);
00229 if (w == std::numeric_limits<float>::infinity ())
00230 PCL_ERROR ("Shape Context Error INF!\n");
00231 if (w != w)
00232 PCL_ERROR ("Shape Context Error IND!\n");
00234 desc[(l*elevation_bins_*radius_bins_) + (k*radius_bins_) + j] += w;
00235
00236 assert (desc[(l*elevation_bins_*radius_bins_) + (k*radius_bins_) + j] >= 0);
00237 }
00238 }
00239
00241 template <typename PointInT, typename PointOutT, typename PointRFT> void
00242 pcl::UniqueShapeContext<PointInT, PointOutT, PointRFT>::computeFeature (PointCloudOut &output)
00243 {
00244 for (size_t point_index = 0; point_index < indices_->size (); point_index++)
00245 {
00246 output[point_index].descriptor.resize (descriptor_length_);
00247 for (int d = 0; d < 9; ++d)
00248 output.points[point_index].rf[d] = frames_->points[point_index].rf[ (4*(d/3) + (d%3)) ];
00249
00250 computePointDescriptor (point_index, output[point_index].descriptor);
00251 }
00252 }
00253
00255 template <typename PointInT, typename PointRFT> void
00256 pcl::UniqueShapeContext<PointInT, Eigen::MatrixXf, PointRFT>::computeFeatureEigen (pcl::PointCloud<Eigen::MatrixXf> &output)
00257 {
00258 output.points.resize (indices_->size (), descriptor_length_ + 9);
00259
00260 for (size_t point_index = 0; point_index < indices_->size (); point_index++)
00261 {
00262 for (int d = 0; d < 9; ++d)
00263 output.points (point_index, d) = frames_->points[point_index].rf[ (4*(d/3) + (d%3)) ];
00264
00265 std::vector<float> descriptor (descriptor_length_);
00266 computePointDescriptor (point_index, descriptor);
00267 for (size_t j = 0; j < descriptor_length_; ++j)
00268 output.points (point_index, 9 + j) = descriptor[j];
00269 }
00270 }
00271
00272 #define PCL_INSTANTIATE_UniqueShapeContext(T,OutT,RFT) template class PCL_EXPORTS pcl::UniqueShapeContext<T,OutT,RFT>;
00273
00274 #endif