用 Python 脚本实现 ImageJ 图像的批处理
使用 Imagej 进行图像处理时,常常会遇到存在大量图片,但处理方法相同的情况。如果耗费大量时间用鼠标进行相同的操作,难免会感到无聊,甚至出错。通过编写 ImageJ 的脚本 Script,我们可以实现 ImageJ 的自动化,从而节省时间,“一劳永逸”。
本方法有 3 个步骤:
- 通过 Recorder 记录操作的 Command
- 用自己喜欢的编程语言编写脚本(本例采用 Python 示范)
- 运行脚本
Command Recorder
使用 Command Recorder 能够为后续的脚本编写提供便捷。
Command Recorder 与 Macro 宏
Command Recorder 是在我们操作 ImageJ 时,同时记录下内部指令的软件。据 ImageJ 官方的介绍
Macro 宏 是一个简单的程序,可以自动执行一系列 ImageJ 指令。创建宏的最简单方法是使用 Command Recorder 指令记录器 记录指令系列,并保存为文本文件,这个文本文件即为宏。通过选择菜单命令、按键或单击 ImageJ 工具栏中的图标来执行保存的宏。
为什么不直接使用 Macro 编写脚本?
官方对 ImageJ 宏的特性描述是
ImageJ 宏语言不如其他脚本语言强大,但设计为易于学习和使用。
当你需要更复杂的功能,或与 ImageJ 之外的程序进行交互时,宏就显得不是那么方便了。在此,因为我有一定的 Python 基础,所以我果断地选择了 Python。ImageJ 官方对 Python 的描述是:
Python是科学家的热门选择。您可以在 ImageJ 内部使用其 script editor(/scripting/script-editor)编写 Jython scripts(/scripting/jython)(一种基于 Java 的 Python 2 语言),或者使用 PyImageJ(/scripting/pyimagej) 从 Python 脚本调用 ImageJ 函数。
ImageJ 脚本还支持采用其他语言编写,如 Groovy, JavaScript, Ruby (JRuby), Lisp (Clojure), R (Renjin), Java, MATLAB, BeanShell, Java.
编写脚本
采用 Python 编写 ImageJ 脚本有 2 种方式,官方对其作了比较 Python (imagej.net):
- 在 ImageJ 内部编写、运行,类似于采用其他语言脚本的方法。
- 优点:能够利用 SciJava 脚本参数,并在支持 SciJava 的多个工具中运行。
- 缺点:将无法使用许多需要本地代码(如 numpy 或 scipy)的 Python 模块。
- 缺点:目前仅支持 Python2 - 采用 pyimagej · PyPI 将 ImageJ 嵌入到 Python 代码中。
- 优点:可以将 ImageJ 与其他图像分析库(如 scikit-image,ITK,OpenCV 等)在单个Python 程序中结合使用。
- 缺点:在 Python 中封装 ImageJ 存在一些限制,有一些 ImageJ 的功能无法很好地发挥作用。
本文采用 方案 1 ,因为作者在使用 方案 2 的时候,出现了一些尚未解决的问题(尴尬)。
从哪里开始?
新建一个脚本文件十分简单,仅需 File - New - Script
,若要使用 Python,则在脚本编辑器的菜单中选择 File - New - Script
。
几乎所有的 ImageJ 中的 Python 脚本的头部都包含一行:
from ij import IJ
从Package 包 "ij" 导入Namespace 命名空间 "IJ" 。 命名空间 是一组函数。包是一组命名空间。
关于采用 Python 编写 Script 的更多指南,可以从 Fiji Programming Tutorial (cam.ac.uk) 和 Welcome to Python.org 获取。本文重点在脚本中插件的使用。
如何在 Python 脚本中使用插件?
有 2 种方法在 Python 脚本中使用插件
ij.plugin.<模块名>
- 通过
IJ.run()
直接执行 Macro Command 宏指令
通过 ij.plugin
引入模块
在 Command Finder 中,能够查找到,为实现一个功能,应该引用哪个模块。具体操作如下:
- 打开 Command Finder:
Plugins - Utilities - Find commands...
- 输入与命令相关的关键词,便会找到一系列指令
- 在指令的 "Class" 栏中,列出了实现它的插件类,注意寻找
ij.plugin
打头的
如此一来我们便能实现插件在 Python 脚本中的使用。但还有一点,参数该填什么?
有 2 个方法寻找参数:
- Fiji java documentation ,也能够通过
Tools - Open help for class (with frames)
打开 - 插件存储在网络上的 source code,在搜索引擎中进行搜索
综上,这种方法较为困难。我们需要一种更为直观而简便的方法来编写程序。
通过 IJ.run()
执行宏指令
这种方法较为简单快速,采用 Command Recorder,在用鼠标操作 ImageJ 时,便会记录下宏指令。将宏指令直接粘贴到 IJ.run()
中,即可执行。本例即采用此法。
举例
本例需要批量处理一系列 .ims 格式的荧光显微镜图片,将其 3 个通道分出,再两两不同通道 merge,随后人工观察一些蛋白的 foci,及共定位现象。加黑部分采用 ImageJ 完成。
# 敬告,路径中不可有空格,且输出文件夹不需要预先建立
# 敬告,请使用双反斜杠
from ij import IJ
import os
folder = "D:\\samples" # 打开文件夹
# 限定各通道显示阈值
c_MinMax = {"0": [100, 500],
"1": [100, 500],
"2": [130, 180]}
# 需要合并哪些通道及对应的颜色
c_Merge = {"01": "01", "02": "02", "12": "12"}
os.mkdir(os.path.join(folder, 'out')) # 新建输出文件夹
# 对每张图片进行操作
for i, filename in enumerate(os.listdir(folder)):
if filename[-4:] == '.ims': # 判断是否为 ims 图片文件
img_path = os.path.join(folder, filename) # 图片路径
# 采用 Bio-Formats 读入图片
img_open_attr = "open=" + img_path + " autoscale \
color_mode=Default rois_import=[ROI manager] \
split_channels view=Hyperstack stack_order=XYCZT"
IJ.run("Bio-Formats Importer", img_open_attr)
save_path = os.path.join(folder, 'out', filename) # 新生成图片保存路径
# 保存拆分开各通道的图片
for c in ["0", "1", "2"]:
IJ.selectWindow(filename + " - C=" + c) # 焦点选择该通道读入图片
IJ.run("Brightness/Contrast...") # 打开调整明暗、对比的窗口
IJ.setMinAndMax(c_MinMax[c][0], c_MinMax[c][1]) # 调整明暗对比
IJ.saveAs("PNG", save_path+" - C="+c+".png") # 保存图片
# 保存任意 2 个通道合并的图片
for pic_n in c_Merge.keys():
pic1, pic2 = pic_n[0], pic_n[1]
IJ.run("Merge Channels...", "c1=[%(filename)s - C=%(pic1)s.png] c3=[%(filename)s - C=%(pic2)s.png] create keep"
% {"filename": filename, "pic1": pic1, "pic2": pic2})
IJ.saveAs("PNG", save_path + "Composite_%s.png" % c_Merge[pic_n])
IJ.run("Close")
# 保存 3 个通道全部合并的图片
IJ.run("Merge Channels...", "c1=[%s - C=2.png] c2=[%s - C=1.png] c3=[%s - C=0.png] create keep"
% (filename, filename, filename))
IJ.saveAs("PNG", save_path + "Composite_B_G_R.png")
# 关闭全部窗口
IJ.run("Close All")