画像エフェクタ

  1. 目的

    画像を徐々に白い画像に変換する「ホワイトアウト」処理を行います。

  2. 利用法

    1. 画像の展開
      読み込んだ画像は、PixelGrabber クラスを利用すると画素の配列に展開することができます。画素配列の各画素を徐々に「白色」に変換します。

    2. 画素配列
       画像ファイルを読み込んだ image クラスのオブジェクトは 次のように、PixelGrabber クラスを利用して、画素配列pixels[]に変換できます。

       int pixels[] = new int[iwidth * iheight];
       PixelGrabber pg =new PixelGrabber(image, 0, 0, iwidth, iheight, pixels, 0, iwidth);
       pg.grabPixels();

      pixels[]は、画像の 幅:iwidth*高さ:iheight の画素の配列で、最初に第0行のiwidth個の画素、次に第1列のiwidth個の画素、..、が記憶される配列です。

    3. 画素
       一つの画素は、4バイトで、各1バイトの A,B,G,R のデータが記録されます。B,G,R は 0..255 までの数値で、青、緑、赤、の色成分の強さを示します。
       Aは「不透明度」で、この画素の色は、0のときB,G,R に無関係に背景の色になり、255のとき不透明度最大(透明度最小)で背景に色に関係なく B,G,R で指定した色になります。
       B,G,R の値がすべて255のとき、明るい白色となります。

    4. ホワイトアウト
       画素を白色にするため、画素の B,G,R に値を加えていきます。ただし、255を超えた場合は、255に戻します。ここでは、一定値10を加えます。
       画素のG(緑)の場合、画素の 15-8 ビットのみを1にし、8ビット右にシフトします。これは、次のような式で表現できます。

       green = ((pixels[y * iwidth + x] & 0xFF00) >> 8) + 10;

       pixels[y * iwidth + x] は、左から x番目 、上から y 番目の画素に相当します。 0xFF00は16進表記で、15-8 ビットのみが1となる定数です。& はビット毎の論理積演算です。>> は右シフトをする演算子です。最後に10を加えて、白色化を行います。
       ただし、255を超えた場合は、255に戻す必要があります。ここでは、この処理を normal(int col) メソッドで行います。
       blue、green、red、の各成分から、画素を構成するには、次のようにします。0xFF000000 は透明度を0とする定数で、これに、blue、green、red、の値を右にシフトしながら、論理和をします。 | が論理和演算です。

      pixels[y * iwidth + x] =(0xFF000000 | blue << 16 | green << 8 | red);

    5. 画素配列から画像を合成する
       画素配列から image クラスの画像を合成するには、MemoryImageSource クラスと、createImage メソッドを利用します。

       image =createImage(new MemoryImageSource(iwidth, iheight, pixels, 0, iwidth));

      これで、白色化したpixcels[]配列から、image を作成することができます。image は、

       g.drawImage(image, 0, 0, iwidth , iheight , this);

      で、グラフィックス画面に表示できます。

  3. プログラム

    1. プログラムの構成
       init()でjbInit() を呼び出し、load ボタンと white ボタンを生成します。load ボタンで load_actionPerformed() が呼び出し、画像ファイル(ccad.gif)を読み込み、Imageクラスの image を作成します。
       white ボタンで、button2_actionPerformed を呼び出し、imageから画素配列 pixcels[] を作成し、各画素を白化します。これから、image を再合成し repaint で、image を表示します。

    2. プログラム
      import java.awt.*;
      import java.awt.event.*;
      import java.applet.*;
      import java.awt.image.*;
      
      public class WhiteOut extends Applet {
          Image image;
      
          Button load = new Button();
          Button button2 = new Button();
      
          public void init() {
              try {
                  jbInit();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          
          //コンポーネントの初期化
          private void jbInit() throws Exception {
              load.setLabel("load");
              load.setBounds(new Rectangle(15, 170, 70, 25));
              load.addActionListener(new java.awt.event.ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      load_actionPerformed(e);
                  }
              });
              this.setLayout(null);
              button2.setLabel("white");
              button2.setBounds(new Rectangle(100, 170, 80, 25));
              button2.addActionListener(new java.awt.event.ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      button2_actionPerformed(e);
                  }
              });
              this.add(load, null);
              this.add(button2, null);
          }
      
          public void paint(Graphics g) {
              int iwidth=0,iheight=0;
              if (image != null) {
                  iwidth = image.getWidth(this);
                  iheight = image.getHeight(this);
                  //System.out.println("size="+iwidth+" "+iheight);
                  g.drawImage(image, 0, 0, iwidth , iheight , this);
              }
          }
      
          void load_actionPerformed(ActionEvent e) {
              //ファイルを読みpixels[]に記録する
              image = getImage(getDocumentBase(), "ccad.gif");
              //System.out.println("load="+image.getWidth(this)+" "+image.getHeight(this));
              repaint();
          }
      
          void button2_actionPerformed(ActionEvent e) {
              int iwidth = image.getWidth(this);
              int iheight = image.getHeight(this);
              //画素の配列
              int pixels[] = new int[iwidth * iheight];
      
              //ファイルを読みpixels[]に記録する
              PixelGrabber pg =
                  new PixelGrabber(image, 0, 0, iwidth, iheight, pixels, 0, iwidth);
              try {
                  pg.grabPixels();
              } catch (InterruptedException ev) {
              }
      
              //色別に処理をする
              int x,y,red,green,blue;
              for (y = 0; y < iheight ; y++) {
                  for (x = 0; x < iwidth ; x++) {
                      red = (pixels[y * iwidth + x] & 0xFF) + 10;
                      red = normal(red);
                      green = ((pixels[y * iwidth + x] & 0xFF00) >> 8) + 10;
                      green = normal(green);
                      blue = ((pixels[y * iwidth + x] & 0xFF0000) >> 16) + 10;
                      blue = normal(blue);
      
                      pixels[y * iwidth + x] =
                          (0xff000000 | blue << 16 | green << 8 | red);
                  }
              }
              //表示用imageにする
              image =createImage(new MemoryImageSource(iwidth, iheight, pixels, 0, iwidth));
              repaint();
          }
      
          int normal(int col) {
              if (col < 0) return 0;
              if (col > 255) return 255;
              return col;
          }
      
      }

    3. 実行結果

       loadボタンで画像が表示されます。white ボタンを押すごとに、徐々に画像の色が白に変化していきます、