Compare commits

...

6 Commits

Author SHA1 Message Date
940ba1be7f add noise filtering 2022-01-05 16:44:35 +01:00
3035ffacb8 start implementing elbéldtnaliuetslntaé,tad,,,uae 2022-01-05 15:59:28 +01:00
fc4bd15ba6 fix mesh reconstruction 2022-01-05 15:59:18 +01:00
908114858d fix hole filling 2022-01-05 15:58:45 +01:00
9aac4d09e6 fix smoothing 2022-01-05 15:55:07 +01:00
810ddaee03 add a method to find connected components 2022-01-05 15:54:46 +01:00
15 changed files with 121 additions and 28 deletions

View File

@ -36,7 +36,9 @@ target_sources(${PROJECT_NAME} PRIVATE
src/hole_filling.cpp src/hole_filling.cpp
src/hole_filling.h src/hole_filling.h
src/double_input.cpp src/double_input.cpp
src/double_input.h) src/double_input.h
src/noise_removal.cpp
src/noise_removal.h)
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Core Qt5::Gui Qt5::Widgets
OpenMeshCore OpenMeshCore

View File

@ -1,6 +1,7 @@
#include "MeshReconstruction.h" #include "MeshReconstruction.h"
#include "Cube.h" #include "Cube.h"
#include "Triangulation.h" #include "Triangulation.h"
#include <iostream>
using namespace MeshReconstruction; using namespace MeshReconstruction;
using namespace std; using namespace std;
@ -44,8 +45,9 @@ Mesh MeshReconstruction::MarchCube(
auto const NumY = static_cast<int>(ceil(domain.size.y / cubeSize.y)); auto const NumY = static_cast<int>(ceil(domain.size.y / cubeSize.y));
auto const NumZ = static_cast<int>(ceil(domain.size.z / cubeSize.z)); auto const NumZ = static_cast<int>(ceil(domain.size.z / cubeSize.z));
auto const HalfCubeDiag = cubeSize.Norm() / 2.0; auto const CubeDiag = cubeSize.Norm();
auto const HalfCubeSize = cubeSize * 0.5; // auto const HalfCubeDiag = cubeSize.Norm() * 0.5;
// auto const HalfCubeSize = cubeSize * 0.5;
Mesh mesh; Mesh mesh;
@ -61,9 +63,10 @@ Mesh MeshReconstruction::MarchCube(
Vec3 min{ x, y, z }; Vec3 min{ x, y, z };
// Process only if cube lies within narrow band around surface. // Process only if cube lies within narrow band around surface.
auto cubeCenter = min + HalfCubeSize; // auto cubeCenter = min + HalfCubeSize;
double dist = std::fabs(sdf(cubeCenter) - isoLevel); // double dist = std::abs(sdf(cubeCenter) - isoLevel);
if (dist > HalfCubeDiag) continue; double dist = std::abs(sdf(min) - isoLevel);
// if (dist > CubeDiag) continue;
Cube cube({ min, cubeSize }, sdf); Cube cube({ min, cubeSize }, sdf);
auto intersect = cube.Intersect(isoLevel); auto intersect = cube.Intersect(isoLevel);

View File

@ -308,12 +308,12 @@ MyMesh fillHoleImplicit(MyMesh &mesh, Hole_Filling &hf,
for (HalfedgeHandle hh : hole) { for (HalfedgeHandle hh : hole) {
verts.push_back(mesh.to_vertex_handle(hh)); verts.push_back(mesh.to_vertex_handle(hh));
} }
auto bb = hf.estimate_BB(verts) ;
verts = hf.next_neighbors(verts); verts = hf.next_neighbors(verts);
auto [system, pts_list] = hf.compute_approx_mat(verts); auto [system, pts_list] = hf.compute_approx_mat(verts);
auto [alpha, beta] = hf.solve_approx(system, pts_list.size(), 10); auto [alpha, beta] = hf.solve_approx(system, pts_list.size(), 10);
Implicit_RBF rbf(alpha, beta, pts_list); Implicit_RBF rbf(alpha, beta, pts_list);
auto bb = hf.estimate_BB(verts) ;
Mesh filling = hf.poly_n_out(rbf, bb); Mesh filling = hf.poly_n_out(rbf, bb);
MyMesh ret; MyMesh ret;
for (const Vec3 &v : filling.vertices) { for (const Vec3 &v : filling.vertices) {
@ -331,27 +331,11 @@ MyMesh fillHoleImplicit(MyMesh &mesh, Hole_Filling &hf,
std::vector<MyMesh> fillHolesImplicit(MyMesh &mesh, std::vector<MyMesh> fillHolesImplicit(MyMesh &mesh,
float scale, float discr) { float scale, float discr) {
Hole_Filling hf(mesh, scale, discr);
mesh.holes = findHoles(mesh); mesh.holes = findHoles(mesh);
std::vector<MyMesh> fillings; std::vector<MyMesh> fillings;
for (auto hole : mesh.holes) { for (auto hole : mesh.holes) {
Hole_Filling hf(mesh, scale, discr);
fillings.push_back(fillHoleImplicit(mesh, hf, hole)); fillings.push_back(fillHoleImplicit(mesh, hf, hole));
} }
return fillings; return fillings;
// auto sdf = [&](Vec3 const& v) { return v.Norm() - 10.; };
// Rect3 domain {{-10, -10, -10}, {20, 20, 20}};
// auto filling = MarchCube(sdf, domain);
// WriteObjFile(filling, "out.obj");
// MyMesh ret;
// for (const Vec3 &v : filling.vertices) {
// VertexHandle vh = ret.new_vertex({v.x, v.y, v.z});
// ret.set_color(vh, ret.default_color);
// }
// for (const Triangle &t : filling.triangles) {
// ret.add_face(ret.vertex_handle(t[0]),
// ret.vertex_handle(t[1]),
// ret.vertex_handle(t[2]));
// }
// return {ret};
} }

View File

@ -25,6 +25,8 @@ static MeshProcessor *create_mesh_processor(const QString &path,
mesh_processor, &MeshProcessor::setImplicitHoleFillingScale); mesh_processor, &MeshProcessor::setImplicitHoleFillingScale);
QObject::connect(&main_window, &MainWindow::fillHolesImplicitDiscrChanged, QObject::connect(&main_window, &MainWindow::fillHolesImplicitDiscrChanged,
mesh_processor, &MeshProcessor::setImplicitHoleFillingDiscr); mesh_processor, &MeshProcessor::setImplicitHoleFillingDiscr);
QObject::connect(&main_window, &MainWindow::filterNoiseClicked,
mesh_processor, &MeshProcessor::removeNoise);
return mesh_processor; return mesh_processor;
} }

View File

@ -9,6 +9,7 @@
#include <QPushButton> #include <QPushButton>
#include <QSlider> #include <QSlider>
#include <QLabel> #include <QLabel>
#include <qnamespace.h>
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
@ -113,4 +114,19 @@ MainWindow::MainWindow(QWidget *parent)
this, &MainWindow::patchViewToggled); this, &MainWindow::patchViewToggled);
curvature_layout->addWidget(patch_mode); curvature_layout->addWidget(patch_mode);
toolbar.addWidget(curvature_box); toolbar.addWidget(curvature_box);
// Noise cleaning
QGroupBox *noise_box = new QGroupBox("Élagage");
QLayout *noise_layout = new QVBoxLayout();
noise_box->setLayout(noise_layout);
QSlider *noise_slider = new QSlider(Qt::Horizontal);
QPushButton *noise_button = new QPushButton("Élaguer");
connect(noise_button, &QPushButton::clicked,
[=]() {
emit filterNoiseClicked(noise_slider->value());
});
noise_layout->addWidget(noise_slider);
noise_layout->addWidget(noise_button);
toolbar.addWidget(noise_box);
} }

View File

@ -32,6 +32,7 @@ signals:
void smoothUniformClicked(); void smoothUniformClicked();
void smoothCotangentClicked(double factor); void smoothCotangentClicked(double factor);
void patchViewToggled(bool checked); void patchViewToggled(bool checked);
void filterNoiseClicked(int value);
public: public:
MeshViewer mesh_viewer; MeshViewer mesh_viewer;

View File

@ -4,6 +4,7 @@
#include "hole_filling.h" #include "hole_filling.h"
#include "smoothing.h" #include "smoothing.h"
#include "curvature.h" #include "curvature.h"
#include "noise_removal.h"
#include <QGenericMatrix> #include <QGenericMatrix>
#include <unordered_set> #include <unordered_set>
@ -131,3 +132,12 @@ void MeshProcessor::click(QVector3D position) {
mesh_viewer.addMesh(patch); mesh_viewer.addMesh(patch);
mesh_viewer.updateForReal(); mesh_viewer.updateForReal();
} }
void MeshProcessor::removeNoise(int value) {
std::cout << value << std::endl;
::remove_noise(mesh, value);
mesh_viewer.removeMesh(mesh);
mesh_viewer.addMesh(mesh);
mesh_viewer.updateForReal();
}

View File

@ -38,6 +38,7 @@ public slots:
void smoothUniform(); void smoothUniform();
void setPatchView(bool on); void setPatchView(bool on);
void click(QVector3D position); void click(QVector3D position);
void removeNoise(int value);
}; };

View File

@ -15,7 +15,7 @@
#define WIREFRAME_COLOR 0, 0, 0 #define WIREFRAME_COLOR 0, 0, 0
#define FOV 70 #define FOV 40
using namespace OpenMesh; using namespace OpenMesh;

View File

@ -14,9 +14,10 @@ struct MyTraits : public OpenMesh::DefaultTraits {
using Point = Eigen::Vector3<qreal>; using Point = Eigen::Vector3<qreal>;
using Normal = Eigen::Vector3<qreal>; using Normal = Eigen::Vector3<qreal>;
using Color = Eigen::Vector3<qreal>; using Color = Eigen::Vector3<qreal>;
VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Color); VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Color | OpenMesh::Attributes::Status);
EdgeAttributes(OpenMesh::Attributes::Status);
HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge); HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge);
FaceAttributes(OpenMesh::Attributes::Normal); FaceAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status);
// EdgeAttributes(OpenMesh::Attributes::Color); // EdgeAttributes(OpenMesh::Attributes::Color);
}; };

15
src/noise_removal.cpp Normal file
View File

@ -0,0 +1,15 @@
#include "noise_removal.h"
#include "util.h"
void remove_noise(MyMesh &mesh, unsigned threshold) {
auto components = find_connected_components(mesh);
for (auto component : components) {
if (component.size() < threshold) {
for (VertexHandle vh : component) {
mesh.delete_vertex(vh);
}
}
}
mesh.garbage_collection();
}

10
src/noise_removal.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef NOISE_REMOVAL_H
#define NOISE_REMOVAL_H
#include "my_mesh.h"
void remove_noise(MyMesh &mesh, unsigned threshold=20);
#endif

View File

@ -132,7 +132,7 @@ void smooth(MyMesh &mesh, SmoothingMethod method, double cotan_factor) {
laplacian = laplacian_matrix(mesh, uniform_weight, uniform_mass); laplacian = laplacian_matrix(mesh, uniform_weight, uniform_mass);
} }
laplacian = laplacian * laplacian; // Mise au carré. // laplacian = laplacian * laplacian; // Mise au carré.
// Transfert des coordonées de chaque point dans une matrice. // Transfert des coordonées de chaque point dans une matrice.
size_t n_verts = mesh.n_vertices(); size_t n_verts = mesh.n_vertices();

View File

@ -1,5 +1,8 @@
#include "util.h" #include "util.h"
#include <stack>
#include <OpenMesh/Core/Utils/PropertyManager.hh>
QDebug operator<<(QDebug dbg, const Point &p) { QDebug operator<<(QDebug dbg, const Point &p) {
return dbg << p[0] << p[1] << p[2]; return dbg << p[0] << p[1] << p[2];
@ -9,3 +12,44 @@ QDebug operator<<(QDebug dbg, const Point &p) {
qreal cotan(const qreal x) { qreal cotan(const qreal x) {
return 1. / qTan(x); return 1. / qTan(x);
} }
static void traverse_connected(MyMesh &mesh, std::vector<VertexHandle> &out,
VertexHandle start) {
auto prop =
OpenMesh::makeTemporaryProperty<MyMesh::VertexHandle, bool>(mesh);
for (VertexHandle vh : mesh.vertices()) {
prop[vh] = false;
}
std::stack<VertexHandle> stack;
stack.push(start);
prop[start] = true;
while (!stack.empty()) {
VertexHandle v = stack.top();
stack.pop();
out.emplace_back(v);
for (VertexHandle v2 : mesh.vv_range(v)) {
if (!prop[v2]) {
stack.push(v2);
prop[v2] = true;
}
}
}
}
std::vector<std::vector<VertexHandle>> find_connected_components(
MyMesh &mesh) {
auto prop =
OpenMesh::makeTemporaryProperty<MyMesh::VertexHandle, bool>(mesh);
for (VertexHandle vh : mesh.vertices()) {
prop[vh] = false;
}
std::vector<std::vector<VertexHandle>> connected_components;
for (VertexHandle vh : mesh.vertices()) {
if (prop[vh]) continue;
connected_components.push_back({});
traverse_connected(mesh, connected_components.back(), vh);
}
return connected_components;
}

View File

@ -101,4 +101,8 @@ standard_deviation(const ForwardIt first,
} }
std::vector<std::vector<VertexHandle>> find_connected_components(
MyMesh &mesh);
#endif #endif