ImageJで多重染色画像をチャンネルごとに並べてひたすらパワポにコピペするだけのマクロ
dir = getDirectory("Select a Directory");
//画像(ここでは3-channel multi-tifを想定)が入ったフォルダを選択
filelist = getFileList(dir)
for (i = 0; i < lengthOf(filelist); i++) {
if (endsWith(filelist[i], ".tif")) {
open(dir + File.separator + filelist[i]);
waitForUser; //画像に矢印など入れたい場合はここで入れる
run("RGB Color"); //マージ画像も載せる
run("Scale...", "x=0.25 y=0.25 interpolation=Bilinear average create");
//画像サイズを0.25倍している
selectWindow(filelist[i]);
Stack.setDisplayMode("grayscale");
run("Make Montage...", "columns=3 rows=1 scale=0.25 border=1");
run("Combine...", "stack1=Montage stack2=[" + filelist[i] + " (RGB)-1]");
run("Select All");
run("Copy to System");
close("*");
waitForUser; //パワポなどにコピペしたらOKを押す
}
}
過去に作ったmovファイルをImageJ/Fijiで開きたい
元々、ImageJはQuickTime形式をサポートしていたので、タイムラプス観察などの画像スタックをプレゼン用の動画にするためにmovファイルに変換したりしていた。ところが、64bit化を期にQuickTime形式がサポートされなくなったため、昔作ったmovファイルを変更するために最新のFijiで開こうとしても開くことができない。元の画像スタックも手元にない。こんなときどうするか?
Fijiでの手順は以下。
ImageJ Updaterを開く(Help > Update...)
Manage update sitesをクリック
FFMPEGにチェックを入れてClose
ImageJ UpdaterにFFMPEG関連のアップデートが表示されるのでApply changes
インストールが終わったらFijiを再起動
File > Import以下にMovie (FFMPEG)...という項目が追加されているのでクリックして対象のmovファイルを選択
optionを選択するダイアログが出てくるので適当に指定してOK(ファイルが大きくない限りVirtual Stackのチェックは外したほうがよい?)
これで開くはず。
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の値がデフォルト値として参照される。
Miji/MIJを用いてMatlabでmulti-tiffファイルを一括処理する
普段、ImageJで使用しているtime-lapse imageなどのmulti-tiff画像をMatlab上で一括処理したいのだけど、Matlabではmulti-tiffをコマンド一発で開くことができない?みたい。
ググッたらループを回して一枚ずつ読み込むようなスクリプトが紹介されていたりするがなんか面倒臭い。
そこでMijiを使ってImageJ経由でMatlabにmulti-tiff画像データを読み込ませることを試してみた。
addpath('/Applications/Fiji.app/scripts'); % Mijiにpathを通す。Macの場合 Miji; %Mijiを起動 DirName = uigetdir; % ファイルが入ったディレクトリを選択 FileList = dir([DirName, '/*.tif']) % ファイルのリストを取得。ワイルドカードの部分を変更することでファイル名で絞り込むことも可能 for i = 1:size(FileList, 1) ImagePath = [DirName, '/', FileList(i).name]; % 各ファイルのパスを取得 [path, ImageName, ext] = fileparts(FileList(i).name); %ファイル名から拡張子を除いたものを取得(保存時に使用)。pathとextは使わない MIJ.run('Open...', ['path=', ImagePath]); % ImageJで画像を開く img = MIJ.getCurrentImage(); % Matlabに読み込む MIJ.run('Close'); % ImageJ上の画像を閉じる % 何かの処理 MIJ.createImage(img); % 処理した画像をImageJに戻す MIJ.run('Save', ['save=[', DirName, '/', ImageName, '_treated.tif]']); % ファイル名を変更して保存 MIJ.run('Close'); end
現状、Mijiには直接ファイルを開いたり保存したりするコマンドがないため、runコマンドを用いてImageJを操作することになる。
ちょっと躓いたのがrunコマンド内で'Open...'や'Save'を使うときのpathの指定方法。MacroやAPIとはちょっと違うので注意。
ImageJ/FijiとJava 8
(16/06/24 追記)
最新のFijiとJava8でアニメーションの遅延は解消されているのを確認。
(追記ここまで)
動作環境:iMac (late2011), Core i7 2.8GHz, memory 16GB, yosemite
2015-06-15 - Major updates in the works - ImageJ
2015-06-17 - Better behavior on OS X - ImageJ
ImageJ/FijiがJava 8に対応したらしく気がついたらFijiがJava 8上で起動してた(Java8自体は前にインストールしてた)。
ああ、やっとかと思ったんだけど、しばらく使ってるとなんか妙に画像の描画が遅い。1024x1024のスタック画像がまともにアニメーションしてくれない。もしやと思ってJava 8をアンインストールしたら元に戻った。アンインストールの方法は下記参照。
このままずっとJava 6というのもまずそうだけど、そのうち直りそうな気もするのでとりあえず暫くの間はJava 6のままで。
512x512くらいの画像であれば普通にアニメーションしてたのでそれくらいの画像を扱う人ならアップデートしてもいいのかも。
MIJ/Mijiを用いてMatlabとImageJ/Fijiの間でデータをやりとりする
*2017/06/05 追記*
突然、Matlab上でMijiが起動しなくなった。
調べてみたところ、Fiji.app/jars内にあるはずのmijのjarファイルがアップデートの過程で消えてしまった模様。
復旧するには、Update...でImageJ Updaterを開き、Manage update sitesでBIG-EPFLを追加。Advanced modeでview all filesにしてmijで検索。出てきたmij.jarを選択してinstallボタンを押しApply changes。これでFiji.app/jars/内にmij-1.3.6-fiji2.jarみたいなファイルが追加されていれば使えるようになるはず。
他のpluginでも突然消えてしまった場合には同様の方法で対処できるかも。
*追記終わり*
Matlabで画像解析を始めたんだけど、画像の表示、GUIによる画像操作、ファイルの入出力あたりがどうもストレスフルで、このへんを使い慣れたImageJでできないかと探してみたら見つけた。詳細は以下のリンクを参照。
簡単に言うとMatlabの上でImageJ/Fijiを起動させるプログラム。現行のFijiにはプリインストールされているのでFijiを使っているなら新たに何かをインストールする必要はない。
使用方法はまずFiji.app/scriptsにMatlabのサーチパスを通す。MacだとGUIからは.app以下が見えないので以下のMatlabコマンドを使用する。
addpath('/Applications/Fiji.app/scripts')
で、
Miji;
とコマンドを入力するとFijiが立ち上がる。注意点として、Matlab上で動かすJAVAプログラムが使用できるメモリはデフォルトではかなり少なく設定されているので、もし大きな画像ファイルを扱いたいのであれば事前に使用可能なメモリ容量を増やしておく必要がある。具体的には、Matlab > 設定 > 一般 > JAVA ヒープ メモリのところの値を増やす。
起動したImageJ上で画像ファイルを開き、
img = MIJ.getCurrentImage;
で画像データを配列として読み込める。一枚の画像であれば2次元配列、画像スタックであれば3次元配列になる。ハイパースタックであったとしてもその設定は無視されて通常のスタック扱いで3次元配列として読み込まれるので注意。
逆にMatlab上の配列は、
MIJ.CreateImage(img);
で、ImageJ上で画像として開くことができる。
終了したいときは、
MIJ.exit;
その他、使用できる機能については以下のリンクを参照。
Bi-directional communication and data exchange from Matlab to ImageJ
使用してみた感想としては、unsigned 16-bitのデータが32-bitで読み込まれたり、ところどころで挙動が怪しかったりするけど上記の目的にはわりと使えそう。あとImageJの方で指定したROIの座標を読み込むこともできるのでそのあたりでも使えそうかな。
Fiji/ImageJのJython scriptでBio-formatsプラグインを使う
Olympus FV1000で取得したoibファイルなどをFiji/ImageJのBio-Formatsプラグインを使って一括でtiffファイルに変換するJython script
Jython scriptでのBio-Formatsの使い方は以下のページを参照
Jython example script for working with the Bio-Formats API in Fiji.
一応、動いたけどきちんとした動作確認はしていないので自己責任で
from loci.plugins import BF from loci.plugins.in import ImporterOptions import os, glob def run(): #変換したいファイルが入ったフォルダを選択(それ以外のファイルを入れないこと) inputDir = DirectoryChooser("Choose input directory").getDirectory() if inputDir is None: #キャンセルした場合 return #出力先のフォルダを選択 targetDir = DirectoryChooser("Choose target directory").getDirectory() if targetDir is None: #キャンセルした場合 return #入力ディレクトリからファイルだけを抽出する files = glob.glob(os.path.join(inputDir, "*.*")) for file in files: options = ImporterOptions() options.setColorMode(ImporterOptions.COLOR_MODE_GRAYSCALE) #関係ないかも options.setId(file) imps = BF.openImagePlus(options) imp = imps[0] #impsはImagePlusオブジェクトのリストになってる? filename = file.split(os.sep)[-1].rsplit(".", 1)[0] #パスからファイル名だけを抽出 output = os.path.join(targetDir, filename + ".tif") IJ.saveAsTiff(imp, output) run()