1 Commits

Author SHA1 Message Date
Paul Leroy bd321fa4bb clean CMakeLists.txt + handle duplicates 2025-09-18 16:39:04 +02:00
4 changed files with 114 additions and 86 deletions
+64 -50
View File
@@ -8,12 +8,12 @@ option( PLUGIN_G3POINT "Install example plugin" OFF )
if ( PLUGIN_G3POINT )
project( G3PointPlugin )
AddPlugin( NAME ${PROJECT_NAME} )
target_sources(G3PointPlugin
PRIVATE
ui/WolmanCustomPlot.ui
PRIVATE
ui/WolmanCustomPlot.ui
)
set(QG3POINT_PLUGIN_VERSION "0.6")
@@ -22,36 +22,50 @@ target_sources(G3PointPlugin
add_subdirectory( src )
add_subdirectory( ui )
# target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) # for mlpack
# EIGEN
set( EIGEN_ROOT_DIR "" CACHE PATH "Eigen root (contains the Eigen directory)" )
if ( NOT EIGEN_ROOT_DIR )
message( SEND_ERROR "No Eigen root directory specified (EIGEN_ROOT_DIR)" )
else()
message( STATUS "EIGEN_ROOT_DIR " ${EIGEN_ROOT_DIR} )
endif()
# BOOST
find_package(Boost REQUIRED)
message(STATUS "Boost_VERSION: ${Boost_VERSION}")
message(STATUS "Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}")
# OPEN3D
find_package( Open3D REQUIRED ) # Find installed Open3D, which exports Open3D::Open3D
message( "Open3D_DIR ${Open3D_DIR}" )
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set( OPENCV_DEP_DLL_FILES
${Open3D_DIR}/../bin/Open3D.dll
${Open3D_DIR}/../bin/tbb12_debug.dll)
elseif(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set( OPENCV_DEP_DLL_FILES
${Open3D_DIR}/../bin/Open3D.dll
${Open3D_DIR}/../bin/tbb12.dll)
endif()
copy_files( "${OPENCV_DEP_DLL_FILES}" "${CLOUDCOMPARE_DEST_FOLDER}" 1) #mind the quotes!
target_include_directories( ${PROJECT_NAME} PRIVATE
C:/opt/eigen-3.4.0
C:/Users/PaulLeroy/miniconda3/envs/env_4_CloudCompare/include
C:/opt/open3d-devel-windows-amd64-0.19.0/include
C:/opt/GeometricTools/GTE
C:/opt/boost_1_77_0
)
# may be needed for debug
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
#============
target_include_directories( ${PROJECT_NAME} PRIVATE
${GEOMETRIC_TOOLS_DIR}/GTE
${EIGEN_ROOT_DIR}
${Boost_INCLUDE_DIRS}
)
target_link_libraries( ${PROJECT_NAME} Open3D::Open3D )
# QCUSTOMPLOT
target_link_libraries(${PROJECT_NAME}
QCustomPlot
Qt5::PrintSupport
)
# Find installed Open3D, which exports Open3D::Open3D
find_package( Open3D REQUIRED )
target_link_libraries( ${PROJECT_NAME} Open3D::Open3D )
message( "Open3D_DIR ${Open3D_DIR}" )
set( OPENCV_DEP_DLL_FILES
${Open3D_DIR}/../bin/Open3D.dll
${Open3D_DIR}/../bin/tbb12.dll
)
copy_files( "${OPENCV_DEP_DLL_FILES}" "${CLOUDCOMPARE_DEST_FOLDER}" 1) #mind the quotes!
# Copy OpenGL shaders
copy_files( "${CMAKE_CURRENT_SOURCE_DIR}/shaders/DrawGrains.vs" "${CLOUDCOMPARE_DEST_FOLDER}/shaders/G3Point" 1) #mind the quotes!
copy_files( "${CMAKE_CURRENT_SOURCE_DIR}/shaders/DrawGrains.fs" "${CLOUDCOMPARE_DEST_FOLDER}/shaders/G3Point" 1) #mind the quotes!
@@ -59,38 +73,38 @@ target_sources(G3PointPlugin
# git commit hash
# Get the current working branch
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH_G3POINT
OUTPUT_STRIP_TRAILING_WHITESPACE)
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH_G3POINT
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Get the latest commit hash
execute_process(
COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH_G3POINT
OUTPUT_STRIP_TRAILING_WHITESPACE)
COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH_G3POINT
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Get the latest commit hash
execute_process(
COMMAND git describe
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_TAG_G3POINT
OUTPUT_STRIP_TRAILING_WHITESPACE)
COMMAND git describe
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_TAG_G3POINT
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Get the current working branch
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH_CC
OUTPUT_STRIP_TRAILING_WHITESPACE)
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH_CC
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Get the latest commit hash
execute_process(
COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH_CC
OUTPUT_STRIP_TRAILING_WHITESPACE)
COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH_CC
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(${PROJECT_NAME} " " GIT_BRANCH_G3POINT " " ${GIT_BRANCH_G3POINT})
message(${PROJECT_NAME} " " GIT_COMMIT_HASH_G3POINT " " ${GIT_COMMIT_HASH_G3POINT})
@@ -100,12 +114,12 @@ target_sources(G3PointPlugin
message(${PROJECT_NAME} " " QG3POINT_VERSION " " ${QG3POINT_PLUGIN_VERSION})
target_compile_definitions(${PROJECT_NAME} PRIVATE
GIT_BRANCH_CC="${GIT_BRANCH_CC}"
GIT_COMMMIT_HASH_CC="${GIT_COMMIT_HASH_CC}"
PUBLIC GIT_BRANCH_G3POINT="${GIT_BRANCH_G3POINT}"
GIT_COMMMIT_HASH_G3POINT="${GIT_COMMIT_HASH_G3POINT}"
GIT_TAG_G3POINT="${GIT_TAG_G3POINT}"
G3POINT_VERSION="${QG3POINT_PLUGIN_VERSION}"
)
GIT_BRANCH_CC="${GIT_BRANCH_CC}"
GIT_COMMMIT_HASH_CC="${GIT_COMMIT_HASH_CC}"
PUBLIC GIT_BRANCH_G3POINT="${GIT_BRANCH_G3POINT}"
GIT_COMMMIT_HASH_G3POINT="${GIT_COMMIT_HASH_G3POINT}"
GIT_TAG_G3POINT="${GIT_TAG_G3POINT}"
G3POINT_VERSION="${QG3POINT_PLUGIN_VERSION}"
)
endif()
+2 -2
View File
@@ -63,9 +63,9 @@ private:
bool updateLocalMaximumIndexes();
bool updateLabelsAndColors();
bool checkStacks(const std::vector<std::vector<int>>& stacks, int count);
void addToStackBraunWillett(int index, const Eigen::ArrayXi& delta, const Eigen::ArrayXi &Di, std::vector<int>& stack, int local_maximum);
void addToStackBraunWillett(int index, const Eigen::ArrayXi& delta, const Eigen::ArrayXi& Di, std::vector<int>& stack, int local_maximum);
int segmentLabelsBraunWillett();
void getNeighborsDistancesSlopes(unsigned index);
void getNeighborsDistancesSlopes(unsigned index, std::vector<char>& duplicates);
void computeNodeSurfaces();
bool computeNormalsAndOrientThemWithCloudCompare();
void orientNormals(const Eigen::Vector3d &sensorCenter);
+36 -22
View File
@@ -369,7 +369,7 @@ Eigen::ArrayXXd G3PointAction::computeMeanAngleBetweenNormalsAtBorders()
Eigen::ArrayXXi duplicated_labels(m_cloud->size(), m_kNN);
for (int n = 0; n < m_kNN; n++)
{
duplicated_labels(Eigen::placeholders::all, n) = m_labels;
duplicated_labels(Eigen::all, n) = m_labels;
}
Eigen::ArrayXXi labels_of_neighbors(m_cloud->size(), m_kNN);
for (int index = 0; index < static_cast<int>(m_cloud->size()); index++)
@@ -403,12 +403,12 @@ Eigen::ArrayXXd G3PointAction::computeMeanAngleBetweenNormalsAtBorders()
for (auto i : indborder)
{
auto neighbors = m_neighborsIndexes(i, Eigen::placeholders::all); // indexes of the neighbors of i
Eigen::Vector3d N1(m_normals(i, Eigen::placeholders::all)); // normal at i
auto neighbors = m_neighborsIndexes(i, Eigen::all); // indexes of the neighbors of i
Eigen::Vector3d N1(m_normals(i, Eigen::all)); // normal at i
for (auto j : neighbors)
{
// Take the normals vector for i and j
Eigen::Vector3d N2(m_normals(j, Eigen::placeholders::all)); // normal at j
Eigen::Vector3d N2(m_normals(j, Eigen::all)); // normal at j
double angle = angleRot2VecMat(N1, N2);
if ((m_labels(i) != -1) && (m_labels(j) != -1)) // points which belong to the discarded grains have the -1 label
{
@@ -1047,7 +1047,7 @@ void G3PointAction::fit()
}
void G3PointAction::exportResults()
{
{
if (m_grainsAsEllipsoids)
{
m_grainsAsEllipsoids->exportResultsAsCloud();
@@ -1263,21 +1263,21 @@ bool G3PointAction::wolman()
Eigen::ArrayXXf dq(n_iter, 3);
Eigen::ArrayXf d_sample = d[0];
dq(0, Eigen::placeholders::all) << quant(d[0], 0.1), quant(d[0], 0.5), quant(d[0], 0.9);
dq(0, Eigen::all) << quant(d[0], 0.1), quant(d[0], 0.5), quant(d[0], 0.9);
for (int i = 1; i < n_iter; i++)
{
Eigen::ArrayXf tmp(d_sample.size() + d[i].size());
tmp << d_sample, d[i];
d_sample = tmp;
dq(i, Eigen::placeholders::all) << quant(d[i], 0.1), quant(d[i], 0.5), quant(d[i], 0.9);
dq(i, Eigen::all) << quant(d[i], 0.1), quant(d[i], 0.5), quant(d[i], 0.9);
}
// std::cout << "d_sample " << d_sample << std::endl;
// compute standard deviation
Eigen::Array3d edq {std_dev(dq(Eigen::placeholders::all, 0)),
std_dev(dq(Eigen::placeholders::all, 1)),
std_dev(dq(Eigen::placeholders::all, 2))};
Eigen::Array3d edq {std_dev(dq(Eigen::all, 0)),
std_dev(dq(Eigen::all, 1)),
std_dev(dq(Eigen::all, 2))};
Eigen::Array3d dq_final {quant(d_sample, 0.1),
quant(d_sample, 0.5),
quant(d_sample, 0.9)};
@@ -1430,11 +1430,11 @@ bool G3PointAction::cleanLabels()
Eigen::RowVector3d centroid = points.colwise().mean();
points.rowwise() -= centroid;
// SVD decomposition A = U S V
s(k, Eigen::placeholders::all) = points.jacobiSvd().singularValues();
s(k, Eigen::all) = points.jacobiSvd().singularValues();
}
// filtering condition: (l2 / l0 > min_flatness) or (l1 / l0 > 2 * min_flatness)
Xb condition = (s(Eigen::placeholders::all, 2) / s(Eigen::placeholders::all, 0) > m_minFlatness)
|| (s(Eigen::placeholders::all, 1) / s(Eigen::placeholders::all, 0) > 2. * m_minFlatness);
Xb condition = (s(Eigen::all, 2) / s(Eigen::all, 0) > m_minFlatness)
|| (s(Eigen::all, 1) / s(Eigen::all, 0) > 2. * m_minFlatness);
size_t numberOfGrainsToKeep = condition.count();
if (numberOfGrainsToKeep == m_stacks.size())
{
@@ -1648,7 +1648,7 @@ int G3PointAction::segmentLabelsBraunWillett()
return nLabels;
}
void G3PointAction::getNeighborsDistancesSlopes(unsigned index)
void G3PointAction::getNeighborsDistancesSlopes(unsigned index, std::vector<char>& duplicates)
{
const CCVector3* P = m_cloud->getPoint(index);
@@ -1670,7 +1670,15 @@ void G3PointAction::getNeighborsDistancesSlopes(unsigned index)
float distance = (*P - *neighbor).norm();
m_neighborsDistances(index, k) = distance;
// compute the slope to the neighbor
m_neighborsSlopes(index, k) = (P->z - neighbor->z) / distance;
if (distance != 0)
{
m_neighborsSlopes(index, k) = (P->z - neighbor->z) / distance;
}
else
{
m_neighborsSlopes(index, k) = 0.; // it is possible to have duplicates in the cloud
duplicates[index] = 1;
}
}
}
}
@@ -1742,7 +1750,7 @@ void G3PointAction::orientNormals(const Eigen::Vector3d& sensorCenter)
{
const CCVector3 *point = m_cloud->getPoint(i);
Eigen::Vector3d P1 = sensorCenter - Eigen::Vector3d(point->x, point->y, point->z);
Eigen::Vector3d P2 = m_normals(i, Eigen::placeholders::all);
Eigen::Vector3d P2 = m_normals(i, Eigen::all);
double angle = atan2(P1.cross(P2).norm(), P1.dot(P2));
if ((angle < - M_PI / 2) || (angle > M_PI / 2))
{
@@ -1810,7 +1818,7 @@ bool G3PointAction::computeNormalsWithOpen3D()
}
bool G3PointAction::queryNeighbors(ccPointCloud* cloud, ccMainAppInterface* appInterface, bool useParallelStrategy)
{
{
QString errorStr;
ccProgressDialog progressDlg(true, appInterface->getMainWindow());
@@ -1838,8 +1846,8 @@ bool G3PointAction::queryNeighbors(ccPointCloud* cloud, ccMainAppInterface* appI
size_t nPoints = m_cloud->size();
CCCoreLib::DgmOctree::NearestNeighboursSearchStruct nNSS;
std::vector<unsigned> pointsIndexes;
pointsIndexes.resize(nPoints);
std::vector<unsigned> pointsIndexes(nPoints);
std::vector<char> duplicates(nPoints, 0);
if (useParallelStrategy)
{
@@ -1850,17 +1858,23 @@ bool G3PointAction::queryNeighbors(ccPointCloud* cloud, ccMainAppInterface* appI
int threadCount = std::max(1, ccQtHelpers::GetMaxThreadCount() - 2);
std::cout << "[query_neighbor] parallel strategy, thread count " << threadCount << std::endl;
QThreadPool::globalInstance()->setMaxThreadCount(threadCount);
QtConcurrent::blockingMap(pointsIndexes, [=](int index){getNeighborsDistancesSlopes(index);});
QtConcurrent::blockingMap(pointsIndexes, [&](int index){getNeighborsDistancesSlopes(index, duplicates);});
}
else
{
//manually call the static per-point method!
for (unsigned i = 0; i < nPoints; ++i)
{
getNeighborsDistancesSlopes(i);
getNeighborsDistancesSlopes(i, duplicates);
}
}
auto trueCount = std::count(duplicates.begin(), duplicates.end(), 1);
if (trueCount)
{
ccLog::Warning("[G3Point] You have duplicates (" + QString::number(trueCount) + "), the algorithm will continue but you may think of cleaning your cloud.");
}
return true;
}
@@ -1950,7 +1964,7 @@ void G3PointAction::getBorders()
Eigen::ArrayXXi duplicatedLabelsInColumns(m_cloud->size(), m_kNN);
for (int n = 0; n < m_kNN; n++)
{
duplicatedLabelsInColumns(Eigen::placeholders::all, n) = m_labels;
duplicatedLabelsInColumns(Eigen::all, n) = m_labels;
}
Eigen::ArrayXXi labelsOfNeighbors(m_cloud->size(), m_kNN);
for (int index = 0; index < static_cast<float>(m_cloud->size()); index++)
+12 -12
View File
@@ -626,15 +626,15 @@ bool GrainsAsEllipsoids::directFit(const Eigen::ArrayX3d& xyz, Eigen::ArrayXd& p
Eigen::MatrixXd d(xyz.rows(), 10);
d << xyz(Eigen::placeholders::all, 0).pow(2).matrix()
, xyz(Eigen::placeholders::all, 1).pow(2).matrix()
, xyz(Eigen::placeholders::all, 2).pow(2).matrix()
, (2 * xyz(Eigen::placeholders::all, 1) * xyz(Eigen::placeholders::all, 2)).matrix()
, (2 * xyz(Eigen::placeholders::all, 0) * xyz(Eigen::placeholders::all, 2)).matrix()
, (2 * xyz(Eigen::placeholders::all, 0) * xyz(Eigen::placeholders::all, 1)).matrix()
, (2 * xyz(Eigen::placeholders::all, 0)).matrix()
, (2 * xyz(Eigen::placeholders::all, 1)).matrix()
, (2 * xyz(Eigen::placeholders::all, 2)).matrix()
d << xyz(Eigen::all, 0).pow(2).matrix()
, xyz(Eigen::all, 1).pow(2).matrix()
, xyz(Eigen::all, 2).pow(2).matrix()
, (2 * xyz(Eigen::all, 1) * xyz(Eigen::all, 2)).matrix()
, (2 * xyz(Eigen::all, 0) * xyz(Eigen::all, 2)).matrix()
, (2 * xyz(Eigen::all, 0) * xyz(Eigen::all, 1)).matrix()
, (2 * xyz(Eigen::all, 0)).matrix()
, (2 * xyz(Eigen::all, 1)).matrix()
, (2 * xyz(Eigen::all, 2)).matrix()
, Eigen::MatrixXd::Ones(xyz.rows(), 1);
Eigen::MatrixXd s = d.transpose() * d;
@@ -686,7 +686,7 @@ bool GrainsAsEllipsoids::directFit(const Eigen::ArrayX3d& xyz, Eigen::ArrayXd& p
{
if (eigenValues(k) == eigenValue)
{
v = eigensolver.eigenvectors()(Eigen::placeholders::all, k).real();
v = eigensolver.eigenvectors()(Eigen::all, k).real();
break;
}
}
@@ -698,7 +698,7 @@ bool GrainsAsEllipsoids::directFit(const Eigen::ArrayX3d& xyz, Eigen::ArrayXd& p
{
if (abs(eigenValues(k)) == eigenValue)
{
v = eigensolver.eigenvectors()(Eigen::placeholders::all, k).real();
v = eigensolver.eigenvectors()(Eigen::all, k).real();
break;
}
}
@@ -710,7 +710,7 @@ bool GrainsAsEllipsoids::directFit(const Eigen::ArrayX3d& xyz, Eigen::ArrayXd& p
{
if (eigenValues(k) == eigenValue)
{
v = eigensolver.eigenvectors()(Eigen::placeholders::all, k).real();
v = eigensolver.eigenvectors()(Eigen::all, k).real();
break;
}
}