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

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

ImageJ対応 相対RGB色マスク画像作成ツール UI プレビュー アルゴリズムメモ (1)

 先日相対RGB色マスク画像作成ツールをアップデートしました。これで一応この夏前から考えていた、ユーザインターフェースの改善については一通り実装したことになります。

 ただ、結構複雑なことをやっているので、自分の備忘録という意味で、また、もしImageJで、何かユーザインターフェースの実装を行っている方がいらっしゃれば参考になるかもしれないので、今回のUIの仕組みの概略のメモを記しておきます。

 なお、相対RGB色マスクと、輝度マスクでは動作の仕組みが異なるので別々に説明します。今回は、相対RGB色マスクのプレビューの仕組みから。

■相対RGB色マスク用プレビューのアルゴリズムの概略

相対RGB色マスク画像プレビューの仕組み

 相対RGB色マスク画像パラメータ指定ダイアログボックスにおけるプレビューの仕組みですが、基本的には、まず描画キャンバスに相当する ImagePlus を用意し、これをその都度表示する画像に書き換える形にしています。

 

 さらに、大きく分けると明度範囲を制限するマスク画像を作成するモジュール(上の図の赤の部分)、相対色マスク画像を作成するモジュール(同青)、最終イメージを作成するモジュール(同黄)の3つのモジュールを class として作成します。

 上の赤、青、黄色の各モジュールには、それぞれの画像を作成する ImagePlus があります。実は当初、この各 ImagePlus を状況に応じてアクティブ & 最前面に表示することで画像表示を切り替えようとしました。ところが、 Linux においては、ImagePlus をアクティブにしても、最も前面に表示してくれないというバグがあることがわかりました(Windows, Mac OS X では問題ありません)。このため、描画キャンバスを1つのみに制限してそれのみ表示するとともに、表示したい画像を、その都度各モジュールの ImagePlus から描画キャンバスの ImagePlus に転記して表示し、他の ImagePlus のウィンドウは隠すことにしました。

 おそらくこれは基本的には Java のバグに起因すると思われますが、JavaWindows < Mac OS X < Linux の順にバグが多くなるようなので、ImageJ でプログラミングを行う際は要注意です。

 明度範囲を指定するスライダーを動かすと明度範囲作成モジュールが呼び出されてアクティブになり、画像を作成して描画キャンバスにイメージを複写します。閾値や透明度を指定する数値ボックスに入力したり、レベル調整等のチェックボックスの状態を変更すると、相対色マスク作成モジュールが呼び出されてアクティブになり、やはり描画キャンバスに作成したイメージを複写します。同時にこの二つのモジュールは表示はされませんが、最終イメージ作成用に、作成したイメージを表示されない ImagePlusに保存します。

 最終画像プレビュー表示チェックボックスにチェックを入れると、最終イメージ (明度範囲+相対色マスク画像複合イメージ) 作成モジュールが呼び出されアクティブになり、その際に保存されていた明度範囲閾値画像、相対色マスク画像を引数として読込み、それに基づき最終イメージを作成して描画キャンバスにイメージを複写します。 なお、ここで作られる ImagePlus はチェックボックスにチェックを入れるたびに作成されますが、キャンバス用 ImagePlus に転記すると、ここの ImagePlus は消去されます。

 なお、各モジュール内でどのイベントが発生しても、プレビューチェックボックスでチェックが外れていない限り、各モジュールごとに同じ描画メソッドが呼び出されます。

 これらのモジュールは引数として描画キャンバスとなる ImagePlusを読み込むことで、随時描画キャンバスに描画できるようにします。

 ダイアログ入力が終わるまで、描画キャンバス、明度範囲イメージ、相対色マスクイメージは保持されます。

 次に、相対色マスク作成モジュール、明度範囲作成モジュールの中身について説明します。

■相対色マスク作成モジュール

相対色マスク画像プレビュー作成モジュール

 相対色マスク作成モジュールは引数として、描画キャンバス、保存画像用キャンバス、R, G, Bのチャンネルのイメージを読み込みます。そして、やはり引数として読んだ対象チャンネルのカラーを指定する変数 (C0) に応じて、対象チャンネルのイメージと、それと比較対照し相対色マスクを作るための対照チャンネルイメージを、対象とならない2つのチャンネルを合成して作成します。対象チャンネルイメージはレベル調整を行ったものと行わないものの2種類を用意します。さらに、マゼンタ/グリーンマスクの場合は、Bチャンネルのみ対象としてマスクを作成するオプションがありますが、この場合は対照チャンネルにBチャンネルのみを指定します。

 そして読み込んだパラメータに応じて、対象チャンネルイメージと対照チャンネルイメージから、イメージカルキュレータを使って、相対色マスク画像を計算・作成します。この時、補色マスクの場合は、対照画像 - 対象画像で、原色マスクは、対象画像 - 対照画像で計算し作成します。計算後、指定範囲除外マスクを作成する場合は、画像を反転します。マスク画像を作成したら描画キャンパスにイメージをコピーして表示するとともに、保存用の ImagePlusに画像を保存します。

 これらのイメージは、関連パラメータが動くたびに、描画メソッド(図中クリーム色の部分)が呼び出され、画像を書き直しますが、常にオリジナルのR, G, B画像からデータが呼び出されて描きなおされます(これ重要!)。このため、前に作成された画像が次に作成される画像に影響を及ぼすことはありません。

 なお、描画キャンバス、保存画像用キャンバスの初期値として、一旦仮に明度範囲作成対象となるチャンネルの画像を読み込みますので、一度、正しいプレビューを作成しないと、あとで表示する最終イメージプレビューも正しい内容が表示されません。

■明度範囲画像作成モジュール

明度範囲閾値画像作成モジュール

 明度範囲画像作成モジュールは、引数として、描画キャンバスと対象となるチャンネル画像のImagePlusを読み込みます。対象チャンネルのImageProcessorに対し、スライダーから読み込んだ閾値を適用しそこから閾値に基づくROIを得ます。このROI をマスク画像を描く、空の ImageProsessor に複写し、ROIの範囲を塗りつぶします。これで2値マスク画像ができます。このマスク画像の ImageProcessorをプレビュー用のキャンバスと、保存用のImagePlusに複写し、明度範囲を示した2値マスク画像を表示します。

 スライダーを動かすたびに、描画メソッド (図中クリーム色の部分) が呼び出され、画像が描き直されます。

 なお、当初読込んだ対象チャンネルの ImagePlus に変更後の画像を書き込み保存用イメージとしますが、画像を描きなおす際は、コンストラクタで複写しておいた当初イメージの ImageProcessor を基に画像を描きなおしますので、上と同様前の描画が、次の描画に影響を与えることはありません。

 なお、描画キャンバスの初期値の扱いに関しては上と同じです。

■最終画像合成モジュール

 最後の最終画像合成モジュールは比較的単純ですので図は省略します。こちらは、描画キャンバス、相対色マスク画像、明度範囲マスク画像の3つの ImagePlus を引数として読み込んでおき、最終画像表示チェックボックスがチェックされるたびに、相対色マスク画像、明度範囲マスク画像を、イメージカルキュレータを使って、比較(暗)で合成し、プレビュー表示キャンバスに複写して表示します。

 但し、2巡目の除外マスクの場合のみ、読み込んだ相対色マスク画像を一旦複写し、その複写画像を反転した上で(つまり一旦ポジマスクに戻す)、明度範囲マスク画像と比較(暗)で合成し、さらに合成した画像を再反転して (ネガマスクにする) 除外マスク画像を作成し、その画像を描画キャンバスに複写して表示します。

 相対色マスク画像を反転する際に一旦一時イメージに複写してから反転するのは、ここで反転した結果が、次の画像描き直しの際に影響を与えないためです。またここで作成された画像は、描画キャンバスに描かれたものを除き、保存しません。

 

 なお、全般的に言えることですが、描画の書き直しのたびに変更されるパラメータのオブジェクトからの読み込みは、以前に指摘したように、描画実行メソッドにまとめて記したほうが良いです。一方、どの描画でも変更のない変数の読み込みはコンストラクタで行うのが良いでしょう。