PCA+梯度下降提取椎骨对称面算法

这个任务主要工作是确定椎骨的中心对称面,为椎弓根螺钉植入提供参考依据,输入的是.nii.gz的单节椎骨分割mask,大致形态如下:

ITK-SNAP下截取的Mask3D可视化示意图

动态效果:

GIF没进度条,而且不能重播,看了一下WP后台的元素改了之后不能可视化,于是就搞了个视频

这里由于之前我们组已经做过细分的模型(以后有空了聊聊,目前手上有超过1000节椎骨,训练出来的模型效果挺不错的),所以直接用了细分的结果,但是实际上不需要这么细致的分割,只需要单一label的即可。

首先将其导入Open3d,转换为点云,转换代码很简单,直接读取nii后令label值大于0的位置有点即可,效果如下:

转换为点云后的情况

下一步我们就开始考虑对称面的提取问题,常用的算法有PCA,尝试后发现不太能精确的定位到目标位置,这里的原因是椎骨在3d情况下本身就不是绝对对称的,只是在特定的角度才能感觉到它的对称:

PCA结果,可以发现偏差较多

但是这个结果仍具有参考价值,因为可以看到离我们想要的目标比较接近,所以我考虑用它作为我的初始平面参数,再用梯度下降来进一步优化它

就像我在上面说的,整个椎骨并不是完全对称的,所以我们的Loss函数设计也应该考虑这一点,仅从某个面(最好是观察面)来计算它的loss,最后我选择了x方向上的投影来近似我们的观察角度,同时叠加了一个所有投影点到面的距离作为另一个loss,可以发现这两个都是我们想要优化的结果

Loss函数公式如下:

  1. 计算每个点到平面的距离:

$$ \text{Dist} = a \cdot x + b \cdot y + c \cdot z + d $$

  1. 投影点到平面:

$$\mathbf{p}_{\text{proj}} = \mathbf{p} – \text{Dist} \cdot \frac{\mathbf{n}}{\|\mathbf{n}\|}$$

其中,$\mathbf{n} = (a, b, c)$ 是法向量。

  1. 对称性误差:

$$\text{SymmetryError} = |\mathbf{p}_{\text{proj}} + \mathbf{p}_{\text{proj}}^{\text{mirror}}|$$

  1. 损失函数:

$$\text{Loss} = 0.5 \cdot \text{Mean}(\text{SymmetryError}^2) + 0.5 \cdot \text{Max}(\text{SymmetryError}^2)$$

运行后发现Loss稳定下降:

Iteration 0, Loss: 2.363346576690674
Iteration 100, Loss: 2.3457834720611572
Iteration 200, Loss: 2.3296475410461426
Iteration 300, Loss: 2.308844566345215
Iteration 400, Loss: 2.2826530933380127
Iteration 500, Loss: 2.2509853839874268
Iteration 600, Loss: 2.2131195068359375
Iteration 700, Loss: 2.187429904937744
Iteration 800, Loss: 2.1866469383239746
Iteration 900, Loss: 2.186018466949463
....

下面截一下它的优化过程:

1000轮:

2000轮:

3000轮:

5000轮:

10000轮:

可以看到平面最终优化到了我们希望的位置,loss从最开始的2.36优化到了0.05,并且继续运行loss还会持续下降,但是考虑到时间成本,10000轮应该就足够了

发表评论