ImageProcessorには以下の記事に書いたように、8bit、256種類の区分(0-255の整数)しかない ByteProcessor, 16bit、65536種類の区分(0-65535の整数)のある ShortProcessor、32bitフルに使う FloatProcessor、RGBを1チャンネル当たり8bit x 3で表し、24bit使う、ColorProcessorの4種類です。
ところで、ImageJの画像データのbit深度を変更する必要がある場合、ImageConverterというAPIを使います。これを使ったときのImageJの挙動について注意点です。
ImageConverterを使ってbit深度を変更すると、たしかにImageProcessorのタイプは変更してくれます。しかし、値の扱いは要注意です。例えば、今、ShortProcessorの画像、imp があるとします。これをByteProcessorに変換するには、
ImageConverter(imp).convertToGray8()
という命令を使うと変換してくれます。この時、元々0-65535整数の値を取っていた画像は当然、0-255整数の値にダウンスケーリングして変換してくれます。しかし、bit深度をアップスケールする際は要注意で、ByteProcessorを、convertToGray16()、convertToGray32()メソッドを使い、ShortやFloatProcessorに変換したり、ShortProcessorをFloatProcessorに変換しても、自動的に値までアップスケーリングしてくれず、変換前の値そのままです。自分で256倍してやらなければなりません。
なお、ImageConverterには、setDoScalingメソッドがあり、setDoScaling(True)を実行することで変更してくれるようですが...
ところで、今まで全くFloatProcessorを使っておらず、今までその挙動を確認してきませんでした。ちょっと今FloatProcessorを使う必要を感じていろいろ確認中ですが、どうも、よく言えば非常に融通が利き、悪く言えば非常にぬえ的な挙動をします。取る値の範囲も決まっていないようで、0~1.0で運用することもできれば、0~16777215 で使う、という運用も可能なようです。さらに+-符号付での運用も可能なようです。そのためか、FloatProcessorに対してsetDoScalingメソッドを実行しても何も値が変わりません。
さらに、ImageJ自体が、16bit 最大値65535までの表示にしか対応しておらず、FloatProcessorを0~16777215で運用すると表示はクリップして真っ白になってしまいます。しかしgetStatisticsなどで、値を調べてみると値はクリップしておらず、ちゃんと保持されているようです。
この0~16777215で作成した画像をTIFファイルに落とし、IrfanViewで読み込むと正常に表示されます。Informationを見てもオリジナルが32bit画像であると出ます。
さらにFloatProcessorを0.0~1.0で使ってみると、今度は画面が真っ黒です。小数点以下のピクセルの表示にも対応していません。
しかし、これも一旦TIFFに保存してIrfanViewで開くと、正常に表示されます。やはりデータ自体はクリップしていません。
[2023.1 追記]
ImageJ のbit深度を変更して最大値を変更したときの表示問題については、表示する明度範囲を変更する API があることが分かりました。但し、GUI上から変更することはできないようです。詳しくは以下の記事をご覧ください。
なお、GIMPの場合は0.0~1.0では正しく読めますが、0~16777215では正しく読み込むことができませんでいた。
因みに、ImageProcessorに、setMinAndMax(最小値, 最大値) という画像の明度の最大値、最小値を設定するメソッドがあるようです。ImageJでは、表示用に8bitのプレビュー画像を使っているので、このメソッドで値を指定すると、適切な表示用プレビュー画像を作るということです。未確認ですが、これを使うと32bit画像でも正しく表示できるのではないかと思います。
なお、ImageJにおいて32bit画像を扱おうとすると、bio-formatプラグインが32bit カラー画像のインポートが現時点では不可能なので、32bit画像を扱える場面は限定されます。ただ画像計算処理のための中間保存のためのオブジェクトとしては十分に使えますし、おそらくfloatProcessorが設けられている主目的も、そのためにあるものと思われます。
なお、ImageProcessorの挙動を検証するための簡単なPython (Jython) スクリプトを書いてみました。一応16bit画像を読むことを想定しています。bit深度を変更し、プリント文で、変換した画像の平均値、最大値、最小値を出力させています。もしよろしければ、ImageJのスクリプトエディタにコピペして、適宜変更してお使いください。
-------------------------------------
from ij import IJ, ImagePlus, CompositeImage
from ij import WindowManager as WM
from ij.io import DirectoryChooser, OpenDialog
from ij.plugin import Duplicator
from ij.process import ImageConverter
from ij import IJ
from loci.plugins import BF
from ij import plugin
# 1. Open an image
Mode = "Go"
window = WM.getActiveWindow()
if not window:
od = OpenDialog("Choose a file")
folder = od.getDirectory()
filename = od.getFileName()
if filename:
path = folder + filename
IJ.log(path)
IJ.log(folder)
IJ.log(filename)
# Always Open file with Bio-format Plugin
imps = BF.openImagePlus(folder + filename) # Open file with Bio-format Plugin
imp0 = imps[0] #imp0: Original Image
imp0.show()
else:
Mode ="Stop"
else:
imp0 = IJ.getImage()
filename = imp0.getTitle()
folder = imp0.getOriginalFileInfo().directory # get image's original directory
path = folder + filename
window = WM.getActiveWindow()
if not window: # if file opening is canceled
Mode = "Stop"
# 2. Convert images
if Mode != "Stop":
imp0_32 = Duplicator().run(imp0)
ImageConverter(imp0_32).convertToGray32()
imp0_8 = Duplicator().run(imp0)
ImageConverter(imp0_8).convertToGray8()
stat_imp0 = imp0_32.getStatistics()
print "statistics org"
print stat_imp0.mean
print stat_imp0.max
print stat_imp0.min
# 以下適当にコマンドを選んでください
IJ.run(imp0_32, "Divide...", "value=65535")
#IJ.run(imp0_32, "Multiply...", "value=256")
#ImageConverter(imp0_32).setDoScaling(True)
#
# 3. Output statistics & show the images
stat_imp0_32 = imp0_32.getStatistics()
print "statistics32"
print stat_imp0_32.mean
print stat_imp0_32.max
print stat_imp0_32.min
imp0_32.show()
stat_imp0_8 = imp0_8.getStatistics()
print "statistics8"
print stat_imp0_8.mean
print stat_imp0_8.max
print stat_imp0_8.min
imp0_8.show()
----------------------------------
[関連記事]