此文介绍如何使用aicsimageio模块读取蔡司显微镜成像数据文件,并展示实际处理数据在INPUT阶段的问题。
软件环境
按照官网说明,除了安装aicsimageio模块之外,还需要安装一些东西。目前我测试过可用的python环境和关键模块版本如下:
python: "3.10.14"
aicsimageio: "4.14.0"
aicspylibczi: "3.2.0"
fsspec: "2023.6.0"
这里专门列出来是,是因为发现在我另外一个 python 3.12 的环境中无法使用。其实这也是使用 python 的一个弊端之一,就是python,模块甚至硬件驱动,操作系统之间不同版本的兼容性问题。也正因如此,使用 conda 管理多个虚拟环境,为不同的软件工具单独配置环境变得非常必要。
读取文件列表
from glob import glob
fps = glob("*/*/*.czi")
fps # 在 jupyter notebook 中会显示 fps 列表中的内容
结果如下:
['三色分辨率\\7701\\Snap-2469.czi', '三色分辨率\\97H\\Snap-2467.czi', '三色分辨率\\hepg2\\Snap-2477.czi', '双色分辨率\\7701\\Snap-2451.czi', '双色分辨率\\97h\\97h u1u35a-05 publish.czi', '双色分辨率\\Hepg2\\hepg2 u1u35a-07 publish.czi']
用户提供的数据包,按照其实验设计进行了简单的分组,但是组别名不统一。这种组别名不统一一般是大小写不一致,或者多了少了个把字符。此外一个容易坑人的地方,就是路径中存在中文可能导致某些模块调用时报错。所以我们这里最好能够写一个简单的文件名转换函数,方便后面处理结果的保存。
def new_name(fp):
if fp.startswith("三"):
a = "3"
else:
a = "2"
if "7701" in fp:
b = "7701"
elif "epg" in fp:
b = "hepg2"
elif "97" in fp:
b = "97h"
return a+"_"+b
上述函数仅是通过对已有的文件列表的情况地观察,写的一个不具备通用性的简单函数。如果文件数量更多,或者情况更加复杂,也可以考虑使用其它正则的方式来重命名。当然了,最好是要求数据 provider 自己做好这个事情。
读取czi文件并查看关键信息
provider 说只分析绿色通道的数据,但除了zeiss自家的软件,无论我们是使用 ImageJ 还是 python 打开 czi 文件,都不会直接告诉你哪个通道是其所说的绿色通道。好在这些信息在原始数据中都有详细记录。
如上图所示,当我们使用 AICSImage 打开一个 czi 文件,返回一个 img 对象,可以查看其数据维度情况,可以看到存在三个通道,Frame大小是 400x400,然后可以进一步查看这三个通道的名字,通过名字大概就知道所谓「绿色通道」应该是第二个 「AF488-T2」。基于蔡司显微镜的成像参数设置,不难理解,AF488是用户设置的染料,而T2代表是第二个 Track。此外还有一个属性是必须要查看,这就是所谓的「pixelsize」,通过这个值我们才能知道拍摄区域的真实物理尺寸,然后保持所有数据的 pixelsize 统一。
注意,Dimensions 无单位,仅代表矩阵在不同 axis 上的数值个数;PhysicalPixelSizes 的单位通常是微米。
批量提取指定通道图像并统一scale然后保存
然后我们可以遍历 czi 文件列表,提取所谓的绿色通道,然后通过 Image 模块来进行 resize,使得所有数据的 pixelsize 统一为 0.1。
为什么要把 pixelsize 统一到 0.1 呢?以共聚焦为例,通常极限辨率是 0.2 微米,那么拍摄的时候 pixelsize 可以调整至分辨率的1/2~1/3,但是用户拍摄数据的时候可能并没有注意这一点。pixelsize有时甚至到了 0.3,这会导致采样率不够,使得一些与空间尺寸相关的测量精度变差。
最后使用 skimage 模块将指定通道单独保存为 tif 图像,并按照一致的方式进行规范命名。具体代码如下:
from aicsimageio import AICSImage
from skimage import io
from PIL import Image
import numpy as np
for fp in fps:
img = AICSImage(fp)
green = img.get_image_data("YX", C=1)
# 通过`.channel_names` 属性已经知道 index=1 的通道为 `AF488-T2`
fname = new_name(fp)
# 转换为规范命名用于保存提取的指定通道的图像
print(fname)
green2 = Image.fromarray(green)
# 统一pixelsize到 0.1,对图像进行resize
w = int(img.dims.X * img.physical_pixel_sizes.X / 0.1)
# 默认是正方形的图像, 且xy 方向的 pixelsize一致
green3 = green2.resize((w, w), resample=Image.Resampling.NEAREST)
green4 = np.array(green3)
io.imsave(f"green_{fname}.tif", green4, check_contrast=False)
此处评论已关闭