521 lines
13 KiB
C++
521 lines
13 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
|
|
|
|
|
|
|
|
1 The Pointcloud2 AnalyzeRaster Operator
|
|
analyzeRaster: pointcloud2(R,tuple(Z1...Zn))
|
|
-> pointcloud2(R,tuple(Z1...Zn,ObjID:int,CatID:int))
|
|
use only with metric pointClouds
|
|
if non metric use project operator to transfer to UTM
|
|
Parameters:
|
|
|
|
* CELL\_SIZE\_IN\_M 0.15; min: 0.01 max: 100.0
|
|
|
|
* DELTA\_ALT\_IN\_M 5.0; min: 0.0 max: 100.0
|
|
|
|
* NEIGHBOUR\_CELLS false; true 8 cells, false only 4
|
|
|
|
* THRESHOLD\_MERGE 0.5; min: 0.0, no limits
|
|
|
|
* DISTANCE\_SIG\_MAXIMA 0.1; min: 0.0, no limits
|
|
|
|
* OVERLAP\_RASTERS 0.1; min: 0.0% max: 50.0%
|
|
|
|
* MIN\_GROUND\_CELLS 100; min: 1 no limits
|
|
|
|
* MAX\_CELLS\_AT\_EDGE 3
|
|
|
|
* RASTER\_CLASSIFY\_EPSILON 1.0
|
|
|
|
* RASTER\_CLASSIFY\_MINPTS 3
|
|
|
|
*/
|
|
#pragma once
|
|
#include <unordered_map>
|
|
#include "Operator.h"
|
|
#include "StandardTypes.h"
|
|
|
|
#include "../tcPointcloud2.h"
|
|
|
|
namespace pointcloud2
|
|
{
|
|
|
|
namespace analyzeRasterConstants
|
|
{
|
|
/*
|
|
CONSTANTS
|
|
*/
|
|
const size_t MIN_NEIGBOR_LOC_MAX = 3;
|
|
//factor for comparing locale maximum and object to ignore maximum
|
|
const double LOC_MAX_NEARLY_OBJ = 0.8;
|
|
|
|
} // namespace analyzeRasterConstants
|
|
|
|
|
|
//one raster cell
|
|
struct RasterPoint
|
|
{
|
|
int objectID = 0;
|
|
int classID = 0;
|
|
int count = 0;
|
|
double minAlt = 0.0;
|
|
double maxAlt = 0.0;
|
|
double averageAlt = 0.0;
|
|
int averageIntensity = 0.0;
|
|
bool initialized = true;
|
|
};
|
|
|
|
//one raster cell in SMI file
|
|
struct RasterPointDB
|
|
{
|
|
CcInt objectID;
|
|
CcInt classID;
|
|
CcInt count;
|
|
CcReal minAlt;
|
|
CcReal maxAlt;
|
|
CcReal averageAlt;
|
|
CcInt averageIntensity;
|
|
CcBool initialized;
|
|
};
|
|
|
|
//one raster cell for save
|
|
struct RasterPointSave
|
|
{
|
|
|
|
int objectID;
|
|
int classID;
|
|
};
|
|
|
|
//one raster cell in SMI file for save
|
|
struct RasterPointDBSave
|
|
{
|
|
CcInt objectID;
|
|
CcInt classID;
|
|
};
|
|
|
|
|
|
|
|
class op_analyzeRaster
|
|
{
|
|
/*
|
|
PRIVATE MEMBERS
|
|
*/
|
|
Pointcloud2* _pc2 = nullptr;
|
|
Rect3 _bb;
|
|
size_t _maxMemory;
|
|
size_t _pointInMem, _pointInMem2;
|
|
size_t _posNewAttributes;
|
|
size_t _posIntensity;
|
|
unsigned _sizeRaster;
|
|
unsigned _sizeRasterOverlap;
|
|
ListExpr _resultType;
|
|
std::vector<int> _neighborD;
|
|
std::vector<int> _neighbor;
|
|
|
|
/*
|
|
ALGEBRA METHODS
|
|
*/
|
|
static ListExpr analyzeRasterTM(ListExpr args);
|
|
|
|
static int analyzeRasterVM(Word *args, Word &result, int message,
|
|
Word &local, Supplier s);
|
|
|
|
std::string getOperatorSpec();
|
|
|
|
/*
|
|
PRIVATE METHODS
|
|
*/
|
|
|
|
/*
|
|
euclidian distance
|
|
*/
|
|
inline double distance_m(double x1, double y1, double x2, double y2) const
|
|
{
|
|
//EUCLID
|
|
return std::sqrt(std::pow((x1 - x2), 2) + std::pow((y1 - y2), 2));
|
|
}
|
|
|
|
|
|
/*
|
|
calculate Bbox of memory part
|
|
*/
|
|
std::unique_ptr<Pointcloud2, std::function<void(Pointcloud2*)>>
|
|
calculateRasterRartition(double x, double y) const;
|
|
|
|
/*
|
|
calculate Pc2 partition
|
|
*/
|
|
std::unique_ptr<Pointcloud2, std::function<void(Pointcloud2*)>>
|
|
calculateRasterRartition(Rect3 bboxRaster) const;
|
|
|
|
/*
|
|
calculate raster points and attributes for memory structure
|
|
*/
|
|
std::vector<RasterPoint>
|
|
fillrastermem(Pointcloud2& pc2RasterPart, double x, double y) const;
|
|
|
|
|
|
/*
|
|
raster points from intern to secondo format
|
|
*/
|
|
RasterPointDB
|
|
structToSecondo(RasterPoint grid) const;
|
|
|
|
|
|
// /*
|
|
// raster points from secondo to intern format
|
|
// */
|
|
// RasterPoint
|
|
// secondoToStruct(RasterPointDB bufferDB) const;
|
|
|
|
/*
|
|
raster points from secondo to intern format
|
|
only ObjectID and ClassID
|
|
*/
|
|
RasterPointSave
|
|
secondoToStructSave(RasterPointDBSave bufferDB) const;
|
|
|
|
/*
|
|
*calculate objects by flooding
|
|
*calculate local maxima
|
|
*calculate significant maxima
|
|
*split objects
|
|
*/
|
|
int
|
|
flooding(std::vector<RasterPoint>& rasterMem, int areaNumber,
|
|
const Rect3 rasterBbox) const;
|
|
|
|
/**
|
|
*calculate local maxima in one object
|
|
*/
|
|
int
|
|
calcLocMax(std::vector<RasterPoint>& rasterMem,
|
|
int areaNumber, Rect bboxObj) const;
|
|
|
|
/**
|
|
*merge local maxima to significant maxima
|
|
*/
|
|
void
|
|
calcEdgeForMerge(std::vector<RasterPoint>& rasterMem,
|
|
int areaNumber, Rect bboxObj) const;
|
|
|
|
/**
|
|
*split objects by significant maxima
|
|
*/
|
|
void
|
|
splitObjects(std::vector<RasterPoint>& rasterMem,
|
|
int areaNumber, Rect bboxObj) const;
|
|
|
|
/*
|
|
*test if between count and other locale maximum lower minimum
|
|
*true if found
|
|
*/
|
|
bool
|
|
testForOtherMin(std::vector<RasterPoint>& rasterMem,
|
|
size_t arrayCount, int neighbor, int areaNumber) const;
|
|
|
|
/*
|
|
*recalculate bbox for objects by newly discoverd points
|
|
*/
|
|
void recalcBbox(Rect& bboxObj, size_t nF) const;
|
|
|
|
|
|
/**
|
|
*overwrite with other areaNumber
|
|
*/
|
|
void
|
|
deleteAreaNumber(std::vector<RasterPoint>& rasterMem,
|
|
int areaNumber, Rect bboxLoc, int areaNumberOld) const;
|
|
|
|
|
|
/**
|
|
*put neighbor cells in stack for flooding
|
|
*/
|
|
void checkNeighbors(std::stack<size_t> &s,
|
|
std::vector<RasterPoint>& rasterMem,
|
|
std::vector<int> neighbor,
|
|
size_t nF, bool& ground, size_t& edge) const;
|
|
|
|
/*
|
|
*neighbor check for flooding to find local maxima
|
|
*definition: is part of object and all cells have same height roughly
|
|
*is higher than all neighbor cells (min 2*THRESHOLD_MERGE)
|
|
*has minimum of three neighbor cells
|
|
*/
|
|
void checkNeighborsMaximum(std::stack<size_t>& s,
|
|
std::vector<RasterPoint>& rasterMem,
|
|
std::vector<int> neighbor, size_t nF, bool& found, size_t& edge,
|
|
int const areaNumber) const;
|
|
|
|
/*
|
|
*merge local maxima
|
|
*/
|
|
void mergeLocMax(std::vector<RasterPoint>& rasterMem,
|
|
size_t const arrayCount, int const areaNumber) const;
|
|
|
|
/**
|
|
*compute merge with Horn algorithm for circle(r)
|
|
*/
|
|
bool calcNearLocMaxByHorn(std::vector<RasterPoint>& rasterMem,
|
|
size_t const arrayCount, int const areaNumber,
|
|
std::vector<std::pair <size_t,size_t>>& newLocMax) const;
|
|
|
|
/*
|
|
*fill vector with local maxima as preparation of calculating convex hull
|
|
*/
|
|
std::vector<std::pair <size_t,size_t>>
|
|
fillVectorWithLocMax(std::vector<RasterPoint>& rasterMem,
|
|
size_t const arrayCount) const;
|
|
|
|
/*
|
|
* add local maximum to be merged to vector
|
|
*/
|
|
void
|
|
fillVectorWithOtherLocMax(std::vector<RasterPoint>& rasterMem,
|
|
const size_t arrayCount, const int areaNumberLocMax,
|
|
std::vector<std::pair <size_t,size_t>>& newLocMax) const;
|
|
|
|
/**
|
|
*calculate convex hull by Gift-Wrapping algorithm
|
|
*/
|
|
std::vector<std::pair <size_t,size_t>>
|
|
calcConvexHull(std::vector<std::pair <size_t,size_t>> newLocMax) const;
|
|
|
|
/*
|
|
*fill convex hull to compute significant maximum by edge list algorithm
|
|
*/
|
|
void
|
|
fillConvexHull(std::vector<RasterPoint>& rasterMem,
|
|
std::vector<std::pair <size_t,size_t>> hullLocMax,
|
|
const int areaNumberLocMax) const;
|
|
|
|
int distanceComp(std::pair <size_t,size_t> a,
|
|
std::pair <size_t,size_t> b,
|
|
std::pair <size_t,size_t> c) const;
|
|
|
|
/*
|
|
*test for new local maximum in distance of central local maxima
|
|
*/
|
|
void testOtherLocMax(std::vector<RasterPoint>& rasterMem,
|
|
size_t const xMin, size_t const xMax, size_t const y,
|
|
const int areaNumberObj, const int areaNumberLocMax,
|
|
bool& countLocMax,
|
|
std::vector<std::pair <size_t,size_t>>& newLocMax) const;
|
|
|
|
|
|
/*
|
|
*calculating points in edge line of convex hull
|
|
*ignores horizontal lines
|
|
*/
|
|
bool computeEdgeLine(std::vector<std::pair <size_t,size_t>> &edgeList,
|
|
const std::pair<size_t, size_t> a,
|
|
const std::pair<size_t, size_t> b) const;
|
|
|
|
|
|
/*
|
|
*write back raster to pointcloud2
|
|
*/
|
|
void saveRasterToPc2(std::vector<SmiFileId>& rasters,
|
|
std::vector<Rect3> rastersBbox,
|
|
std::shared_ptr<std::unordered_map<int,size_t>> classMap,
|
|
std::shared_ptr<std::unordered_map<int,int>> duples,
|
|
Pointcloud2* res) const;
|
|
|
|
/*
|
|
*write points
|
|
*/
|
|
void savePoint(Pointcloud2* res,
|
|
const Pointcloud2& rasterPart,
|
|
const Rect3 rasterBbox,
|
|
const SmiRecord& record,
|
|
PcPoint& pcPoint,
|
|
std::vector<RasterPointSave> const &rasterMem,
|
|
std::shared_ptr<std::unordered_map<int,size_t>> classMap) const;
|
|
|
|
/*
|
|
*erase double objects in overlappings
|
|
*/
|
|
void recalcOverlapping(std::vector<RasterPointSave> &rasterMem,
|
|
const Rect3 rasterBbox, const size_t i,
|
|
const std::shared_ptr<std::unordered_map<int,int>> duples,
|
|
std::vector <RasterPointSave> &rasterOverlapH,
|
|
std::vector<std::vector<RasterPointSave>> &rasterOverlapUnder,
|
|
std::vector<std::vector<RasterPointSave>> &rasterOverlapUnderEdge,
|
|
std::vector<std::vector<RasterPointSave>> &rasterOverlapOver,
|
|
std::vector<std::vector<RasterPointSave>> &rasterOverlapOverEdge) const;
|
|
|
|
public:
|
|
|
|
explicit op_analyzeRaster() = default;
|
|
|
|
op_analyzeRaster(Pointcloud2 *pc2,
|
|
size_t maxMemory,
|
|
size_t pos,
|
|
size_t posIntensity,
|
|
const ListExpr resultType
|
|
)
|
|
: _pc2(pc2),
|
|
_maxMemory(maxMemory),
|
|
_posNewAttributes(pos),
|
|
_posIntensity(posIntensity),
|
|
_resultType(resultType)
|
|
{
|
|
_bb = _pc2->getBoundingBox();
|
|
|
|
//use 3/4 of memory for raster partition
|
|
_pointInMem = sqrt(0.7 * _maxMemory / sizeof(RasterPoint));
|
|
_pointInMem2 = pow(_pointInMem, 2);
|
|
_sizeRaster = ceil(_pointInMem * Pointcloud2::CELL_SIZE_IN_M);
|
|
_sizeRasterOverlap = ceil((1.0 - Pointcloud2::OVERLAP_RASTERS) *
|
|
(double)_pointInMem * Pointcloud2::CELL_SIZE_IN_M);
|
|
//vectors for neighbor search
|
|
_neighborD = {
|
|
(int)_pointInMem - 1,
|
|
(int)_pointInMem + 1
|
|
- (int)_pointInMem +1,
|
|
- (int)_pointInMem - 1,
|
|
};
|
|
|
|
_neighbor = {
|
|
-1,
|
|
(int)_pointInMem,
|
|
1,
|
|
- (int)_pointInMem
|
|
};
|
|
|
|
}
|
|
|
|
~op_analyzeRaster() = default;
|
|
|
|
std::shared_ptr<Operator> getOperator();
|
|
|
|
size_t getPointInMem() const { return _pointInMem; };
|
|
size_t getPointInMem2() const { return _pointInMem2; };
|
|
size_t getPositionNewAttributes() const { return _posNewAttributes; };
|
|
unsigned getSizeRaster() const { return _sizeRaster; };
|
|
unsigned getSizeRasterOverlap() const { return _sizeRasterOverlap; };
|
|
|
|
void setPointInMem(size_t pointInMem) {
|
|
_pointInMem = pointInMem;
|
|
_pointInMem2 = pow(_pointInMem, 2);
|
|
};
|
|
void setSizeRaster(unsigned sizeRaster) { _sizeRaster = sizeRaster; };
|
|
void setSizeRasterOverlap(unsigned sizeRasterOverlap) {
|
|
_sizeRasterOverlap = sizeRasterOverlap;
|
|
};
|
|
void setNeighbor(){
|
|
_neighbor = {
|
|
-1,
|
|
(int)_pointInMem,
|
|
1,
|
|
-(int)_pointInMem
|
|
};
|
|
};
|
|
void setNeighborD(){
|
|
_neighborD = {
|
|
- (int)_pointInMem - 1,
|
|
(int)_pointInMem - 1,
|
|
(int)_pointInMem + 1,
|
|
- (int)_pointInMem + 1
|
|
};
|
|
};
|
|
|
|
static RasterPoint
|
|
secondoToStruct(RasterPointDB bufferDB);
|
|
/**
|
|
*calculate objects:
|
|
*fill raster
|
|
*compute objects
|
|
*find local maxima, combine them to significant maxima
|
|
*and split object by significant maxima
|
|
*/
|
|
void
|
|
calculateObjects(std::vector<SmiFileId>& rasters,
|
|
std::vector<Rect3>& rastersBbox) const;
|
|
|
|
/**
|
|
*
|
|
*/
|
|
inline std::tuple<double, double> getRasterSize() const
|
|
{
|
|
double x1 = _bb.MinD(0);
|
|
double y1 = _bb.MinD(1);
|
|
double x2 = _bb.MaxD(0);
|
|
double y2 = _bb.MaxD(1);
|
|
double distX = distance_m(x1, y1, x2, y1);
|
|
double distY = distance_m(x1, y1, x1, y2);
|
|
|
|
return std::tuple<double, double>(distX, distY);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
inline std::tuple<double, double> getXDimension() const
|
|
{
|
|
return std::tuple<double, double>(_bb.MinD(0), _bb.MaxD(0));
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
inline std::tuple<double, double> getYDimension() const
|
|
{
|
|
return std::tuple<double, double>(_bb.MinD(1), _bb.MaxD(1));
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
inline double GRID_PER_M2 () const
|
|
{
|
|
return 1.0 / pow(Pointcloud2::CELL_SIZE_IN_M, 2);
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
inline unsigned getMemoryUsageOfRaster(
|
|
const std::tuple<double, double> &rasterSize) const
|
|
{
|
|
double rasterX, rasterY;
|
|
std::tie(rasterX, rasterY) = rasterSize;
|
|
return ceil(rasterX *
|
|
rasterY *
|
|
GRID_PER_M2() *
|
|
sizeof(RasterPoint));
|
|
}
|
|
|
|
};
|
|
} // namespace pointcloud2
|