省型旧形国電の残影を求めて

戦前型旧形国電および鉄道と変褪色フィルム写真を中心とした写真補正編集の話題を扱います。他のサイトでは得られない、筆者独自開発の写真補正ツールや補正技法についても情報提供しています。写真補正技法への質問はコメント欄へどうぞ

ImageJ / Python Tips: ChannelSplitterの使用に注意!

 前回同様にプラグイン・サイレントバージョン作成過程で気づいたTipsです。

オリジナルのプラグインでは、次のマクロコマンドでウィンドウで開いたRGB画像を3チャンネルに分割していました。

IJ.run("Split Channels") →アクティブウィンドウの画像を3Ch.のウィンドウに分割
# R ch.
IJ.selectWindow("C1-", filename)  →Rチャンネルのウィンドウを選択
impR = IJ.getImage() →アクティブウィンドウの画像をimpRに代入
IJ.saveAsTiff(impR, folder + filename +"_R.tif") →Rチャンネル画像をTIFFとして保存
# G ch.
IJ.selectWindow("C2-", filename)  →Gチャンネルのウィンドウを選択
impG = IJ.getImage() →アクティブウィンドウの画像をimpGに代入
IJ.saveAsTiff(impG, folder + filename +"_G.tif") →Gチャンネル画像をTIFFとして保存
# B ch.
IJ.selectWindow("C3-", filename)  →Gチャンネルのウィンドウを選択
impB = IJ.getImage() →アクティブウィンドウの画像をimpBに代入
IJ.saveAsTiff(impB, folder + filename +"_B.tif") →Bャンネル画像をTIFFとして保存

 

 これを画像をウィンドウで開かないまま処理するため次のようなコマンドに置き換えました。imp0がオリジナルの画像、impsはチャンネル分割した画像を格納する配列です。またfolderは保存フォルダ、filnenameは保存ファイル名の接頭部分です。

from ij.plugin import ChannelSplitter →ライブラリ ChannelSplitterを使う宣言

--------------------

imps = ChannelSplitter.split(imp0) →imp0の画像をimps[0],[1],[2]の3つに分割
impR = imps[0]
IJ.saveAsTiff(impR, folder + filename +"_R.tif")
impG = imps[1]
IJ.saveAsTiff(impG, folder + filename +"_G.tif")
impB = imps[2]
IJ.saveAsTiff(impB, folder + filename +"_B.tif")

 ところがここでまたハマりました。これでできた画像をGIMPで読み込むと、画像が正しく表示されません。マクロコマンド経由でプラグインである "Split Channels" で分割した場合と、プラグイン・ライブラリ ChannelSplitterで分割した場合で、仕様が異なるようです。おそらくChannelSplitterで分割すると、何らかの余計なプロパティが付加されていて、GIMPで読み込んだ時に悪さをするようです。正確な原因は分かりませんが、とりあえず、分割された画像をImageConverterを使ってグレースケール変換することで対応しました。

from ij.plugin import ChannelSplitter 
from ij.process import ImageConverter →ライブラリ ImageConverterを使う宣言
--------------------
imps = ChannelSplitter.split(imp0) 
for i in imps:
    if Mode == "8-bit": →Modeは画像が何bit画像かを指定する変数
         ImageConverter(i).convertToGray8() →8bit画像なら8bitグレースケール化
     elif Mode == "16-bit":
         ImageConverter(i).convertToGray16() →16bit画像なら16bitグレースケール化
     else:
         ImageConverter(i).convertToGray32() →32bit画像なら32bitグレースケール化

impR = imps[0]
IJ.saveAsTiff(impR, folder + filename +"_R.tif")
impG = imps[1]
IJ.saveAsTiff(impG, folder + filename +"_G.tif")
impB = imps[2]
IJ.saveAsTiff(impB, folder + filename +"_B.tif")

 原因がはっきり分からないのは、気持ち悪いですが、これで、とりあえずは一件落着です。

 

--------

※お断り
 当記事は、ImageJ - Fijiディストリビューションの記事執筆時点での最新バージョンを前提とした記事です。ImageJのオリジナルバージョンだと、環境設定をご自分で整備しない限り、同様に動作しない可能性があります。

--------

[2023.2 追記]

 本記事執筆時は、ImageJ の画像データ構造についてよく分かっていませんでしたが、今考えてみると、8bitフルカラー画像に Channnel Splitter を適用すると、おそらく ColorProsessor という構造は変わらないまま、各当該チャンネル以外のチャンネル情報を消す (すべてのピクセルに0を入れる) という形でチャンネル分割をしているものと思われます。そのため、TIFFファイルなどに変換して他アプリケーションで活用しようとすると、不都合が生じるものと推測します。

 このファイルに対し ImageConverter を適用すると、ColorProsessor から、ByteProcessor に変換されますので、問題が解消されるということかと思われます。

 従って、そもそも ColorProsessor ではなく、スタックに 3チャンネルの ShortProcessor を別々に入れている 16bit ファイルの場合は、Channnel Splitter を適用しただけでも問題はありません。というのは、適用によって単チャンネルのみ保持した ImagePlus に変換されるとともに、チャンネルを示すカラー情報はLUTの形で保持され、画像データ自体とは別途のデータとして保持されるからです。

 おそらく ImageJ の仕様が 16bit画像が扱えるように拡張された際に、16bit (以上の) 画像の場合 ColorProcessor が使えないので、内部的に R, G, B を区別するために、LUT で区別するよう仕様が変更されたものと推測します。このため 8bit と 16bit では Channnel Splitter 適用後の仕様が異なるものと考えられます。

 以下の記事をご参照ください。

yasuo-ssi.hatenablog.com