情報学部 菅沼ホーム Java 目次 基礎技術目次 索引

ビットマップ,フィルタ,外部画像

  1. ビットマップ
      図を描く方法として,MemoryImageSource クラスを利用し,ピクセルPixel )単位に色を指定することによって描く方法があります.この例においては,上に示す左側の矩形を Graphics クラスfillRect を使用して,また,右側の矩形は MemoryImageSource クラスによってイメージを生成した後,そのイメージを Graphics クラスの drawImage を使用して描いています( 75 行目).
    01	import java.awt.*;
    02	import java.awt.event.*;
    03	import java.awt.image.*;
    04	import javax.swing.*;
    05	
    06	public class Test {
    07		public static void main (String[] args)
    08		{
    09			Win win = new Win("ビットマップ");
    10		}
    11	}
    12	
    13	class Win extends JFrame
    14	{
    15		/******************/
    16		/* コンストラクタ */
    17		/******************/
    18		Win(String name)
    19		{
    20						// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    21			super(name);
    22						// Windowの大きさ
    23			setSize(310, 200);   // +40, +70
    24						// ContentPane の取得とパネルの追加と MainPanel の追加
    25			MainPanel pn = new MainPanel();   // MainPanel オブジェクトの生成
    26			getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    27			pn.setSize(270, 130);
    28						// ウィンドウを表示
    29			setVisible(true);
    30						// イベントアダプタ
    31			addWindowListener(new WinEnd());
    32		}
    33	
    34		/******************************/
    35		/* 上,左,下,右の余白の設定 */
    36		/******************************/
    37		public Insets getInsets()
    38		{
    39			return new Insets(50, 20, 20, 20);
    40		}
    41	
    42		/************/
    43		/* 終了処理 */
    44		/************/
    45		class WinEnd extends WindowAdapter
    46		{
    47			public void windowClosing(WindowEvent e) {
    48				System.exit(0);
    49			}
    50		}
    51	}
    52	
    53	class MainPanel extends JPanel
    54	{
    55		Image im;
    56		MainPanel()
    57		{
    58			setBackground(new Color(238, 255, 238));   // 背景色の設定
    59			int pixels[] = new int [100*100];
    60			for (int i1 = 0; i1 < 100; i1++) {
    61				for (int i2 = 0; i2 < 100; i2++)
    62					pixels[i1*100+i2] = 0xff00ff00;
    63			}
    64			MemoryImageSource mis = new MemoryImageSource(100, 100, pixels, 0, 100);
    65			im = createImage(mis);
    66		}
    67						// 描画
    68		public void paintComponent(Graphics g)
    69		{
    70			super.paintComponent(g);   // 親クラスの描画
    71	
    72			g.setColor(Color.green);
    73			g.fillRect(20, 15, 100, 100);
    74	
    75			g.drawImage(im, 150, 15, this);
    76		}
    77	}
    			
    55 行目

      今までの例においては,変数の定義をすべてメソッド内で行ってきました.メソッド内で定義された変数は,メソッド内またはブロック内だけで有効となります(ローカル変数).例えば,pixels は,このメソッド内だけで,また,i1 及び i2 は,後に説明するように,for ブロック内だけで有効です.

      しかし,55 行目で使用されている変数 im は,このメソッド内だけでなく,メソッド paintComponent 内においても必要とされます.そこで,変数 im に関しては,この例に示すように,グロ-バル変数として,メソッドの外側で定義しておく必要があります.

    59 行目

      100 行 100 列( 10000 個)のピクセルからなる画像の各ピクセル情報を保存するための配列array )です.

    60 行目~ 61 行目

      変数 i1 と i2 の有効範囲について説明しておきます.変数 i1 と i2 は,ここで( for 文の中で)宣言されています.そのため,60 行目で宣言された変数 i1 の有効範囲は対応する for ブロック( 60 行目~ 63 行目)の中だけ,さらに,61 行目で宣言された変数 i2 の有効範囲は対応する for ブロック( 61 行目~ 62 行目)の中だけになります(「変数の有効範囲」参照).

    62 行目

      一般に,高さ height,幅 width の画像は,(height×width) 個のピクセルから構成されています.各ピクセルの値を適当に設定すれば任意のイメージを作成できるわけですが,そのためには,各ピクセルの値を記憶するための変数が必要です.今まで説明した単純変数を使用すれば (height×width) 個の変数が必要になります.これは,現実的に不可能ですし,ここで使用されているような for 文も使用できなくなります.

      そこで,59 行目のような形で定義される配列を使用することになります.配列変数の各要素は,各々,pixels[0],pixels[1],pixels[2] のように括弧と添え字(必ず 0 から始まる)によって参照することができます.また,同様な方法で,多次元配列を作成することができます.例えば,表に対応する 2 次元配列は,i 行 j 列要素を x[i][j] のように参照することになります( i も j も,必ず 0 から始まる).

      幅が w 個のピクセル,高さが h 個のピクセルで構成されている画像の場合,

        1行1列 1行2列 ・・・ 1行w列
        2行1列 2行2列 ・・・ 2行w列
            ・・・・・
        h行1列 h行2列 ・・・ h行w列

    のように並べて表示されます.従って,2 次元配列 x を使用し,各ピクセルの値を,

        x[0][0] x[0][1] ・・・ x[0][w-1]
        x[1][0] x[1][1] ・・・ x[1][w-1]
            ・・・・・
        x[h-1][0] x[h-1][1] ・・・ x[h-1][w-1]

    のように,2 次元配列の各要素に記憶すれば良いことになります.

      しかしながら,Java においては,各ピクセルのデータを 1 次元配列として取り扱います.各ピクセル情報は,透明度,赤,緑,青(透明度RGB )の強さから構成され,各々,0 ~ 255( 0xff )の値を持ちます.従って,画像における 2 次元配列上の位置を,1 次元配列上の位置に変換する必要があります.記憶されている順番は,x[0][0] を先頭に,左から右,上から下の順(列番号が最初に変化する順)で記憶されていますので,例えば,画像上の i 行 j 列にあるピクセルデータは,1 次元配列上の ( i * 2次元配列の列数 + j ) という位置に相当します.62 行目においては,この関係と for 文を使用して,i1 行 i2 列のピクセルに値を設定しています(ただし,すべて同じ値).

    64 行目~ 65 行目

      ピクセル情報からイメージを生成し,このイメージを 75 行目で描画しています.

  2. 外部画像
      外部にある画像を取り込むことも可能です.この例において,左側の矩形は Graphics クラスの fillRect を使用して描き,また,右側の矩形は,JFrame クラスの getToolkit メソッドによって Toolkit クラスのオブジェクトを取得し,そのメソッド getImage を使用して外部画像 rect.gif を取り込み( 24 行目),読み込んだ Image クラスのオブジェクト im を,引数として MainPanel クラスの渡しています( 25 行目).その後,drawImage を使用して表示しています( 69 行目).
    01	import java.awt.*;
    02	import java.awt.event.*;
    03	import javax.swing.*;
    04	
    05	public class Test {
    06		public static void main (String[] args)
    07		{
    08			Win win = new Win("外部画像");
    09		}
    10	}
    11	
    12	class Win extends JFrame
    13	{
    14		/******************/
    15		/* コンストラクタ */
    16		/******************/
    17		Win(String name)
    18		{
    19						// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    20			super(name);
    21						// Windowの大きさ
    22			setSize(310, 200);   // +40, +70
    23						// ContentPane の取得と MainPanel の追加
    24			Image im = getToolkit().getImage("rect.gif");   // 画像の読み込み
    25			MainPanel pn = new MainPanel(im);   // MainPanel オブジェクトの生成
    26			getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    27			pn.setSize(270, 130);
    28						// ウィンドウを表示
    29			setVisible(true);
    30						// イベントアダプタ
    31			addWindowListener(new WinEnd());
    32		}
    33	
    34		/******************************/
    35		/* 上,左,下,右の余白の設定 */
    36		/******************************/
    37		public Insets getInsets()
    38		{
    39			return new Insets(50, 20, 20, 20);
    40		}
    41	
    42		/************/
    43		/* 終了処理 */
    44		/************/
    45		class WinEnd extends WindowAdapter
    46		{
    47			public void windowClosing(WindowEvent e) {
    48				System.exit(0);
    49			}
    50		}
    51	}
    52	
    53	class MainPanel extends JPanel
    54	{
    55		Image im;
    56		MainPanel(Image im1)
    57		{
    58			im = im1;
    59			setBackground(new Color(238, 255, 238));   // 背景色の設定
    60		}
    61						// 描画
    62		public void paintComponent(Graphics g)
    63		{
    64			super.paintComponent(g);   // 親クラスの描画
    65	
    66			g.setColor(Color.green);
    67			g.fillRect(20, 15, 100, 100);
    68	
    69			g.drawImage(im, 150, 13, this);
    70		}
    71	}
    			

  3. フィルタ
      描画した図形に対して,様々なフィルタを適用することによって,図形にアクセントをつけることができます.この例では,左側の矩形に対して,BufferedImage クラス,及び,ConvolveOp クラスを利用してぼかしを加えてあります.
    01	import java.awt.*;
    02	import java.awt.event.*;
    03	import java.awt.image.*;
    04	import javax.swing.*;
    05	import javax.imageio.*;
    06	
    07	public class Test {
    08		public static void main (String[] args)
    09		{
    10			Win win = new Win("フィルタ(ぼかし)");
    11		}
    12	}
    13	
    14	class Win extends JFrame
    15	{
    16		/******************/
    17		/* コンストラクタ */
    18		/******************/
    19		Win(String name)
    20		{
    21						// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    22			super(name);
    23						// Windowの大きさ
    24			setSize(310, 200);   // +40, +70
    25						// ContentPane の取得と MainPanel の追加
    26			MainPanel pn = new MainPanel();   // MainPanel オブジェクトの生成
    27			getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    28			pn.setSize(270, 130);
    29						// ウィンドウを表示
    30			setVisible(true);
    31						// イベントアダプタ
    32			addWindowListener(new WinEnd());
    33		}
    34	
    35		/******************************/
    36		/* 上,左,下,右の余白の設定 */
    37		/******************************/
    38		public Insets getInsets()
    39		{
    40			return new Insets(50, 20, 20, 20);
    41		}
    42	
    43		/************/
    44		/* 終了処理 */
    45		/************/
    46		class WinEnd extends WindowAdapter
    47		{
    48			public void windowClosing(WindowEvent e) {
    49				System.exit(0);
    50			}
    51		}
    52	}
    53	
    54	class MainPanel extends JPanel
    55	{
    56		BufferedImage im2;
    57		MainPanel()
    58		{
    59			setBackground(new Color(238, 255, 238));   // 背景色の設定
    60						// BufferedImageの生成
    61			int w = 100;
    62			int h = 100;
    63			BufferedImage im0 = new BufferedImage(110, 110, BufferedImage.TYPE_INT_RGB);
    64			Graphics g = im0.getGraphics();
    65			g.setColor(new Color(238, 255, 238));
    66			g.fillRect(0, 0, 110, 110);
    67			g.setColor(Color.blue);
    68			g.fillRect(5, 5, 100, 100);
    69			g.dispose();   // グラフィックスコンテキストを破棄
    70						// フィルタ(ぼかし)
    71			ConvolveOp c = new ConvolveOp(new Kernel(7, 7,
    72				new float[] {
    73					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    74					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    75					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    76					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    77					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    78					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    79					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f
    80				}), ConvolveOp.EDGE_NO_OP, null);
    81			im2 = c.filter(im0, im2);
    82		}
    83						// 描画
    84		public void paintComponent(Graphics g)
    85		{
    86			super.paintComponent(g);   // 親クラスの描画
    87	
    88			g.setColor(Color.blue);
    89			g.fillRect(20, 15, 100, 100);
    90	
    91			g.drawImage((Image)im2, 150, 10, this);
    92		}
    93	}
    			
    63 行目

      110 × 110 の BufferedImage を生成しています.

    64 行目~ 69 行目

      画像の外側境界をぼかすため,BufferedImage に背景色で 110 × 110 の矩形を描いた( 66 行目)後,その内側に,青色で 100 × 100 の矩形を描いています( 68 行目).

    71 行目~ 80 行目

      im0 にぼかしを加えるため,7 行 7 列のフィルタを設定しています.Kernel クラスは,たたみ込み演算を行う行列を定義するクラスであり,例えば,3 行 3 列の場合,以下のような意味を持ちます.
    	/* ぼかし */
    	Kernel K1 = new Kernel(3, 3,
    		new float[]{
    			1/9f, 1/9f, 1/9f,
    			1/9f, 1/9f, 1/9f,
    			1/9f, 1/9f, 1/9f,
    		});
    
    	/* シャープ */
    	Kernel K2 = new Kernel(3, 3,
    		new float[]{
    			-1, -1, -1,
    			-1,  9, -1,
    			-1, -1, -1,
    		});
    
    	/* エンボス(立体視) */
    	Kernel K3 = new Kernel(3, 3,
    		new float[]{
    			 7,  0,  0,
    			 0, -3,  0,
    			 0,  0, -3,
    		});
    
    	/* エッジ */
    	Kernel K4 = new Kernel(3, 3,
    		new float[]{
    			-1,  0,  1,
    			-2,  0,  2,
    			-1,  0,  1,
    		});				
    81 行目

      ぼかしの実行です.ぼかされた画像 im2 は,91 行目で表示されます.

  4. もう一つの例

      この例では,外部から読み込んだ画像ぼかしを加えています.大きな画像の場合,27 行目~ 32 行目を記述しないと,正しく読み込めないようです.
    01	import java.awt.*;
    02	import java.awt.event.*;
    03	import java.awt.image.*;
    04	import javax.swing.*;
    05	import javax.imageio.*;
    06	
    07	public class Test {
    08		public static void main (String[] args)
    09		{
    10			Win win = new Win("フィルタ(ぼかし,外部画像)");
    11		}
    12	}
    13	
    14	class Win extends JFrame
    15	{
    16		/******************/
    17		/* コンストラクタ */
    18		/******************/
    19		Win(String name)
    20		{
    21						// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
    22			super(name);
    23						// Windowの大きさ
    24			setSize(590, 370);   // +40, +70
    25						// 画像が完全に読み込まれるまで待つ
    26			Image im = getToolkit().getImage("hana.gif");
    27			MediaTracker trk = new MediaTracker(this);
    28			trk.addImage(im, 0);
    29			try {
    30				trk.waitForID(0);
    31			}
    32			catch (InterruptedException e) {}
    33						// ContentPane の取得と MainPanel の追加
    34			MainPanel pn = new MainPanel(im);   // MainPanel オブジェクトの生成
    35			getContentPane().add(pn);   // MainPanel オブジェクトを ContentPane に追加
    36			pn.setSize(550, 300);
    37						// ウィンドウを表示
    38			setVisible(true);
    39						// イベントアダプタ
    40			addWindowListener(new WinEnd());
    41		}
    42	
    43		/******************************/
    44		/* 上,左,下,右の余白の設定 */
    45		/******************************/
    46		public Insets getInsets()
    47		{
    48			return new Insets(50, 20, 20, 20);
    49		}
    50	
    51		/************/
    52		/* 終了処理 */
    53		/************/
    54		class WinEnd extends WindowAdapter
    55		{
    56			public void windowClosing(WindowEvent e) {
    57				System.exit(0);
    58			}
    59		}
    60	}
    61	
    62	class MainPanel extends JPanel
    63	{
    64		Image im1;
    65		BufferedImage im2;
    66		MainPanel(Image im)
    67		{
    68			im1 = im;
    69			setBackground(Color.white);   // 背景色の設定
    70						// BufferedImageに変換
    71			int w = im1.getWidth(null);
    72			int h = im1.getHeight(null);
    73			BufferedImage im0 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    74			Graphics g = im0.getGraphics();
    75			g.drawImage(im1, 0, 0, null);
    76			g.dispose();
    77						// フィルタ(ぼかし)
    78			ConvolveOp c = new ConvolveOp(new Kernel(7, 7,
    79				new float[] {
    80					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    81					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    82					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    83					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    84					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    85					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f,
    86					1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f, 1/49f
    87				}), ConvolveOp.EDGE_NO_OP, null);
    88			im2 = c.filter(im0, im2);
    89		}
    90						// 描画
    91		public void paintComponent(Graphics g)
    92		{
    93			super.paintComponent(g);   // 親クラスの描画
    94	
    95			g.drawImage(im1, 50, 50, this);
    96	
    97			g.drawImage((Image)im2, 300, 50, this);
    98		}
    99	}
    			

情報学部 菅沼ホーム Java 目次 基礎技術目次 索引