3Dviewerをスクリプトで動かす・録画する

以下、教科書2章4節の解説をさらに発展させた使い方である。

3DViewerはマウスを使ってぐりぐりと動かしながら扱うことがほとんどの場合だろう。とはいえ、スクリプトからも比較的容易にアクセスすることが可能であり、特に複雑な3次元画像のムービーを作るときにはスクリプトを書くことでその動きを細かく制御することができる。このページでは、Jythonを使って3DViewerを使う方法を紹介する。

Jythonの書き方がわからない、という方は以下のページで学んでほしい。

3Dviewerへのプロット

以下のコードを実行すれば、サンプル画像[Fly brain]が3Dviewerにプロットされる。まずは試してみて欲しい。

from ij import IJ

from ij3d import Image3DUniverse

flyurl = "http://imagej.nih.gov/ij/images/flybrain.zip" 

imp = IJ.openImage(flyurl) 

univ = Image3DUniverse() 

univ.show() 

c = univ.addVoltex(imp) 

コードを解説しよう。

3Dviewerのオブジェクトを動かす

さて、この3DViewerに描画された三次元オブジェクトを動かしてみよう。下のコードを上のコードに続けて貼り付けて実行すると、オブジェクトがぐるぐるとまわる。

from ij3d.behaviors import ViewPlatformTransformer 

from javax.media.j3d import Transform3D 

from javax.vecmath import Vector3d 

import time  


vtf = ViewPlatformTransformer(univ, univ) 

x1z1 = Vector3d(1, 0, 1) 

univ.rotateToPositiveXY() 

for zm in range(1,3000, 10):

   vtf.zoomTo(zm)   

   vtf.rotate(x1z1, 0.03)

   time.sleep(0.01)

for zm in range(3000, 1000, -10):

   vtf.zoomTo(zm)

   vtf.rotate(x1z1, 0.03)

   time.sleep(0.01) 

コードを解説する。

3Dviewerのオブジェクトを動きを動画にする

以上で3DViewer上でオブジェクトを動かすスクリプトの書き方はわかったと思うのだが、これをムービーにして保存するには要所要所でスナップショットを撮影し、スタックに保存することが必要になる。以下のような感じである。

imp = univ.takeSnapshot()

stk = ImageStack(imp.width, imp.height)

stk.addSlice(imp.getProcessor()) 

Image3DUniverseのメソッドのひとつにtakeSnapshot()がある。返り値がImagePlusオブジェクトであり、これをこのままスタックに保持していけば良い。二行目で空のスタックオブジェクトを用意し、三行目でスナップショットのImageProcessorインスタンスを加えている。実際のスクリプトでは、ループ毎に一枚ずつ撮影し、スタックにキープする、という形になる。以下はここまでのすべてを組み合わせたスクリプトである。

2020年10月21日追記

回転の際の一番目の引数で使われる三次元ベクトルのクラスが、Java純正からScijavaのクラスに変更されていることに気がついた。これに伴い、上のコードはエラーを返す。訂正したものが以下になる。

from ij import IJ

from ij3d import Image3DUniverse

from ij3d.behaviors import ViewPlatformTransformer 

from javax.media.j3d import Transform3D 

#from javax.vecmath import Vector3d

from org.scijava.vecmath import Vector3d 

import time

from ij import IJ, ImageStack


def addSnapShot(univ, stk):

imp = univ.takeSnapshot()

#stk = ImageStack(imp.width, imp.height)

stk.addSlice(imp.getProcessor()) 

flyurl = "http://imagej.nih.gov/ij/images/flybrain.zip" 

imp = IJ.openImage(flyurl)

snapshotstk = ImageStack(imp.width, imp.height)


univ = Image3DUniverse() 

univ.show() 

c = univ.addVoltex(imp)


vtf = ViewPlatformTransformer(univ, univ) 

x1z1 = Vector3d(1, 0, 1) 

univ.rotateToPositiveXY() 

for zm in range(1,3000, 10):

   vtf.zoomTo(zm)   

   vtf.rotate(x1z1, 0.03)

   time.sleep(0.01)

for zm in range(3000, 1000, -10):

   vtf.zoomTo(zm)

   vtf.rotate(x1z1, 0.03)

   time.sleep(0.01) 

このコードは以下にある。

https://gist.github.com/miura/8520754

出力されるスタックをmpeg4圧縮のムービーに変換したものが以下の動画である 。スタックを [File > SaveAs > Avi...]でエクスポートし(ファイル名はてきとうにout-2.aviとした)、ffmepeg を使って次のようなコマンドで変換した。

ffmpeg -i out-2.avi -vcodec mpeg4 -qscale 0 out-2.mov