#include "onf_stepconvertrastertovector.h" #include "imgproc/types_c.h" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/core/core.hpp" ONF_StepConvertRasterToVector::ONF_StepConvertRasterToVector() : SuperClass() { _filter = true; _surfaceThreshold = 6250.0; } QString ONF_StepConvertRasterToVector::description() const { return tr("Convertir un raster en polygones"); } QString ONF_StepConvertRasterToVector::detailledDescription() const { return tr(""); } QString ONF_StepConvertRasterToVector::inputDescription() const { return SuperClass::inputDescription() + tr("

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

"); } QString ONF_StepConvertRasterToVector::detailsDescription() const { return tr(""); } QString ONF_StepConvertRasterToVector::URL() const { //return tr("STEP URL HERE"); return CT_AbstractStep::URL(); //by default URL of the plugin } CT_VirtualAbstractStep* ONF_StepConvertRasterToVector::createNewInstance() const { return new ONF_StepConvertRasterToVector(); } //////////////////// PROTECTED METHODS ////////////////// void ONF_StepConvertRasterToVector::declareInputModels(CT_StepInModelStructureManager& manager) { manager.addResult(_inResult, tr("Segmentation")); manager.setZeroOrMoreRootGroup(_inResult, _inZeroOrMoreRootGroup); manager.addGroup(_inZeroOrMoreRootGroup, _inGroup); manager.addItem(_inGroup, _inClusters, tr("Segmentation")); } void ONF_StepConvertRasterToVector::declareOutputModels(CT_StepOutModelStructureManager& manager) { manager.addResultCopy(_inResult); manager.addGroup(_inGroup, _groupCluster, tr("Polygone")); manager.addItem(_groupCluster, _outPolygon, tr("Polygone")); manager.addItemAttribute(_outPolygon, _outPolygonIDAtt, PS_CATEGORY_MANAGER->findByUniqueName(CT_AbstractCategory::DATA_ID), tr("PolygonID")); } void ONF_StepConvertRasterToVector::fillPostInputConfigurationDialog(CT_StepConfigurableDialog *postInputConfigDialog) { postInputConfigDialog->addBool(tr("Ne concerver que les polygones s'une surface minimale"), "", "", _filter); postInputConfigDialog->addDouble(tr("Seuil de surface minimale"), "m²", 0, std::numeric_limits::max(), 2, _surfaceThreshold); } void ONF_StepConvertRasterToVector::compute() { int PolygonID = 1; for (CT_StandardItemGroup* grp : _inGroup.iterateOutputs(_inResult)) { for (const CT_AbstractImage2D* clusters : grp->singularItems(_inClusters)) { if (isStopped()) {return;} QMap areas; for (int y = 0 ; y < clusters->ydim() ; y++) { for (int x = 0 ; x < clusters->xdim() ; x++) { size_t index; clusters->index(x, y, index); double cluster = clusters->valueAtIndexAsDouble(index); if (!qFuzzyCompare(cluster, clusters->NAAsDouble())) { if (!areas.contains(cluster)) {areas.insert(cluster, new ONF_StepConvertRasterToVector::pixelsArea());} ONF_StepConvertRasterToVector::pixelsArea *area = areas.value(cluster); if (x < area->_xmin) {area->_xmin = x;} if (x > area->_xmax) {area->_xmax = x;} if (y < area->_ymin) {area->_ymin = y;} if (y > area->_ymax) {area->_ymax = y;} } } } QMapIterator it(areas); while (it.hasNext()) { it.next(); double cluster = it.key(); if (cluster > 0) { ONF_StepConvertRasterToVector::pixelsArea* area = it.value(); // Create a 1-pixel buffer around each crown area->_xmin--; area->_ymin--; area->_xmax++; area->_ymax++; double minx = clusters->minX() + (area->_xmin) * clusters->resolution(); double miny = clusters->maxY() - (area->_ymax + 1) * clusters->resolution(); int dimx = area->_xmax - area->_xmin + 1; int dimy = area->_ymax - area->_ymin + 1; CT_Image2D *clusterMask = new CT_Image2D(minx, miny, dimx, dimy, clusters->resolution(), 0, 0, 0); for (int y = area->_ymin ; y <= area->_ymax ; y++) { for (int x = area->_xmin ; x <= area->_xmax ; x++) { size_t index; clusters->index(x, y, index); if (qFuzzyCompare(clusters->valueAtIndexAsDouble(index), cluster)) { int localCol = x - area->_xmin; int localLin = y - area->_ymin; clusterMask->setValue(localCol, localLin, 1); } } } std::vector > contours; cv::Mat_ maskTmp = clusterMask->getMat().clone(); cv::findContours(maskTmp, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); maskTmp.release(); if (contours.size() > 0) { QList polygonDataList; for (int i = 0; i < contours.size(); i++) { std::vector contour = contours[i]; QVector vertices; std::reverse(contour.begin(), contour.end()); clusterMask->convertPixelContourToPolygon(contour, vertices); CT_Polygon2DData* polyData = new CT_Polygon2DData(vertices); polygonDataList.append(polyData); } for (CT_Polygon2DData* poly : polygonDataList) { CT_Image2D clusterMaskTmp(minx, miny, dimx, dimy, clusters->resolution(), 0, 0, 0); for (size_t index = 0 ; index < clusterMask->nCells() ; index++) { double val = clusterMask->valueAtIndexAsDouble(index); Eigen::Vector3d center; clusterMask->getCellCenterCoordinates(index, center); bool inside = false; if (poly->contains(center(0), center(1))) { inside = true; } if (inside && val < 1) { clusterMaskTmp.setValueAtIndex(index, 1); } else { clusterMaskTmp.setValueAtIndex(index, 0); } } contours.clear(); maskTmp = clusterMaskTmp.getMat(); cv::findContours(maskTmp, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); maskTmp.release(); for (int i = 0; i < contours.size(); i++) { std::vector contour = contours[i]; QVector vertices; std::reverse(contour.begin(), contour.end()); clusterMask->convertPixelContourToPolygon(contour, vertices); CT_Polygon2DData* polyData = new CT_Polygon2DData(vertices); poly->addInnerPolygon(polyData); } if (!_filter || (_filter && poly->getArea() > _surfaceThreshold)) { CT_StandardItemGroup *clusterGroup = new CT_StandardItemGroup(); grp->addGroup(_groupCluster, clusterGroup); CT_Polygon2D* po = new CT_Polygon2D(poly); clusterGroup->addSingularItem(_outPolygon, po); po->addItemAttribute(_outPolygonIDAtt, new CT_StdItemAttributeT(PS_CATEGORY_MANAGER->findByUniqueName(CT_AbstractCategory::DATA_ID), PolygonID++)); } } } delete clusterMask; } } qDeleteAll(areas); } } }