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

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

ImageJ / Pyhon Tips 画像ピクセルの輝度値の取得 / 設定・書換え

 ImageJでPython (Jython) を使って画像の個々のピクセルにアクセスし、そこに記されている輝度(明るさ)の値を取得したり、設定(書換え)する方法についてのメモを記しておきます。

ピクセルの輝度値の取得

これに必要なライブラリの呼び出しは次の通りです。

from ij import IJ, ImagePlus

そして、具体的には次のようなコードで取得します。

a = imp.getPixel(x, y)

a: 取得した値を格納する任意の名前の変数
imp: 値を読む画像 (任意の名前の imagePlus オブジェクト)
x: 値を読みだすピクセルの x 座標値(整数)
y: 値を読みだすピクセルの y 座標値(整数)

getPixel( , ): ピクセル値を読みだすimagePlus メソッド

緑色の字は任意に名前を変えられる部分です。

 ところで、bio-formatプラグインで読み込んだ画像ファイルをRGB分解に掛け、分解した単独のチャンネル画像からこれでピクセル値を取得したところ、てっきり単独の値が取得できるものと思っていましたら、実は取得した値が配列(リスト)になっていることが分かりました。どのような値かというと、

a[輝度(グレースケール)値, r値, g値, b値]

という構造になるようです (グレースケール画像だと、r, g, b値はいずれも 0 になります)。ですので、輝度だけ読みたい場合は、取得した後、 a[0] というような形で扱わないとプログラムエラーになってしまいます。

 なお、取得した値がどのような構造になるかは、ひょっとするとファイル形式や、読み込み方 (bio-formatで読み込むか、通常の方式で読み込むか) によって異なるかもしれませんので (まだきちんと確認していません)、要注意です。bio-formatで読み込むと基本チャンネルをばらしたスタック構造で読み込むようですので、ピクセル値の構造がこうなるのはそのためである可能性があります。

 

ピクセルの輝度値の設定

 getPixel メソッドでピクセルの値が読み出せたので、てっきりsetPixelというようなメソッドが imagePlusオブジェクトにあるのではないかと探しましたが見当たりません(setPixels はありましたが用途が違います)。どうも、ImageJのクラスやメソッドの体系がまだよくわかっていませんので、やみくもに検索をかけて探さなければなりません。そのためやりたいことを実現するためのメソッドやクラスを探すのに時間がかかっています。

 結局、ピクセルを書き換えるには imagePlusオブジェクトのメソッドだけではだめで、imageProcessor を使わないといけないようです。で、必要なライブラリの呼び出しは、上に加えて...

from ij.process import ImageProcessor

具体的な作業コードは、

imp.getProcessor(i).set(x, y, int)

getProcessor(i):
 imageProcessorの呼び出し。単純に getProcessor()と書くと、impの中の現在アクティブなimageProcessorオブジェクト(= 画像データ自体。imagePlus オブジェクトがスタック構造であれば 一つの imagePlus オブジェクトに複数の imageProcessor が存在しうる)に対し、操作を行う。imp.getProcessor( i )と書くと、impの中の i 番目のスライスの imageProcessor を呼び出す。

set(x, y, int):
 x, yで指定された数値(整数)の座標のピクセルに対し、輝度値を書き込むimageProcessorのメソッド。intには具体的な書き込みたい整数の輝度値が入る。8bit画像であれば 0~255までの値、16bit画像であれば 0~65535の値を入れる。0が最暗値 255もしくは65535が最明値になる。上の例の場合、getProcessor(i) の i にスタックのスライス番号を指定しその番号の imageProcessor 対して、輝度値を設定する。

 

になります。

なお、この set メソッドは putPixel と書き換えても同じです。

imp.getProcessor(  ).putPixel(x, y, int)

ただし putPixel は set よりも高機能です。例えば set だと輝度値がクリップするかどうかチェックしませんが、 putPixel はチェックして値がクリップしないよう自動修正します。その分 set の方が実行が高速です。また、getPixel で値を取得すると配列になると記しましたが、putPixel はgetProcessor の( )内にスライス番号を書く代わりに、配列で値を書き込むことができます( putPixel(x, y, [int0, int1, int2, int3]) )。set は単一の輝度値しか書き込めません。

 さらに、32bit浮動小数点で画像を扱う場合は、輝度値の書き込みに、putPixelValue メソッドを使うようです。

f:id:yasuo_ssi:20210316170627j:plain

ImagePlusとImageProcessorの関係

 なお、imagePlusオブジェクトにせよimageProcessorにせよ、任意の名前を付けることができますが、それではそのオブジェクトの種類(クラス)が何なのか分かりません。imagePlusなら imp何とか あるいは 何とかimp、imageProcessor なら ip何とか あるいは 何とかip という風に名前を付けるのが慣例です。サンプルプログラムの類はそうなっています。こうすることで名前から imagePlusなのかimageProcessorなのか判断できるので、プログラムの可読性が上がります。

 なおImageProcessorの変種として、ByteProcessor (8bit画像に限定されたImageProcessor), ShortProcessor(同16bit画像), FloatProcessor(同32bit 浮動小数点画像), ColorProcessor(RGB 24bit画像)があります。