ルックアップテーブルの操作
一律に輝度を計算するのではなく、それぞれの値ごとに変更する値を細かに指定したい場合には、「ルックアップテーブル」と呼ばれるものを操作するフィルタ処理を行います。通常、フルカラーのビットマップイメージでは、各ビットのRGB(A)のそれぞれに0~255の値が設定されています。これを「輝度がゼロの場合は○○にする」「輝度が1の場合は××にする」……というように0~255のすべての値ごとに変更する値を指定するテーブルを用意し、これに基づいて輝度の変更を行うわけです。
これも、実際に簡単な例を挙げましょう。
public BufferedImage getModifiedImage(BufferedImage im) { byte[] table = new byte[256]; for (int i = 0; i < 256; i++) { table[i] = (byte)(i < 128 ? 0 : 255); } int w1 = im.getWidth(), h1 = im.getHeight(); BufferedImage im2 = new BufferedImage(w1, h1, im.getType()); ByteLookupTable blt = new ByteLookupTable(0,table); LookupOp op = new LookupOp(blt,null); op.filter(im, im2); return im2; }

これは、輝度が128未満ならばゼロに、それ以上なら255に変更するものです。つまり、RGBのそれぞれで輝度を強制的に2階調にしてしまうわけです。いかにもフィルタ処理した、という感じになってきましたね?
ここで使用しているのは、「LookupOp」というクラスです。これは、あらかじめ用意してあるルックアップテーブルのクラス「LookupTable」のインスタンスと、RenderingHintsインスタンスを引数に指定して作成をします。
new LookupOp( LookupTable table, RenderingHints hint)
このような形です。RescaleOpと同様、RenderingHintsは不要ならnullでかまいません。そして、filterメソッドを呼び出すことで、第1引数のイメージをフィルタ処理し、第2引数のBufferedImageに描画します。
このLookupOpのポイントは、引数に指定するLookupTableをどのように作成するか、でしょう。LookupTableクラスは抽象クラスとして定義されているので、通常はこれを継承したByteLookupTableかShortLookupTableを利用するのが一般的です。
ここではByteLookupTableを使っています。これは、第1引数にオフセット値を、第2引数に各輝度の値をどのような値に変更するかをbyte配列としてまとめたものを指定します。ここでは、配列の値を次のようにして用意していますね。
byte[] table = new byte[256]; for (int i = 0; i < 256; i++) { table[i] = (byte)(i < 128 ? 0 : 255); }
128未満であればゼロを、それ以上ならば255を指定しています。これですべての輝度をゼロか255に変更するテーブルが作成できたわけです。同様の考え方で、4階調、8階調などに変更することも行えるでしょう。
また、先のRescaleOpと同様に、複数のテーブル用配列を用意することで、RGB(A)のそれぞれにテーブルを指定して変換することも可能です。
public BufferedImage getModifiedImage(BufferedImage im) { byte[] tableR = new byte[256]; byte[] tableG = new byte[256]; byte[] tableB = new byte[256]; for (int i = 0; i < 256; i++) { tableR[i] = (byte)(i < 128 ? 0 : 255); tableG[i] = (byte)i; tableB[i] = (byte)(256 -i); } int w1 = im.getWidth(), h1 = im.getHeight(); BufferedImage im2 = new BufferedImage(w1, h1, im.getType()); ByteLookupTable blt = new ByteLookupTable(0,new byte[][]{tableR,tableG,tableB}); LookupOp op = new LookupOp(blt,null); op.filter(im, im2); return im2; }

ここでは、赤を2階調にし、緑をそのまま、青の階調を逆転させるというフィルタ処理をさせてみました。ここでは、あらかじめ3つのbyte配列を用意しておき、ByteLookupTableの引数に、new byte[][]{tableR,tableG,tableB}として各配列を一つの配列にまとめたものを渡しています。
