149 lines
6.4 KiB
C++
149 lines
6.4 KiB
C++
/*
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2019,
|
|
Faculty of Mathematics and Computer Science,
|
|
Database Systems for New Applications.
|
|
|
|
SECONDO is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
SECONDO is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with SECONDO; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
----
|
|
|
|
|
|
//[<] [\ensuremath{<}]
|
|
//[>] [\ensuremath{>}]
|
|
|
|
\setcounter{tocdepth}{3}
|
|
\tableofcontents
|
|
|
|
|
|
|
|
3 Parameter class
|
|
|
|
Contains only parameters that determine the
|
|
algorithm.
|
|
Parts of this are intended to be toyed
|
|
with by the user.
|
|
|
|
*/
|
|
#include "ParamsAnalyzeGeom.h"
|
|
#include <cmath>
|
|
|
|
#include "../tcPointcloud2.h"
|
|
|
|
using namespace pointcloud2;
|
|
|
|
int ParamsAnalyzeGeom::_maxMMRCloudSequenceLength = -1;
|
|
// or MMRTREE_NODE_SIZE_MAX?
|
|
|
|
ParamsAnalyzeGeom::ParamsAnalyzeGeom(
|
|
const int pointCount, const double typicalPointDistance) {
|
|
|
|
// settings given by the user
|
|
_typicalPointDistance = typicalPointDistance;
|
|
_minimumObjectExtent = Pointcloud2::MINIMUM_OBJECT_EXTENT;
|
|
double neighborhoodSize = Pointcloud2::NEIGHBORHOOD_SIZE;
|
|
double softDiffusion = Pointcloud2::SOFT_DIFFUSION;
|
|
double roughDiffusion = Pointcloud2::ROUGH_DIFFUSION;
|
|
|
|
|
|
// parameters calculated from the above parameters
|
|
|
|
// 1. _sampleSize and _typicalSampleDistance
|
|
// -----------------------------------------
|
|
// to recognize an object, our sample should hold at least 50 points of
|
|
// this object, or rather 100. So, we need approx. 10 points per dimension
|
|
// since we are recognizing surfaces:
|
|
const double REQUIRED_OBJ_POINTS_PER_DIM = 10.0;
|
|
// we therefore want to choose a sample size that provides the required
|
|
// typical distance between sample points:
|
|
double suggestSampleDist =
|
|
_minimumObjectExtent / REQUIRED_OBJ_POINTS_PER_DIM;
|
|
// if, for instances, a typical point distance is 0.1, but for samples,
|
|
// a distance of 0.2 is enough (so, selectivity 2 for per dimension),
|
|
// we can choose 1 sample point from 2 * 2 = 4 original points
|
|
// (as we are talking surfaces!)
|
|
double sampleSelectivity1D = suggestSampleDist / _typicalPointDistance;
|
|
double sampleSelectivity2D = sampleSelectivity1D * sampleSelectivity1D;
|
|
// this leads to the sample size which, of course, must be somehow bounded
|
|
_sampleSize = (size_t)(pointCount / sampleSelectivity2D);
|
|
_sampleSize = MAX(_sampleSize, 1000); // 1K
|
|
_sampleSize = MIN(_sampleSize, 1000000); // 1M
|
|
_sampleSize = MIN(_sampleSize, size_t(pointCount));
|
|
// now we calculate the above values again with the actual sample size
|
|
sampleSelectivity2D = pointCount / static_cast<double>(_sampleSize);
|
|
sampleSelectivity1D = std::sqrt(sampleSelectivity2D);
|
|
_typicalSampleDistance = _typicalPointDistance * sampleSelectivity1D;
|
|
|
|
|
|
// 2. neighborhoods for dual point calculation
|
|
// -------------------------------------------
|
|
double NEIGHBORS_PER_DIMENSION = std::sqrt(neighborhoodSize);
|
|
// with _neighborhoodDiameter = 10.0 * _typicalSampleDistance, an equal
|
|
// distribution of sample points along the XY plane would result
|
|
// in neighborhoods that contain approx. 100 sample points.
|
|
_neighborhoodDiameter = NEIGHBORS_PER_DIMENSION * _typicalSampleDistance;
|
|
// if the points of an object have _typicalSampleDistance, even a
|
|
// neighborhood at the corner of an object should usually contain 20+
|
|
// points.
|
|
_neighborhoodSizeMin = 16; // points
|
|
// since we assume that even for small objects, we have 100 sample points,
|
|
// it is enough to create 1 dual point from each sample point (in
|
|
// combination with a number of random points from its neighborhood as
|
|
// required by the respective geometric primitive)
|
|
_dualPointsPerSamplePoint = 1;
|
|
|
|
|
|
// 3. DBSCAN in dual space
|
|
// -----------------------
|
|
// the creation of dual points is performed by the geometric primitives
|
|
// in a way that tries to maintain the meaning of a "typical point
|
|
// distance" (e.g. we do not use angles in dual space)
|
|
// therefore, we can use multiples of point distances for the epsilon
|
|
// value. Note that *point* distance rather than *sample* distance
|
|
// should be used here since the proximity of the dual points does not
|
|
// depend on the size of our sample, but rather on the precision of
|
|
// the point data (diffusion)
|
|
_dualScanEps = 1.0 * _typicalPointDistance; // not sample dist here!
|
|
// points in dual space will often have 6, 8, or 10 neighbors, so for
|
|
// dual point clusters that belong to an actual shape, 4 should be
|
|
// easy to fulfill.
|
|
_dualScanMinPts = 4;
|
|
// clusters in dual space are recursively refined by reducing _dualScanEps
|
|
// until a cluster's bbox is small enough (in each dimension):
|
|
_dualScanMaxBboxExtent = 8.0 * _dualScanEps;
|
|
// even for small objects with just 100 sample points, a lot of points
|
|
// should be inside the cluster (unless diffusion is very high)
|
|
_dualScanRequiredClusterSize = 20; // points
|
|
|
|
|
|
// 4. Matching shapes to objects in point data
|
|
// --------------------------------------------
|
|
// at this point, our sample is irrelevant since now we are working
|
|
// with the complete point data. We tolerate some diffusion (also bearing
|
|
// in mind that because of diffusion, the shapes obtained above are
|
|
// probably not a perfect match) // not sample dist here!
|
|
_matchTolerance = roughDiffusion * _typicalPointDistance;
|
|
// for all points that could potentially belong to a given shape,
|
|
// another DBSCAN is performed to keep only clusters of actual points.
|
|
// For _matchScanEps, often 1.4 or 1.5 is enough, depending on the
|
|
// "soft diffusion", i.e. how far points deviate from a regular grid
|
|
_matchScanEps = (1.4 + softDiffusion) * _typicalPointDistance;
|
|
_matchScanMinPts = 4; // or 3 (but not 2, otherwise mere intersection
|
|
// lines will be regarded as a shape)
|
|
_matchScanRequiredCohesion = 100; // 100 neighborhood relationships
|
|
// _matchScanRequiredClusterSize = 16;
|
|
}
|