スクラッチ


  1. スクラッチ


    1. スクラッチとは

      ここでは、爪をマウスに替えて、画像をドラッグすると画像が現れる遊びです。画像処理の応用として面白いでしょう?

    2. 原理

      2つの配列を利用します。ひとつは現在の Image の状態を示す paper _pix[]、もうひとつは最初は隠しておき削るごろに表示する Image:src_pix[] です。init()でこれらの配列を初期化します。マウスドラッグに伴い、マウス位置周辺の表示用画素を原画像の画素で置き換えます。

  2. ソース


    1. 関数

      クラス scratch:Applet継承、マウスモーションリスナー実装
      init():画像ファイル読み込み、配列生成、イメージ生成、マウスモーションリスナー追加
      paint():イメージの描画
      update():paint()の実行
      mouseMoved():何もせず
      mouseDragged():現在位置の取得、削る操作、画像の再描画
      get_pixels():画像のデータを配列に格納(init()から実行)
      cover():表示イメージの初期化(init()から実行)
      scratch():配列を変更してイメージを再構成(mouseDragged()から実行)
       

    2. ソース

      init() ではファイル数の最大値を アップレットタグから受け取り乱数でファイルを決定しいます。
      scratch() では画像の縁で、範囲を逸脱しないかチェックが必要です。
      (練習のため、ところどころ虫食い状態です)
      //画像処理によるスクラッチ
      import java.applet.*;
      import java.awt.*;
      import java.awt.event.*;
      import java.awt.image.*;
      
      /*
      <applet code="scratch" width="100" height="100">
      <param name="files" value="1">
      </applet>
      */
      
      public class scratch extends Applet implements MouseMotionListener{
      
       Image paper;
       int[] src_pix,paper_pix;
       int imgWDH,imgHGT;
       //
       public void init(){
      
        //乱数で使用するファイル名をさだめる
        int n = Integer.parseInt(getParameter("files"));
         n = 1 + (int)(Math.random() * n);
        Image img = getImage(getCodeBase(),"image" + n + ".gif");//画像を読む
        src_pix = get_pixels(img);//画像の画素を取得
      
        paper = cover();//表示画像の初期化
        resize(imgWDH,imgHGT);//画像にあわせてサイズ変更
      
        addMouseMotionListener(this);
      
       }//init
      
       public void update(Graphics g){
      //clearRect(やるとちらつく)
        paint(g);
       }//update
      
       public void paint(Graphics g){
        g.drawImage(paper,0,0,this);
       }//paint
      
       public void mouseMoved(MouseEvent me){
      //do nothing
       }//moved
      
       public void mouseDragged(MouseEvent me){
      //マウスの位置を取得
        Point pt = me.??Point();
      
        if(pt.x >= 0 && pt.x < imgWDH && pt.y >= 0 && pt.y < img???){
         int address = (int)pt.getX() + imgWDH * (int)pt.getY();//画素配列は一次元なので変換
      //   System.out.println("address : " + address);
      
         paper = sc???(address);//マウス位置周辺を削る
         repaint();//再描画
        }//if
      
       }//dragged
      
       public int[] get_pixels(Image src){
      //画像の画素配列と、高さ・幅情報の取得
        MediaTracker mt = new MediaTracker(this);
        mt.addImage(src,0);
      
        try{
         mt.waitForID(0);
        }//try
         catch(InterruptedException e){
         System.out.println("cannnot read.");
        }//catch
      
        imgWDH = src.getWidth(this);//MediaTrackerを介さないと読めない
        imgHGT = src.getHeight(this);
        int pix[] = new int[imgWDH * imgHGT];
        //画像を画素に展開
        try{
         PixelGrabber pg = new PixelGrabber(src,0,0,imgWDH,imgHGT,pix,0,imgWDH);
          pg.grabPixels();
        }//try
        catch(InterruptedException e){       
        }//catch
        return pix;
       }//getPixels
      
       public Image cover(){
      //削られていない状態の画素配列の生成
        paper_pix = new int[imgWDH * imgHGT];
      
        for(int i = 0; i < paper_pix.length;i++){
         paper_pix[i] = 0xffcccccc;//初期の色
        }//for
      
        MemoryImageSource img_m = new MemoryImageSource(imgWDH,imgHGT,paper_pix,0,imgWDH);
         Image new_img = createImage(img_m);
        return new_img;
      
       }//covered
      
       public Image scratch(int ad){
      //マウスの位置を中心に周囲の12ピクセルの色を原画像の色に置き換える
      //上下は配列範囲のチェック
      //左右は回り込みのチェック
      
        paper_pix[ad] = src_pix[ad];//中心
      
        if(ad >= imgWDH)
         paper_pix[ad - imgWDH] = src_pix[ad - imgWDH];//上1
        if(ad >= imgWDH ??)
         paper_pix[ad - (imgWDH * 2)] = src_pix[ad - (imgWDH * 2)];//上2
         
        if(ad % imgWDH != 0)
         paper_pix[ad - 1] = src_pix[ad - 1];//左1
        if(ad % imgWDH != 1)
         paper_pix[ad - ??] = src_pix[ad - ??];//左2
         
        if(ad + imgWDH < paper_pix.length)
         paper_pix[ad + imgWDH] = src_pix[ad + imgWDH];//下1
         
        if(ad + (imgWDH * 2) < paper_pix.length)
         paper_pix[ad + (imgWDH * 2)] = src_pix[ad + (imgWDH * 2)];//下2
         
        if(ad % imgWDH != imgWDH - 1)
         paper_pix[ad + 1] = src_pix[ad + 1];//右1
        if(ad % imgWDH != imgWDH - 2)
         paper_pix[ad + 2] = src_pix[ad + 2];//右2
      
        if(ad >= imgWDH && ad % imgWDH != 0)
         paper_pix[ad - imgWDH - 1] = src_pix[ad - imgWDH - 1];//左下
        if(ad >= imgWDH && ad % imgWDH != imgWDH - 1)
         paper_pix[ad - imgWDH + 1] = src_pix[ad - imgWDH + 1];//右下
         
        if(ad + imgWDH < paper_pix.length && ad % imgWDH != 0)
         paper_pix[ad + imgWDH - 1] = src_pix[ad + imgWDH - 1];//左上
        if(ad + imgWDH < paper_pix.length && ad % imgWDH != imgWDH - 1)
         paper_pix[ad + imgWDH + 1] = src_pix[ad + imgWDH + 1];//右上
      
      //変更された配列をもとにImageを再度生成
        MemoryImageSource img_m = new MemoryImageSource(imgWDH,imgHGT,paper_pix,0,imgWDH);
        Image new_img = createImage(img_m);
      
        return new_img;
      
       }//scratched
      
      }//scratch

  3. 演習、アンケート


    1. 演習

      1 scratch() を繰り返しループで処理する方法を考えてください。
      2 吉、中吉、凶、などの画像を作成し、占いスクラッチにしてみてください。

    2. アンケート

      1 プログラムは理解できましたか?
       1:できた、 2:だいたい 3:よくわからん
      2 プログラムの実行はできましたか?
       1:できた、 2:多分 3:できない
      3:演習1はできましたか
       1:できた 2:だいたい 3:わからん