Compare commits

...

7 Commits

Author SHA1 Message Date
mckay 77c4e0dc37 feat: Add configurable CSV output filename for evaluation results 4 months ago
mckay 5a708af310 docs: preprocess readme 4 months ago
mckay 46eae8e02d fix refactor 4 months ago
mckay 13617025ac director separate 4 months ago
mckay e4b6a7b47f docs:Enhance normalization process in Source.cpp for mesh vertices 5 months ago
mckay 8940f83fcc Add FeatureSampleConfig class for command line configuration parsing 5 months ago
mckay a443756499 Enhance idea.md with new research points and implementation suggestions; add Dockerfile and .gitignore for pre-processing setup 5 months ago
  1. 5
      code/evaluation/evaluation.py
  2. 3
      code/pre_processing/.gitignore
  3. 23
      code/pre_processing/Dockerfile
  4. 94
      code/pre_processing/FeatureSample/FeatureSampleConfig.cpp
  5. 48
      code/pre_processing/FeatureSample/FeatureSampleConfig.h
  6. 189
      code/pre_processing/FeatureSample/Source.cpp
  7. 48
      code/pre_processing/README.md
  8. 18
      idea.md

5
code/evaluation/evaluation.py

@ -30,6 +30,7 @@ parser.add_argument('--pred_path', type=str,
parser.add_argument('--name_list', type=str, default='broken_bullet_name.txt', help='names of models to be evaluated, if you want to evaluate the whole dataset, please set it as all_names.txt')
parser.add_argument('--nsample', type=int, default=50000, help='point batch size')
parser.add_argument('--regen', default = False, action="store_true", help = 'regenerate feature curves')
parser.add_argument('--csv_name', type=str, default='eval_results.csv', help='csv file name')
args = parser.parse_args()
def distance_p2p(points_src, normals_src, points_tgt, normals_tgt):
@ -230,9 +231,9 @@ def compute_all():
# 保存结果
df = pd.DataFrame(results)
df.to_csv('eval_results.csv', index=False)
df.to_csv(args.csv_name, index=False)
logger.info(f"Evaluation completed. Results saved to {os.path.abspath('eval_results.csv')}")
logger.info(f"Evaluation completed. Results saved to {os.path.abspath(args.csv_name)}")
except Exception as e:
logger.error(f"Error in compute_all: {str(e)}")

3
code/pre_processing/.gitignore

@ -0,0 +1,3 @@
training_data/
raw_input/
Bin/

23
code/pre_processing/Dockerfile

@ -0,0 +1,23 @@
# 基础版本
FROM ubuntu:20.04
# 基本设置
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Shanghai
# 安装基础包
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
python3 \
python3-pip \
libboost-all-dev \
git \
vim \
&& rm -rf /var/lib/apt/lists/*
# 工作目录
WORKDIR /app
# 启动终端
CMD ["/bin/bash"]

94
code/pre_processing/FeatureSample/FeatureSampleConfig.cpp

@ -0,0 +1,94 @@
#include "FeatureSampleConfig.h"
#include <iostream>
namespace MeshLib {
FeatureSampleConfig FeatureSampleConfig::FromCommandLine(int argc, char** argv) {
cxxopts::Options options("FeatureSample", "Feature sampling for 3D meshes");
options.add_options()
("i,input", "input mesh (obj/off format)", cxxopts::value<std::string>())
("f,feature", "input feature file (fea format)", cxxopts::value<std::string>())
("p,pointcloud", "input pointcloud", cxxopts::value<std::string>())
("pf", "face of input pointcloud", cxxopts::value<std::string>())
("o,output", "output mesh/points", cxxopts::value<std::string>())
("k,mask", "output mask file", cxxopts::value<std::string>())
("fs", "feature samples", cxxopts::value<int>())
("ns", "non-feature samples", cxxopts::value<int>())
("m,mode", "processing mode", cxxopts::value<int>())
("c,color", "use coloring", cxxopts::value<int>())
("mp", "max patches per cluster", cxxopts::value<int>())
("cot", "use cotangent weight", cxxopts::value<int>())
("s,sigma", "position noise sigma", cxxopts::value<double>())
("sn", "normal noise sigma", cxxopts::value<double>())
("csg", "generate csg tree", cxxopts::value<int>())
("convex", "is first layer convex", cxxopts::value<int>())
("r,repairturn", "repair turn vertex", cxxopts::value<int>())
("verbose", "verbose level", cxxopts::value<int>())
("strict", "strict mode")
("repairtree", "repair tree feature")
("h,help", "print help");
auto result = options.parse(argc, argv);
if (result.count("help")) {
std::cout << options.help() << std::endl;
exit(0);
}
FeatureSampleConfig config;
// 检查必需参数
if (!result.count("m") || !result.count("i") || !result.count("o")) {
throw std::runtime_error("Missing required parameters");
}
// 设置文件路径
config.files.input_mesh = result["i"].as<std::string>();
config.files.output_file = result["o"].as<std::string>();
if (result.count("f")) config.files.input_feature = result["f"].as<std::string>();
if (result.count("p")) config.files.input_pointcloud = result["p"].as<std::string>();
if (result.count("pf")) config.files.input_pointcloud_face = result["pf"].as<std::string>();
if (result.count("k")) config.files.output_mask = result["k"].as<std::string>();
// 设置采样参数
if (result.count("fs")) config.sampling.feature_samples = result["fs"].as<int>();
if (result.count("ns")) config.sampling.nonfeature_samples = result["ns"].as<int>();
if (result.count("s")) config.sampling.sigma = result["s"].as<double>();
if (result.count("sn")) config.sampling.sigma_normal = result["sn"].as<double>();
if (result.count("cot")) config.sampling.use_cotweight = result["cot"].as<int>();
// 设置处理选项
config.processing.mode = result["m"].as<int>();
if (result.count("c")) config.processing.use_color = result["c"].as<int>();
if (result.count("mp")) config.processing.max_patches = result["mp"].as<int>();
if (result.count("csg")) config.processing.generate_csg = result["csg"].as<int>();
if (result.count("convex")) config.processing.is_convex = result["convex"].as<int>();
if (result.count("r")) config.processing.repair_turn = result["r"].as<int>();
if (result.count("verbose")) config.processing.verbose = result["verbose"].as<int>();
if (result.count("strict")) config.processing.strict_mode = true;
if (result.count("repairtree")) config.processing.repair_tree = true;
return config;
}
bool FeatureSampleConfig::Validate() const {
// 检查文件路径
if (files.input_mesh.empty() || files.output_file.empty()) {
return false;
}
// 检查采样参数
if (sampling.feature_samples < 0 || sampling.nonfeature_samples < 0) {
return false;
}
// 检查处理模式
if (processing.mode != 0 && processing.mode != 1) {
return false;
}
return true;
}
} // namespace MeshLib

48
code/pre_processing/FeatureSample/FeatureSampleConfig.h

@ -0,0 +1,48 @@
#pragma once
#include <string>
#include "cxxopts.hpp"
namespace MeshLib {
class FeatureSampleConfig {
public:
// 文件路径
struct FilePaths {
std::string input_mesh; // 输入网格文件
std::string input_feature; // 输入特征文件
std::string input_pointcloud; // 输入点云文件
std::string input_pointcloud_face; // 输入点云面片文件
std::string output_file; // 输出文件
std::string output_mask; // 输出掩码文件
} files;
// 采样参数
struct SamplingParams {
int feature_samples = 10000; // 特征边采样点数
int nonfeature_samples = 40000; // 非特征面采样点数
double sigma = 0.0; // 位置噪声标准差
double sigma_normal = 0.0; // 法向噪声标准差
bool use_cotweight = false; // 是否使用余切权重
} sampling;
// 处理选项
struct ProcessingOptions {
int mode = 1; // 处理模式 (0:标准化, 1:特征采样)
bool use_color = false; // 是否使用颜色
int max_patches = -1; // 每个颜色簇的最大面片数
bool generate_csg = false; // 是否生成CSG树
bool is_convex = false; // 第一层是否为凸的
bool repair_turn = true; // 是否修复转角顶点
bool repair_tree = false; // 是否修复树特征
bool strict_mode = false; // 是否使用严格模式
int verbose = 0; // 详细输出级别
} processing;
// 从命令行参数解析配置
static FeatureSampleConfig FromCommandLine(int argc, char** argv);
// 验证配置是否有效
bool Validate() const;
};
} // namespace MeshLib

189
code/pre_processing/FeatureSample/Source.cpp

@ -10,6 +10,7 @@
#include "helper.h"
#include "happly.h"
#include "Tree.h"
#include "FeatureSampleConfig.h"
using namespace MeshLib;
@ -115,65 +116,31 @@ int check_mesh_edge_convex(Mesh3d* m, HE_edge<double>* he)
return res;
}
void normalize_mesh(Mesh3d& mesh, std::string outputfile);
int generate_feature_sample(Mesh3d& mesh,std::string inputfile, std::string outputfile, FeatureSampleConfig& config);
int main(int argc, char** argv)
{
try
{
cxxopts::Options options("FeaturedModelPointSample", "Point Sampling program for featured CAD models (author: Haoxiang Guo, Email: guohaoxiangxiang@gmail.com)");
options
.positional_help("[optional args]")
.show_positional_help()
.allow_unrecognised_options()
.add_options()
("i,input", "input mesh (obj/off format)", cxxopts::value<std::string>())
("f,feature", "input feature file (fea format)", cxxopts::value<std::string>())
("p,pointcloud", "input pointcloud", cxxopts::value<std::string>())
("pf", "face of input pointcloud", cxxopts::value<std::string>())
("o,output", "output mesh/points (obj/off/points/xyz format)", cxxopts::value<std::string>())
("k,mask", "output mask file (txt format)", cxxopts::value<std::string>())
("fs", "number of samples on feature edges(default: 10000)", cxxopts::value<int>())
("ns", "number of samples on non-feature faces(default: 40000)", cxxopts::value<int>())
("m,mode", "processing mode: 0 for normalization and 1 for feature sample", cxxopts::value<int>())
("c,color", "whether coloring is used, 0: not used, 1: used, default: 0", cxxopts::value<int>())
("mp", "maximum number of patches in each colored cluster, only work for csg, default -1(no upper bound)", cxxopts::value<int>())
("cot", "whether cotangent weight is used for sampling, 0: not used, 1: used, default: 0", cxxopts::value<int>())
("s,sigma", "sigma for noisy points position, default 0.0", cxxopts::value<double>())
("sn", "sigma for noisy points normal in degrees, default 0.0", cxxopts::value<double>())
("csg", "whether generating csg tree for model, default: 0", cxxopts::value<int>())
("convex", "whether the first layer is convex, default: 0", cxxopts::value<int>())
("r,repairturn", "whether the turn vertex are repaired, default: 1", cxxopts::value<int>())
("verbose", "verbose setting, default: 0", cxxopts::value<int>())
("strict", "treat all edges as either strictly convex or concave")
("repairtree", "repair tree feature")
("h,help", "print help");
auto result = options.parse(argc, argv);
if (result.count("help"))
{
std::cout << options.help({ "", "Group" }) << std::endl;
exit(0);
}
int n_nonfeature_sample = 50000;
int n_feature_sample = 0;
int min_sample_perpatch = 50;
double sigma = -1.0;
double sigma_n = -1.0;
assert(result.count("m"));
int processing_mode = result["m"].as<int>();
assert(result.count("i") && result.count("o"));
auto& inputfile = result["i"].as<std::string>();
auto& outputfile = result["o"].as<std::string>();
//output pts by colors
int last_dot = (int)outputfile.find_last_of(".");
auto output_prefix = outputfile.substr(0, last_dot);
int flag_csg = 0;
// 解析命令行参数到配置类
auto config = FeatureSampleConfig::FromCommandLine(argc, argv);
bool flag_sample_pts = true; //simply generate mask and csg tree of a given point cloud
if (result.count("p"))
{
flag_sample_pts = false;
// 验证配置
if (!config.Validate()) {
throw std::runtime_error("Invalid configuration");
}
// int n_nonfeature_sample = 50000;
// int n_feature_sample = 0;
// int min_sample_perpatch = 50;
// double sigma = -1.0;
// double sigma_n = -1.0;
int processing_mode = config.processing.mode;
auto& inputfile = config.files.input_mesh;
auto& outputfile = config.files.output_file;
std::string inputext = GetFileExtension(inputfile);
Mesh3d mesh;
@ -182,40 +149,56 @@ int main(int argc, char** argv)
else if (inputext == "off")
mesh.load_off(inputfile.c_str());
std::cout << "verts: " << mesh.get_vertices_list()->size() << " face: " << mesh.get_faces_list()->size() << std::endl;
bool flag_verbose = false;
if (result.count("verbose"))
if (processing_mode == 0)
{
normalize_mesh(mesh, outputfile);
return 1;
}
else if (processing_mode == 1)
{
flag_verbose = (bool)result["verbose"].as<int>();
return generate_feature_sample(mesh, inputfile, outputfile, config);
}
bool flag_strict = false;
if (result.count("strict"))
}
catch (const cxxopts::OptionException& e)
{
flag_strict = true;
std::cout << "error parsing options: " << e.what() << std::endl;
exit(1);
}
return 0;
}
if (processing_mode == 0)
{
void normalize_mesh(Mesh3d& mesh, std::string outputfile)
{
// 网络处理模式
//normalization part begin
//[-0.9, 0.9]^3
std::vector<TinyVector<double, 3>> pts_nl(mesh.get_vertices_list()->size());
// 1. 计算模型的包围盒大小
double max_range = mesh.xmax - mesh.xmin;
max_range = max_range < (mesh.ymax - mesh.ymin) ? (mesh.ymax - mesh.ymin) : max_range;
max_range = max_range < (mesh.zmax - mesh.zmin) ? (mesh.zmax - mesh.zmin) : max_range;
// 2. 计算模型中心点
double xcenter = (mesh.xmin + mesh.xmax) / 2;
double ycenter = (mesh.ymin + mesh.ymax) / 2;
double zcenter = (mesh.zmin + mesh.zmax) / 2;
std::cout << "center " << xcenter << " " << ycenter << " " << zcenter << std::endl;
// 3. 对每个顶点进行规范化
for (size_t i = 0; i < mesh.get_vertices_list()->size(); i++)
{
// 将顶点移动到中心,然后缩放到[-0.9, 0.9]范围
mesh.get_vertices_list()->at(i)->pos[0] = (mesh.get_vertices_list()->at(i)->pos[0] - xcenter) / max_range * 1.8;
mesh.get_vertices_list()->at(i)->pos[1] = (mesh.get_vertices_list()->at(i)->pos[1] - ycenter) / max_range * 1.8;
mesh.get_vertices_list()->at(i)->pos[2] = (mesh.get_vertices_list()->at(i)->pos[2] - zcenter) / max_range * 1.8;
}
//output mesh
// 4. 输出规范化后的网格
std::string outputext = GetFileExtension(outputfile);
if (outputext == "obj")
{
@ -226,38 +209,38 @@ int main(int argc, char** argv)
{
mesh.write_off(outputfile.c_str());
}
return 1;
}
else if (processing_mode == 1)
{
}
int generate_feature_sample(Mesh3d& mesh, std::string inputfile, std::string outputfile, FeatureSampleConfig& config)
{
//first sample feature parts then non-feature parts
//mask:
//feature: 0
//non feature: 1,2,3...indicating coloring
assert(result.count("f") && result.count("k"));
auto& inputfeaturefile = result["f"].as<std::string>();
auto& outputmaskfile = result["k"].as<std::string>();
if (result.count("fs"))
n_feature_sample = result["fs"].as<int>();
if (result.count("ns"))
n_nonfeature_sample = result["ns"].as<int>();
if (result.count("s"))
sigma = result["s"].as<double>();
if (result.count("sn"))
sigma_n = result["sn"].as<double>();
bool flag_repair_turn_features = true;
if (result.count("r"))
flag_repair_turn_features = result["r"].as<int>();
bool flag_repair_tree_features = false;
if (result.count("repairtree"))
{
flag_repair_tree_features = true;
}
assert(!config.files.input_feature.empty() && !config.files.output_mask.empty());
auto& inputfeaturefile = config.files.input_feature;
auto& outputmaskfile = config.files.output_mask;
int n_feature_sample = config.sampling.feature_samples ? config.sampling.feature_samples : 0;
int n_nonfeature_sample = config.sampling.nonfeature_samples ? config.sampling.nonfeature_samples : 50000;
int min_sample_perpatch = 50;
double sigma = config.sampling.sigma ? config.sampling.sigma : -1.0;
double sigma_n = config.sampling.sigma_normal ? config.sampling.sigma_normal : -1.0;
//output pts by colors
int last_dot = (int)outputfile.find_last_of(".");
auto output_prefix = outputfile.substr(0, last_dot);
int flag_csg = 0;
bool flag_sample_pts = false ? config.files.input_pointcloud.empty():true; //simply generate mask and csg tree of a given point cloud
bool flag_verbose = (bool)config.processing.verbose ? config.processing.verbose : false;
bool flag_strict = (bool)config.processing.strict_mode ? config.processing.strict_mode : false;
bool flag_repair_turn_features = config.processing.repair_turn;
bool flag_repair_tree_features = true ?config.processing.repair_tree:false;
if (result.count("csg"))
flag_csg = result["csg"].as<int>();
if (config.processing.generate_csg)
flag_csg = true;
bool flag_skip_hanging_features = false; //not skipping hanging features
std::vector<int> sample_mask;
@ -267,13 +250,14 @@ int main(int argc, char** argv)
std::vector<size_t> sample_pts_tris; //used for assign labels of sample pts
if (!flag_sample_pts)
{
auto& inputpcfile = result["p"].as<std::string>();
// 从点云文件中加载点云数据
auto& inputpcfile = config.files.input_pointcloud;
load_xyz_file(inputpcfile.c_str(), sample_pts, sample_pt_normals);
sample_pts_tris.resize(sample_pts.size(), 0);
if (result.count("pf"))
if (!config.files.input_pointcloud_face.empty())
{
auto& inputpffile = result["pf"].as<std::string>();
auto& inputpffile = config.files.input_pointcloud_face;
std::ifstream ifs(inputpffile);
for (size_t ii = 0; ii < sample_pts.size(); ii++)
@ -285,12 +269,16 @@ int main(int argc, char** argv)
}
else
{
// 如果未提供点云面文件,则从网格中提取顶点和面信息。
//search id by aabb
std::vector<std::array<double, 3>> tri_verts;
std::vector<std::vector<size_t>> tri_faces;
// 从给定的网格 mesh 中提取顶点和面信息。
get_mesh_vert_faces(mesh, tri_verts, tri_faces);
// 将提取的顶点和面信息转换为 Eigen 库的矩阵格式。
Eigen::MatrixXd input_pts(tri_verts.size(), 3);
Eigen::MatrixXi input_faces(tri_faces.size(), 3);
// 将顶点信息从 tri_verts 复制到 input_pts。
for (size_t i = 0; i < tri_verts.size(); i++)
{
for (size_t j = 0; j < 3; j++)
@ -310,6 +298,7 @@ int main(int argc, char** argv)
std::vector<vec3d> closest;
std::vector<double> dist;
// 计算样本点与输入网格之间的最短距离。
compute_shortest_dist_AABB(input_pts, input_faces, sample_pts, closest, dist, sample_pts_tris);
}
@ -635,14 +624,14 @@ int main(int argc, char** argv)
int n_color = cluster_id;
//coloring
bool flag_coloring = false;
if (result.count("c"))
flag_coloring = result["c"].as<int>();
if (config.processing.use_color)
flag_coloring = true;
bool flag_first_convex = false;
if (result.count("convex"))
flag_first_convex = result["convex"].as<int>();
if (config.processing.is_convex)
flag_first_convex = true;
if (flag_coloring && !flag_csg)
{
@ -979,8 +968,8 @@ int main(int argc, char** argv)
if (flag_coloring)
{
int max_patch_per_cluster = -1;
if (result.count("mp"))
max_patch_per_cluster = result["mp"].as<int>();
if (config.processing.max_patches)
max_patch_per_cluster = config.processing.max_patches;
std::vector<size_t> cluster_color(connectivity_v.size(), -1);
n_color = tree_coloring<size_t>(tree, connectivity_v, cluster_color, 0, max_patch_per_cluster) + 1;
for (size_t i = 0; i < face_clusters.size(); i++)
@ -1002,7 +991,7 @@ int main(int argc, char** argv)
//sampling on triangles
std::vector<double> tri_mean_curvature_normalize(tri_verts.size(), 0.0);
if (result.count("cot"))
if (config.sampling.use_cotweight)
{
//compute tri_mean_curvature
std::vector<double> vert_curvature;
@ -1128,13 +1117,5 @@ int main(int argc, char** argv)
outputmask.close();
return 1;
}
}
catch (const cxxopts::OptionException& e)
{
std::cout << "error parsing options: " << e.what() << std::endl;
exit(1);
}
return 0;
}

48
code/pre_processing/README.md

@ -10,11 +10,15 @@ Please first download the prepared ABC dataset from [BaiduYun](https://pan.baidu
**\[Optional\]** If you want to split the models and generate the correponding *.fea files from the raw ABC dataset, please first put the *.yml and *.obj files in folder _abc_data_ (make sure that file in different formats share the same prefix). Install the PyYAML package via:
$ pip install PyYAML
```
$ pip install PyYAML
```
and run:
$ python split_and_gen_fea.py
```
$ python split_and_gen_fea.py
```
You will find the split models and *.fea files in _raw_input_.
@ -22,39 +26,55 @@ You will find the split models and *.fea files in _raw_input_.
Please first install the Boost and eigen3 library:
$ sudo apt install libboost-all-dev
$ sudo apt install libeigen3-dev
```
$ sudo apt install libboost-all-dev
$ sudo apt install libeigen3-dev
```
Then run:
$ cd PATH_TO_NH-REP/code/pre_processing
$ mkdir build && cd build
$ cmake ..
$ make
```
$ cd PATH_TO_NH-REP/code/pre_processing
$ mkdir build && cd build
$ cmake ..
$ make
```
You can generate the training data:
$ cd ..
$ python gen_training_data_yaml.py
```
$ cd ..
$ python gen_training_data_yaml.py
```
The generated training data can be found in _training_data_ folder.
If you do not have a yaml file and want to generate sample points from meshes, you can prepare the *.fea file as sharp feature curves of the meshes, then run:
$ python gen_training_data_mesh.py
```
$ python gen_training_data_mesh.py
```
Please make sure that you set 'in_path' in _gen_training_data_yaml.py_ and _gen_training_data_mesh.py_ as the path containing the *.fea files.
When patch decomposition is conducted (like model 00007974_5), there will be *fixtree.obj and *fixtree.fea in _training_data_, which can be used for generating point samples in later round:
$ python gen_training_data_yaml.py -r
```
$ python gen_training_data_yaml.py -r
```
or
$ python gen_training_data_mesh.py -r
```
$ python gen_training_data_mesh.py -r
```
You can find the generated training data of the decomposed patch in _training_data_repair_. By default we only decompose one patch and it is enough for most models. But if you find *fixtree.obj and *fixtree.fea in _training_data_repair_, that means that more patches need to decomposed. There are two ways to achieve this. First, you can copy _training_data_repair./*fixtree.obj_ and _training_data_repair./*fixtree.fea_ to _training_data_, and re-run 'python gen_training_data_yaml.py -r', until enough patches are decomposed (i.e. *.conf files can be found in _training_data_repair_). Another way is to decompose all patches at once, to achieve this, simple uncomment the following line in _FeatureSample/helper.cpp_:
https://github.com/guohaoxiang/NH-Rep/blob/42ae22bf8fc3f1b4f9f5592443c29aafe86905bd/code/pre_processing/FeatureSample/helper.cpp#L722
After that, rebuild the executable files, and re-run 'python gen_training_data_yaml.py' and 'python gen_training_data_yaml.py -r'. There will be generated training data in _training_data_repair_.
docker build -t brep_pre_processing:v1 .
docker run -it --name brep_processor -v ~/NH-Rep/code/pre_processing:/app brep_pre_processing:v1

18
idea.md

@ -3,29 +3,35 @@
## 1. 数据噪声鲁棒性增强
### 研究问题
现有的方法对数据噪声有一定的鲁棒性,但仍有改进空间。研究如何进一步提高算法对噪声的鲁棒性。
### 创新点
- **噪声建模**:引入更复杂的噪声模型(高斯噪声、椒盐噪声等),测试算法在不同噪声条件下的表现
- **对抗训练**:使用对抗生成网络(GAN)或自监督学习方法,增强模型对噪声的鲁棒性
- **正则化技术**:探索新的正则化方法(平滑损失、总变差正则化等),减少噪声对模型的影响
- **多尺度处理**:结合多尺度分析,处理不同层次的几何细节,提高对局部噪声的鲁棒性
### 预期成果
开发一种更鲁棒的隐式转换方法,能够在存在噪声的情况下保持较高的转换质量。
## 2. 特征保留与细节增强
### 研究问题
虽然现有的方法在保留尖锐特征方面表现出色,但仍然有提升空间。研究如何更好地捕捉和保留B-Rep模型中的细小特征。
### 创新点
- **特征检测改进**:引入更先进的特征检测算法(基于深度学习的边缘检测、曲率估计等)
- **特征增强损失**:设计专门针对特征保留的损失函数(如特征角度误差FAE的加权版本)
- **多分辨率表示**:结合多分辨率表示方法,动态调整特征区域的采样密度
- **后处理优化**:研究等值面提取后的后处理方法,增强特征的清晰度和准确性
### 预期成果
提出一种能够在保持整体几何精度的同时,更好保留尖锐特征和细节的隐式转换方法。
[... 其他部分类似格式 ...]
@ -33,26 +39,30 @@
# 实施建议
1. **选择具体切入点**
- 根据兴趣和资源选择研究重点
- 每个方向都有其独特的挑战和机遇
2. **文献综述**
- 进行广泛的文献综述
- 了解当前研究进展和存在的问题
- 找到研究空白点
3. **实验设计**
- 设计合理的实验方案
- 选择合适的数据集
- 设定评估指标
- 搭建实验环境
4. **代码实现**
- 使用合适的编程工具(Python、PyTorch、TensorFlow等)
- 参考开源项目
- 确保代码原创性
5. **论文撰写**
- 撰写详细的毕业论文
- 包含完整的研究内容
- 突出创新点和贡献
1.15

Loading…
Cancel
Save