/**************************************************************************** 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_steppolygonfrommask.h" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/imgproc/types_c.h" #include "opencv2/core/core.hpp" ONF_StepPolygonFromMask::ONF_StepPolygonFromMask() : SuperClass() { _mode = 0; } QString ONF_StepPolygonFromMask::description() const { return tr("Création de polygones à partir d'un masque"); } QString ONF_StepPolygonFromMask::detailledDescription() const { return tr(""); } QString ONF_StepPolygonFromMask::inputDescription() const { return SuperClass::inputDescription() + tr("

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

"); } QString ONF_StepPolygonFromMask::detailsDescription() const { return tr(""); } CT_VirtualAbstractStep* ONF_StepPolygonFromMask::createNewInstance() const { // cree une copie de cette etape return new ONF_StepPolygonFromMask(); } //////////////////// PROTECTED ////////////////// void ONF_StepPolygonFromMask::fillPreInputConfigurationDialog(CT_StepConfigurableDialog* preInputConfigDialog) { CT_ButtonGroup &bg_mode = preInputConfigDialog->addButtonGroup(_mode); preInputConfigDialog->addExcludeValue("", "", tr("Un unique polygone par masque"), bg_mode, 0); preInputConfigDialog->addExcludeValue("", "", tr("Un ou plusieurs polygones par masque"), bg_mode, 1); } void ONF_StepPolygonFromMask::declareInputModels(CT_StepInModelStructureManager& manager) { manager.addResult(_inResult, tr("Dalles"), "", true); manager.setZeroOrMoreRootGroup(_inResult, _inZeroOrMoreRootGroup); manager.addGroup(_inZeroOrMoreRootGroup, _inGroup); manager.addItem(_inGroup, _inImage, tr("Masque")); manager.addItem(_inGroup, _inItemWithXY, tr("XYRef (optionnel)")); manager.addItemAttribute(_inItemWithXY, _inXattribute, CT_AbstractCategory::DATA_X, tr("X")); manager.addItemAttribute(_inItemWithXY, _inYattribute, CT_AbstractCategory::DATA_Y, tr("Y")); } void ONF_StepPolygonFromMask::declareOutputModels(CT_StepOutModelStructureManager& manager) { manager.addResultCopy(_inResult); manager.addGroup(_inGroup, _outPolygonGrp, tr("Groupe")); if (_mode == 0) { manager.addItem(_inGroup, _outPolygon, tr("Polygone")); } else { manager.addItem(_outPolygonGrp, _outPolygon, tr("Polygone")); } manager.addItemAttribute(_outPolygon, _att_X, PS_CATEGORY_MANAGER->findByUniqueName(CT_AbstractCategory::DATA_X), tr("X_Ref")); manager.addItemAttribute(_outPolygon, _att_Y, PS_CATEGORY_MANAGER->findByUniqueName(CT_AbstractCategory::DATA_Y), tr("Y_Ref")); } void ONF_StepPolygonFromMask::compute() { for (CT_StandardItemGroup* group : _inGroup.iterateOutputs(_inResult)) { if (isStopped()) {return;} CT_Image2D *mask = const_cast*>(group->singularItem(_inImage)); const CT_AbstractSingularItemDrawable *refItem = group->singularItem(_inItemWithXY); if (mask != nullptr) { std::vector > contours; cv::Mat_ maskTmp = mask->getMat().clone(); cv::findContours(maskTmp, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); maskTmp.release(); size_t n = contours.size(); if (_mode == 0 && n > 0) {n = 1;} for (size_t i = 0 ; i < n ; i++) { const std::vector &contour = contours.at(i); QVector vertices; double demiRes = mask->resolution() / 2.0; int xxLast = 0; int yyLast = 0; if (contour.size() > 0) { const cv::Point &vert = contour.at(contour.size() - 1); xxLast = vert.x; yyLast = vert.y; } for (size_t j = 0 ; j < contour.size() ; j++) { const cv::Point &vert = contour.at(j); int xx = vert.x; int yy = vert.y; double x = mask->getCellCenterColCoord(xx); double y = mask->getCellCenterLinCoord(yy); bool sides[4]; sides[0] = (mask->value(xx+1, yy) == 0); sides[1] = (mask->value(xx, yy-1) == 0); sides[2] = (mask->value(xx-1, yy) == 0); sides[3] = (mask->value(xx, yy+1) == 0); if (sides[0] && sides[2] && !sides[1] && !sides[3]) { if (yy < yyLast) { vertices.append(Eigen::Vector2d(x + demiRes, y + demiRes)); } else { vertices.append(Eigen::Vector2d(x - demiRes, y - demiRes)); } } else if (sides[1] && sides[3] && !sides[0] && !sides[2]) { if (xx < xxLast) { vertices.append(Eigen::Vector2d(x - demiRes, y + demiRes)); } else { vertices.append(Eigen::Vector2d(x + demiRes, y - demiRes)); } } else if (sides[0] && sides[1] && sides[2] && sides[3]) { vertices.append(Eigen::Vector2d(x + demiRes, y + demiRes)); vertices.append(Eigen::Vector2d(x - demiRes, y + demiRes)); vertices.append(Eigen::Vector2d(x - demiRes, y - demiRes)); vertices.append(Eigen::Vector2d(x + demiRes, y - demiRes)); } else if (sides[0] && !sides[3]) { vertices.append(Eigen::Vector2d(x + demiRes, y + demiRes)); if (sides[1]) { vertices.append(Eigen::Vector2d(x - demiRes, y + demiRes)); if (sides[2]) { vertices.append(Eigen::Vector2d(x - demiRes, y - demiRes)); } } } else if (sides[1] && !sides[0]) { vertices.append(Eigen::Vector2d(x - demiRes, y + demiRes)); if (sides[2]) { vertices.append(Eigen::Vector2d(x - demiRes, y - demiRes)); if (sides[3]) { vertices.append(Eigen::Vector2d(x + demiRes, y - demiRes)); } } } else if (sides[2] && !sides[1]) { vertices.append(Eigen::Vector2d(x - demiRes, y - demiRes)); if (sides[3]) { vertices.append(Eigen::Vector2d(x + demiRes, y - demiRes)); if (sides[0]) { vertices.append(Eigen::Vector2d(x + demiRes, y + demiRes)); } } } else if (sides[3] && !sides[2]) { vertices.append(Eigen::Vector2d(x + demiRes, y - demiRes)); if (sides[0]) { vertices.append(Eigen::Vector2d(x + demiRes, y + demiRes)); if (sides[1]) { vertices.append(Eigen::Vector2d(x - demiRes, y + demiRes)); } } } xxLast = xx; yyLast = yy; } if (vertices.size() > 0) { CT_Polygon2DData* dataPoly = new CT_Polygon2DData(vertices); CT_Polygon2D* poly = new CT_Polygon2D(dataPoly); if (_mode == 0) { group->addSingularItem(_outPolygon, poly); } else { CT_StandardItemGroup* outGrpPoly = new CT_StandardItemGroup(); group->addGroup(_outPolygonGrp, outGrpPoly); outGrpPoly->addSingularItem(_outPolygon, poly); } if (refItem != nullptr) { const CT_AbstractItemAttribute *attributeX = refItem->itemAttribute(_inXattribute); const CT_AbstractItemAttribute *attributeY = refItem->itemAttribute(_inYattribute); if (attributeX != nullptr && attributeY != nullptr) { bool okX, okY; double valX = attributeX->toDouble(refItem, &okX); double valY = attributeY->toDouble(refItem, &okY); if (okX && okY) { poly->addItemAttribute(_att_X, new CT_StdItemAttributeT(CT_AbstractCategory::DATA_X, valX)); poly->addItemAttribute(_att_Y, new CT_StdItemAttributeT(CT_AbstractCategory::DATA_Y, valY)); } } } } } } } }