#include "onf_stepfiltermaximabyneighbourhood02.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/core/core.hpp"
ONF_StepFilterMaximaByNeighbourhood02::ONF_StepFilterMaximaByNeighbourhood02() : SuperClass()
{
_scoreThreshold = 0.5;
_minRadius = 1.5;
_maxRadius = 10.0;
}
QString ONF_StepFilterMaximaByNeighbourhood02::description() const
{
return tr("Filtrer les maxima par voisinage");
}
QString ONF_StepFilterMaximaByNeighbourhood02::detailledDescription() const
{
return tr("");
}
QString ONF_StepFilterMaximaByNeighbourhood02::inputDescription() const
{
return SuperClass::inputDescription() + tr("
");
}
QString ONF_StepFilterMaximaByNeighbourhood02::outputDescription() const
{
return SuperClass::outputDescription() + tr("
");
}
QString ONF_StepFilterMaximaByNeighbourhood02::detailsDescription() const
{
return tr("");
}
QString ONF_StepFilterMaximaByNeighbourhood02::URL() const
{
//return tr("STEP URL HERE");
return SuperClass::URL(); //by default URL of the plugin
}
CT_VirtualAbstractStep* ONF_StepFilterMaximaByNeighbourhood02::createNewInstance() const
{
return new ONF_StepFilterMaximaByNeighbourhood02();
}
//////////////////// PROTECTED METHODS //////////////////
void ONF_StepFilterMaximaByNeighbourhood02::declareInputModels(CT_StepInModelStructureManager& manager)
{
manager.addResult(_inResult, tr("MNS et Maxima"));
manager.setZeroOrMoreRootGroup(_inResult, _inZeroOrMoreRootGroup);
manager.addGroup(_inZeroOrMoreRootGroup, _inGroup);
manager.addItem(_inGroup, _inImage, tr("MNS"));
manager.addItem(_inGroup, _inMaxima, tr("Maxima"));
manager.addResult(_inResultDTM, tr("MNT"), "", true);
manager.setZeroOrMoreRootGroup(_inResultDTM, _inZeroOrMoreRootGroupDTM);
manager.addGroup(_inZeroOrMoreRootGroupDTM, _inGroupDTM);
manager.addItem(_inGroupDTM, _inDTM, tr("MNT"));
}
void ONF_StepFilterMaximaByNeighbourhood02::declareOutputModels(CT_StepOutModelStructureManager& manager)
{
manager.addResultCopy(_inResult);
manager.addItem(_inGroup, _filteredMaxima, tr("Maxima filtrés"));
}
void ONF_StepFilterMaximaByNeighbourhood02::fillPostInputConfigurationDialog(CT_StepConfigurableDialog* postInputConfigDialog)
{
postInputConfigDialog->addDouble(tr("Seuil de profondeur pour regrouper deux houppiers"), "m", 0, 10, 2, _scoreThreshold);
postInputConfigDialog->addDouble(tr("Rayon de houppier minimal"), "m", 0, 1000, 2, _minRadius);
postInputConfigDialog->addDouble(tr("Rayon de houppier maximal"), "m", 0, 1000, 2, _maxRadius);
}
void ONF_StepFilterMaximaByNeighbourhood02::compute()
{
const CT_Image2D* mnt = nullptr;
for (const CT_Image2D* constMnt : _inDTM.iterateInputs(_inResultDTM))
{
mnt = constMnt;
}
for (CT_StandardItemGroup* grp : _inGroup.iterateOutputs(_inResult))
{
if (isStopped()) {return;}
const CT_Image2D* imageIn = grp->singularItem(_inImage);
CT_Image2D* maximaIn = const_cast*>(grp->singularItem(_inMaxima));
if (maximaIn != nullptr && imageIn != nullptr)
{
Eigen::Vector2d min;
maximaIn->getMinCoordinates(min);
CT_Image2D* filteredMaxima = new CT_Image2D(min(0), min(1), maximaIn->xdim(), maximaIn->ydim(), maximaIn->resolution(), maximaIn->level(), maximaIn->NA(), 0);
grp->addSingularItem(_filteredMaxima, filteredMaxima);
filteredMaxima->getMat().release();
filteredMaxima->getMat() = maximaIn->getMat().clone();
setProgress(20);
// Get maxima coordinates list
QMultiMap maximaCoords;
QMultiMap maximaHeights;
for (int xx = 0 ; xx < maximaIn->xdim() ; xx++)
{
for (int yy = 0 ; yy < maximaIn->ydim() ; yy++)
{
qint32 maximaID = maximaIn->value(xx, yy);
if (maximaID > 0 && maximaID != maximaIn->NA())
{
Eigen::Vector3d* coords = new Eigen::Vector3d();
if (maximaIn->getCellCenterCoordinates(xx, yy, *coords))
{
(*coords)(2) = double(imageIn->value(xx, yy));
double h = (*coords)(2);
if (mnt != nullptr)
{
float zmnt = mnt->valueAtCoords((*coords)(0), (*coords)(1));
if (!qFuzzyCompare(zmnt, mnt->NA()))
{
h -= double(zmnt);
}
}
maximaCoords.insert(maximaID, coords);
maximaHeights.insert(h, maximaID);
}
}
}
}
setProgress(25);
// Compute ordered vector of maxima ids
QList validMaxima;
QMapIterator itH(maximaHeights);
itH.toBack();
while (itH.hasPrevious())
{
itH.previous();
qint32 cl = itH.value();
if (!validMaxima.contains(cl)) {validMaxima.append(cl);}
}
QVector orderedMaxima = validMaxima.toVector();
int mxSize = orderedMaxima.size();
validMaxima.clear();
CT_Grid3D_Points* optimGrid = new CT_Grid3D_Points(maximaIn->minX(), maximaIn->minY(), 0 - _maxRadius / 10.0, maximaIn->xdim(), maximaIn->ydim(), 1, _maxRadius/2.0);
// Create maxima coords vector
QVector coords(mxSize);
for (int i = 0 ; i < mxSize ; i++)
{
qint32 id = orderedMaxima.at(i);
QList coordinates = maximaCoords.values(id);
coords[i] = *(coordinates.at(0));
// Compute position of the current maxima if more than one pixel
int size = coordinates.size();
if (size > 1)
{
for (int j = 1 ; j < size ; j++)
{
Eigen::Vector3d* pos = coordinates.at(j);
coords[i](0) += (*pos)(0);
coords[i](1) += (*pos)(1);
if ((*pos)(2) > coords[i](2)) {coords[i](2) = (*pos)(2);}
}
coords[i](0) /= size;
coords[i](1) /= size;
}
size_t cellIndex = 0;
optimGrid->indexAtXYZ(coords[i](0), coords[i](1), 0, cellIndex);
optimGrid->addPointAtIndex(cellIndex, size_t(i));
}
setProgress(30);
for (int i = 0 ; i < mxSize ; i++)
{
qint32 id = orderedMaxima.at(i);
if (id > 0)
{
size_t cellIndex = 0;
optimGrid->indexAtXYZ(coords[i](0), coords[i](1), 0, cellIndex);
QList maximaToTriangulate;
optimGrid->getPointsInCellsIntersectingSphere(cellIndex, _maxRadius*2.0, &maximaToTriangulate);
if (maximaToTriangulate.size() > 0)
{
bool modified = true;
while (modified)
{
modified = false;
// Compute triangulation
CT_DelaunayTriangulation *delaunay = new CT_DelaunayTriangulation();
delaunay->init(maximaIn->minX(), maximaIn->minY(), maximaIn->maxX(), maximaIn->maxY());
CT_DelaunayVertex* baseVertex = delaunay->addVertex(new Eigen::Vector3d(coords[i](0), coords[i](1), i), true);
for (int j = 0 ; j < maximaToTriangulate.size() ; j++)
{
int idx = int(maximaToTriangulate.at(j));
qint32 id2 = orderedMaxima.at(idx);
if (idx != i && id2 > 0)
{
delaunay->addVertex(new Eigen::Vector3d(coords[idx](0), coords[idx](1), idx), true);
}
}
delaunay->doInsertion();
delaunay->computeVerticesNeighbors();
QList &neighbours = baseVertex->getNeighbors();
for (int j = 0 ; j < neighbours.size() ; j++)
{
CT_DelaunayVertex* neighbour = neighbours.at(j);
double score = computeScore(imageIn, baseVertex, neighbour);
if (score < _scoreThreshold)
{
orderedMaxima[qint32((*(neighbour->getData()))(2))] = 0;
modified = true;
}
}
delete delaunay;
}
}
}
}
setProgress(60);
for (int i = 0 ; i < mxSize ; i++)
{
qint32 cl = orderedMaxima.at(i);
if (cl > 0) {validMaxima.append(cl);}
}
setProgress(70);
QMap newIds;
qint32 cpt = 1;
// effectively delete toRemove maximum and numbers them in a continuous way
for (int xx = 0 ; xx < filteredMaxima->xdim() ; xx++)
{
for (int yy = 0 ; yy < filteredMaxima->ydim() ; yy++)
{
qint32 maximaID = filteredMaxima->value(xx, yy);
if (maximaID > 0)
{
if (validMaxima.contains(maximaID))
{
qint32 newId = newIds.value(maximaID, 0);
if (newId == 0)
{
newId = cpt++;
newIds.insert(maximaID, newId);
}
filteredMaxima->setValue(xx, yy, newId);
} else {
filteredMaxima->setValue(xx, yy, 0);
}
}
}
}
newIds.clear();
setProgress(90);
filteredMaxima->computeMinMax();
qDeleteAll(maximaCoords.values());
setProgress(99);
}
}
setProgress(100);
}
double ONF_StepFilterMaximaByNeighbourhood02::computeScore(const CT_Image2D* heightImage, CT_DelaunayVertex* baseVertex, CT_DelaunayVertex* neighbourVertex)
{
Eigen::Vector3d baseCoord3D = *(baseVertex->getData());
Eigen::Vector3d neighbCoord3D = *(neighbourVertex->getData());
baseCoord3D(2) = double(heightImage->valueAtCoords(baseCoord3D(0), baseCoord3D(1)));
neighbCoord3D(2) = double(heightImage->valueAtCoords(neighbCoord3D(0), neighbCoord3D(1)));
if (neighbCoord3D(2) > baseCoord3D(2)) {return std::numeric_limits::max();}
Eigen::Vector2d baseCoord(baseCoord3D(0), baseCoord3D(1));
Eigen::Vector2d neighbCoord(neighbCoord3D(0), neighbCoord3D(1));
double dist = sqrt(pow(baseCoord(0) - neighbCoord(0), 2) + pow(baseCoord(1) - neighbCoord(1), 2));
if (dist <= _minRadius) {return 0;}
if (dist >= _maxRadius) {return std::numeric_limits::max();}
double dist3D = sqrt(pow(baseCoord3D(0) - neighbCoord3D(0), 2) + pow(baseCoord3D(1) - neighbCoord3D(1), 2) + pow(baseCoord3D(2) - neighbCoord3D(2), 2));
Eigen::Vector3d dir = neighbCoord3D - baseCoord3D;
double offset = 1 / (dist3D / (heightImage->resolution() / 10.0));
double deltaHMax = 0;
for (double l = 0 ; l < 1 ; l += offset)
{
Eigen::Vector3d pos = baseCoord3D + dir*l;
float h = heightImage->valueAtCoords(pos(0), pos(1));
if (!qFuzzyCompare(h, heightImage->NA()))
{
double deltaH = pos(2) - double(h);
if (deltaH > deltaHMax) {deltaHMax = deltaH;}
}
}
return deltaHMax;
}