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 #include "OutlierFiltersImpl.h"
00037 #include "PointMatcherPrivate.h"
00038 #include "Functions.h"
00039
00040 #include <algorithm>
00041 #include <vector>
00042 #include <iostream>
00043 #include <limits>
00044
00045 using namespace std;
00046 using namespace PointMatcherSupport;
00047
00048
00049 template<typename T>
00050 typename PointMatcher<T>::OutlierWeights OutlierFiltersImpl<T>::NullOutlierFilter::compute(
00051 const DataPoints& filteredReading,
00052 const DataPoints& filteredReference,
00053 const Matches& input)
00054 {
00055 return OutlierWeights::Constant(input.ids.rows(), input.ids.cols(), 1);
00056 }
00057
00058 template struct OutlierFiltersImpl<float>::NullOutlierFilter;
00059 template struct OutlierFiltersImpl<double>::NullOutlierFilter;
00060
00061
00062
00063 template<typename T>
00064 OutlierFiltersImpl<T>::MaxDistOutlierFilter::MaxDistOutlierFilter(const Parameters& params):
00065 OutlierFilter("MaxDistOutlierFilter", MaxDistOutlierFilter::availableParameters(), params),
00066 maxDist(Parametrizable::get<T>("maxDist"))
00067 {
00068 }
00069
00070
00071 template<typename T>
00072 typename PointMatcher<T>::OutlierWeights OutlierFiltersImpl<T>::MaxDistOutlierFilter::compute(
00073 const DataPoints& filteredReading,
00074 const DataPoints& filteredReference,
00075 const Matches& input)
00076 {
00077 return OutlierWeights((input.dists.array() <= maxDist).template cast<T>());
00078 }
00079
00080 template struct OutlierFiltersImpl<float>::MaxDistOutlierFilter;
00081 template struct OutlierFiltersImpl<double>::MaxDistOutlierFilter;
00082
00083
00084 template<typename T>
00085 OutlierFiltersImpl<T>::MinDistOutlierFilter::MinDistOutlierFilter(const Parameters& params):
00086 OutlierFilter("MinDistOutlierFilter", MinDistOutlierFilter::availableParameters(), params),
00087 minDist(Parametrizable::get<T>("minDist"))
00088 {
00089 }
00090
00091 template<typename T>
00092 typename PointMatcher<T>::OutlierWeights OutlierFiltersImpl<T>::MinDistOutlierFilter::compute(
00093 const DataPoints& filteredReading,
00094 const DataPoints& filteredReference,
00095 const Matches& input)
00096 {
00097 return OutlierWeights((input.dists.array() >= minDist).template cast<T>());
00098 }
00099
00100 template struct OutlierFiltersImpl<float>::MinDistOutlierFilter;
00101 template struct OutlierFiltersImpl<double>::MinDistOutlierFilter;
00102
00103
00104
00105
00106 template<typename T>
00107 OutlierFiltersImpl<T>::MedianDistOutlierFilter::MedianDistOutlierFilter(const Parameters& params):
00108 OutlierFilter("MedianDistOutlierFilter", MedianDistOutlierFilter::availableParameters(), params),
00109 factor(Parametrizable::get<T>("factor"))
00110 {
00111 }
00112
00113 template<typename T>
00114 typename PointMatcher<T>::OutlierWeights OutlierFiltersImpl<T>::MedianDistOutlierFilter::compute(
00115 const DataPoints& filteredReading,
00116 const DataPoints& filteredReference,
00117 const Matches& input)
00118 {
00119 const T median = input.getDistsQuantile(0.5);
00120 const T limit = factor * median;
00121 return OutlierWeights((input.dists.array() <= limit).template cast<T>());
00122 }
00123
00124 template struct OutlierFiltersImpl<float>::MedianDistOutlierFilter;
00125 template struct OutlierFiltersImpl<double>::MedianDistOutlierFilter;
00126
00127
00128
00129 template<typename T>
00130 OutlierFiltersImpl<T>::TrimmedDistOutlierFilter::TrimmedDistOutlierFilter(const Parameters& params):
00131 OutlierFilter("TrimmedDistOutlierFilter", TrimmedDistOutlierFilter::availableParameters(), params),
00132 ratio(Parametrizable::get<T>("ratio"))
00133 {
00134 }
00135
00136 template<typename T>
00137 typename PointMatcher<T>::OutlierWeights OutlierFiltersImpl<T>::TrimmedDistOutlierFilter::compute(
00138 const DataPoints& filteredReading,
00139 const DataPoints& filteredReference,
00140 const Matches& input)
00141 {
00142 const T limit = input.getDistsQuantile(ratio);
00143 return OutlierWeights((input.dists.array() <= limit).template cast<T>());
00144 }
00145
00146 template struct OutlierFiltersImpl<float>::TrimmedDistOutlierFilter;
00147 template struct OutlierFiltersImpl<double>::TrimmedDistOutlierFilter;
00148
00149
00150 template<typename T>
00151 OutlierFiltersImpl<T>::VarTrimmedDistOutlierFilter::VarTrimmedDistOutlierFilter(const Parameters& params):
00152 OutlierFilter("VarTrimmedDistOutlierFilter", VarTrimmedDistOutlierFilter::availableParameters(), params),
00153 minRatio(Parametrizable::get<T>("minRatio")),
00154 maxRatio(Parametrizable::get<T>("maxRatio")),
00155 lambda(Parametrizable::get<T>("lambda"))
00156 {
00157 if (this->minRatio >= this->maxRatio)
00158 {
00159 throw InvalidParameter((boost::format("VarTrimmedDistOutlierFilter: minRatio (%1%) should be smaller than maxRatio (%2%)") % minRatio % maxRatio).str());
00160 }
00161 }
00162
00163 template<typename T>
00164 typename PointMatcher<T>::OutlierWeights OutlierFiltersImpl<T>::VarTrimmedDistOutlierFilter::compute(
00165 const DataPoints& filteredReading,
00166 const DataPoints& filteredReference,
00167 const Matches& input)
00168 {
00169 const T tunedRatio = optimizeInlierRatio(input);
00170 LOG_INFO_STREAM("Optimized ratio: " << tunedRatio);
00171
00172 const T limit = input.getDistsQuantile(tunedRatio);
00173 return OutlierWeights((input.dists.array() <= limit).template cast<T>());
00174 }
00175
00176 template<typename T>
00177 T OutlierFiltersImpl<T>::VarTrimmedDistOutlierFilter::optimizeInlierRatio(const Matches& matches)
00178 {
00179 typedef typename PointMatcher<T>::ConvergenceError ConvergenceError;
00180 typedef typename Eigen::Array<T, Eigen::Dynamic, 1> LineArray;
00181
00182 const int points_nbr = matches.dists.rows() * matches.dists.cols();
00183
00184
00185 std::vector<T> tmpSortedDist;
00186 tmpSortedDist.reserve(points_nbr);
00187 for (int x = 0; x < matches.dists.cols(); ++x)
00188 for (int y = 0; y < matches.dists.rows(); ++y)
00189 if ((matches.dists(y, x) != numeric_limits<T>::infinity()) && (matches.dists(y, x) > 0))
00190 tmpSortedDist.push_back(matches.dists(y, x));
00191 if (tmpSortedDist.size() == 0)
00192 throw ConvergenceError("no outlier to filter");
00193
00194 std::sort(tmpSortedDist.begin(), tmpSortedDist.end());
00195
00196 const int minEl = floor(this->minRatio*points_nbr);
00197 const int maxEl = floor(this->maxRatio*points_nbr);
00198
00199
00200 Eigen::Map<LineArray> sortedDist(&tmpSortedDist[0], points_nbr);
00201
00202 const LineArray trunkSortedDist = sortedDist.segment(minEl, maxEl-minEl);
00203 const T lowerSum = sortedDist.head(minEl).sum();
00204 const LineArray ids = LineArray::LinSpaced(trunkSortedDist.rows(), minEl+1, maxEl);
00205 const LineArray ratio = ids / points_nbr;
00206 const LineArray deno = ratio.pow(this->lambda);
00207 const LineArray FRMS = deno.inverse().square() * ids.inverse() * (lowerSum + trunkSortedDist);
00208 int minIndex(0);
00209 FRMS.minCoeff(&minIndex);
00210 const T optRatio = (float)(minIndex + minEl)/ (float)points_nbr;
00211
00212
00213
00214 return optRatio;
00215
00216 }
00217
00218 template struct OutlierFiltersImpl<float>::VarTrimmedDistOutlierFilter;
00219 template struct OutlierFiltersImpl<double>::VarTrimmedDistOutlierFilter;
00220
00221
00222 template<typename T>
00223 OutlierFiltersImpl<T>::SurfaceNormalOutlierFilter::SurfaceNormalOutlierFilter(const Parameters& params):
00224 OutlierFilter("SurfaceNormalOutlierFilter", SurfaceNormalOutlierFilter::availableParameters(), params),
00225 eps(cos(Parametrizable::get<T>("maxAngle"))),
00226 warningPrinted(false)
00227 {
00228
00229 }
00230
00231 template<typename T>
00232 typename PointMatcher<T>::OutlierWeights OutlierFiltersImpl<T>::SurfaceNormalOutlierFilter::compute(
00233 const DataPoints& filteredReading,
00234 const DataPoints& filteredReference,
00235 const Matches& input)
00236 {
00237 const BOOST_AUTO(normalsReading, filteredReading.getDescriptorViewByName("normals"));
00238 const BOOST_AUTO(normalsReference, filteredReference.getDescriptorViewByName("normals"));
00239
00240
00241 OutlierWeights w(input.dists.rows(), input.dists.cols());
00242
00243 if(normalsReading.cols() != 0 && normalsReference.cols() != 0)
00244 {
00245 for (int x = 0; x < w.cols(); ++x)
00246 {
00247 const Vector normalRead = normalsReading.col(x).normalized();
00248
00249 for (int y = 0; y < w.rows(); ++y)
00250 {
00251 const int idRef = input.ids(y, x);
00252
00253 const Vector normalRef = normalsReference.col(idRef).normalized();
00254
00255 const T value = anyabs(normalRead.dot(normalRef));
00256
00257 if(value < eps)
00258 w(y, x) = 0;
00259 else
00260 w(y, x) = 1;
00261 }
00262 }
00263 }
00264 else
00265 {
00266 if(warningPrinted == false)
00267 {
00268 LOG_INFO_STREAM("SurfaceNormalOutlierFilter: surface normals not available. Skipping filtering");
00269 warningPrinted = true;
00270 }
00271
00272 w = Matrix::Ones(input.dists.rows(), input.dists.cols());
00273 }
00274
00275 return w;
00276 }
00277
00278 template struct OutlierFiltersImpl<float>::SurfaceNormalOutlierFilter;
00279 template struct OutlierFiltersImpl<double>::SurfaceNormalOutlierFilter;
00280
00281
00282 template<typename T>
00283 OutlierFiltersImpl<T>::GenericDescriptorOutlierFilter::GenericDescriptorOutlierFilter(const Parameters& params):
00284 OutlierFilter("GenericDescriptorOutlierFilter", GenericDescriptorOutlierFilter::availableParameters(), params),
00285 source(Parametrizable::getParamValueString("source")),
00286 descName(Parametrizable::getParamValueString("descName")),
00287 useSoftThreshold(Parametrizable::get<bool>("useSoftThreshold")),
00288 useLargerThan(Parametrizable::get<bool>("useLargerThan")),
00289 threshold(Parametrizable::get<T>("threshold"))
00290 {
00291 if(source != "reference" && source != "reading")
00292 {
00293 throw InvalidParameter(
00294 (boost::format("GenericDescriptorOutlierFilter: Error, the parameter named 'source' can only be set to 'reference' or 'reading' but was set to %1%") % source).str());
00295 }
00296 }
00297
00298 template<typename T>
00299 typename PointMatcher<T>::OutlierWeights OutlierFiltersImpl<T>::GenericDescriptorOutlierFilter::compute(
00300 const DataPoints& filteredReading,
00301 const DataPoints& filteredReference,
00302 const Matches& input)
00303 {
00304 typedef typename DataPoints::ConstView ConstView;
00305
00306 const int knn = input.dists.rows();
00307 const int readPtsCount = input.dists.cols();
00308
00309 OutlierWeights w(knn, readPtsCount);
00310
00311 const DataPoints *cloud;
00312
00313 if(source == "reference")
00314 cloud = &filteredReference;
00315 else
00316 cloud = &filteredReference;
00317
00318 ConstView desc(cloud->getDescriptorViewByName(descName));
00319
00320 if(desc.rows() != 1)
00321 {
00322 throw InvalidParameter(
00323 (boost::format("GenericDescriptorOutlierFilter: Error, the parameter named 'descName' must be a 1D descriptor but the field %1% is %2%D") % descName % desc.rows()).str());
00324 }
00325
00326 for(int k=0; k < knn; k++)
00327 {
00328 for(int i=0; i < readPtsCount; i++)
00329 {
00330 if(useSoftThreshold == false)
00331 {
00332 if(useLargerThan == true)
00333 {
00334 if(desc(0, input.ids(k,i)) > threshold)
00335 w(k,i) = 1;
00336 else
00337 w(k,i) = 0;
00338 }
00339 else
00340 {
00341 if(desc(0, input.ids(k,i)) < threshold)
00342 w(k,i) = 1;
00343 else
00344 w(k,i) = 0;
00345 }
00346 }
00347 else
00348 {
00349
00350 w(k,i) = desc(0, input.ids(k,i));
00351 }
00352 }
00353 }
00354
00355
00356 if(useSoftThreshold)
00357 w = w/w.maxCoeff();
00358
00359 return w;
00360 }
00361
00362 template struct OutlierFiltersImpl<float>::GenericDescriptorOutlierFilter;
00363 template struct OutlierFiltersImpl<double>::GenericDescriptorOutlierFilter;
00364
00365