Processing3で行うエッジ検出

今回はProcessing3を用いてエッジ検出(輪郭抽出)を行いたいと思います。

前回(PROCESSING3で平滑化(ガウシアンフィルタ))行ったフィルタ処理ではProcessing3に実装されている関数を使用したため画素の情報をいじることなく平滑化することができました。

しかし、エッジ検出は2015年12月の段階ではfilter()関数には実装されていません。ということで画素の情報をこちらで取得して微分フィルタをかけてやる必要があります。

今回実装する微分フィルタについてはこちらのページを参考にしました1次微分(差分)によるエッジ検出

サンプルスケッチは次のようになります。

PImage img, img_mask;

void setup() {

  size(512, 512);
  img_mask = createImage(512, 512, RGB);
  img = loadImage("hogehoge.jpg");
  image(img, 0, 0, 512, 512);
  //filter(GRAY);
  edge(img, img_mask);
  image(img_mask, 0, 0, 512, 512);
}

void draw() {
}

void edge(PImage input, PImage output) {
  float gvs;
  float ghs;
  float g;
  // エッジ検出
  for (int y = 1; y < input.height-1; y++) { 
    for (int x = 1; x < input.width-1; x++) {
      // 畳み込み計算
      ghs = - red(input.get(x-1, y-1)) - 2*red(input.get(x-1, y)) - red(input.get(x-1, y+1)) + red(input.get(x+1, y-1)) + 2*red(input.get(x+1, y)) + red(input.get(x+1, y+1));
      gvs = - red(input.get(x-1, y-1)) - 2*red(input.get(x, y-1)) - red(input.get(x+1, y-1)) + red(input.get(x-1, y+1)) + 2*red(input.get(x, y+1)) + red(input.get(x+1, y+1));
      g = sqrt(pow(ghs, 2) + pow(gvs, 2));
      output.set(x, y, color(abs(g)));  // 出力画像の画素値を設定
    }
  }
}
  • ウィンドウサイズを指定
size(512, 512)

Processingのウィンドウサイズは原画像の画像のサイズを使うことにします。自分が使いたい画像に合わせてsize()関数の引数を任意で変更してください(今回使ったlenaの画像は512×512なのでsize(512,512))。

  • 画像読み込み
img = loadImage("hogehoge.jpg")

Processingのスケッチが入っているフォルダ(.pdeファイルが入っているフォルダ)に原画像ファイルをいれるのを忘れないでください。また、ソースコード上では”hogehoge.jpg”となっていますが自分の使いたい画像の名前に書き換えてください。

  • 画像表示
image(img, 0, 0, 512, 512)

image()関数を用いていったん原画像の表示を行います(今回は必要ないのでコメントにして消しておいてもかまいません)。

肝心のエッジ検出のためにedge()関数をつくったので少し紹介をします。

  • Color get(int x, int y)

まず、PImage型の画素の情報を得るためにget()関数とred()関数を用います。get()関数は画像のx座標とy座標を引数とする(今回はimg.get(x,y))ことでその座標のRGB成分をColor型で返してくれます。

  • float red(Color img)

red()関数はColor型の変数を引数とすることでColor型の変数に格納されたRGB成分の中のR成分を取得してくれます。つまりred(img.get(x,y))という形で画素のR成分を取得することになります。

これで、PImage型に格納された画像の画素の情報を得ることができるようになりました。次はフィルタ処理について軽く説明しようと思います。

1次微分(差分)によるエッジ検出のカーネル(格子に係数が入ったもの)をもとに考えていきます。リンク先のページで説明されているgvsとghsを計算しそれぞれの二乗の和の平方根をとることで注目画素の画素値を決定します。

画像の端の処理ですが今回は上下左右1ピクセルずつ読み飛ばすことで画像の領域外の情報を取ってくるエラーが出ないようにします。

サンプルスケッチを見てわかるとおり、今回は画像のR成分のみをもとにエッジ検出を行いました。しかし、本来はグレースケール化する必要があるため

red(input.get(x, y))

この部分を次のようにしたら、さらに良い結果が得られるかもしれません(すいません、検証してないです…)。

red(input.get(x, y) + green(input.get(x, y)) + blue(input.get(x, y)) ) / 3

もし実験できたら番外編にして記事に載せようかな。

最後に原画像と処理結果を載せておきます。

lena

20151216_1

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to top