ImageJ2のパラメータ記法を使ってスクリプト書きをちょっとだけ楽する
忙しいんですけど、現実逃避のためのエントリ。
さて、みんな大好きImageJですが、実は数年前からImageJ2というものが開発されています。2014年にRC版が公開されました。
ImageJ2はSciJavaと呼ばれるフレームワークをベースにして完全に新しく作り直されたもので、Plugin作成の際に使用するライブラリも従来のImageJ1.xのものとは全く異なっています。ただし、後方互換性に非常に気を使って作られているので、これまでのImageJ1.x用のPluginやScirpt、Macroも問題なく動きますし、ユーザーレベルだと今のところあまり大きな違いはありません。実際、現在のFijiにはすでにImageJ2が同梱されています。
ImageJ2の細かい説明はこのへん。
で、ImageJ2は従来のImageJでは限界があった部分がいろいろと改良されており、いずれは移行するべきなのでしょうけど、正直、一からScriptの書き方を勉強し直すのも面倒くさい一部機能がベータ版だったりと発展途上ではあるので、とりあえずまだ様子見でいいんじゃないかと思います。ただ、ImageJ2の機能を使うとScript書きが楽になる場面があったりするので今回はそれの紹介です。
これまでのImageJ1.xにおいて、ScriptやMacroの実行時にファイルやディレクトリを指定する、またはパラメータを入力する、などといった場合にはOpenDialogやDirectoryChooser、GenericDialogといったものが使われていました。しかし、これをScriptの中に実装しようとすると微妙に面倒くさい。
たとえば、とあるディレクトリを指定するためのダイアログを表示させるためのJython Scriptだと
from ij.io import DirectoryChooser dc = DirectoryChooser("Choose a folder") folder = dc.getDirectory() if folder is None: print "User canceled the dialog!" else print "Selected folder:", folder
こんな感じ(ここから参照しました)。
パラメータを入力するときは、
from ij.gui import GenericDialog def getName(): gd = GenericDialog("What's your name?") gd.addStringField("name", "Masuda") gd.showDialog() if gd.wasCanceled(): print("User canceled dialog!") return input_name = gd.getNextString() return input_name name = getName() if name is not None: print("Your name is " + name + "!")
パラメータが増えると、
from ij.gui import GenericDialog def getPersonalData(): gd = GenericDialog("enter your personal data") gd.addStringField("name", "Masuda") gd.addNumericField("age", 17, 0) bloodtypes = ["A", "B", "O", "AB"] gd.addChoice("blood type", bloodtypes, bloodtypes[0]) gd.showDialog() if gd.wasCanceled(): print("User canceled dialog!") return name = gd.getNextString() age = gd.getNextNumber() b_type = gd.getNextChoice() return name, age, b_type data = getPersonalData() if data is not None: name, age, b_type = data print name, age, b_type
面倒くさい。
そこで、#@parameterという記法を使います。たとえば、
#@String name print("Your name is " + name)
として実行すると、文字列を入力するためのダイアログが出てくる。入力したダイアログは変数nameに格納される。
#@output <変数型> <変数名>で出力もできる。
#@String name #@output String result result = "Your name is " + name
いろいろできる。
#@String(label = "What's your name?", value = "Masuda") name #@output String result result = "Your name is " + name
GenericDialogを用いて作った上の例は
#@String(label = "name", value = "Masuda") name #@Integer(label = "age", value = 17) age #@String(label = "blood type", choices = {"A", "B", "O", "AB"}, style = "listBox") b_type print name, age, b_type
と書ける。
ディレクトリを指定したいときは
#@File(label = "select a directory", style = "directory") my_dir print(my_dir)
また、表示している画像オブジェクトを取得したいときは
#@ImagePlus img print(img.getTitle())
とするとactive windowのImagePlusオブジェクトが取得できる。
今回のScriptはJythonだけど、他のScript言語やMacroでも同じように使える(らしい)。また、従来のImageJ1.xのAPIを用いた記述と混ぜて使うこともできる。
細かいことは以下のリンクを参考に。
https://imagej.net/Script_Parameters
http://imagej.github.io/presentations/2015-09-04-imagej2-scripting/#/
今のところ、まだお試し程度にしか使っていないので自己責任で。
(追記)
これ書きながら、Scriptを繰り返し実行したときにデフォルト値がvalueで指定した値にならずに前の入力を引きずっているのが気になっていたんだけど、Forumを検索していて原因がわかった。parameterにはpersistというpropertyがあってデフォルトではtrueになっている。これがtrueになっていると前回の入力がvalueで指定した値を上書きするらしい。なので、
#@String(label = "What's your name?", value = "Masuda", persist = false) name #@output String result result = "Your name is " + name
のように書くと正しくvalueの値がデフォルト値として参照される。