|
Point Cloud Library (PCL)
1.5.1
|
00001 /* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Point Cloud Library (PCL) - www.pointclouds.org 00005 * Copyright (c) 2010-2011, Willow Garage, Inc. 00006 * 00007 * All rights reserved. 00008 * 00009 * Redistribution and use in source and binary forms, with or without 00010 * modification, are permitted provided that the following conditions 00011 * are met: 00012 * 00013 * * Redistributions of source code must retain the above copyright 00014 * notice, this list of conditions and the following disclaimer. 00015 * * Redistributions in binary form must reproduce the above 00016 * copyright notice, this list of conditions and the following 00017 * disclaimer in the documentation and/or other materials provided 00018 * with the distribution. 00019 * * Neither the name of Willow Garage, Inc. nor the names of its 00020 * contributors may be used to endorse or promote products derived 00021 * from this software without specific prior written permission. 00022 * 00023 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00024 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00025 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00026 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00027 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00028 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00029 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00030 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00031 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00032 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00033 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00034 * POSSIBILITY OF SUCH DAMAGE. 00035 * 00036 * 00037 */ 00038 00039 #ifndef PCL_FEATURES_IMPL_SHOT_H_ 00040 #define PCL_FEATURES_IMPL_SHOT_H_ 00041 00042 #include "pcl/features/shot.h" 00043 #include "pcl/features/shot_common.h" 00044 #include <utility> 00045 00047 00054 inline bool 00055 areEquals (double val1, double val2, double zeroDoubleEps = zeroDoubleEps15) 00056 { 00057 return (fabs (val1 - val2)<zeroDoubleEps); 00058 } 00059 00061 00068 inline bool 00069 areEquals (float val1, float val2, float zeroFloatEps = zeroFloatEps8) 00070 { 00071 return (fabs (val1 - val2)<zeroFloatEps); 00072 } 00073 00075 template <typename PointNT, typename PointOutT> float 00076 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::sRGB_LUT[256] = {- 1}; 00077 00079 template <typename PointNT, typename PointOutT> float 00080 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::sXYZ_LUT[4000] = {- 1}; 00081 00083 template <typename PointNT, typename PointOutT> void 00084 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::RGB2CIELAB (unsigned char R, unsigned char G, 00085 unsigned char B, float &L, float &A, 00086 float &B2) 00087 { 00088 if (sRGB_LUT[0] < 0) 00089 { 00090 for (int i = 0; i < 256; i++) 00091 { 00092 float f = i / 255.0f; 00093 if (f > 0.04045) 00094 sRGB_LUT[i] = (float)pow ((f + 0.055) / 1.055, 2.4); 00095 else 00096 sRGB_LUT[i] = f / 12.92; 00097 } 00098 00099 for (int i = 0; i < 4000; i++) 00100 { 00101 float f = i / 4000.0f; 00102 if (f > 0.008856) 00103 sXYZ_LUT[i] = pow (f, (float)0.3333); 00104 else 00105 sXYZ_LUT[i] = (7.787 * f) + (16.0 / 116.0); 00106 } 00107 } 00108 00109 float fr = sRGB_LUT[R]; 00110 float fg = sRGB_LUT[G]; 00111 float fb = sRGB_LUT[B]; 00112 00113 // Use white = D65 00114 const float x = fr * 0.412453 + fg * 0.357580 + fb * 0.180423; 00115 const float y = fr * 0.212671 + fg * 0.715160 + fb * 0.072169; 00116 const float z = fr * 0.019334 + fg * 0.119193 + fb * 0.950227; 00117 00118 float vx = x / 0.95047; 00119 float vy = y; 00120 float vz = z / 1.08883; 00121 00122 vx = sXYZ_LUT[int(vx*4000)]; 00123 vy = sXYZ_LUT[int(vy*4000)]; 00124 vz = sXYZ_LUT[int(vz*4000)]; 00125 00126 L = 116.0 * vy - 16.0; 00127 if (L>100) 00128 L=100; 00129 00130 A = 500.0 * (vx - vy); 00131 if (A>120) 00132 A=120; 00133 else if (A<- 120) 00134 A=- 120; 00135 00136 B2 = 200.0 * (vy - vz); 00137 if (B2>120) 00138 B2=120; 00139 else if (B2<- 120) 00140 B2=- 120; 00141 } 00142 00144 template <typename PointInT, typename PointNT, typename PointOutT> void 00145 pcl::SHOTEstimationBase<PointInT, PointNT, PointOutT>::createBinDistanceShape ( 00146 int index, 00147 const std::vector<int> &indices, 00148 const std::vector<float> &sqr_dists, 00149 const pcl::PointCloud<PointInT> &input, 00150 const pcl::PointCloud<PointNT> &normals, 00151 const pcl::PointCloud<PointInT> &surface, 00152 double search_radius, 00153 std::vector<double> &bin_distance_shape, 00154 std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf) 00155 { 00156 bin_distance_shape.resize (indices.size ()); 00157 00158 if (rf.size () != 3) 00159 rf.resize (3); 00160 00161 Eigen::Vector4f central_point = input.points[index].getVector4fMap (); 00162 central_point[3] = 0; 00163 if (pcl::getLocalRF (surface, search_radius, central_point, indices, sqr_dists, rf)) 00164 return; 00165 00166 for (size_t i_idx = 0; i_idx < indices.size (); ++i_idx) 00167 { 00168 double cosineDesc = normals.points[indices[i_idx]].getNormalVector4fMap ().dot (rf[2]); //feat[i].rf[6]*normal[0] + feat[i].rf[7]*normal[1] + feat[i].rf[8]*normal[2]; 00169 00170 if (cosineDesc > 1.0) 00171 cosineDesc = 1.0; 00172 if (cosineDesc < - 1.0) 00173 cosineDesc = - 1.0; 00174 00175 bin_distance_shape[i_idx] = ((1.0 + cosineDesc) * nr_shape_bins_) / 2; 00176 } 00177 } 00178 00180 template <typename PointInT, typename PointNT, typename PointOutT> void 00181 pcl::SHOTEstimationBase<PointInT, PointNT, PointOutT>::normalizeHistogram ( 00182 Eigen::VectorXf &shot, int desc_length) 00183 { 00184 double acc_norm = 0; 00185 for (int j = 0; j < desc_length; j++) 00186 acc_norm += shot[j] * shot[j]; 00187 acc_norm = sqrt (acc_norm); 00188 for (int j = 0; j < desc_length; j++) 00189 shot[j] /= acc_norm; 00190 } 00191 00193 template <typename PointInT, typename PointNT, typename PointOutT> void 00194 pcl::SHOTEstimationBase<PointInT, PointNT, PointOutT>::interpolateSingleChannel ( 00195 const std::vector<int> &indices, 00196 const std::vector<float> &sqr_dists, 00197 const Eigen::Vector4f ¢ral_point, 00198 const std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf, 00199 std::vector<double> &binDistance, 00200 const int nr_bins, 00201 Eigen::VectorXf &shot) 00202 { 00203 if (rf.size () != 3) 00204 { 00205 PCL_ERROR ("[pcl::%s::interpolateSingleChannel] RF size different than 9! Aborting...\n"); 00206 return; 00207 } 00208 00209 for (size_t i_idx = 0; i_idx < indices.size (); ++i_idx) 00210 { 00211 Eigen::Vector4f delta = surface_->points[indices[i_idx]].getVector4fMap () - central_point; 00212 delta[3] = 0; 00213 00214 // Compute the Euclidean norm 00215 double distance = sqrt (sqr_dists[i_idx]); 00216 00217 if (areEquals (distance, 0.0)) 00218 continue; 00219 00220 double xInFeatRef = delta.dot (rf[0]); //(x * feat[i].rf[0] + y * feat[i].rf[1] + z * feat[i].rf[2]); 00221 double yInFeatRef = delta.dot (rf[1]); //(x * feat[i].rf[3] + y * feat[i].rf[4] + z * feat[i].rf[5]); 00222 double zInFeatRef = delta.dot (rf[2]); //(x * feat[i].rf[6] + y * feat[i].rf[7] + z * feat[i].rf[8]); 00223 00224 // To avoid numerical problems afterwards 00225 if (fabs (yInFeatRef) < 1E-30) 00226 yInFeatRef = 0; 00227 if (fabs (xInFeatRef) < 1E-30) 00228 xInFeatRef = 0; 00229 if (fabs (zInFeatRef) < 1E-30) 00230 zInFeatRef = 0; 00231 00232 00233 unsigned char bit4 = ((yInFeatRef > 0) || ((yInFeatRef == 0.0) && (xInFeatRef < 0))) ? 1 : 0; 00234 unsigned char bit3 = ((xInFeatRef > 0) || ((xInFeatRef == 0.0) && (yInFeatRef > 0))) ? !bit4 : bit4; 00235 00236 assert (bit3 == 0 || bit3 == 1); 00237 00238 int desc_index = (bit4<<3) + (bit3<<2); 00239 00240 desc_index = desc_index << 1; 00241 00242 if ((xInFeatRef * yInFeatRef > 0) || (xInFeatRef == 0.0)) 00243 desc_index += (fabs (xInFeatRef) >= fabs (yInFeatRef)) ? 0 : 4; 00244 else 00245 desc_index += (fabs (xInFeatRef) > fabs (yInFeatRef)) ? 4 : 0; 00246 00247 desc_index += zInFeatRef > 0 ? 1 : 0; 00248 00249 // 2 RADII 00250 desc_index += (distance > radius1_2_) ? 2 : 0; 00251 00252 int step_index = static_cast<int>(floor (binDistance[i_idx] +0.5)); 00253 int volume_index = desc_index * (nr_bins+1); 00254 00255 //Interpolation on the cosine (adjacent bins in the histogram) 00256 binDistance[i_idx] -= step_index; 00257 double intWeight = (1- fabs (binDistance[i_idx])); 00258 00259 if (binDistance[i_idx] > 0) 00260 shot[volume_index + ((step_index+1) % nr_bins)] += binDistance[i_idx]; 00261 else 00262 shot[volume_index + ((step_index - 1 + nr_bins) % nr_bins)] += - binDistance[i_idx]; 00263 00264 //Interpolation on the distance (adjacent husks) 00265 00266 if (distance > radius1_2_) //external sphere 00267 { 00268 double radiusDistance = (distance - radius3_4_) / radius1_2_; 00269 00270 if (distance > radius3_4_) //most external sector, votes only for itself 00271 intWeight += 1 - radiusDistance; //peso=1-d 00272 else //3/4 of radius, votes also for the internal sphere 00273 { 00274 intWeight += 1 + radiusDistance; 00275 shot[(desc_index - 2) * (nr_bins+1) + step_index] -= radiusDistance; 00276 } 00277 } 00278 else //internal sphere 00279 { 00280 double radiusDistance = (distance - radius1_4_) / radius1_2_; 00281 00282 if (distance < radius1_4_) //most internal sector, votes only for itself 00283 intWeight += 1 + radiusDistance; //weight=1-d 00284 else //3/4 of radius, votes also for the external sphere 00285 { 00286 intWeight += 1 - radiusDistance; 00287 shot[(desc_index + 2) * (nr_bins+1) + step_index] += radiusDistance; 00288 } 00289 } 00290 00291 //Interpolation on the inclination (adjacent vertical volumes) 00292 double inclinationCos = zInFeatRef / distance; 00293 if (inclinationCos < - 1.0) 00294 inclinationCos = - 1.0; 00295 if (inclinationCos > 1.0) 00296 inclinationCos = 1.0; 00297 00298 double inclination = acos (inclinationCos); 00299 00300 assert (inclination >= 0.0 && inclination <= PST_RAD_180); 00301 00302 if (inclination > PST_RAD_90 || (fabs (inclination - PST_RAD_90) < 1e-30 && zInFeatRef <= 0)) 00303 { 00304 double inclinationDistance = (inclination - PST_RAD_135) / PST_RAD_90; 00305 if (inclination > PST_RAD_135) 00306 intWeight += 1 - inclinationDistance; 00307 else 00308 { 00309 intWeight += 1 + inclinationDistance; 00310 assert ((desc_index + 1) * (nr_bins+1) + step_index >= 0 && (desc_index + 1) * (nr_bins+1) + step_index < descLength_); 00311 shot[(desc_index + 1) * (nr_bins+1) + step_index] -= inclinationDistance; 00312 } 00313 } 00314 else 00315 { 00316 double inclinationDistance = (inclination - PST_RAD_45) / PST_RAD_90; 00317 if (inclination < PST_RAD_45) 00318 intWeight += 1 + inclinationDistance; 00319 else 00320 { 00321 intWeight += 1 - inclinationDistance; 00322 assert ((desc_index - 1) * (nr_bins+1) + step_index >= 0 && (desc_index - 1) * (nr_bins+1) + step_index < descLength_); 00323 shot[(desc_index - 1) * (nr_bins+1) + step_index] += inclinationDistance; 00324 } 00325 } 00326 00327 if (yInFeatRef != 0.0 || xInFeatRef != 0.0) 00328 { 00329 //Interpolation on the azimuth (adjacent horizontal volumes) 00330 double azimuth = atan2 (yInFeatRef, xInFeatRef); 00331 00332 int sel = desc_index >> 2; 00333 double angularSectorSpan = PST_RAD_45; 00334 double angularSectorStart = - PST_RAD_PI_7_8; 00335 00336 double azimuthDistance = (azimuth - (angularSectorStart + angularSectorSpan*sel)) / angularSectorSpan; 00337 00338 assert ((azimuthDistance < 0.5 || areEquals (azimuthDistance, 0.5)) && (azimuthDistance > - 0.5 || areEquals (azimuthDistance, - 0.5))); 00339 00340 azimuthDistance = (std::max)(- 0.5, std::min (azimuthDistance, 0.5)); 00341 00342 if (azimuthDistance > 0) 00343 { 00344 intWeight += 1 - azimuthDistance; 00345 int interp_index = (desc_index + 4) % maxAngularSectors_; 00346 assert (interp_index * (nr_bins+1) + step_index >= 0 && interp_index * (nr_bins+1) + step_index < descLength_); 00347 shot[interp_index * (nr_bins+1) + step_index] += azimuthDistance; 00348 } 00349 else 00350 { 00351 int interp_index = (desc_index - 4 + maxAngularSectors_) % maxAngularSectors_; 00352 assert (interp_index * (nr_bins+1) + step_index >= 0 && interp_index * (nr_bins+1) + step_index < descLength_); 00353 intWeight += 1 + azimuthDistance; 00354 shot[interp_index * (nr_bins+1) + step_index] -= azimuthDistance; 00355 } 00356 00357 } 00358 00359 assert (volume_index + step_index >= 0 && volume_index + step_index < descLength_); 00360 shot[volume_index + step_index] += intWeight; 00361 } 00362 } 00363 00365 template <typename PointNT, typename PointOutT> void 00366 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::interpolateDoubleChannel ( 00367 const std::vector<int> &indices, 00368 const std::vector<float> &sqr_dists, 00369 const Eigen::Vector4f ¢ral_point, 00370 const std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf, 00371 std::vector<double> &binDistanceShape, 00372 std::vector<double> &binDistanceColor, 00373 const int nr_bins_shape, 00374 const int nr_bins_color, 00375 Eigen::VectorXf &shot) 00376 { 00377 if (rf.size () != 3) 00378 { 00379 PCL_ERROR ("[pcl::%s::interpolateDoubleChannel] RF size different than 9! Aborting...\n"); 00380 return; 00381 } 00382 00383 int shapeToColorStride = nr_grid_sector_*(nr_bins_shape+1); 00384 00385 for (size_t i_idx = 0; i_idx < indices.size (); ++i_idx) 00386 { 00387 Eigen::Vector4f delta = surface_->points[indices[i_idx]].getVector4fMap () - central_point; 00388 delta[3] = 0; 00389 00390 // Compute the Euclidean norm 00391 double distance = sqrt (sqr_dists[i_idx]); 00392 00393 if (areEquals (distance, 0.0)) 00394 continue; 00395 00396 double xInFeatRef = delta.dot (rf[0]); //(x * feat[i].rf[0] + y * feat[i].rf[1] + z * feat[i].rf[2]); 00397 double yInFeatRef = delta.dot (rf[1]); //(x * feat[i].rf[3] + y * feat[i].rf[4] + z * feat[i].rf[5]); 00398 double zInFeatRef = delta.dot (rf[2]); //(x * feat[i].rf[6] + y * feat[i].rf[7] + z * feat[i].rf[8]); 00399 00400 // To avoid numerical problems afterwards 00401 if (fabs (yInFeatRef) < 1E-30) 00402 yInFeatRef = 0; 00403 if (fabs (xInFeatRef) < 1E-30) 00404 xInFeatRef = 0; 00405 if (fabs (zInFeatRef) < 1E-30) 00406 zInFeatRef = 0; 00407 00408 unsigned char bit4 = ((yInFeatRef > 0) || ((yInFeatRef == 0.0) && (xInFeatRef < 0))) ? 1 : 0; 00409 unsigned char bit3 = ((xInFeatRef > 0) || ((xInFeatRef == 0.0) && (yInFeatRef > 0))) ? !bit4 : bit4; 00410 00411 assert (bit3 == 0 || bit3 == 1); 00412 00413 int desc_index = (bit4<<3) + (bit3<<2); 00414 00415 desc_index = desc_index << 1; 00416 00417 if ((xInFeatRef * yInFeatRef > 0) || (xInFeatRef == 0.0)) 00418 desc_index += (fabs (xInFeatRef) >= fabs (yInFeatRef)) ? 0 : 4; 00419 else 00420 desc_index += (fabs (xInFeatRef) > fabs (yInFeatRef)) ? 4 : 0; 00421 00422 desc_index += zInFeatRef > 0 ? 1 : 0; 00423 00424 // 2 RADII 00425 desc_index += (distance > radius1_2_) ? 2 : 0; 00426 00427 int step_index_shape = static_cast<int>(floor (binDistanceShape[i_idx] +0.5)); 00428 int step_index_color = static_cast<int>(floor (binDistanceColor[i_idx] +0.5)); 00429 00430 int volume_index_shape = desc_index * (nr_bins_shape+1); 00431 int volume_index_color = shapeToColorStride + desc_index * (nr_bins_color+1); 00432 00433 //Interpolation on the cosine (adjacent bins in the histrogram) 00434 binDistanceShape[i_idx] -= step_index_shape; 00435 binDistanceColor[i_idx] -= step_index_color; 00436 00437 double intWeightShape = (1- fabs (binDistanceShape[i_idx])); 00438 double intWeightColor = (1- fabs (binDistanceColor[i_idx])); 00439 00440 if (binDistanceShape[i_idx] > 0) 00441 shot[volume_index_shape + ((step_index_shape + 1) % nr_bins_shape)] += binDistanceShape[i_idx]; 00442 else 00443 shot[volume_index_shape + ((step_index_shape - 1 + nr_bins_shape) % nr_bins_shape)] -= binDistanceShape[i_idx]; 00444 00445 if (binDistanceColor[i_idx] > 0) 00446 shot[volume_index_color + ((step_index_color+1) % nr_bins_color)] += binDistanceColor[i_idx]; 00447 else 00448 shot[volume_index_color + ((step_index_color - 1 + nr_bins_color) % nr_bins_color)] -= binDistanceColor[i_idx]; 00449 00450 //Interpolation on the distance (adjacent husks) 00451 00452 if (distance > radius1_2_) //external sphere 00453 { 00454 double radiusDistance = (distance - radius3_4_) / radius1_2_; 00455 00456 if (distance > radius3_4_) //most external sector, votes only for itself 00457 { 00458 intWeightShape += 1 - radiusDistance; //weight=1-d 00459 intWeightColor += 1 - radiusDistance; //weight=1-d 00460 } 00461 else //3/4 of radius, votes also for the internal sphere 00462 { 00463 intWeightShape += 1 + radiusDistance; 00464 intWeightColor += 1 + radiusDistance; 00465 shot[(desc_index - 2) * (nr_bins_shape+1) + step_index_shape] -= radiusDistance; 00466 shot[shapeToColorStride + (desc_index - 2) * (nr_bins_color+1) + step_index_color] -= radiusDistance; 00467 } 00468 } 00469 else //internal sphere 00470 { 00471 double radiusDistance = (distance - radius1_4_) / radius1_2_; 00472 00473 if (distance < radius1_4_) //most internal sector, votes only for itself 00474 { 00475 intWeightShape += 1 + radiusDistance; 00476 intWeightColor += 1 + radiusDistance; //weight=1-d 00477 } 00478 else //3/4 of radius, votes also for the external sphere 00479 { 00480 intWeightShape += 1 - radiusDistance; //weight=1-d 00481 intWeightColor += 1 - radiusDistance; //weight=1-d 00482 shot[(desc_index + 2) * (nr_bins_shape+1) + step_index_shape] += radiusDistance; 00483 shot[shapeToColorStride + (desc_index + 2) * (nr_bins_color+1) + step_index_color] += radiusDistance; 00484 } 00485 } 00486 00487 //Interpolation on the inclination (adjacent vertical volumes) 00488 double inclinationCos = zInFeatRef / distance; 00489 if (inclinationCos < - 1.0) 00490 inclinationCos = - 1.0; 00491 if (inclinationCos > 1.0) 00492 inclinationCos = 1.0; 00493 00494 double inclination = acos (inclinationCos); 00495 00496 assert (inclination >= 0.0 && inclination <= PST_RAD_180); 00497 00498 if (inclination > PST_RAD_90 || (fabs (inclination - PST_RAD_90) < 1e-30 && zInFeatRef <= 0)) 00499 { 00500 double inclinationDistance = (inclination - PST_RAD_135) / PST_RAD_90; 00501 if (inclination > PST_RAD_135) 00502 { 00503 intWeightShape += 1 - inclinationDistance; 00504 intWeightColor += 1 - inclinationDistance; 00505 } 00506 else 00507 { 00508 intWeightShape += 1 + inclinationDistance; 00509 intWeightColor += 1 + inclinationDistance; 00510 assert ((desc_index + 1) * (nr_bins_shape+1) + step_index_shape >= 0 && (desc_index + 1) * (nr_bins_shape+1) + step_index_shape < descLength_); 00511 assert (shapeToColorStride + (desc_index + 1) * (nr_bins_color+ 1) + step_index_color >= 0 && shapeToColorStride + (desc_index + 1) * (nr_bins_color+1) + step_index_color < descLength_); 00512 shot[(desc_index + 1) * (nr_bins_shape+1) + step_index_shape] -= inclinationDistance; 00513 shot[shapeToColorStride + (desc_index + 1) * (nr_bins_color+1) + step_index_color] -= inclinationDistance; 00514 } 00515 } 00516 else 00517 { 00518 double inclinationDistance = (inclination - PST_RAD_45) / PST_RAD_90; 00519 if (inclination < PST_RAD_45) 00520 { 00521 intWeightShape += 1 + inclinationDistance; 00522 intWeightColor += 1 + inclinationDistance; 00523 } 00524 else 00525 { 00526 intWeightShape += 1 - inclinationDistance; 00527 intWeightColor += 1 - inclinationDistance; 00528 assert ((desc_index - 1) * (nr_bins_shape+1) + step_index_shape >= 0 && (desc_index - 1) * (nr_bins_shape+1) + step_index_shape < descLength_); 00529 assert (shapeToColorStride + (desc_index - 1) * (nr_bins_color+ 1) + step_index_color >= 0 && shapeToColorStride + (desc_index - 1) * (nr_bins_color+1) + step_index_color < descLength_); 00530 shot[(desc_index - 1) * (nr_bins_shape+1) + step_index_shape] += inclinationDistance; 00531 shot[shapeToColorStride + (desc_index - 1) * (nr_bins_color+1) + step_index_color] += inclinationDistance; 00532 } 00533 } 00534 00535 if (yInFeatRef != 0.0 || xInFeatRef != 0.0) 00536 { 00537 //Interpolation on the azimuth (adjacent horizontal volumes) 00538 double azimuth = atan2 (yInFeatRef, xInFeatRef); 00539 00540 int sel = desc_index >> 2; 00541 double angularSectorSpan = PST_RAD_45; 00542 double angularSectorStart = - PST_RAD_PI_7_8; 00543 00544 double azimuthDistance = (azimuth - (angularSectorStart + angularSectorSpan*sel)) / angularSectorSpan; 00545 assert ((azimuthDistance < 0.5 || areEquals (azimuthDistance, 0.5)) && (azimuthDistance > - 0.5 || areEquals (azimuthDistance, - 0.5))); 00546 azimuthDistance = (std::max)(- 0.5, std::min (azimuthDistance, 0.5)); 00547 00548 if (azimuthDistance > 0) 00549 { 00550 intWeightShape += 1 - azimuthDistance; 00551 intWeightColor += 1 - azimuthDistance; 00552 int interp_index = (desc_index + 4) % maxAngularSectors_; 00553 assert (interp_index * (nr_bins_shape+1) + step_index_shape >= 0 && interp_index * (nr_bins_shape+1) + step_index_shape < descLength_); 00554 assert (shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color >= 0 && shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color < descLength_); 00555 shot[interp_index * (nr_bins_shape+1) + step_index_shape] += azimuthDistance; 00556 shot[shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color] += azimuthDistance; 00557 } 00558 else 00559 { 00560 int interp_index = (desc_index - 4 + maxAngularSectors_) % maxAngularSectors_; 00561 intWeightShape += 1 + azimuthDistance; 00562 intWeightColor += 1 + azimuthDistance; 00563 assert (interp_index * (nr_bins_shape+1) + step_index_shape >= 0 && interp_index * (nr_bins_shape+1) + step_index_shape < descLength_); 00564 assert (shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color >= 0 && shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color < descLength_); 00565 shot[interp_index * (nr_bins_shape+1) + step_index_shape] -= azimuthDistance; 00566 shot[shapeToColorStride + interp_index * (nr_bins_color+1) + step_index_color] -= azimuthDistance; 00567 } 00568 } 00569 00570 assert (volume_index_shape + step_index_shape >= 0 && volume_index_shape + step_index_shape < descLength_); 00571 assert (volume_index_color + step_index_color >= 0 && volume_index_color + step_index_color < descLength_); 00572 shot[volume_index_shape + step_index_shape] += intWeightShape; 00573 shot[volume_index_color + step_index_color] += intWeightColor; 00574 } 00575 } 00576 00577 00579 template <typename PointNT, typename PointOutT> void 00580 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::computePointSHOT ( 00581 const int index, const std::vector<int> &indices, const std::vector<float> &sqr_dists, Eigen::VectorXf &shot, 00582 std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf) 00583 { 00584 if (rf.size () != 3) 00585 rf.resize (3); 00586 00587 // Clear the resultant shot 00588 shot.setZero (); 00589 std::vector<double> binDistanceShape; 00590 std::vector<double> binDistanceColor; 00591 int nNeighbors = indices.size (); 00592 //Skip the current feature if the number of its neighbors is not sufficient for its description 00593 if (nNeighbors < 5) 00594 { 00595 PCL_WARN ("[pcl::%s::computePointSHOT] Warning! Neighborhood has less than 5 vertexes. Aborting description of point with index %d\n", getClassName ().c_str (), index); 00596 return; 00597 } 00598 00599 //Compute the local Reference Frame for the current 3D point 00600 Eigen::Vector4f central_point = input_->points[index].getVector4fMap (); 00601 central_point[3] = 0; 00602 if (pcl::getLocalRF (*surface_, search_radius_, central_point, indices, sqr_dists, rf)) 00603 return; 00604 00605 //If shape description is enabled, compute the bins activated by each neighbor of the current feature in the shape histogram 00606 if (b_describe_shape_) 00607 { 00608 binDistanceShape.resize (nNeighbors); 00609 00610 for (size_t i_idx = 0; i_idx < indices.size (); ++i_idx) 00611 { 00612 double cosineDesc = normals_->points[indices[i_idx]].getNormalVector4fMap ().dot (rf[2]); //feat[i].rf[6]*normal[0] + feat[i].rf[7]*normal[1] + feat[i].rf[8]*normal[2]; 00613 00614 if (cosineDesc > 1.0) 00615 cosineDesc = 1.0; 00616 if (cosineDesc < - 1.0) 00617 cosineDesc = - 1.0; 00618 00619 binDistanceShape[i_idx] = ((1.0 + cosineDesc) * nr_shape_bins_) / 2; 00620 } 00621 } 00622 00623 //If color description is enabled, compute the bins activated by each neighbor of the current feature in the color histogram 00624 if (b_describe_color_) 00625 { 00626 binDistanceColor.resize (nNeighbors); 00627 00628 unsigned char redRef = input_->points[index].rgba >> 16 & 0xFF; 00629 unsigned char greenRef = input_->points[index].rgba >> 8& 0xFF; 00630 unsigned char blueRef = input_->points[index].rgba & 0xFF; 00631 00632 float LRef, aRef, bRef; 00633 00634 RGB2CIELAB (redRef, greenRef, blueRef, LRef, aRef, bRef); 00635 LRef /= 100.0; 00636 aRef /= 120.0; 00637 bRef /= 120.0; //normalized LAB components (0<L<1, -1<a<1, -1<b<1) 00638 00639 for (size_t i_idx = 0; i_idx < indices.size (); ++i_idx) 00640 { 00641 unsigned char red = surface_->points[indices[i_idx]].rgba >> 16 & 0xFF; 00642 unsigned char green = surface_->points[indices[i_idx]].rgba >> 8 & 0xFF; 00643 unsigned char blue = surface_->points[indices[i_idx]].rgba & 0xFF; 00644 00645 float L, a, b; 00646 00647 RGB2CIELAB (red, green, blue, L, a, b); 00648 L /= 100.0; 00649 a /= 120.0; 00650 b /= 120.0; //normalized LAB components (0<L<1, -1<a<1, -1<b<1) 00651 00652 double colorDistance = (fabs (LRef - L) + ((fabs (aRef - a) + fabs (bRef - b)) / 2)) /3; 00653 00654 if (colorDistance > 1.0) 00655 colorDistance = 1.0; 00656 if (colorDistance < 0.0) 00657 colorDistance = 0.0; 00658 00659 binDistanceColor[i_idx] = colorDistance * nr_color_bins_; 00660 } 00661 } 00662 00663 //Apply quadrilinear interpolation on the activated bins in the shape and/or color histogram(s) 00664 00665 if (b_describe_shape_ && b_describe_color_) 00666 interpolateDoubleChannel (indices, sqr_dists, input_->points[index].getVector4fMap (), rf, binDistanceShape, binDistanceColor, 00667 nr_shape_bins_, nr_color_bins_, 00668 shot); 00669 else if (b_describe_color_) 00670 interpolateSingleChannel (indices, sqr_dists, input_->points[index].getVector4fMap (), rf, binDistanceColor, nr_color_bins_, shot); 00671 else 00672 interpolateSingleChannel (indices, sqr_dists, input_->points[index].getVector4fMap (), rf, binDistanceShape, nr_shape_bins_, shot); 00673 00674 // Normalize the final histogram 00675 this->normalizeHistogram (shot, descLength_); 00676 } 00677 00678 00680 template <typename PointInT, typename PointNT, typename PointOutT> void 00681 pcl::SHOTEstimation<PointInT, PointNT, PointOutT>::computePointSHOT ( 00682 const int index, const std::vector<int> &indices, const std::vector<float> &sqr_dists, Eigen::VectorXf &shot, 00683 std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf) 00684 { 00685 //Skip the current feature if the number of its neighbors is not sufficient for its description 00686 if (indices.size () < 5) 00687 { 00688 PCL_WARN ("[pcl::%s::computePointSHOT] Warning! Neighborhood has less than 5 vertexes. Aborting description of point with index %d\n", getClassName ().c_str (), index); 00689 return; 00690 } 00691 00692 // Clear the resultant shot 00693 std::vector<double> binDistanceShape; 00694 this->createBinDistanceShape (index, indices, sqr_dists, *input_, *normals_, *surface_, search_radius_, binDistanceShape, rf); 00695 00696 // Interpolate 00697 shot.setZero (); 00698 interpolateSingleChannel (indices, sqr_dists, input_->points[index].getVector4fMap (), rf, binDistanceShape, nr_shape_bins_, shot); 00699 00700 // Normalize the final histogram 00701 this->normalizeHistogram (shot, descLength_); 00702 } 00703 00704 00706 template <typename PointInT, typename PointNT> void 00707 pcl::SHOTEstimation<PointInT, PointNT, Eigen::MatrixXf>::computePointSHOT ( 00708 const int index, const std::vector<int> &indices, const std::vector<float> &sqr_dists, Eigen::VectorXf &shot, 00709 std::vector<Eigen::Vector4f, Eigen::aligned_allocator<Eigen::Vector4f> > &rf) 00710 { 00711 //Skip the current feature if the number of its neighbors is not sufficient for its description 00712 if (indices.size () < 5) 00713 { 00714 PCL_WARN ("[pcl::%s::computePointSHOT] Warning! Neighborhood has less than 5 vertexes. Aborting description of point with index %d\n", getClassName ().c_str (), index); 00715 return; 00716 } 00717 00718 // Clear the resultant shot 00719 std::vector<double> binDistanceShape; 00720 this->createBinDistanceShape (index, indices, sqr_dists, *input_, *normals_, *surface_, search_radius_, binDistanceShape, rf); 00721 00722 // Interpolate 00723 shot.setZero (); 00724 interpolateSingleChannel (indices, sqr_dists, input_->points[index].getVector4fMap (), rf, binDistanceShape, nr_shape_bins_, shot); 00725 00726 // Normalize the final histogram 00727 this->normalizeHistogram (shot, descLength_); 00728 } 00729 00730 00734 template <typename PointNT, typename PointOutT> void 00735 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, PointOutT>::computeFeature (PointCloudOut &output) 00736 { 00737 if (rf_.size () != 3) 00738 rf_.resize (3); 00739 00740 // Compute the current length of the descriptor 00741 descLength_ = (b_describe_shape_) ? nr_grid_sector_*(nr_shape_bins_+1) : 0; 00742 descLength_ += (b_describe_color_) ? nr_grid_sector_*(nr_color_bins_+1) : 0; 00743 00744 // Useful values 00745 sqradius_ = search_radius_*search_radius_; 00746 radius3_4_ = (search_radius_*3) / 4; 00747 radius1_4_ = search_radius_ / 4; 00748 radius1_2_ = search_radius_ / 2; 00749 00750 shot_.setZero (descLength_); 00751 rf_[0].setZero (); 00752 rf_[1].setZero (); 00753 rf_[2].setZero (); 00754 00755 if (output.points[0].descriptor.size () != (size_t)descLength_) 00756 for (size_t idx = 0; idx < indices_->size (); ++idx) 00757 output.points[idx].descriptor.resize (descLength_); 00758 // if (output.points[0].size != (size_t)descLength_) 00759 // { 00760 // PCL_ERROR ("[pcl::%s::computeFeature] The desired descriptor size (%lu) does not match the output point type feature (%lu)! Aborting...\n", getClassName ().c_str (), descLength_, (unsigned long) output.points[0].size); 00761 // return; 00762 // } 00763 00764 // Allocate enough space to hold the results 00765 // \note This resize is irrelevant for a radiusSearch (). 00766 std::vector<int> nn_indices (k_); 00767 std::vector<float> nn_dists (k_); 00768 00769 output.is_dense = true; 00770 // Iterating over the entire index vector 00771 for (size_t idx = 0; idx < indices_->size (); ++idx) 00772 { 00773 if (!isFinite ((*input_)[(*indices_)[idx]]) || 00774 this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0) 00775 { 00776 // Copy into the resultant cloud 00777 for (int d = 0; d < shot_.size (); ++d) 00778 output.points[idx].descriptor[d] = std::numeric_limits<float>::quiet_NaN (); 00779 for (int d = 0; d < 9; ++d) 00780 output.points[idx].rf[d] = std::numeric_limits<float>::quiet_NaN (); 00781 00782 output.is_dense = false; 00783 continue; 00784 } 00785 00786 // Compute the SHOT descriptor for the current 3D feature 00787 computePointSHOT ((*indices_)[idx], nn_indices, nn_dists, shot_, rf_); 00788 00789 // Copy into the resultant cloud 00790 for (int d = 0; d < shot_.size (); ++d) 00791 output.points[idx].descriptor[d] = shot_[d]; 00792 for (int d = 0; d < 9; ++d) 00793 output.points[idx].rf[d] = rf_[d/3][d%3]; 00794 } 00795 } 00796 00800 template <typename PointNT> void 00801 pcl::SHOTEstimation<pcl::PointXYZRGBA, PointNT, Eigen::MatrixXf>::computeFeatureEigen (pcl::PointCloud<Eigen::MatrixXf> &output) 00802 { 00803 if (rf_.size () != 3) 00804 rf_.resize (3); 00805 00806 // Compute the current length of the descriptor 00807 descLength_ = (b_describe_shape_) ? nr_grid_sector_*(nr_shape_bins_+1) : 0; 00808 descLength_ += (b_describe_color_) ? nr_grid_sector_*(nr_color_bins_+1) : 0; 00809 00810 // Set up the output channels 00811 output.channels["shot"].name = "shot"; 00812 output.channels["shot"].offset = 0; 00813 output.channels["shot"].size = 4; 00814 output.channels["shot"].count = descLength_ + 9; 00815 output.channels["shot"].datatype = sensor_msgs::PointField::FLOAT32; 00816 00817 // Useful values 00818 sqradius_ = search_radius_*search_radius_; 00819 radius3_4_ = (search_radius_*3) / 4; 00820 radius1_4_ = search_radius_ / 4; 00821 radius1_2_ = search_radius_ / 2; 00822 00823 shot_.setZero (descLength_); 00824 rf_[0].setZero (); 00825 rf_[1].setZero (); 00826 rf_[2].setZero (); 00827 00828 output.points.resize (indices_->size (), descLength_ + 9); 00829 00830 // Allocate enough space to hold the results 00831 // \note This resize is irrelevant for a radiusSearch (). 00832 std::vector<int> nn_indices (k_); 00833 std::vector<float> nn_dists (k_); 00834 00835 output.is_dense = true; 00836 // Iterating over the entire index vector 00837 for (size_t idx = 0; idx < indices_->size (); ++idx) 00838 { 00839 if (!isFinite ((*input_)[(*indices_)[idx]]) || 00840 this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0) 00841 { 00842 output.points.row (idx).setConstant (std::numeric_limits<float>::quiet_NaN ()); 00843 00844 output.is_dense = false; 00845 continue; 00846 } 00847 00848 // Compute the SHOT descriptor for the current 3D feature 00849 this->computePointSHOT ((*indices_)[idx], nn_indices, nn_dists, shot_, rf_); 00850 00851 // Copy into the resultant cloud 00852 for (int d = 0; d < shot_.size (); ++d) 00853 output.points (idx, d) = shot_[d]; 00854 for (int d = 0; d < 9; ++d) 00855 output.points (idx, shot_.size () + d) = rf_[d/3][d%3]; 00856 } 00857 } 00858 00859 00863 template <typename PointInT, typename PointNT, typename PointOutT> void 00864 pcl::SHOTEstimationBase<PointInT, PointNT, PointOutT>::computeFeature (pcl::PointCloud<PointOutT> &output) 00865 { 00866 if (rf_.size () != 3) 00867 rf_.resize (3); 00868 00869 descLength_ = nr_grid_sector_ * (nr_shape_bins_+1); 00870 00871 sqradius_ = search_radius_ * search_radius_; 00872 radius3_4_ = (search_radius_*3) / 4; 00873 radius1_4_ = search_radius_ / 4; 00874 radius1_2_ = search_radius_ / 2; 00875 00876 shot_.setZero (descLength_); 00877 rf_[0].setZero (); 00878 rf_[1].setZero (); 00879 rf_[2].setZero (); 00880 00881 if (output.points[0].descriptor.size () != (size_t)descLength_) 00882 for (size_t idx = 0; idx < indices_->size (); ++idx) 00883 output.points[idx].descriptor.resize (descLength_); 00884 // if (output.points[0].size != (size_t)descLength_) 00885 // { 00886 // PCL_ERROR ("[pcl::%s::computeFeature] The desired descriptor size (%lu) does not match the output point type feature (%lu)! Aborting...\n", getClassName ().c_str (), descLength_, (unsigned long) output.points[0].size); 00887 // return; 00888 // } 00889 00890 // Allocate enough space to hold the results 00891 // \note This resize is irrelevant for a radiusSearch (). 00892 std::vector<int> nn_indices (k_); 00893 std::vector<float> nn_dists (k_); 00894 00895 output.is_dense = true; 00896 // Iterating over the entire index vector 00897 for (size_t idx = 0; idx < indices_->size (); ++idx) 00898 { 00899 if (!isFinite ((*input_)[(*indices_)[idx]]) || 00900 this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0) 00901 { 00902 // Copy into the resultant cloud 00903 for (int d = 0; d < shot_.size (); ++d) 00904 output.points[idx].descriptor[d] = std::numeric_limits<float>::quiet_NaN (); 00905 for (int d = 0; d < 9; ++d) 00906 output.points[idx].rf[d] = std::numeric_limits<float>::quiet_NaN (); 00907 00908 output.is_dense = false; 00909 continue; 00910 } 00911 00912 // Estimate the SHOT at each patch 00913 computePointSHOT ((*indices_)[idx], nn_indices, nn_dists, shot_, rf_); 00914 00915 // Copy into the resultant cloud 00916 for (int d = 0; d < shot_.size (); ++d) 00917 output.points[idx].descriptor[d] = shot_[d]; 00918 for (int d = 0; d < 9; ++d) 00919 output.points[idx].rf[d] = rf_[d/3][d%3]; 00920 } 00921 } 00922 00926 template <typename PointInT, typename PointNT> void 00927 pcl::SHOTEstimationBase<PointInT, PointNT, Eigen::MatrixXf>::computeFeatureEigen (pcl::PointCloud<Eigen::MatrixXf> &output) 00928 { 00929 if (rf_.size () != 3) 00930 rf_.resize (3); 00931 00932 descLength_ = nr_grid_sector_ * (nr_shape_bins_+1); 00933 00934 // Set up the output channels 00935 output.channels["shot"].name = "shot"; 00936 output.channels["shot"].offset = 0; 00937 output.channels["shot"].size = 4; 00938 output.channels["shot"].count = descLength_ + 9; 00939 output.channels["shot"].datatype = sensor_msgs::PointField::FLOAT32; 00940 00941 sqradius_ = search_radius_ * search_radius_; 00942 radius3_4_ = (search_radius_*3) / 4; 00943 radius1_4_ = search_radius_ / 4; 00944 radius1_2_ = search_radius_ / 2; 00945 00946 shot_.setZero (descLength_); 00947 rf_[0].setZero (); 00948 rf_[1].setZero (); 00949 rf_[2].setZero (); 00950 00951 output.points.resize (indices_->size (), descLength_ + 9); 00952 00953 // Allocate enough space to hold the results 00954 // \note This resize is irrelevant for a radiusSearch (). 00955 std::vector<int> nn_indices (k_); 00956 std::vector<float> nn_dists (k_); 00957 00958 output.is_dense = true; 00959 // Iterating over the entire index vector 00960 for (size_t idx = 0; idx < indices_->size (); ++idx) 00961 { 00962 if (!isFinite ((*input_)[(*indices_)[idx]]) || 00963 this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists) == 0) 00964 { 00965 output.points.row (idx).setConstant (std::numeric_limits<float>::quiet_NaN ()); 00966 00967 output.is_dense = false; 00968 continue; 00969 } 00970 00971 // Estimate the SHOT at each patch 00972 this->computePointSHOT ((*indices_)[idx], nn_indices, nn_dists, shot_, rf_); 00973 00974 // Copy into the resultant cloud 00975 for (int d = 0; d < shot_.size (); ++d) 00976 output.points (idx, d) = shot_[d]; 00977 for (int d = 0; d < 9; ++d) 00978 output.points (idx, shot_.size () + d) = rf_[d/3][d%3]; 00979 } 00980 } 00981 00982 #define PCL_INSTANTIATE_SHOTEstimationBase(T,NT,OutT) template class PCL_EXPORTS pcl::SHOTEstimationBase<T,NT,OutT>; 00983 #define PCL_INSTANTIATE_SHOTEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::SHOTEstimation<T,NT,OutT>; 00984 00985 #endif // PCL_FEATURES_IMPL_SHOT_H_ 00986
1.8.0