Python图像处理:从电子显微镜测量层宽度

3 投票
1 回答
980 浏览
提问于 2025-04-18 11:18

我有一张电子显微镜拍的图片,展示了生物系统中密集和稀疏的层,如下所示。

VDTap.png

图片中间的层是我想要关注的部分,从“re”标签附近开始,向左逐渐变窄。我想要做的是:

1) 统计总共有多少个深色/密集层和浅色/稀疏层

2) 测量每一层的宽度,右下角的黑色刻度条长1微米

我一直在尝试用Python来完成这个任务。如果我提前裁剪图片,只保留几层的部分,比如这里显示的3个深色层和3个浅色层:

test.png

我可以用以下代码来统计层的数量:

import numpy as np
import matplotlib.pyplot as plt
from scipy import ndimage
from PIL import Image

tap = Image.open("VDtap.png").convert('L')
tap_a = np.array(tap)

tap_g = ndimage.gaussian_filter(tap_a, 1)
tap_norm = (tap_g - tap_g.min())/(float(tap_g.max()) - tap_g.min())
tap_norm[tap_norm < 0.5] = 0
tap_norm[tap_norm >= 0.5] = 1

result = 255 - (tap_norm * 255).astype(np.uint8)

tap_labeled, count = ndimage.label(result)

plt.imshow(tap_labeled)
plt.show()

不过,我不太确定怎么把刻度条考虑进去,来测量我已经统计的这些层的宽度。更糟糕的是,当我分析整张图片时,想要包括刻度条,我甚至很难从图片中的其他部分分辨出这些层。

我非常希望能得到一些建议来解决这个问题。谢谢大家。

编辑 1:

到目前为止,我在这个问题上有了一些进展。如果我提前裁剪图片,只保留一部分层,我可以使用以下代码来获取每层的厚度。

import numpy as np
import matplotlib.pyplot as plt
from scipy import ndimage
from PIL import Image
from skimage.measure import regionprops

tap = Image.open("VDtap.png").convert('L')
tap_a = np.array(tap)

tap_g = ndimage.gaussian_filter(tap_a, 1)
tap_norm = (tap_g - tap_g.min())/(float(tap_g.max()) - tap_g.min())
tap_norm[tap_norm < 0.5] = 0
tap_norm[tap_norm >= 0.5] = 1

result = 255 - (tap_norm * 255).astype(np.uint8)

tap_labeled, count = ndimage.label(result)

props = regionprops(tap_labeled)
ds = np.array([])

for i in xrange(len(props)):
    if i==0:
        ds = np.append(ds, props[i].bbox[1] - 0)
    else:
        ds = np.append(ds, props[i].bbox[1] - props[i-1].bbox[3])

    ds = np.append(ds, props[i].bbox[3] - props[i].bbox[1])

基本上,我发现了一个叫做skimage的Python模块,它可以处理标记的图片数组,并返回每个标记对象的边界框的四个坐标;1和[3]的位置给出了边界框的x坐标,所以它们的差值就能得到每层在x方向上的范围。此外,for循环的第一部分(if-else条件)用于获取每个深色层之前的浅色层,因为只有深色层会被ndimage.label标记。

不过,这样还是不太理想。首先,我希望不必提前裁剪图片,因为我打算对很多这样的图片重复这个过程。我考虑过也许可以用某种滤波器来突出层的(大致)周期性,但我不确定是否存在这样的滤波器?其次,上面的代码实际上只给出了每层的相对宽度——我仍然没有找到办法把刻度条结合进来,以便得到实际的宽度。

1 个回答

0

我不想扫你的兴,但我觉得你的问题比你想的要复杂。因为你提到的内容有很多地方需要仔细分析,所以我不能给你一个完整的代码示例。我在几个生物医学实验室工作过,这种工作通常是由人来标记特定的图像点,然后由计算机来计算距离。不过,话说回来,还是应该尝试自动化处理 =D。

对你来说,这个问题看起来是一个简单但繁琐的工作,就是拿出尺子测量几百个点。这听起来很适合计算机,对吧?其实是有点复杂。计算机并不知道如何识别图片中的任何条纹,它必须被明确告知它要找的是什么,这会比较棘手。

识别比例尺

你对所有图片中的比例尺了解多少?它们的竖直和水平条数总是一样吗?它们总是纯黑色的吗?总是只有一根条吗(那字母r的实线呢)?我建议你尝试一下小波变换。想象一下这个函数的二维版本:

(画出这个函数可能会更有帮助) f(x) = 当 |x| > 1 时,值为 0, 当 |x| < 1 且 |x| > 0.5 时,值为 1 当 |x| < 0.5 时,值为 -1

然后,当我们的小波 f(x, y) 在图像上进行卷积时,输出的图像只有在找到黑色比例尺时才会有高值。此外,我设置的长度为1也可以调整,这样也能帮助你找到比例尺。

寻找脊线

我建议先解决上面的问题,因为它看起来更简单,并且为这个问题打下基础。我会为这个问题构建另一个小波,但这只是一个预处理步骤。对于这个小波,我会再次尝试一个二维的0和盒子函数,但这次要尝试匹配三个(或更多)相邻的盒子。此外,除了盒子的高度和宽度参数外,我们还需要一个间距和倾斜角度的参数。你可能不需要非常精确,只要足够接近,让图像的其他部分变黑就可以了。

测量脊线

有很多方法可以做到这一点,但为了简单起见,我们可以用之前的步骤。拿你的三个盒子的小波结果,它应该正好位于中间的脊线上,并报告一个“宽度”,这个宽度是它捕捉到的三个脊线的平均宽度。考虑到宽度变化得很慢,这个结果应该差不多够用了!

祝你好运!

撰写回答