我知道编辑这个网站吗?
the original version of ImageJ本页介绍与 the original version of ImageJ 相关的内容。点击徽标查看详情。

JRuby 脚本

JRuby是一个不起眼的项目,它创建了在 JVM 中运行的 Ruby 的完整实现。JRuby 作者的出色工作使我们可以非常简单地将 JRuby 脚本添加到 ImageJ 中。

ImageJ 中的 JRuby 脚本是使用 ImageJ 的第 macro language 脚本的一个很好的替代方案。它具有以下优点:

  • 您不必学习新语言来编写 ImageJ 脚本(假设您了解 Ruby)
  • 您不限于使用宏语言公开的功能:您可以使用 ImageJ 中的任何类、其插件之一或标准 Java 类
  • 与用Java开发插件相比,开发JRuby脚本非常快

These advantages, of course, are shared by all the scripting languages available in ImageJ2, including Jython, Clojure, BeanShell and JavaScript.

如果您对 ImageJ 中的 JRuby 脚本有任何疑问或建议,请联系Image.sc Forum。玩得开心!

教程

让我们立即开始编写一些 JRuby — 通过转到 FileOpen SamplesT1 Head (2.4M, 16-bits) 启动解释器。将弹出解释器窗口,但 JRuby 运行时可能需要一些时间才能准备好。您首先应该看到以下消息:

Starting JRuby ...

…当它准备好时,该行:

Done.

现在您可以开始在该窗口中输入 Ruby 表达式,例如:

>>> "hello there".upcase[1..4]
ELLO

快速浏览一下第 Scripting Help 上页以获取有关使用此解释器窗口的提示是个好主意。

尝试通过转到PluginsScriptingJRuby Interpreter加载ImageJ示例图像之一。完成后,我们将使用JRuby检查图像。您可以使用ij.IJ.getImage获取对当前图像的引用。尝试将结果分配给变量,如下所示:

>>> i = ij.IJ.getImage
imp[t1-head.tif 256x256x129]

现在我们可以像这样查找堆栈的宽度和深度:

>>> w = i.getWidth
256
>>> d = i.getStackSize
129

您可能想要对图像执行的许多操作都可以通过与切片关联的图像处理器来实现。例如,想要获取当前切片,请执行以下操作:

i.getProcessor.invert

这实际上不会在图像上产生可见的效果,除非你在图像上调用i.updateAndDraw

i.updateAndDraw

如果您现在滚动浏览堆栈,应该会发现其中一个切片是您的食材。

姓名注意事项

如果你习惯了Java和ImageJ API,你可能会发现上面的§§0§§§的使用有点可疑。ij是Java包名称,IJ是该包中的类名称,getImage是该类中的静态方法,它返回对表示当前图像的ImagePlus对象的引用,如果没有,则返回null。这是如何运行的?我们在ImageJ中设置了JRuby解释器,以便如果找不到方法或类名称,将会在 ij.* 包中查找相应的类或方法名称。情况默认下,JRuby 对 java.* 类执行此操作,因此例如以下消耗显式包含 java.util.Random 类:

>>> rng = java.util.Random.new
java.util.Random@bf9a12
>>> rng.nextInt 1024
603
>>> rng.nextInt 1024
94

请注意,这是在 JRuby 中创建对象的示例;您使用 Ruby 的常用 Something.new 语法,但它标准创建 Java 类的对象。希望您会想“太棒了!”或当前阶段类似的事情……

导入类

如果您需要使用不在 java.*ij.* 层次结构中的类,或者如果您正在 Script EditorImageJ2 中开发 JRuby 脚本,则必须显式包含它们。要从 JRuby 中引用 Java 类,您需要导入它们。

与原始 ImageJ 不同,ImageJ2(因此也包括 Fiji)不会自动导入任何类。因此,为 ImageJ 编写的脚本如果不添加正确的导入,将无法在 ImageJ2 中运行。原因是自动导入功能并不安全。如果两个同名类位于两个不同的包中怎么办?或者引入了一个新类,使原本唯一的名称产生歧义怎么办?突然间,所有引用原始类的脚本都不再工作。简而言之:自动导入存在危险的精确性问题。


例如,在 Fiji 的类路径中,有一个名为 util.BatchOpener, 的有用类,它具有用于将文件作为 ImagePlus 对象读取(每个通道一个)打开的静态方法,而不是显示它们。要使用这些方法,您必须执行以下操作:

>>> java_import 'util.BatchOpener'
util.BatchOpener

然后,您可以执行以下操作:

>>> a = BatchOpener.open "/home/mark/confocal/test.lsm"
[Lij.ImagePlus;@b1406b
>>> a.length
2
>>> a[0].getTitle
C1-test.lsm
>>> a[1].getTitle
C2-test.lsm
>>> a[1].show

示例:生成等离子云

在第一个示例中,我们将创建一个小脚本来创建分形“等离子云”图像。我们将开始在解释器中进行实验,以确保我们拥有创建正确图像的代码。为了首先创建 RGB,我们创建一个 ColorProcessor,然后创建一个 ImagePlus

>>> w = 800
800
>>> h = 600
600
>>> cp = ij.process.ColorProcessor.new(w,h)
ip[width=800, height=600, min=0.0, max=255.0]
>>> i = ij.ImagePlus.new "Plasma Cloud", cp
imp[Plasma Cloud 800x600x1]

…现展示:

>>> i.show

我们将直接操作像素数组,因此值得检查这是否可以正常工作。这里我们尝试将图像的一半设置为绿色:

>>> i
imp[Plasma Cloud 800x600x1]
>>> pixels = cp.getPixels
[I@e038c4
>>> 0.upto( w * (h / 2) - 1) { |j| pixels[j] = 0x0000FF00 }
0
>>> i.updateAndDraw

希望这一切顺利。这里指定的颜色值采用 ARGB 格式。您可能已经注意到,这一步相当缓慢 - JRuby 在 Ruby 和 Java 之间的透明访问涉及相当多的魔力,这必然会带来性能成本。但是,如果您的目标不是提高脚本的执行速度,而是不需要快速地获得可速度的脚本,那么 JRuby 脚本工作很可能是您的最佳工具。

(顺便说一句,有时甚至可以在 ruby​​ 中使用 java 的优化。替换

0.upto( w * (h / 2) - 1) { |j| pixels[j] = 0x0000FF00 }

java.util.Arrays.fill(pixels, 0, w*h/2 - 1, 0x0000FF00)

并获得免费的240倍加速。)

在此阶段,您可以切换到文本编辑器并在 Fiji 插件目录中创建一个名为“.rb”的扩展,并且名称中包含下划线的脚本。您应该在 plugins/Examples 中找到一个示例 Plasma_Cloud.rb 脚本,它基于我们上面计算出的基础知识。该脚本的输出如下所示:

Example "Plasma Cloud" image

示例:大规模转换文件格式

这是一个简短的示例脚本,展示了如何使用 JRuby 和我上面提到的第 §§2§§§ 方法将 LSM 文件目录转换为 BioRad .PIC 格式方便。这硬只是编码文件系统中的路径,因此如果您想做类似的事情,则需要进行编辑。尽管如此,希望这具有启发性:使用 JRuby 过滤文件名等通常比使用 ImageJ 宏语言替代:

input_directory  = "/home/mark/lsm-examples/"
output_directory = "/home/mark/lsm-examples/biorad/"

include_class 'util.BatchOpener'
include_class 'Biorad_Writer'

# Check that the input directory exists:
unless FileTest.directory? input_directory
  ij.IJ.error "Input directory '#{input_directory} was not found"
  exit(-1)
end

# Create the output directory if it doesn't exist:
unless FileTest.exist? output_directory
  Dir.mkdir output_directory
end

# Biorad filenames have a standard format, which we generate with
# this function.  ('channel' should be 1-indexed):
def make_biorad_filename(lsm_filename,channel)
  lsm_filename.gsub(/.lsm$/,sprintf("%02d.pic",channel))
end

Dir.entries(input_directory).each do |e|
  # Skip anything that doesn't have a '.lsm' extension:
  next unless e =~ /\.lsm$/
  puts "Converting: #{e}"
  # Open the image file to an array of ImagePlus objects:
  a = BatchOpener.open("#{input_directory}#{e}")
  # Create the writer plugin object:
  writer = Biorad_Writer.new
  # Now, for each channel in the input image, write out
  index = 0
  a.each do |image|
    # The Biorad_Writer doesn't like COLOR_256 images, so convert to
    # GRAY8:
    ij.process.StackConverter.new(image).convertToGray8
    biorad_filename = make_biorad_filename e, index + 1
    puts "    Writing: #{biorad_filename}"
    writer.save image, output_directory, biorad_filename
    index += 1
    image.close
  end
end
  
ij.IJ.showMessage("Finished converting to Biorad format!")

将 ImageJ 宏转换为 JRuby

为了帮助将现有的 ImageJ 宏移植到 JRuby,我开始将类似命名的 JRuby 函数实现为标准 ImageJ 宏。这些已使用惯用的 Ruby 函数名称以及“小驼峰式”定义风格的 ImageJ 宏名称进行,因此您可以使用以下任何方法来代替上面使用的 image = ij.IJ.getImage

image = getImage

或者:

image = get_image

run方法对于调用现有的 ImageJ 插件和命令也可能特别有用。下面有一个使用此功能的示例。将 ImageJ 分发中的 “Blobs Demo” macrocan be found here 进行比较可能会有所了解。JRuby 中类似函数的使用并不相同的,例如,如果您比较 getSelectionCoordinates, 的调用,您会发现 ImageJ 宏版本输入输出数据:

getSelectionCoordinates(xCoordinates, yCoordinates);

… JRuby版本可以返回多个仓库:

x_coordinates, y_coordinates = get_selection_coordinates

给感兴趣的程序员的提示:其中,大部分已经完成了 15% 的宏函数,如果有人愿意帮忙完成剩余的部分,那就太好了!源代码a version ported to JRuby

示例:生成红色/青色浮雕

此示例脚本可以在斐济的 §§4§§§ 文件夹中找到。将获取图像堆栈并填充生成图像,该图像在通过红色和青色眼镜观看时应为 3D。所做的就是从两个不同的角度进行两个最大强度投影将它们合并在一起。这是一个很好的例子,所有工作都是由现有的 ImageJ 命令完成的。如果显示您查看该脚本,您会发现步骤正在运行“3D 项目…”,包含其中一些简单复杂的选项:

projection_options = "projection=[Brightest Point] axis=Y-Axis "
projection_options += "initial=-#{degree_separation / 2} "
projection_options += "total=#{degree_separation} "
projection_options += "rotation=#{degree_separation} "
projection_options += "interpolate"

run "3D Project...", projection_options

总的来说,弄清楚这些选项应该是什么的最佳方法是使用 PluginsMacrosRecord… 启动宏记录器并运行插件。在这种情况下,宏记录器中的输出如下所示:

run("3D Project...", "projection=[Brightest Point] axis=Y-Axis slice=1.20 initial=-2 total=4
              rotation=4 lower=1 upper=255 opacity=0 surface=100 interior=50 interpolate");

希望我如何从该输出中导出脚本中的第§§3§§§字符串应该是延续的。脚本的下一部分会分割该命令生成的超堆栈,并将其与适当的颜色合并。同样,这可以在宏记录器的帮助下解决,最后要点是必须预测每一步输出的图像的名称。脚本本身还有更多有用的注释。

一些示例输出:

Example anaglyph image

脚本参数

This section describes features specific to ImageJ2, which are not available in the original ImageJ.

当使用 Script Parameters 时,例如在 Script Editor 中,由于范围限制,您需要在 @ variables 之前使用 $,如 Script Templates 中的示例:

Greeting.rb

图书馆

为了方便起见,ImageJ 的 Fiji 发行版包含一个名为 imagej.rb 的库。它包含许多与 ImageJ 相关的有用函数。在Script Editor中创建新的 JRuby 脚本时默认加载它。

##接下来怎么办?

您可能需要首先快速浏览一下第 §§12§§§ 页面,了解使用解释器和脚本接口的一般说明,以及第 Scripting comparisons 页面,了解使用多种不同的可用脚本语言编写的示例。 JRuby 示例展示了如何在 JRuby 中实现 Java 接口。

JRuby 提供了一些更好的功能,请在 JRuby documentation 中查看它们。

当然,如果您想了解如何使用 ImageJ 或其任何项目中的类,请访问javadoc.scijava.org