1. 整体操作流程

  1. 对生数据进行重新命名和移动
  2. 对crown的生mesh进行watertight处理(包含对齐z轴、watertight检查)
  3. 处理OCC点
  4. 对训练/验证集进行划分
  5. 后续的内容追加

1. 重新组织文件及命名阶段

首先,创建两个文件夹:1. tooth_crown 2. jaw。分别存放义齿和上下颚。3. normal_info。存放边缘线以及一些参数

对于每个分别保存在tooth_crown和jaw的数据,需要简化数字名字,然后再作命名。例如说:0000000 -> 0;0000001 -> 1。用来简化名字的命名。第二,需要将牙齿的编号融入名字,例如说对于0000000文件夹下的tooth_crown_21 会被放在如下的路径:tooth_crown/0_21.obj。对于上下颚就会被放在如下的路径:jaw/0_21.obj。对于normal_info来说就是normal_info/0_boundary_lines_21.json。

该文件的具体内容位于:

https://github.com/Tinysqua/Teeth-Data-Processing/blob/main/organize_dental_files.py

该代码能够保证一对上下颌文件对应多个牙冠的情况。

3. Watertight阶段

3.1. Scale阶段

关键参数:因为mesh_fusion官方代码的限制,只有将mesh限制在-0.5~0.5之间才能正常生成,因此在这一步normalize的目标是0.5。同时能够读取并保存一个scale_info.json的文件,这个文件中key为每个mesh的mesh name。而值为其scale and transformation。保存这个的目的是:1. 后期测试能够返回原始空间 2. 能够对boundary lines进行相同放缩。

具体的代码为:

https://github.com/Tinysqua/my-mesh-fusion/blob/main/1_scale_diy.py

对应的参数在脚本文件当中有:

https://github.com/Tinysqua/my-mesh-fusion/blob/main/scripts/scale.sh
#!/bin/bash
nohup python 1_scale_diy.py --in_dir /ssd_data/shizhen/Aidite_Crown_Dataset_second --out_dir /ssd_data/shizhen/Aidite_Crown_Dataset_scale_second --padding 0.1 > scale_output.log 2>&1 &

其中/ssd_data/shizhen/Aidite_Crown_Dataset_second 就是上个阶段重新命名过程的输出文件夹,/ssd_data/shizhen/Aidite_Crown_Dataset_scale_second就是这个阶段scale完之后的输出文件夹。

3.2 Align阶段

scale之后,还需要将上下颌以及牙冠对齐到z轴上,采用的方法是计算上下颌mesh的接触点,根据这些接触点拟合一个平面,然后将这个平面选择到xy平面上。

具体的代码为:

https://github.com/Tinysqua/Teeth-Data-Processing/blob/main/align_teeth.py

注意更改最下面的三个变量,以及第223行的scale_info_path变量。运行方式为:

nohup python before_water/align_teeth.py > align.log 2>&1 &

该代码会保存对齐后的上下颌以及牙冠,边缘线到指定的文件夹

3.3. Render阶段

N_viewer目前为100

因为在render的阶段读取的方式是用它自己实现的read off函数,因此可能和trimesh writeoff的方式有轴对不上,所以需要手动在render读取之后将z轴和x轴交换:

mesh.vertices[:, [0, 2]] = mesh.vertices[:, [2, 0]]

具体的代码为:

https://github.com/Tinysqua/my-mesh-fusion/blob/main/2_fusion.py

对应的参数在脚本文件当中有:

https://github.com/Tinysqua/my-mesh-fusion/blob/main/scripts/render.sh

3.4. Fusion阶段

分辨率之前是256,但是现在基本都使用512。这是因为256会有圈形纹理,而512没有。但是512得到的mesh面太多了,因此又要引入pymeshlab中的减面减到120000面。

为了保证fusion和render互不影响,现在render和fusion采用两套代码,代码在:

https://github.com/Tinysqua/my-mesh-fusion/blob/main/fusion_diy.py

对应的参数在脚本文件当中有:

https://github.com/Tinysqua/my-mesh-fusion/blob/main/scripts/fusion.sh

3.5 Watertight检查

用上述方法得到的watertight很有可能因为减面而不是watertight,因此引入了两个部分的代码:第一、检查所有的obj文件是否watertight,如果不是watertight尝试修复。第二、对于那些修复也失败了的,采用另一个watertight方法。
首先通过trimesh中的函数检查是否watertight,如果不是,尝试进行初级的修复:包含破洞修复等。如果初级的修复不能完成,则将仍然不是watertight的mesh记录到一个txt文件当中

在得到这些文件之后,采用Dora的watertight方式,也就是直接用marching cubes进行处理,然后得到watertight的mesh。得到后进行减面,然后保存替换原来的mesh。

4. OCC点阶段

注意在scale阶段是0.5倍大小的,因此采样点云的时候需要先乘2,然后再采样,其他地方保持一致。

要开始OCC点生成,需要有一个文件夹里面装着watertight-mesh,另外需要设定一个文件夹装mesh的表面采样,还有一个文件夹装occ点。

具体代码在:

https://github.com/Tinysqua/Teeth-Data-Processing/blob/main/diy_compute_occ_format_points_data.py

当前的不足是:

任务在固定处理300多样本的时候就会自动停止,并且目前找不到是因为什么。我的猜测是其打开虚拟窗口的方案,也就是from pyvirtualdisplay import 的Display自身有自杀时间。或者是打开300个窗口就是Display的极限。

需要注意的点:

Pyglet的版本是2.0.18,尽量保持,会有兼容性问题

5. 训练集/验证集的划分

在得到surface points和对应的OCC点之后,需要在训练集和验证集上进行划分,目前采取的是生成一个train.txt和一个val.txt,并在相应的代码上进行读取。

该部分的具体代码为:

https://github.com/Tinysqua/Teeth-Data-Processing/blob/main/split_crown_names.py

6. 追加操作

由于医院送过来的数据是分段的,因此后面处理的数据需要追加到现有数据集

在经过整个流程后,产生的occ点和surface sample直接move到现有数据集。牙冠的mesh建议是复制过去,或者是干脆不动。主要是方便后面出问题了溯源。新生成的train.txt和val.txt也需要被追加。需要注意的是:一定要保证被追加的txt文件最后一行是空的,也就是多一个回车,否则是不行的。

代码为:

https://github.com/Tinysqua/Teeth-Data-Processing/blob/main/update_txt.py
最后修改:2025 年 07 月 14 日
如果觉得我的文章对你有用,请随意赞赏