1. 整体操作流程
- 对生数据进行重新命名和移动
- 对crown的生mesh进行watertight处理(包含对齐z轴、watertight检查)
- 处理OCC点
- 对训练/验证集进行划分
- 后续的内容追加
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