使用 Python 在灰度 CT 图像中隔离头部
Isolating the head in a grayscale CT image using Python
我正在处理包含患者头部以及 'shadows' 金属圆柱体的 CT 图像。
这些 'shadows' 可以出现在下方、左侧或右侧。在上图中,它仅出现在图像的下侧。在下图中,它出现在左右方向。我不知道图像中是否有圆柱体的阴影。我必须以某种方式检测并删除它。然后我可以继续分割出 skull/head.
为了创建一个可重现的示例,我想提供代表图像的 numpy 数组 (128x128),但我不知道如何将它上传到 Whosebug。
如何实现我的 objective?
我尝试使用 ndimage 和 scikit-image 进行分割,但它不起作用。我得到的细分太多了。
12张原始图片
二值化的 12 张图像
剥离的 12 个图像(膨胀、腐蚀 = 0.1、0.1)
红色标注的图片不禁做出了一个长方形的遮罩,将头骨包裹起来,这就是我的终极objective。
请注意,在算法应用过程中,我将无法一张一张地检查图像。
您可以结合使用侵蚀(使用适当的迭代次数)来移除薄细节,然后使用膨胀(也使用适当的迭代次数)将非薄细节恢复到大约原始大小.
在代码中,这看起来像:
import io
import requests
import numpy as np
import scipy as sp
import matplotlib as mpl
import PIL as pil
import scipy.ndimage
import matplotlib.pyplot as plt
# : load the data
url = 'https://i.stack.imgur.com/G4cQO.png'
response = requests.get(url)
img = pil.Image.open(io.BytesIO(response.content)).convert('L')
arr = np.array(img)
mask_arr = arr.astype(bool)
# : strip thin objects
struct = None
n_erosion = 6
n_dilation = 7
strip_arr = sp.ndimage.binary_dilation(
sp.ndimage.binary_erosion(mask_arr, struct, n_erosion),
struct, n_dilation)
plt.imshow(mask_arr, cmap='gray')
plt.imshow(strip_arr, cmap='gray')
plt.imshow(mask_arr ^ strip_arr, cmap='gray')
从这张图片开始 (mask_arr
):
有人会看到这张图片 (strip_arr
):
不同之处在于 (mask_arr ^ strip_arr
):
编辑
(解决评论中提出的问题)
使用不同的输入图像,例如使用低得多的阈值对输入进行二值化,将有助于获得更大且不薄的头部细节,这些细节不会在侵蚀过程中消失。
或者,您可以通过将椭圆拟合到头部来获得更可靠的结果。
而不是 "pure" 图像处理,如上面的 Ander Biguri,我建议可能采用不同的方法(实际上是两种)。
这里的概念是不依赖于纯粹的算法图像处理,而是利用您所拥有的具体情况的知识:
1) 鉴于容器是金属的(如您所述),另一种可能更简单的方法是根据金属框架的特定 HU 编号进行阈值处理。
虽然您将图像显示为简单的灰度图像,但实际上 CT 图像是 16 位图像,当以 256 位灰度表示形式查看时 window 已调平 - 因此上面的图片不是真实的表示图像数据中可用的全部信息,实际上是 16 位。
金属框架的 HU 值可能明显不同于(高于)解剖结构中的任何值。如果是这种情况,那么简单的阈值处理然后减法删除它会更简单。
2) 另一种方法也将基于考虑您所拥有的特定情况的几何形状和属性:
在上面的图像中,您可以在图像中间(按列)向上查看垂直剖面以找到框架的位置 - 该位置是垂直剖面与 HU 的交叉点与框架匹配的值。
从那时起,您可以使用泛洪填充方法(例如 scikit flood_fill)在特定公差范围内找到所有连接点。
这还会为您提供一组与框架匹配的点(蒙版),您可以使用这些点将其从原始图像中删除。
我认为对于您提出的情况,这两种方法中的任何一种都会更快、更可靠。
我正在处理包含患者头部以及 'shadows' 金属圆柱体的 CT 图像。
这些 'shadows' 可以出现在下方、左侧或右侧。在上图中,它仅出现在图像的下侧。在下图中,它出现在左右方向。我不知道图像中是否有圆柱体的阴影。我必须以某种方式检测并删除它。然后我可以继续分割出 skull/head.
为了创建一个可重现的示例,我想提供代表图像的 numpy 数组 (128x128),但我不知道如何将它上传到 Whosebug。
如何实现我的 objective?
我尝试使用 ndimage 和 scikit-image 进行分割,但它不起作用。我得到的细分太多了。
12张原始图片
二值化的 12 张图像
剥离的 12 个图像(膨胀、腐蚀 = 0.1、0.1)
红色标注的图片不禁做出了一个长方形的遮罩,将头骨包裹起来,这就是我的终极objective。
请注意,在算法应用过程中,我将无法一张一张地检查图像。
您可以结合使用侵蚀(使用适当的迭代次数)来移除薄细节,然后使用膨胀(也使用适当的迭代次数)将非薄细节恢复到大约原始大小.
在代码中,这看起来像:
import io
import requests
import numpy as np
import scipy as sp
import matplotlib as mpl
import PIL as pil
import scipy.ndimage
import matplotlib.pyplot as plt
# : load the data
url = 'https://i.stack.imgur.com/G4cQO.png'
response = requests.get(url)
img = pil.Image.open(io.BytesIO(response.content)).convert('L')
arr = np.array(img)
mask_arr = arr.astype(bool)
# : strip thin objects
struct = None
n_erosion = 6
n_dilation = 7
strip_arr = sp.ndimage.binary_dilation(
sp.ndimage.binary_erosion(mask_arr, struct, n_erosion),
struct, n_dilation)
plt.imshow(mask_arr, cmap='gray')
plt.imshow(strip_arr, cmap='gray')
plt.imshow(mask_arr ^ strip_arr, cmap='gray')
从这张图片开始 (mask_arr
):
有人会看到这张图片 (strip_arr
):
不同之处在于 (mask_arr ^ strip_arr
):
编辑
(解决评论中提出的问题)
使用不同的输入图像,例如使用低得多的阈值对输入进行二值化,将有助于获得更大且不薄的头部细节,这些细节不会在侵蚀过程中消失。
或者,您可以通过将椭圆拟合到头部来获得更可靠的结果。
而不是 "pure" 图像处理,如上面的 Ander Biguri,我建议可能采用不同的方法(实际上是两种)。
这里的概念是不依赖于纯粹的算法图像处理,而是利用您所拥有的具体情况的知识:
1) 鉴于容器是金属的(如您所述),另一种可能更简单的方法是根据金属框架的特定 HU 编号进行阈值处理。
虽然您将图像显示为简单的灰度图像,但实际上 CT 图像是 16 位图像,当以 256 位灰度表示形式查看时 window 已调平 - 因此上面的图片不是真实的表示图像数据中可用的全部信息,实际上是 16 位。
金属框架的 HU 值可能明显不同于(高于)解剖结构中的任何值。如果是这种情况,那么简单的阈值处理然后减法删除它会更简单。
2) 另一种方法也将基于考虑您所拥有的特定情况的几何形状和属性:
在上面的图像中,您可以在图像中间(按列)向上查看垂直剖面以找到框架的位置 - 该位置是垂直剖面与 HU 的交叉点与框架匹配的值。
从那时起,您可以使用泛洪填充方法(例如 scikit flood_fill)在特定公差范围内找到所有连接点。
这还会为您提供一组与框架匹配的点(蒙版),您可以使用这些点将其从原始图像中删除。
我认为对于您提出的情况,这两种方法中的任何一种都会更快、更可靠。