第15回 疑似カラー・空間フィルタリング・そのほかの処理

準備

まず2枚の元画像を用意する。

  1. 1枚目の画像 (「元a.jpg」としてデスクトップに保存する)
  2. 2枚目の画像 (「元b.jpg」としてデスクトップに保存する)

  3. ※ ダウンロードした画像がjpg以外の形式だった場合は、ペイントで開いて形式をJPGに指定して保存する。
    ※ このあと実行する課題で、元画像のサイズが大きすぎるとメモリが不足してエラーになることがある。その場合はGIMPやペイントなどで画像を小さくしてから実行する。
    ※ 画像の縦横のサイズはアイコンにマウスカーソルを当てる (クリックはしない) と確認できる。

課題 1 (疑似カラー)

143ページの図5.20のトーンカーブを使った疑似カラー画像を作る。

    元画像のそれぞれのピクセルの明るさに応じて、出力画像の赤、緑、青成分の明るさを下のトーンカーブによって決める。


  1. Processingを起動する。
  2. 以下のプログラムのコードをコピーし、Processingのエディタに貼り付ける。
  3. PImage img;
    img = loadImage("元a.jpg"); // 画像を読み込む
    img.filter(GRAY); // グレースケール化
    // 疑似カラー化
    float r, g, b;
    for (int i=0;i<img.pixels.length;i++){
      float br=brightness(img.pixels[i])/255; // i番目のピクセルの明度を取得して0~1に規格化
      if (br<0.25){ // 0~0.25の明るさ
        r=0; g=br*4; b=1;
      }else if(br<0.5){// 0.25~0.5の明るさ
        r=0; g=1; b=(0.5-br)*4;
      }else if(br<0.75){// 0.5~0.75の明るさ
        r=(br-0.5)*4; g=1; b=0;
      }else{// 3/4~1の明るさ
        r=1; g=(1-br)*4; b=0;
      }
      img.pixels[i] = color(r*255, g*255, b*255);
    }
    img.save("data/1疑似カラー.jpg"); // ファイルに保存
    

  4. 「ex15」という名前で保存する。
  5. 元a.jpgをProcessingのエディタにドラッグ&ドロップする。
  6. プログラムを実行する。
  7. プログラムのdataフォルダーを開く(メニューの「スケッチ」→「スケッチフォルダーを開く」)。
  8. そのフォルダーにできた「1疑似カラー.jpg」を開き、「暗いところは青、明るいところは赤、中間の明るさのところが緑」になっていることを確認する。
  9. 元a.jpg1疑似カラー.jpg

    ※ 出力画像に赤・緑・青の3つの部分がない (元画像の明るさが偏っている) ときは、元画像を変えてやり直す。

課題 2 (平滑化)

Processingのライブラリ機能を使って、画像を平滑化する。

  1. Processingのエディタのコードを消し、以下のコードをコピー&ペーストする。
  2. PImage img;
    img = loadImage("元a.jpg"); // 画像を読み込む
    img.filter(BLUR, 5); // 画像をぼかす
    img.save("data/2平滑化.jpg"); // ファイルに保存
    

  3. プログラムを実行する。
  4. dataフォルダーにできた「2平滑化.jpg」と「元a.jpg」を見比べて、「2平滑化.jpg」の方がぼやけた状態になっていることを確認する。
  5. 元a.jpg2平滑化.jpg

    ※ このアルゴリズムでは、ある位置のピクセルの色を、(元画像の)それを囲む正方形の色を平均して決める。プログラムの「img.filter(BLUR, 5);」の「5」のところに入れる数値によってその正方形の大きさが変わる。これを大きくするほどぼやけ方が強くなる。

課題 3 (エッジ抽出)

テキストの図5.32, 5.35のフィルタを使い、画像からエッジを取り出す。

  1. Processingのエディタのコードを消し、以下のコードをコピー&ペーストする。
  2. PImage img;
    img = loadImage("元a.jpg"); // 画像を読み込む
    img.filter(GRAY); // グレースケールにする
    float[] outX = new float[img.width*img.height]; // 横の明度差を入れる配列
    float[] outY = new float[img.width*img.height]; // 縦の明度差を入れる配列
    for(int j=0;j<img.height;j++){
      for(int i=0;i<img.width;i++){
        int pos=i+j*img.width;
        if (i<img.width-1) outX[pos]=brightness(img.pixels[pos+1])-brightness(img.pixels[pos]); // 横に並んだピクセルの明度の差
        if (j>0) outY[pos]=brightness(img.pixels[pos-img.width])-brightness(img.pixels[pos]); // 縦に並んだピクセルの明度の差
      }
    }
    // 縦横の明度差の2乗の平方根を明度とした画像を作る
    for (int i=0;i<img.pixels.length;i++){
      img.pixels[i]=color(sqrt(outX[i]*outX[i]+outY[i]*outY[i]));
    }
    img.save("data/3エッジ.jpg"); // ファイルに保存
    

  3. プログラムを実行する。
  4. dataフォルダーにできた「3エッジ.jpg」を開き、輪郭線が白で抽出されていることを確認する。
  5. 元a.jpg3エッジ.jpg

    ※ このプログラムでは、149ページの(5.6)式の「勾配」を計算し、それを明るさとして使っている。そのおかげで縦、横、斜めの線すべてがきれいに取り出せる。

課題 4 (ハーフトーニング)

テキスト156ページの図5.50のディザパターン(Bayer型)を使い、ハーフトーニングした画像を作る。

  1. Processingのエディタのコードを消し、以下のコードをコピー&ペーストする。
  2. PImage img;
    int[] bayer={0,8,2,10,12,4,14,6,3,11,1,9,15,7,13,5};
    img = loadImage("元a.jpg"); // 画像を読み込む
    img.filter(GRAY); // グレースケールにする
    for(int j=0;j<img.height;j+=4){
      for(int i=0;i<img.width;i+=4){
        for (int k=0;k<16;k++){
          int ci=i+k%4; // チェック位置(横)
          int cj=j+k/4; // チェック位置(縦)
          if (ci>=img.width || cj>=img.height) continue; // チェック位置が画像範囲外なら処理をスキップ
          if (brightness(img.pixels[ci+cj*img.width])>=bayer[k]*16+8){
            img.pixels[ci+cj*img.width]=color(255);
          }else{
            img.pixels[ci+cj*img.width]=color(0);
          }
        }
      }
    }
    img.save("data/4ディザ.jpg"); // ファイルに保存
    

  3. プログラムを実行する。
  4. dataフォルダーにできた「4ディザ.jpg」を開き、白黒の点の集まりでできていることを確認する。
  5. 元a.jpg4ディザ.jpg

    ※ 暗いところは黒い点の密度、明るいところは白い点の密度が高くなるので、白黒の点しか使っていないのに離れて見るとグレースケールのように見える。

課題 5 (アルファブレンディング)

テキスト157ページの(5.9)式の重み付けを使い、2つの画像を合成する。

  1. Processingのエディタのコードを消し、以下のコードをコピー&ペーストする。
  2. PImage img1, img2;
    float alpha=0.5; // 重み
    img1 = loadImage("元a.jpg"); // 画像を読み込む
    img2 = loadImage("元b.jpg"); // 画像を読み込む
    for(int i=0;i<img1.pixels.length;i++){
      float r=alpha*red(img1.pixels[i])+(1-alpha)*red(img2.pixels[i]);
      float g=alpha*green(img1.pixels[i])+(1-alpha)*green(img2.pixels[i]);
      float b=alpha*blue(img1.pixels[i])+(1-alpha)*blue(img2.pixels[i]);
      img1.pixels[i]=color(r,g,b);
    }
    img1.save("data/5合成.jpg"); // ファイルに保存
    

  3. 最初に用意した「元b.jpg」をProcessingのエディタにドラッグ&ドロップする
  4. プログラムを実行する。
  5. dataフォルダーにできた「5合成.jpg」を開き、2枚の元画像が合成されたものになっていることを確認する。
  6. 元a.jpg元b.jpg
     
    5合成.jpg

    ※ 2行目の「alpha」に入れる値を0~1の範囲で変えると、片方の影響が強くなる (大きくすると「元a.jpg」の方が強く、小さくすると「元b.jpg」の影響が強く出るようになる)。

課題 6 (エンボス)

テキスト159ページの(5.10)式を使い、レリーフのような画像を作る。

  1. Processingのエディタのコードを消し、以下のコードをコピー&ペーストする。
  2. PImage img;
    int d=2; // ずらし幅
    img = loadImage("元a.jpg"); // 画像を読み込む
    img.filter(GRAY);
    PImage imgOut = createImage(img.width-d, img.height-d, RGB); // 出力画像
    for (int j=0;j<img.height-d;j++){
      for (int i=0;i<img.width-d;i++){
        float f1=brightness(img.pixels[i+d+(j+d)*img.width]); // 元画像の(i+d, j+d)の位置の明度
        float f2=255-brightness(img.pixels[i+j*img.width]); // 元画像の(i, j)の位置の明度を反転した値
        imgOut.pixels[i+j*imgOut.width]=color(f1+f2-128);
      }
    }
    imgOut.save("data/6エンボス.jpg"); // ファイルに保存
    

  3. プログラムを実行する。
  4. dataフォルダーにできた「6エンボス.jpg」を開き、「元画像の明るい部分が盛り上がっていて、左上から光が当たった浮き彫りのような画像」になっていることを確認する。
  5. 元a.jpg6エンボス.jpg

    ※ 2行目のdの値を変えると「浮き彫りの厚さ」が変わる。
    ※ 画像を斜めにずらして合成しているので、ずらし幅分だけ画像の縦横のサイズは小さくなる。

提出

戻る inserted by FC2 system