/**************************************************************************** Copyright (C) 2010-2012 the Office National des Forêts (ONF), France All rights reserved. Contact : alexandre.piboule@onf.fr Developers : Alexandre PIBOULE (ONF) This file is part of PluginONF library. PluginONF is free library: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PluginONF 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 Lesser General Public License along with PluginONF. If not, see . *****************************************************************************/ #include "onf_stepsegmentfromseedgrid.h" #include ONF_StepSegmentFromSeedGrid::ONF_StepSegmentFromSeedGrid() : SuperClass() { _maxDistZ = 1.5; _maxDistXY = 0.5; _downward = false; } QString ONF_StepSegmentFromSeedGrid::description() const { // Gives the descrption to print in the GUI return tr("Segment using seed voxel grid"); } QString ONF_StepSegmentFromSeedGrid::detailledDescription() const { return tr(""); } QString ONF_StepSegmentFromSeedGrid::inputDescription() const { return SuperClass::inputDescription() + tr("

"); } QString ONF_StepSegmentFromSeedGrid::outputDescription() const { return SuperClass::outputDescription() + tr("

"); } QString ONF_StepSegmentFromSeedGrid::detailsDescription() const { return tr(""); } CT_VirtualAbstractStep* ONF_StepSegmentFromSeedGrid::createNewInstance() const { // Creates an instance of this step return new ONF_StepSegmentFromSeedGrid(); } void ONF_StepSegmentFromSeedGrid::declareInputModels(CT_StepInModelStructureManager& manager) { manager.addResult(_inResult, tr("Grilles"), "", true); manager.setZeroOrMoreRootGroup(_inResult, _inZeroOrMoreRootGroup); manager.addGroup(_inZeroOrMoreRootGroup, _inGroup); manager.addItem(_inGroup, _inGridPoints, tr("Grille de points")); manager.addItem(_inGroup, _inGridSeeds, tr("Grille de graines")); manager.addResult(_inResultPriority, tr("Priorités"), "", true); manager.setZeroOrMoreRootGroup(_inResultPriority, _inZeroOrMoreRootGroupPriority); manager.addItem(_inZeroOrMoreRootGroupPriority, _inItemPriority, tr("Item")); manager.addItemAttribute(_inItemPriority, _inAttID, CT_AbstractCategory::DATA_ID, tr("ID")); manager.addItemAttribute(_inItemPriority, _inAttPriority, CT_AbstractCategory::DATA_VALUE, tr("Priorité")); } void ONF_StepSegmentFromSeedGrid::declareOutputModels(CT_StepOutModelStructureManager& manager) { manager.addResultCopy(_inResult); manager.addItem(_inGroup, _outSegmentationGrid, tr("Segmentation")); manager.addItem(_inGroup, _outTopologyGrid, tr("Topologie")); manager.addItem(_inGroup, _outReverseTopologyGrid, tr("Topologie inverse")); } void ONF_StepSegmentFromSeedGrid::fillPostInputConfigurationDialog(CT_StepConfigurableDialog* postInputConfigDialog) { postInputConfigDialog->addDouble(tr("Distance de recherche maximale en Z"), "m", 0, std::numeric_limits::max(), 2, _maxDistZ); postInputConfigDialog->addDouble(tr("Distance de recherche maximale en XY"), "m", 0, std::numeric_limits::max(), 2, _maxDistXY); postInputConfigDialog->addBool(tr("Activer recherche descendante"), "", "", _downward); } void ONF_StepSegmentFromSeedGrid::compute() { size_t NAval = std::numeric_limits::max(); QMap priorities; for (const CT_AbstractSingularItemDrawable* item : _inItemPriority.iterateInputs(_inResultPriority)) { const CT_AbstractItemAttribute* attID = item->itemAttribute(_inAttID); int id = 0; if (attID != nullptr) { id = attID->toInt(item, nullptr); } else { qDebug() << "Attribut ID non trouvé !!!"; } const CT_AbstractItemAttribute* att = item->itemAttribute(_inAttPriority); double priority = 0; if (att != nullptr) { priority = att->toDouble(item, nullptr); } else { qDebug() << "Attribut priority non trouvé !!!"; } if (attID != nullptr && att != nullptr) { priorities.insert(id, priority); } } for (CT_StandardItemGroup* group : _inGroup.iterateOutputs(_inResult)) { if (isStopped()) {return;} const CT_Grid3D_Points* pointGrid = group->singularItem(_inGridPoints); const CT_Grid3D_Sparse* seedGrid = group->singularItem(_inGridSeeds); if (pointGrid != nullptr && seedGrid != nullptr) { // Declaring the output grids CT_Grid3D_Sparse* outSegmentationGrid = new CT_Grid3D_Sparse(pointGrid->minX(), pointGrid->minY(), pointGrid->minZ(), pointGrid->xdim(), pointGrid->ydim(), pointGrid->zdim(), pointGrid->resolution(), -1, -1); CT_Grid3D_Sparse* outTopologyGrid = new CT_Grid3D_Sparse(pointGrid->minX(), pointGrid->minY(), pointGrid->minZ(), pointGrid->xdim(), pointGrid->ydim(), pointGrid->zdim(), pointGrid->resolution(), NAval, NAval); CT_Grid3D_Points* outReverseTopologyGrid = new CT_Grid3D_Points(pointGrid->minX(), pointGrid->minY(), pointGrid->minZ(), pointGrid->xdim(), pointGrid->ydim(), pointGrid->zdim(), pointGrid->resolution()); QList list; seedGrid->getIndicesWithData(list); for (int i = 0 ; i < list.size() ; i++) { size_t index = list.at(i); outSegmentationGrid->setValueAtIndex(index, seedGrid->valueAtIndex(index)); } //setProgress(5.0); QList filledCells; pointGrid->getIndicesWithPoints(filledCells); int size = filledCells.size(); for (int i = 0 ; i < size ; i++) { if (outTopologyGrid->valueAtIndex(filledCells.at(i)) == NAval) { findParentCell(outSegmentationGrid, outTopologyGrid, priorities, filledCells.at(i), true); } //setProgress(5.0f + 64.0f*(float(i) / float(size))); } for (int i = filledCells.size() - 1 ; _downward && i >= 0 ; i--) { if (outTopologyGrid->valueAtIndex(filledCells.at(i)) == NAval) { findParentCell(outSegmentationGrid, outTopologyGrid, priorities, filledCells.at(i), false); } //setProgress(70.0f + 19.0f*(float(size - i) / float(size))); } outSegmentationGrid->computeMinMax(); outTopologyGrid->computeMinMax(); for (int i = 0 ; i < size ; i++) { size_t index = filledCells.at(i); size_t value = outTopologyGrid->valueAtIndex(index); if (value != NAval) { outReverseTopologyGrid->addPointAtIndex(value, index); } //setProgress(90.0f + 9.0f*(float(i) / float(size))); } group->addSingularItem(_outSegmentationGrid, outSegmentationGrid); group->addSingularItem(_outTopologyGrid, outTopologyGrid); group->addSingularItem(_outReverseTopologyGrid, outReverseTopologyGrid); } } //setProgress(99); } void ONF_StepSegmentFromSeedGrid::findParentCell(CT_Grid3D_Sparse* segmentationGrid, CT_Grid3D_Sparse* topologyGrid, const QMap &priorities, size_t cellIndex, bool growthUp) { Eigen::Vector3d baseCenter; if (!segmentationGrid->getCellCenterCoordinates(cellIndex, baseCenter)) {return;} int baseLabel = segmentationGrid->valueAtIndex(cellIndex); int xxbase = 0, yybase = 0, zzbase = 0; segmentationGrid->indexToGrid(cellIndex, xxbase, yybase, zzbase); double maxDistZ2 = _maxDistZ*_maxDistZ; double maxDistXY2 = _maxDistXY*_maxDistXY; int ncellsXY = int(std::ceil(_maxDistXY / segmentationGrid->resolution())); if (ncellsXY < 1) {ncellsXY = 1;} int firstX = xxbase - ncellsXY; int lastX = xxbase + ncellsXY; if (firstX < 0) {firstX = 0;} if (lastX > segmentationGrid->xdim() - 1) {lastX = segmentationGrid->xdim() - 1;} int firstY = yybase - ncellsXY; int lastY = yybase + ncellsXY; if (firstY < 0) {firstY = 0;} if (lastY > segmentationGrid->ydim() - 1) {lastY = segmentationGrid->ydim() - 1;} int ncellsZ = int(std::ceil(_maxDistZ / segmentationGrid->resolution())); if (ncellsZ < 1) {ncellsZ = 1;} int firstZ = zzbase - ncellsZ; int lastZ = zzbase - 1; if (!growthUp) { firstZ = zzbase + 1; lastZ = zzbase + ncellsZ; } if (firstZ < 0) {firstZ = 0;} if (lastZ < 0) {lastZ = 0;} if (firstZ > segmentationGrid->zdim() - 1) {firstZ = segmentationGrid->zdim() - 1;} if (lastZ > segmentationGrid->zdim() - 1) {lastZ = segmentationGrid->zdim() - 1;} double smallestDist = maxDistXY2 + maxDistZ2 + 0.00001; double highestPriority = 0; //int highestPriorityID = -1; bool usePriority = !priorities.isEmpty(); for (int zz = firstZ ; zz <= lastZ ; zz++) { for (int xx = firstX ; xx <= lastX ; xx++) { for (int yy = firstY ; yy <= lastY ; yy++) { size_t currentIndex; if (segmentationGrid->index(xx, yy, zz, currentIndex)) { Eigen::Vector3d currentCenter; if (segmentationGrid->getCellCenterCoordinates(currentIndex, currentCenter)) { double dx = currentCenter(0) - baseCenter(0); double dy = currentCenter(1) - baseCenter(1); double distXY = dx*dx + dy*dy; if (distXY < maxDistXY2) { double dz = currentCenter(2) - baseCenter(2); double dist = dx*dx + dy*dy + dz*dz; int currentLabel = segmentationGrid->valueAtIndex(currentIndex); if (currentLabel >= 0) { bool replace = (dist < smallestDist); if (usePriority) { double priority = priorities.value(currentLabel, 0); if (priority >= highestPriority) { replace = true; highestPriority = priority; //highestPriorityID = currentLabel; } else { replace = false; } } if (replace) { if (baseLabel >= 0) { if (baseLabel == currentLabel && growthUp) { smallestDist = dist; topologyGrid->setValueAtIndex(cellIndex, currentIndex); } } else { smallestDist = dist; topologyGrid->setValueAtIndex(cellIndex, currentIndex); segmentationGrid->setValueAtIndex(cellIndex, currentLabel); } } } } } } } } } }