冠状动脉中心线提取
2018.12.5
1简介
1.1步骤和实现方式
本次任务是从冠状动脉增强图像提取血管中心线。步骤和实现方式大致如下:
•图像二值化:读入.mha格式CT图像,阈值处理;
•空洞填充白色链球菌
•图像细化:类似腐蚀,取最大内切球心的集合
桂花糕怎么做•端点分叉点检测:考虑26邻域内像素个数,卷积实现
•断裂分支重连:寻找连接点,条件判断,Dijkstra最小代价连接
•构建中心线:在分叉点集基础上追踪,数组存储在Cell中
1.2运行说明
coronary_refine.m是主要的运行函数。其他函数和脚本:branchReconnect输入细化后的图像和权重(原始CT volume的像素值为可能性),其中调用了三维的Dijkstra函数;directConnect脚本很简短地实现在三维图像中两点连直线,但因为用了最短路径所以没有采用;其余函数都是由比较冗长的小功能封装成的。两张图片运行时间小于一分钟。
什么的发现
2实现方法
2.1阈值
为了不让阈值化后丢失的成分过多,对后续分支重连的步骤造成困难,这里选择了较小的阈值0.1*原图最大值(2^16)。这也导致最后结果中分支会显得比0.5的阈值下丰富很多,但算法能够原图(mha)保证最终中心线和真实血管走向的一致性。
2.2空洞填充
一开始使用的是imfill函数,通过查看源代码可见这个函数调用了imcomplement和imreconstruct对二值图像进行填充。imfill对三维图像的处理速度较慢,最终使用形态学库函数bwmorph3中的fill功能进行处理。
图1:Skeleton of a rectangle defined in terms of bi-tangent circles.
2.3图像细化
程序中调用了bwskel来实现。Thinning在文献中有两种最为常见的方法,一种被称为“Onion peeling”1,顾名思义用不断的腐蚀操作来一层一层地剥开血管,难点是设置一定的条件来保证原有拓扑结构。这个方法也是bwskel的参考文献中使用的方法。2还有一种细化方法也和腐蚀有些类似,基本思路是求连通域内部的内切圆心(三维为球心)集合,如图一。
口若悬什么
2.4基于卷积的端点分叉点检测
虽然形态学库函数中同样有branch和endpoint的功能,但这两个功能的feature都导致它们并不适合直接使用。比如bwmorph3中branch会返回所有分叉点以及分叉点各自的相邻点。面对如此古怪的feature,不如构造简单的卷积核来求端点分叉点。
•分叉点检测
首先考虑3*3*3全1的卷积核。在二值、细化图像非分叉部分,其响应应该为3。如果将响应大于3的视为分叉,其结果中会有很多处于真正的分叉点附近、实际却为原图空白部分的点被误判成分叉。原因就是分叉附近往往点较为密集,空白点的26邻域内也容易出现多个1,导致超出阈值。解决方法很简单,要让卷积能区分出原中心线上的点和空白格,只要在kernel的中心加大权重,这样空白格的响应和值为1的点差距会变得很大,从而被排除在外。代码如下(因为convolution包含padding,最终结果还需删除padding部分):
1A Sequential3D Thinning Algorithm and Its Medical Applications
2Ta-Chih Lee,Rangasami L.Kashyap and Chong-Nam Chu Building skeleton models via3-D medial surface/axis thinning algorithms. Computer Vision,Graphics,and Image Processing,56(6):462-478,1994.
女生八块腹肌
冷图片
图2:Convolution-bad branch detection
kernel=ones(3,3,3);
抹茶戚风a(2,2,2)=2;
branch=convn(kernel,sk)>=5;
•端点检测
类似地如果考虑3*3*3全1的卷积核,按照直觉,末端的响应应该为2。然而在和中心线平行的空白邻域内也有大量的点响应为2,导致结果一眼看上去是原细化图像的”壳“。解决方法同样是加大kernel中心点的权重,记为w,周围不变;那么响应为w+1的就可以确定是端点。
美味的英语怎么说因为检测都是基于卷积,以convn等函数的优化程度,其总运行时间也不过1-2秒,相比遍历轻便许多。下面以branch为例考察其结果,图中分叉处标红。
可以看到几何位置正确且没有遗漏。实际上,如果使用bwmorph3的branch库函数,二者结果粗看完全相同。关于分支点检测,看文献时常有一些八仙过海各显神通的操作,比如图3中这种用球体沿着中心线切血管表面再取球心的方法:
2.5断裂分支重连
代码在branchReconnect函数中。
重连的问题可以描述成将图片中小的片段连接到coronary artery的端点或主干上,并丢弃CT图中原有的noi和artifacts。可见所有待连接线至少有一端是在endpoints集合中的。于是重连的基本思路就是遍历细化图像的所有endpoints,寻找其周围空间内和自己不在一个连通域的点,对其中条件适当的点予
以连接。
图3:branch detection
2.5.1最小代价路径
代码在DijkstraConnect中。因为原.mha volume实际上是可能性矩阵,那么将其归一化后用1减(相当于取反),就得到了cost(penalty)三维数组。这里权重非负,求最短路径的算法是Dijkstra。matlab中有graph相关库函数,但在三维volume中实现这样的搜索仍然比较繁琐,因为待搜索的图的边数为O(n3),其中n为边长(以正方体为例)。同时为了减小计算复杂度,在上一步获得了始末点之后,把路径搜索的区域先缩小到始末点之间的长方体再进行搜索。
2.5.2连接条件
在获得了路径后,还需进行一定的判断才能将刚画出来的路径安置到原图,这是为了避免错误连接的出现。判断路径是否合理本程序采用了两个约束。一是路径上每个点的平均代价,当代价超过某个阈值时,这条路径很可能是被Dijkstra强行撮合,强扭的瓜不甜。二是禁止血管的”方向发生突变“,这里计算两个向量的夹角:1出发点向外延长线的方向向量2从出发点到目标点的向量。这里完全没有将目标点处的方向纳入考虑,因为血管几乎可以从任何角度搭接到主动脉上,所以如果使用了这个角度,反而会让一些该连的线被丢弃。此外,放弃连接的条件是以上两个条件相与,也就是当方向特别流畅或者代价特别小的时候,仍然允许连接。用两重条件也增强了鲁棒性。
若无约束,可能出现的极端情况:
图4:Minimum cost reconstruction
连接效果(红色部分):
2.6构建中心线:
代码在coronary_refine 中。这里为了分开各分支,并保持点的有序性,只能在骨架上进行遍历,这里采用的是类似深度优先的实现方式(但因为没有代价、权重等考虑,简单许多)。主要的思路是:维护一个clod 表,记录所有已经搜索过的位置;每次搜索从分叉点开始,到无法找到新邻居结束,搜索的同时构建branch 。