目次||

第5章

イメージング

Java 2D APIでは、3種類のイメージング・モデルがサポートされています。

  • 旧バージョンのJDKで提供されているプロデューサ/コンシューマ(プッシュ)モデル。
  • 直接方式モデル。
  • 直接方式モデルと互換性のあるパイプライン(プル)モデル。将来のJava Advanced Imaging APIで完全に実装される。

次の表は、3種類のイメージング・モデルの機能を比較したものです。

 
プッシュ・モデル
直接方式イメージ・バッファ・モデル
プル・モデル
主要なインタフェースとクラス
  • Image
  • ImageProducer
  • ImageConsumer
  • ImageObserver
  • BufferedImage
  • Raster
  • BufferedImageOp
  • RasterOp
    (Java 2D API)
  • RenderableImage
  • RenderableImageOp
    (Java 2D API)
  • RenderedOp
  • RenderableOp
  • TiledImage
    (Java Advanced Imaging API)
長所
  • ネットワーク経由などでイメージの可用性によって引き出される処理
  • インクリメンタルに処理されるイメージ
  • もっとも単純なプログラミング・インタフェース
  • 共通使用モデル
  • 必要なデータのみを格納/処理
  • 消極的評価の許容
短所
  • 処理せずに転送を要求
  • より複雑なプログラミング・インタフェース
  • イメージ全体のメモリー割当てが必要
  • イメージ全体の処理が必要
  • より複雑なプログラミング・インタフェース
  • より複雑な実装

この章では、直接方式イメージング・モデルのオブジェクトと技法について説明します。Java 2D APIの直接方式イメージング用のクラスとインタフェースでは、メモリーにデータが格納されているピクセルにマッピングされたイメージを扱うための方法が提供されています。このAPIは、さまざまな格納形式のイメージ・データへのアクセスと、何種類かのフィルタ・リング操作を使ったイメージ・データの処理をサポートしています。

5.1 インタフェースとクラス

Java 2D APIの直接方式イメージングAPIは、インタフェース、イメージ・データ・クラス、イメージ操作クラス、サンプル・モデル・クラス、カラー・モデル・クラスおよび例外の6つのカテゴリに分類できます。

5.1.1 イメージング・インタフェース

インタフェース
説明
BufferedImageOp
BufferedImageオブジェクトで実行される単一入力/単一出力の操作を記述します。AffineTransformOpColorConvertOpConvolveOpLookupOp、およびRescaleOpによって実装されます。
RasterOp
Rasterオブジェクトで実行される単一入力/単一出力の操作を定義します。AffineTransformOpBandCombineOpColorConvertOpConvolveOpLookupOp、およびRescaleOpによって実装されます。
RenderedImage
Rastersの形式のイメージ・データを含む、または生成できるオブジェクトに対する共通プロトコルを定義します。
WritableRenderedImage
スーパー・クラス: RenderedImage
変更が可能なRastersの形式のイメージ・データを含む、または生成できるオブジェクトに対する共通プロトコルを定義します。
TileObserver
WritableRenderedImageの変更状態が変化したときに通知する必要があるオブジェクトのためのプロトコルを定義します。

5.1.2 イメージ・データ・クラス

クラス
説明
BufferedImage
スーパー・クラス: Image
インタフェース: WriteableRenderedImage
アクセス可能なデータ・バッファのあるイメージです。BufferedImageには、イメージ・データのColorModelRasterが含まれます。
ByteLookupTable
スーパー・クラス: LookupTable
バイト・データを含むLookupTableです。
DataBuffer
ピクセル・データを保持する1つ以上のデータ配列をラップします。各データ配列をバンクと呼びます。
DataBufferByte
スーパー・クラス: DataBuffer (final)
バイト型のデータを格納するデータ・バッファです。(Java Advanced Imaging APIで使われます)。
DataBufferInt
スーパー・クラス: DataBuffer (final))
整数型のデータを格納するデータ・バッファです(Java Advanced Imaging APIで使われます)。
DataBufferShort
スーパー・クラス: DataBuffer (final)
short型のデータを格納するデータ・バッファです(Java Advanced Imaging APIで使われます)。
DataBufferUShort
スーパー・クラス: DataBuffer (final)
符号なしshort型のデータを格納するデータ・バッファです。
Kernel
入力ピクセルとその周囲のピクセルがConvolveOpフィルタ・リング操作の出力ピクセルの値に与える影響を記述する行列です。
LookupTable
スーパー・クラス: Object
単一バンド化されたピクセル・データの値をカラー値にマッピングする表です。
Raster
イメージ・データを取り出すことのできるピクセルの矩形配列です。Rasterには、DataBufferSampleModelが含まれています。
ShortLookupTable
スーパー・クラス: LookupTable
short型のデータを含むルックアップ表です。
WritableRaster
スーパー・クラス: Raster
変更できるRasterです。

5.1.3 イメージ操作クラス

クラス
説明
AffineTransformOp
インタフェース: BufferedImageOp, RasterOp
変換元のImageまたはRasterの2次元座標から、変換先のImageまたはRasterの2次元座標への線形マッピングを行うアフィン変換を定義するクラスです。このクラスでは、バイリニアまたは最近傍のアフィン変換操作を実行できます。
BandCombineOp
インタフェース: RasterOp
指定された行列を使って、Rasterのバンドの任意の線形結合を実行します。
BufferedImageFilter
スーパー・クラス: ImageFilter
BufferedImageOp (単一ソース/単一デスティネーションのイメージ演算子)を使ってBufferedImageまたはRasterのフィルタ・リングを行うための簡単な手段を提供するImageFilterです。
ColorConvertOp
インタフェース: BufferedImageOp, RasterOp
ソース・イメージのデータに対しピクセル単位のカラー変換を行います。
ConvolveOp
インタフェース: BufferedImageOp, RasterOp
Kernelを使って、ソース・イメージの畳込みを行います。畳込みは、入力ピクセルの周囲のピクセルにカーネル値を掛けて出力ピクセルの値を生成する空間演算です。Kernelは、入力ピクセルに隣接するピクセルと出力ピクセルの間の関係を数学的に定義しています。
LookupOp
インタフェース: BufferedImageOp, RasterOp
ソースからデスティネーションへのルックアップ操作を行います。Rastersの場合、ルックアップはサンプル値に対して行われます。BufferedImagesの場合、ルックアップはカラー成分とアルファ成分に対して行われます。
RescaleOp
インタフェース: BufferedImageOp, RasterOp
ソース・イメージのデータについて、ピクセル単位の再スケーリングを行います。そのためには、各ピクセルの値にスケーリング係数を掛けてから、オフセットを加えます。

5.1.4 サンプル・モデル・クラス

クラス
説明
BandedSampleModel
スーパー・クラス: ComponentSampleModel (final)
格納されているイメージ・データへのアクセスを提供します。同種のサンプルがバンドとして、DataBufferの別々のバンクに格納されています。1つのピクセルは、各バンドから得られる1つのサンプルで構成されます。
ComponentSampleModel
スーパー・クラス: SampleModel
格納されているイメージ・データへのアクセスを提供します。ピクセルの各サンプルは、DataBufferの独立した要素の中にあります。ピクセルの異なる種類のインタリーブがサポートされています。
MultiPixelPackedSampleModel
スーパー・クラス: SampleModel
格納されているイメージ・データへのアクセスを提供します。複数の単一サンプル・ピクセルが、DataBufferの1つの要素に収められています。
PixelInterleavedSampleModel
スーパー・クラス: ComponentSampleModel
格納されているイメージ・データへのアクセスを提供します。各ピクセルのサンプル・データはデータ配列の隣接する要素に収められており、すべての要素はDataBufferの単一のバンクに収められています。
SampleModel
基になっているデータがDataBufferにどのように格納されているかを認識せずに、イメージからサンプル・データを抽出するメカニズムを定義している抽象クラスです。
SinglePixelPackedSampleModel
スーパー・クラス: SampleModel
格納されているイメージ・データへのアクセスを提供します。個別のピクセルに属するすべてのサンプルが、DataBufferの1つの要素に格納されています。

5.1.5 カラー・モデル・クラス

クラス
説明
ColorModel
インタフェース: Transparency
イメージのピクセル値を赤、緑、青などの色成分に変換するメソッドを定義している抽象クラスです。
ComponentColorModel
スーパー・クラス: ColorModel
任意のColorSpaceと色成分の配列を処理し、そのColorSpaceに適合させることのできるColorModelです。このクラスを使うと、ほとんどの種類のGraphicsDevices上で大半のカラー・モデルを表すことができます。
DirectColorModel
スーパー・クラス: PackedColorModel
このColorModelは、ピクセルのビットにRGBの色成分が直接埋め込まれているピクセル値を表します。X11のTrueColorと類似したカラー・モデルです。ColorModel.getRGBdefaultから返されるデフォルトのRGBのColorModelは、DirectColorModelです。
IndexColorModel
スーパー・クラス: ColorModel
このColorModelは、sRGBのColorSpaceにある固定カラー・マップへのインデックスであるピクセル値を表します。
PackedColorModel
スーパー・クラス: ColorModel
この抽象ColorModelクラスは、ピクセルのビットに色成分が直接埋め込まれているピクセル値を表します。RGBの色成分を含むピクセルをサポートするため、DirectColorModelPackedColorModelを継承しています。

5.1.6 例外クラス

クラス
説明
ImagingOpException
スーパー・クラス: RuntimeException
BufferedImageOpまたはRasterOpのフィルタ・メソッドがイメージを処理できない場合にスローされます。
RasterFormatException
スーパー・クラス: RuntimeException
Rasterに無効なレイアウト情報がある場合にスローされます。

5.2 直接方式イメージングのコンセプト

直接方式イメージング・モデルは、メモリーに格納されている固定解像度のイメージに対応しています。また、イメージ・データに対するフィルタ・リング操作もサポートしています。このモデルでは、多くのクラスとインタフェースが使われています。

次のコンテキストでこのグラフィックスを説明します。

図5-1 BufferedImageとサポート・クラス

図5-1に示すように、BufferedImageはイメージの全体的な管理機能を提供します。BufferedImageはメモリー内に直接作成でき、それを使って、ファイルまたはURLから取得したイメージ・データを保持および操作できます。BufferedImageは、任意のGraphics2Dオブジェクトを使って画面装置に表示したり、適切なGraphics2Dコンテキストを使ってほかの出力先にレンダリングしたりできます。BufferedImageオブジェクトには、ほかの2つのオブジェクト(RasterオブジェクトとColorModelオブジェクト)が含まれています。

Rasterクラスは、イメージ・データの管理機能を提供します。これは、イメージの矩形座標を表し、メモリーにイメージ・データを保持し、単一のイメージ・データ・バッファから複数のサブイメージを作成するメカニズムを提供します。また、イメージ内の特定のピクセルにアクセスするためのメソッドも提供しています。Rasterオブジェクトには、2つのオブジェクト(DataBufferオブジェクトとSampleModelオブジェクト)が含まれています。

DataBufferクラスは、メモリー内にピクセル・データを保持します。

SampleModelクラスは、バッファのデータを解釈し、それを個別のピクセルまたはピクセルの矩形範囲として提供します。

ColorModelクラスは、イメージのサンプル・モデルで提供されるピクセル・データの色を解釈する機能を提供します。

imageパッケージでは、ほかに、BufferedImageオブジェクトとRasterオブジェクトに対するフィルタ・リング操作を定義するクラスが提供されています。イメージ処理のそれぞれの操作は、BufferedImageOpインタフェースとRasterOpインタフェースのどちらかまたはその両方を実装するクラスで具体化されています。操作クラスでは、実際のイメージ操作を行うfilterメソッド群が定義されています。

図5-2は、Java 2D APIのイメージ処理の基本的なモデルを示しています。

フロー・ダイアグラムに、ソース・イメージがデスティネーション・イメージになる前のイメージ処理操作のフローを示します。

図5-2 イメージ処理モデル

イメージ操作では、次の機能がサポートされています。

  • アフィン変換
  • 振幅スケーリング
  • ルックアップ表の変更
  • バンドの線形結合
  • 色の変換
  • 畳込み

イメージの表示と操作だけが必要な場合は、BufferedImageクラスとフィルタ・リング操作クラスを理解するだけで十分です。一方、フィルタを記述したりイメージ・データに直接アクセスしたりする場合は、BufferedImageクラスと関連のあるクラスを理解する必要があります。

5.2.1 用語

次の用語は、このあとの説明で使われているものです。

データ要素: イメージ・データを記憶する単位として使われているプリミティブ型です。DataBuffer配列の個々のメンバーです。データ・バッファ内の要素のレイアウトは、イメージのSampleModelによって行われるピクセルとしてのデータの解釈には依存しません。

サンプル: イメージのピクセルを構成する個別のメンバーです。SampleModelは、DataBufferの要素をピクセルとそのサンプルに変換するメカニズムを提供します。ピクセルのサンプルは、特定のカラー・モデルの基本的な値を表す場合があります。たとえば、RGBカラー・モデルのピクセルは、赤、緑、青という3つのサンプルで構成されています。

成分: 色の解釈に依存しないピクセルの値です。成分とサンプルの違いは、IndexColorModelで役に立ちます。IndexColorModelの場合、ピクセルの成分はLookupTableのインデックスになります。

バンド: イメージに含まれる同じ種類の全サンプルの集合です。たとえば、赤の全サンプルや緑の全サンプルなどです。ピクセル・データは様々な方法で格納できますが、Java 2D APIでは、バンド化方式とピクセル・インタリーブ化方式の2種類がサポートされています。バンド化記憶方式の場合、イメージ・データはバンドの単位で編成されて、ピクセルは各バンドの同じ位置にあるサンプル・データで構成されます。ピクセル・インタリーブ化記憶方式の場合は、イメージ・データはピクセル単位で編成されます。すべてのピクセルが1つの配列に含まれていて、バンドは各ピクセルの同じインデックス位置にあるサンプルのセットで構成されます。

原色: 特定のカラー・モデルにおけるカラー値の個別のメンバーです。たとえば、RGBモデルでは、原色の赤と緑と青からカラー値を生成します。

5.3 BufferedImageクラスの使用方法

BufferedImageクラスは、直接イメージング・モードのサポートで中心となるクラスです。メモリー内のイメージを管理し、ピクセル・データを格納および解釈したり、GraphicsコンテキストまたはGraphics2Dコンテキストにピクセル・データをレンダリングしたりする手段を提供しています。

5.3.1 BufferedImageの作成

BufferedImageを作成するには、Component.createImageメソッドを呼び出します。このメソッドからはBufferedImageが返され、その描画特性は、オブジェクトの作成に使われたコンポーネントの描画特性に対応しています。作成されるイメージは不透明で、Componentのフォアグラウンドとバックグラウンドの色を持ち、イメージの透明度を調節することはできません。この方法を使用すると、コンポーネントのアニメーションでダブル・バッファリングの描画を行うことができます。詳細については、「オフスクリーン・バッファでの描画」を参照してください。

    public Graphics2D createDemoGraphics2D(Graphics g) { 
        Graphics2D g2 = null; 
        int width = getSize().width;  
        int height = getSize().height;  
 
        if (offImg == null || offImg.getWidth() != width || 
                        offImg.getHeight() != height) { 
            offImg = (BufferedImage) createImage(width, height); 
        }  
 
        if (offImg != null) { 
            g2 = offImg.createGraphics(); 
            g2.setBackground(getBackground()); 
        } 
 
        // .. clear canvas .. 
        g2.clearRect(0, 0, width, height); 
 
        return g2; 
    } 

いくつか提供されているコンストラクタ・メソッドを使って、空のBufferedImageをメモリー内に作成することもできます。

5.3.2 オフスクリーン・バッファでの描画

BufferedImageクラスを使うと、グラフィック要素をオフスクリーンの状態で用意し、それを画面にコピーできます。この方法は、グラフィックが複雑な場合、または1つのグラフィックを繰返し使う場合に、特に有効です。たとえば、複雑な図形を何度も表示する必要がある場合は、オフスクリーン・バッファにその図形を一度描画してから、ウィンドウの別の場所にそれをコピーします。一度描画した図形をコピーすることで、グラフィックの表示を高速化できます。

java.awtパッケージでは、ウィンドウに描画する場合と同じ方法でImageオブジェクトに描画できるので、簡単にオフスクリーン・バッファを使うことができます。オフスクリーン・イメージにレンダリングするときも、Java 2D APIのすべてのレンダリング機能を使用できます。

オフスクリーン・バッファは、アニメーションでよく使われます。たとえば、オフスクリーン・バッファを使用してオブジェクトを1回描画し、ウィンドウの中でそれを動き回らせるような使い方ができます。同様に、ユーザーがマウスを使用してグラフィックを移動させるときのフィードバックにも、オフスクリーン・バッファを利用できます。すべてのマウス位置でグラフィックを再描画するのではなく、1度オフスクリーン・バッファに描画したグラフィックを、ユーザーがマウスをドラッグするのに合わせて、マウスの位置にコピーします。1

次のコンテキストでこのグラフィックスを説明します。

図5-3 オフスクリーン・バッファの使用方法

図5-3は、オフスクリーン・イメージに描画してからそのイメージをウィンドウに何回もコピーしているプログラムの例です。最後にイメージをコピーするときは、イメージを変換しています。変換を指定してイメージを再描画する代わりに描画されているイメージを変換すると、不十分な結果になる場合があることに注意してください。

5.3.2.1 オフスクリーン・バッファの作成

オフスクリーン・バッファとして使用できるイメージを作る場合は、Component.createImageメソッドを使うのがもっとも簡単な方法です。

色空間、色深度、およびピクセル・レイアウトが描画先のウィンドウと正確に一致するイメージを作ることで、イメージをグラフィックス装置に効率よくブリットできます。これにより、drawImageはジョブをすばやく実行できます。

BufferedImageオブジェクトを直接作成し、オフスクリーン・バッファとして使うこともできます。この方法は、オフスクリーン・イメージの型または透明度を制御する必要がある場合に便利です。

BufferedImageでサポートされている定義済みのイメージ型を次に示します。

  • TYPE_3BYTE_BGR
  • TYPE_4BYTE_ABGR
  • TYPE_4BYTE_ABGR_PRE
  • TYPE_BYTE_BINARY
  • TYPE_BYTE_GRAY
  • TYPE_BYTE_INDEXED
  • TYPE_CUSTOM
  • TYPE_INT_ARGB_PRE
  • TYPE_INT_ARGB
  • TYPE_INT_BGR
  • TYPE_INT_RGB
  • TYPE_USHORT_555_RGB
  • TYPE_USHORT_565_RGB
  • TYPE_INT_GRAY

BufferedImageオブジェクトは、アルファ・チャネルを含むことができます。図5-3では、アルファ・チャネルを使って、描画される領域と描画されない領域を区別し、すでに描画されているグラフィック(この場合はシェーディングされた矩形)の上に不規則な図形を表示できます。また、アルファ・チャネルを使うと、既存のイメージの色と新しいイメージの色を混合することもできます。

注: 透明度の指定のためにアルファ・イメージ・データが必要な場合以外は(つまり図5-2に示す不規則な形状のイメージを描画するような場合は)、アルファ情報を持つオフスクリーン・バッファの作成を避ける必要があります。必要がない場合にアルファ値を使うと、レンダリングのパフォーマンスが低下します。

GraphicsConfigurationでは、使っている構成と互換性のある形式で、バッファリングされたイメージを自動的に作成する便利なメソッドが提供されています。また、ウィンドウが存在するグラフィックス装置に関連付けられたグラフィックス構成を問い合わせて、互換性のあるBufferedImageオブジェクトの作成に必要な情報を取得することもできます。

5.3.2.2 オフスクリーン・バッファでの描画

バッファのイメージに描画するには、そのBufferedImage.createGraphicsメソッドを呼び出します。このメソッドからは、Graphics2Dオブジェクトが返されます。このオブジェクトを使用すると、すべてのGraphics2Dメソッドを呼び出して、グラフィックス・プリミティブをレンダリングしたり、テキストを配置したり、イメージに他のイメージをレンダリングしたりできます。この描画技法は、2Dイメージング・パッケージで提供されているディザリングなどの拡張機能をサポートしています。次のコードは、オフスクリーン・バッファリングの使用方法を示したものです。

 
    public void update(Graphics g){ 
        Graphics2D g2 = (Graphics2D)g; 
        if(firstTime){ 
            Dimension dim = getSize(); 
            int w = dim.width; 
            int h = dim.height; 
            area = new Rectangle(dim); 
            bi = (BufferedImage)createImage(w, h); 
            big = bi.createGraphics(); 
            rect.setLocation(w/2-50, h/2-25); 
            big.setStroke(new BasicStroke(8.0f)); 
            firstTime = false; 
        }  
 
        // Clears the rectangle that was previously drawn. 
        big.setColor(Color.white); 
        big.clearRect(0, 0, area.width, area.height); 
 
        // Draws and fills the newly positioned rectangle to the buffer. 
        big.setPaint(strokePolka); 
        big.draw(rect); 
        big.setPaint(fillPolka); 
        big.fill(rect); 
 
        // Draws the buffered image to the screen. 
        g2.drawImage(bi, 0, 0, this); 
             
    } 
 

5.3.3 BufferedImageデータの直接的な操作

BufferedImageに直接描画する以外に、2種類の方法で、イメージのピクセル・データに直接アクセスして操作できます。「イメージの処理と拡張」で説明されているように、この技法は、BufferedImageOpのフィルタリング・インタフェースを実装する場合に役に立ちます。

BufferedImage.setRGBメソッドを使用すると、ピクセルまたはピクセル配列の値を特定のRGB値に直接設定できます。ただし、ピクセルを直接変更すると、ディザリングは行われません。また、BufferedImageに関連するWritableRasterオブジェクトを操作することによってピクセル・データを操作することもできます。詳細については、「Rasterの管理と操作」を参照してください。

5.3.4 BufferedImageのフィルタ・リング

BufferedImageOpインタフェースを実装するオブジェクトを使って、BufferedImageにフィルタ・リング操作を適用できます。フィルタリングおよびこのフィルタリング・インタフェースを提供するクラスについては、「イメージの処理と拡張」を参照してください。

5.3.5 BufferedImageのレンダリング

バッファリングされたイメージを特定のコンテキストにレンダリングするには、コンテキストのGraphicsオブジェクトで提供されているdrawImageメソッドのどれかを呼び出します。たとえば、Component.paintメソッドの中でレンダリングするときは、メソッドに渡されたグラフィックス・オブジェクトのdrawImageメソッドを呼び出します。

    public void paint(Graphics g) { 
 
        if (getSize().width <= 0 || getSize().height <= 0) 
            return; 
 
        Graphics2D g2 = (Graphics2D) g; 
 
        if (offImg != null && isShowing())  { 
            g2.drawImage(offImg, 0, 0, this); 
        } 
    } 

5.4 Rasterの管理と操作

BufferedImageオブジェクトは、Rasterを使ってピクセル・データの矩形配列を管理します。Rasterクラスでは、イメージの座標系のためのフィールドとして、幅、高さ、および原点が定義されています。Rasterオブジェクト自体は、DataBufferSampleModelという2つのオブジェクトを使って、ピクセル・データを管理します。DataBufferはラスターのピクセル・データを格納するオブジェクトで(を参照)、SampleModelDataBufferからのピクセル・データの解釈を提供します(を参照)。

5.4.1 Rasterの作成

ほとんどの場合、Rasterを直接作成する必要はありません。メモリーにBufferedImageを作成すると、Rasterが必ず提供されます。ただし、BufferedImageのコンストラクタ・メソッドの1つでは、WritableRasterを渡してRasterを作成できます。

Rasterクラスでは、DataBuffersSampleModelsを指定してRastersを作成するためのstaticファクトリ・メソッドがいくつか提供されています。RasterOpフィルタリング・クラスを実装するときは、これらのファクトリを使うことができます。

5.4.2 親と子のラスター

Rasterクラスには、親ラスターと子ラスターのコンセプトが組み込まれています。これにより、同じ親からいくつでもバッファリングされたイメージを作成できるので、ストレージの効率を向上させることができます。親とその子はすべて同じデータ・バッファを参照し、それぞれの子は、バッファ内で自分のイメージの位置を識別するために固有のオフセットと境界を持っています。子は、getParentメソッドを使って所有権を識別します。

サブラスタを作成するには、Raster.createSubRasterメソッドを使います。サブラスタを作成する際には、サブラスタがカバーする親の領域と親の原点からのオフセットを指定します。

5.4.3 Rasterに対する操作

Rasterクラスでは、ピクセルとピクセル・データにアクセスするための様々な方法が定義されています。これらの方法は、RasterOpインタフェースを実装するときまたは低レベルのピクセル操作を行う必要のあるメソッドを実装するときに、役に立ちます。RasterOpインタフェースは、イメージ・データに対するラスター・レベルのフィルタリングおよび操作を提供します。

Raster.getPixelメソッドを使用すると、ピクセルを個別に取得できます。ピクセルは、配列の中の個別のサンプルとして返されます。Raster.getDataElementsメソッドからは、指定した一連の解釈されていないイメージ・データがDataBufferから取り出されて返されます。Raster.getSampleメソッドからは、個別のピクセルのサンプルが返されます。getSamplesメソッドからは、イメージの特定の範囲に対するバンドが返されます。

これらのメソッドのほかに、Rasterクラスのインスタンス変数を使用してデータ・バッファおよびサンプル・モデルにアクセスすることもできます。これらのオブジェクトでは、Rasterのピクセル・データにアクセスして解釈するための別の手段が提供されています。

5.4.4 WritableRasterサブクラス

WritableRasterサブクラスでは、ピクセル・データとサンプルを設定するメソッドが提供されます。BufferedImageに関連するRasterは実際にはWritableRasterであるため、ピクセル・データの操作に必要なすべてのアクセスが提供されます。

5.5 イメージ・データとDataBuffer

Rasterに属しているDataBufferは、イメージ・データの配列を表します。直接またはBufferedImageのコンストラクタを使ってRasterを作るときは、ピクセルで幅と高さを指定するとともに、イメージ・データのSampleModelを指定します。この情報を使って、適切なデータ型とサイズのDataBufferが作成されます。

DataBufferには3つのサブクラスがあり、それぞれが異なる種類のデータ要素を表しています。

  • DataBufferByte (8ビット値を表す)
  • DataBufferInt (32ビット値を表す)
  • DataBufferShort (16ビット値を表す)
  • DataBufferUShort (符号なしshort値を表す)

前で定義したように、要素はデータ・バッファの配列の連続していないメンバーで、成分またはサンプルは、まとめられてピクセルを形成する不連続の値です。DataBufferに格納されている特定の種類の要素と、SampleModelで表される特定の種類のピクセルの間には、さまざまなマッピングが考えられます。このようなマッピングを実装し、特定のDataBufferから特定のピクセルを取得する手段を提供することは、SampleModelのさまざまなサブクラスの役割です。

DataBufferのコンストラクタは、特定のサイズで特定の数のバンクを持つバッファを作成するための手段を提供します。

DataBufferのイメージ・データには直接アクセスできますが、一般に、RasterクラスとWritableRasterクラスのメソッドを使ってアクセスする方が簡単で便利です。

5.6 SampleModelからのピクセル・データの抽出

抽象クラスのSampleModelでは、基になっているデータの格納方法を知らなくてもイメージのサンプルを抽出できるメソッドが定義されています。このクラスは、関連するDataBufferのイメージ・データの高さと幅を追跡するためのフィールドと、そのバッファのバンド数とデータ型を記述するためのフィールドを提供しています。SampleModelのメソッド群はピクセルの集合としてイメージ・データを提供し、各ピクセルは多くのサンプルまたは成分で構成されています。

java.awt.imageパッケージでは、5種類のサンプル・モデルが提供されています。

  • ComponentSampleModel - DataBufferの1つのバンクの独立したデータ配列要素群にサンプル・データが格納されているイメージからピクセルを抽出する。
  • BandedSampleModel - 個別のデータ要素に各サンプルが格納されているイメージからピクセルを抽出する。バンドは、連続したデータ要素に格納されている。
  • PixelInterleavedSampleModel - 個別のデータ要素に各サンプルが格納されているイメージからピクセルを抽出する。ピクセルは、連続したデータ要素に格納されている。
  • MultiPixelPackedSampleModel - 1つのデータ要素に1つのサンプルの複数のピクセルが格納されている単一バンド化されたイメージからピクセルを抽出する。
  • SinglePixelPackedSampleModel - DataBufferの最初のバンクにある1つのデータ配列要素に単一ピクセルのサンプル・データが格納されているイメージからサンプルを抽出する。

データ・ソースの種類により、SampleModelで表されるピクセル・データと特定のカラー・モデルのカラー・データ表現との間には、直接的な関連がある場合とない場合があります。たとえば、写真イメージ・データの場合、サンプルはRGBデータを表す場合があります。医療用画像装置のイメージ・データの場合は、温度や骨密度など、異なる種類のデータをサンプルが表している可能性があります。

イメージ・データにアクセスするためのメソッドには、3つの種類があります。getPixel系メソッドは、サンプルごとに1つのエントリがある配列としてピクセル全体を返します。getDataElementメソッドを使うと、DataBufferに格納されている解釈されていない未処理のデータにアクセスできます。getSampleメソッドは、特定のバンドのピクセル成分に対するアクセスを提供します。

5.7 ColorModelとカラー・データ

Rasterオブジェクトはイメージ・データを管理するためのものですが、BufferedImageクラスには、これ以外に、カラー・ピクセル値としてデータを解釈するColorModelが含まれています。抽象クラスのColorModelでは、イメージのピクセル・データを対応するColorSpaceのカラー値に変換するメソッドが定義されています。

java.awt.imageパッケージでは、4種類のカラー・モデルが提供されています。

  • PackedColorModel - 整数型ピクセルのビットに色成分が直接埋め込まれているピクセル値を表す抽象ColorModelクラス。DirectColorModelは、PackedColorModelのサブクラスです。
  • DirectColorModel - ピクセル自体のビットにRGBの色成分が直接埋め込まれているピクセル値を表すColorModelDirectColorModelモデルの表示はX11のTrueColorと類似しています。
  • ComponentColorModel - 任意のColorSpaceと色成分の配列を処理し、そのColorSpaceに適合させることのできるColorModel
  • IndexColorModel - sRGBの色空間にある固定カラー・マップへのインデックスであるピクセル値を表すColorModel

DataBufferのデータに基づいて、SampleModelColorModelにピクセルを提供し、ColorModelはそのピクセルを色として解釈します。

5.7.1 ルックアップ表

ルックアップ表には、1つ以上のチャネルまたはイメージ成分のデータが含まれています。たとえば、赤と緑と青の独立した配列などです。java.awt.imageパッケージでは、バイト型のデータを含むもの(ByteLookupTable)とshort型のデータを含むもの(ShortLookupData)の2種類のルックアップ表が定義されていて、どれもLookupTable抽象クラスを継承しています。

5.8 イメージの処理と拡張

imageパッケージでは、BufferedImageオブジェクトとRasterオブジェクトに対する操作を定義する次の2つのインタフェースが提供されています。BufferedImageOpおよびRasterOp

これらのインタフェースを実装するクラスとしては、AffineTransformOp、BandCombineOp、ColorConvertOp、ConvolveOp、LookupOp、RescaleOpがあります。これらのクラスを使って、イメージに対する幾何学的変換、ぼかし、シャープ化、コントラスト強調、しきい値、色調補正などの処理を行うことができます。

図5-4は、輪郭の検出と強調の結果を示したものです。この操作は、イメージ内の輝度の大幅な変化を強調するものです。輪郭の検出は、普通、医療用画像処理アプリケーションや地図アプリケーションで使われます。輪郭の検出を使用すると、イメージ内の隣接する構造の間のコントラストが強くなり、より細部まで識別できるようになります。

前の文で、このグラフィックスを説明しています。

図5-4 輪郭の検出と強調

次のコードは、輪郭の検出について記述したものです。

float[] elements = { 0.0f, -1.0f, 0.0f, 
                    -1.0f, 4.f, -1.0f, 
                    0.0f, -1.0f, 0.0f}; 
... 
 
BufferedImage bimg = new BufferedImage(bw,bh,BufferedImage.TYPE_INT_RGB); 
Kernel kernel = new Kernel(3, 3, elements); 
ConvolveOp cop = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP,                                             null); 
cop.filter(bi,bimg); 

図5-5は、ルックアップ表操作の例です。ルックアップ操作は、ピクセルの個別のコンポーネントを変更する場合に使用できます。

前の文で、このグラフィックスを説明しています。

図5-5 ルックアップ表操作

次のコードは、ルックアップ表操作について記述したものです。

        byte reverse[] = new byte[256]; 
   for (int j=0; j<200; j++){  
                reverse[j]=(byte)(256-j);  
        }        
        ByteLookupTable blut=new ByteLookupTable(0, reverse);  
        LookupOp lop = new LookupOp(blut, null);  
   lop.filter(bi,bimg);   

図5-6は、再スケーリングの例です。再スケーリングでは、すべての点の輝度を強くしたり弱くしたりできます。再スケーリングを使うと、メリハリのないイメージのダイナミック・レンジを拡大して、平板に見える領域の細部を際立たせることができます。

前の文で、このグラフィックスを説明しています。

図5-6 再スケーリング

次のコードは、再スケーリングについて記述したものです。

        RescaleOp rop = new RescaleOp(1.5f, 1.0f, null); 
        rop.filter(bi,bimg); 

5.8.1 イメージ処理操作の使用方法

畳込みは、ほとんどの空間フィルタリング・アルゴリズムの基になっている処理です。畳込みでは、イメージの各ピクセルの値と周囲のピクセルの値の間で重み付けを行ったり、平均化したりする処理が行われます。これにより、カーネルで数学的に指定できる方法に従って、出力される各ピクセルに周囲の隣接するピクセルからの影響を反映させることができます。図5-7は、畳込みの例です。

前の文で、このグラフィックスを説明しています。

図5-7 畳込みを使ったぼかし

次に示すコードの抜粋は、イメージ処理クラスの1つであるConvolveOpの使用方法の例です。次の例では、ソース・イメージの各ピクセルは、隣接する8つのピクセルと均等に平均化されます。

float weight = 1.0f/9.0f;float[] elements = new float[9]; // create 2D array// fill the array with nine equal elements 
for (i = 0; i < 9; i++) {   elements[i] = weight;}// use the array of elements as argument to create a Kernelprivate Kernel myKernel = new Kernel(3, 3, elements);public ConvolveOp simpleBlur = new ConvolveOp(myKernel); 
 
// sourceImage and destImage are instances of BufferedImagesimpleBlur.filter(sourceImage, destImage) // blur the image 

変数simpleBlurには、BufferedImageまたはRasterのぼかし操作を実装するConvolveOpの新しいインスタンスが格納されます。sourceImageとdestImageは、BufferedImageの2つのインスタンスとします。ConvolveOpクラスの核となるメソッドのfilterを呼び出すと、ソース・イメージのピクセルとそれを囲む8つのピクセルの値が平均化されて、デスティネーション・イメージの対応するピクセルの値に設定されます。

この例の畳込みカーネルは、4桁の有効数字で指定される要素を持つ次の行列で表されます。

すべての値が0.1111の3×3の行列。

イメージの畳込みでは、デスティネーション・イメージの各ピクセルの値は、そのピクセルの値と周囲のピクセルの値を平均化するときの荷重値の組としてカーネルを使って算出されます。この操作は、イメージのチャネルごとに行われます。

次の式は、畳込みを行うときにカーネルの荷重値をソース・イメージのピクセルと関連付ける方法を示しています。カーネルの各値は、イメージの空間位置に結び付けられます。

3×3の行列。最初の行の値は、i - 1、j - 1、i、j - 1、およびi+1、j - 1です。2番目の行の値は、i - 1、j、i、j、およびi+1、jです。3番目の行の値は、i - 1、j+1、i、j+1、およびi+1、j+1です。

デスティネーション・ピクセルの値は、対応するソース・ピクセルの値をカーネルの加重値に掛けた積を合計したものです。多くの単純な操作では、カーネルは対称の正方行列であり、加重値を合計すると1になります。2

この例の畳込みカーネルは、比較的単純なものです。このカーネルでは、ソース・イメージの各ピクセルが均等に加重されます。ほかのカーネルを選択し、ソース・イメージに対する荷重レベルを高くしたり低くしたりすることで、デスティネーション・イメージの輝度を強くしたり弱くしたりできます。ConvolveOpコンストラクタで設定されるKernelオブジェクトで、実行されるフィルタ・リングの種類が決まります。ほかの値を設定すれば、ぼかし(ガウス、円形、移動など)、シャープ化、平滑化操作など、ほかの種類の畳込みを実行できます。図5-8は、畳込みを使ったシャープ化の例です。

前の文で、このグラフィックスを説明しています。

図5-8 畳込みを使ったシャープ化

次に示すコードは、畳込みを使ったシャープ化の例です。

float[] elements = { 0.0f, -1.0f, 0.0f, 
                    -1.0f,  5.f, -1.0f, 
                     0.0f, -1.0f,  0.0f}; 
... 
 
Kernel kernel = new Kernel(3,3,elements); 
ConvolveOp cop = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP,                                                                                                          null); 
        cop.filter(bi,bimg); 

1新たな位置にコピーを新規作成する前に、以前のバージョンのイメージを「消去」する場合、そのことをプログラマが記述する必要があります。これは、バックグラウンドを再描画したり、別のオフスクリーン・バッファからバックグラウンドをコピーしたりすることによって行うことができます。
2行列内の荷重値の合計が1である場合、デスティネーション・イメージの輝度はソースと同一です。

目次||

Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved.