From 1d02e4bde7e311fdc64a2f11769d85ff62f97518 Mon Sep 17 00:00:00 2001 From: Daniel Girardeau-Montaut Date: Sat, 1 Dec 2018 14:39:11 +0100 Subject: [PATCH] Bug fix + parallel computation of features --- PointFeature.cpp | 34 +++++++++++++++++++++++++++++----- q3DMASC.cpp | 2 ++ q3DMASCClassifier.cpp | 6 +++--- q3DMASCTools.cpp | 29 +++++++++++++++++++++++------ 4 files changed, 57 insertions(+), 14 deletions(-) diff --git a/PointFeature.cpp b/PointFeature.cpp index 3a182b0..dc6eea0 100644 --- a/PointFeature.cpp +++ b/PointFeature.cpp @@ -33,6 +33,9 @@ //system #include +//Qt +#include + static const char* s_echoRatioSFName = "EchoRat"; static const char* s_NIRSFName = "NIR"; static const char* s_M3C2SFName = "M3C2 distance"; @@ -583,10 +586,11 @@ static CCLib::ScalarField* ExtractStat( const CorePoints& corePoints, resultSF->computeMinAndMax(); int newSFIdx = corePoints.cloud->addScalarField(static_cast(resultSF)); //update display - if (corePoints.cloud->getDisplay()) + //if (corePoints.cloud->getDisplay()) { corePoints.cloud->setCurrentDisplayedScalarField(newSFIdx); - corePoints.cloud->getDisplay()->redraw(); + //corePoints.cloud->getDisplay()->redraw(); + //QCoreApplication::processEvents(); } return resultSF; @@ -698,7 +702,7 @@ bool PointFeature::prepare( const CorePoints& corePoints, // return false; //} - //and the scalar fielda + //and the scalar field assert(!statSF1); statSF1 = PrepareSF(corePoints, qPrintable(resultSFName)); //CCLib::ScalarField* statSF1 = ExtractStat(corePoints, cloud1, field1.data(), scale, stat, qPrintable(resultSFName), progressCb); @@ -802,10 +806,11 @@ bool PointFeature::prepare( const CorePoints& corePoints, resultSF->computeMinAndMax(); int newSFIdx = corePoints.cloud->addScalarField(static_cast(resultSF)); //update display - if (corePoints.cloud->getDisplay()) + //if (corePoints.cloud->getDisplay()) { corePoints.cloud->setCurrentDisplayedScalarField(newSFIdx); - corePoints.cloud->getDisplay()->redraw(); + //corePoints.cloud->getDisplay()->redraw(); + //QCoreApplication::processEvents(); } } @@ -971,6 +976,15 @@ bool PointFeature::finish(const CorePoints& corePoints, QString& error) if (statSF1) { statSF1->computeMinAndMax(); + + //update display + //if (corePoints.cloud->getDisplay()) + { + int sfIndex1 = corePoints.cloud->getScalarFieldIndexByName(statSF1->getName()); + corePoints.cloud->setCurrentDisplayedScalarField(sfIndex1); + //corePoints.cloud->getDisplay()->redraw(); + //QCoreApplication::processEvents(); + } } if (statSF2) @@ -1031,6 +1045,16 @@ QString PointFeature::toString() const description += "_" + cloud1Label; + if (cloud2 && !cloud2Label.isEmpty()) + { + description += "_" + cloud2Label; + + if (op != NO_OPERATION) + { + description += "_" + OpToString(op); + } + } + //Point features always have a scale equal to 0 by definition return description; } diff --git a/q3DMASC.cpp b/q3DMASC.cpp index d8ac038..79a06ce 100644 --- a/q3DMASC.cpp +++ b/q3DMASC.cpp @@ -274,6 +274,8 @@ void q3DMASCPlugin::doTrainAction() QCoreApplication::processEvents(); pDlg.setAutoClose(true); //restore the default behavior of the progress dialog + m_app->redrawAll(); + //randomly select the training points QScopedPointer trainSubset(new CCLib::ReferenceCloud(corePoints.cloud)); QScopedPointer testSubset(new CCLib::ReferenceCloud(corePoints.cloud)); diff --git a/q3DMASCClassifier.cpp b/q3DMASCClassifier.cpp index 3fc7ff8..765d89c 100644 --- a/q3DMASCClassifier.cpp +++ b/q3DMASCClassifier.cpp @@ -137,7 +137,6 @@ bool Classifier::classify(const Feature::Set& features, ccPointCloud* cloud, QSt { classificationSF = cloud->getScalarField(classifSFIdx); } - cloud->setCurrentDisplayedScalarField(classifSFIdx); assert(classificationSF); classificationSF->fill(0); //0 = no classification? @@ -549,12 +548,13 @@ bool Classifier::toFile(QString filename, QWidget* parentWidget/*=nullptr*/) con pDlg.show(); QCoreApplication::processEvents(); - m_rtrees->save(filename.toStdString()); + cv::String cvFilename = filename.toStdString(); + m_rtrees->save(cvFilename); pDlg.close(); QCoreApplication::processEvents(); - ccLog::Print("Classifier file saved to: " + filename); + ccLog::Print("Classifier file saved to: " + QString::fromStdString(cvFilename)); return true; } diff --git a/q3DMASCTools.cpp b/q3DMASCTools.cpp index d65dc46..60d67f8 100644 --- a/q3DMASCTools.cpp +++ b/q3DMASCTools.cpp @@ -35,6 +35,7 @@ #include #include #include +#include //system #include @@ -900,7 +901,11 @@ bool Tools::PrepareFeatures(const CorePoints& corePoints, Feature::Set& features ccLog::Print(QString("Computing fields for cloud %1 (core points: %2)").arg(sourceCloud->getName()).arg(pointCount)); CCLib::NormalizedProgress nProgress(progressCb, pointCount); - for (unsigned i = 0; i < pointCount; ++i) + QMutex mutex; +#if defined(_OPENMP) +#pragma omp parallel for +#endif + for (int i = 0; i < static_cast(pointCount); ++i) { //spherical neighborhood extraction structure CCLib::DgmOctree::NearestNeighboursSphericalSearchStruct nNSS; @@ -948,6 +953,12 @@ bool Tools::PrepareFeatures(const CorePoints& corePoints, Feature::Set& features double outputValue = 0; for (PointFeature::Shared& feature : fas.features) { + if (feature->scale != fas.scales[scaleIndex]) + { + //we use the current neighborhood only for the features with the corresponding scales! + continue; + } + if (feature->cloud1 == sourceCloud && feature->statSF1 && feature->field1) { if (!feature->computeStat(nNSS.pointsInNeighbourhood, feature->field1, outputValue)) @@ -983,12 +994,18 @@ bool Tools::PrepareFeatures(const CorePoints& corePoints, Feature::Set& features } //for each scale - if (progressCb && !nProgress.oneStep()) + if (progressCb) { - //process cancelled by the user - ccLog::Warning("Process cancelled"); - error = true; - break; + mutex.lock(); + bool cancelled = !nProgress.oneStep(); + mutex.unlock(); + if (cancelled) + { + //process cancelled by the user + ccLog::Warning("Process cancelled"); + error = true; + break; + } } } //for each point