補講1 様々なフィルタ処理


今回のプログラムの最終的な機能

はじめに、これから作るプログラムが完成した時点の機能をざっと見ておく。


エンボス処理


課題 1

    ベースのプログラム (このままではキーを押しても黒い画像ができるだけ)
    PImage img;    // 元画像の変数
    float sx, sy;  // モーションブラーの方向決めのためのドラッグ開始場所
    
    // 4近傍の鮮鋭化フィルタのマスク
    float[] maskS4 = {
      0, -1, 0, 
      -1, 5, -1, 
      0, -1, 0
    };
    
    // 8近傍の鮮鋭化フィルタのマスク
    float[] maskS8 = {
    };
    
    void setup() {
      size(400, 300);
      img = loadImage("1元.jpg");
      image(img, 0, 0, width, height);
    }
    
    void draw() {
    }
    
    // ずれ幅diffのエンボス画像を表示し、ファイルに保存
    void emboss(int diff) {
      PImage outputImg = createImage(img.width-diff, img.height-diff, ARGB);
      for (int j=0; j<img.height-diff; j++) {
        for (int i=0; i<img.width-diff; i++) {
          // 元画像の(i+diff, j+diff)のピクセルの明るさをfloat f1に入れる
          // 元画像の(i, j)のピクセルの明るさを反転させてfloat f2に入れる
          // 出力画像の(i, j)のピクセルの明るさを(f1+f2-128)にする
        }
      }
      outputImg.updatePixels();
      image(outputImg, 0, 0, width, height);
      outputImg.save("data/1エンボス" + diff + ".jpg");
    }
    
    // neighbor個の近傍ピクセルを使って鮮鋭化した画像を表示し、ファイルに保存
    void sharpen(int neighbor) {
      PImage outputImg = createImage(img.width-2, img.height-2, ARGB);
      outputImg.updatePixels();
      image(outputImg, 0, 0, width, height);
      for (int j=1; j<img.height-1; j++) {
        for (int i=1; i<img.width-1; i++) {
          // 出力画像の(i-1, j-1)のピクセルの色を、getSharpenedColor関数で調べた「近傍数neighborで鮮鋭化した、元画像(i, j)の位置のピクセルの色」にする
          outputImg.pixels[i-1+(j-1)*outputImg.width] = color(getSharpenedColor(i, j, neighbor));
        }
      }
      outputImg.updatePixels();
      image(outputImg, 0, 0, width, height);
      outputImg.save("data/2鮮鋭化" + neighbor + ".jpg");
    }
    
    // タイプに応じて鮮鋭化処理後のピクセルの色を返す
    color getSharpenedColor(int x, int y, int neighbor) {
      float[] mask = new float[0];
      if (neighbor==4) {
        mask = maskS4;
      } else {
        mask = maskS8;
      }
      // ピクセル色とマスクの積を足し上げた値を入れる変数
      float br=0;
      float bg=0;
      float bb=0;
      int n=0;
      for (int j=y-1; j<=y+1; j++) {
        for (int i=x-1; i<=x+1; i++) {
          // br, bg, bbに「元画像の(i, j)の位置のピクセルの赤・緑・青成分」×「マスクn番目の値」を加える
          br += red(img.pixels[i+j*img.width]) * mask[n];
          bg += green(img.pixels[i+j*img.width]) * mask[n];
          bb += blue(img.pixels[i+j*img.width]) * mask[n];
          n++;
        }
      }
      return color(br, bg, bb); // br, bg, bbから作った色を返す
    }
    
    // 画素半径raのモーションブラー画像を表示し、ファイルに保存
    void motionBlur(int ra) {
      PImage outputImg = createImage(img.width-ra*2, img.height-ra*2, ARGB);
      outputImg.updatePixels();
      save("data/3モーションブラー" + ra + "向き.jpg"); // スクリーンショットを画像として保存
      image(outputImg, 0, 0, width, height);
      for (int j=ra; j<img.height-ra; j++) {
        for (int i=ra; i<img.width-ra; i++) {
          // 出力画像の(i-ra, j-ra)のピクセルの色を、getBluredColor関数で調べた「画素半径raでモーションブラーをかけた、元画像(i, j)の位置のピクセルの色」にする
          outputImg.pixels[i-ra+(j-ra)*outputImg.width] = color(getBluredColor(i, j, ra));
        }
      }
      outputImg.updatePixels();
      image(outputImg, 0, 0, width, height);
      outputImg.save("data/3モーションブラー" + ra + ".jpg");
    }
    
    // 画素半径に応じてモーションブラー処理後のピクセルの色を返す
    color getBluredColor(int x, int y, int ra) {
      float[] mask = new float[(ra*2+1)*(ra*2+1)];
      float sum = 0;
      int n = 0;
      PVector d = new PVector(mouseX-sx, mouseY-sy); // ドラッグの方向ベクトル
      d.normalize(); // 長さを1にする
      // 中心からの距離に応じた値を入れる
      for (int j=-ra; j<=ra; j++) {
        for (int i=-ra; i<=ra; i++) {
          mask[n] = exp(-(i*d.y-j*d.x)*(i*d.y-j*d.x));
          sum += mask[n];
          n++;
        }
      }
      // 総和が1になるように修正
      for (int i=0; i<mask.length; i++) {
        mask[i] /= sum;
      }
      // ピクセル色とマスクの積を足し上げた値を入れる変数
      float br=0;
      float bg=0;
      float bb=0;
      return color(br, bg, bb); // br, bg, bbから作った色を返す
    }
    
    // ドラッグ開始
    void mousePressed() {
      sx = mouseX;
      sy = mouseY;
    }
    
    // ドラッグ中にドラッグ方向を赤線で表示
    void mouseDragged() {
      image(img, 0, 0, width, height);
      strokeWeight(2);
      stroke(255, 0, 0);
      line(sx, sy, mouseX, mouseY);
    }
    
    // ドラッグ終了時にモーションブラー処理を実行
    void mouseReleased() {
      if (mouseButton == LEFT) {
        motionBlur(5);
      } else {
        motionBlur(10);
      }
    }
    
    void keyPressed() {
      switch(key) {
      case '1':
      case '2':
      case '3':
        emboss(key-'0');
        break;
      case '4':
      case '5':
        sharpen((key-'4')*4+4);
        break;
      }
    }
    

  1. Processingのエディタに上のサンプルプログラムのコードをコピー&ペーストする。
  2. 「imgs1」という名前で保存する。
  3. 適当に画像検索してサンプル用の画像(ざらつきの少ないノッペリした被写体で、エッジがなるべくクッキリしているもの。小物を室内で単体で撮った写真などがよい)を用意する。
  4. 画像の形式に応じて以下の変更を加える。
  5. 画像の横幅が400ピクセルになるようにリサイズする (画像サイズが大きいとメモリ不足でエラーになることがある。また、課題3のモーションブラーの効果が確認しにくい)。
  6. 「1元.jpg」をProcessingのウインドウにドラッグ&ドロップする。
  7. emboss関数の「// 元画像の(i+diff, j+diff)のピクセルの明るさをfloat f1に入れる」と「// 元画像の(i, j)のピクセルの明るさを反転させてfloat f2に入れる」の下に、それぞれ対応するコードを入れる。

  8. emboss関数の「// 出力画像の(i, j)のピクセルの明るさを(f1+f2-128)にする」の下に対応するコードを入れる。

  9. 実行して画面をクリックしてから、「1」「2」「3」のキーを押す。
  10. ここで作る提出物
    ※ うまくいかないときは最終的なemboss関数とコードを見比べる。

鮮鋭化フィルタ

課題 2

  1. 実行画面をクリックしてから「4」キーを押す。


  2. プログラム先頭部分のmaskS8に、然るべき値を入れる。


  3. 実行画面をクリックしてから「5」キーを押す。


  4. ここで作る提出物
    ※ うまくいかないときは最終的なmaskS8配列とコードを見比べる。

モーションブラー

課題 3

  1. getBluredColor関数の「return color(br, bg, bb); // br, bg, bbから作った色を返す」の上に、以下のコードをコピー&ペーストする。
  2.   n=0;
      for (int j=y-ra; j<=y+ra; j++) {
        for (int i=x-ra; i<=x+ra; i++) {
          // br, bg, bbに「元画像の(i, j)の位置のピクセルの赤・緑・青成分」×「マスクn番目の値」を加える
          br += red(img.pixels[i+j*img.width]) * mask[n];
          bg += green(img.pixels[i+j*img.width]) * mask[n];
          bb += blue(img.pixels[i+j*img.width]) * mask[n];
          n++;
        }
      }
    

  3. 実行して、左ボタンで「ブラーをかけたい方向に」ドラッグする。

  4. 同様に、右ボタンでブラーをかけたい方向にドラッグする。
  5. ここで作る提出物
    ※ うまくいかないときは最終的なgetBluredColor関数とコードを見比べる。

提出



戻る inserted by FC2 system