2010年11月4日木曜日

androidで簡単な画像処理をする

次のような画像処理をandroidでやってみましょう。
  1. 画像を読み込む
  2. 平均値フィルタをかけて、画像をぼかす
  3. 処理をした画像を表示する

今回はこの画像をぼかして(平滑化して)みようと思います。


ソース
package com.android.avg_filter;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.ImageView;

public class main extends Activity {
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  // 1. 画像を読み込む
  Bitmap src = BitmapFactory.decodeResource(getResources(), R.drawable.lenna);

  // 2. 平均値フィルタをかけて、画像をぼかす
  Bitmap dst;
  dst = avgFilter(src);

  // 3. 処理をした画像を表示する
  ImageView iv = (ImageView)findViewById(R.id.ImageView01);
  iv.setImageBitmap(dst);
 }
 
 // 画像をぼかす(平滑化する)メソッド
 private Bitmap avgFilter(Bitmap src) {
  Bitmap dst = Bitmap.createBitmap(src.getWidth(), src.getHeight(),Bitmap.Config.ARGB_8888);
  int width = src.getWidth();
  int height = src.getHeight();
  
  // 出力画像の初期化処理
  int initpixels[] = new int[width * height];
  dst.setPixels(initpixels, 0, width, 0, 0, width, height);

  // カーネルの宣言
  double[][] kernel = {
    {1.0/9.0, 1.0/9.0, 1.0/9.0},
    {1.0/9.0, 1.0/9.0, 1.0/9.0},
    {1.0/9.0, 1.0/9.0, 1.0/9.0}};


  // 処理を行う
  int dstpixels[] = new int[width * height];
  for(int i = 1; i < width - 1; i++){
   for(int j = 1; j < height - 1; j++){
    double red = 0.0;
    double green = 0.0;
    double blue = 0.0;
    
    // 畳込み演算
    for(int inR = -1; inR <=1; inR++){
     for(int inC = -1; inC <=1; inC++){
      red += kernel[inR+1][inC+1]*Color.red(src.getPixel(i+inR, j+inC));
      green += kernel[inR+1][inC+1]*Color.green(src.getPixel(i+inR, j+inC));
      blue += kernel[inR+1][inC+1]*Color.blue(src.getPixel(i+inR, j+inC));
     }
    }
    dstpixels[i + j * width] = Color.rgb((int)red, (int)green, (int)blue); 
   }
  }
  
  // 画素値をセットする
  dst.setPixels(dstpixels, 0, width, 0, 0, width, height);
  return dst;
 }
}

結果はこちら

それではポイントを見ていきましょう。

// 1. 画像を読み込む
  Bitmap src = BitmapFactory.decodeResource(getResources(), R.drawable.lenna);
では res/drawable に入っている lenna.jpg からBitmapインスタンスを生成しています。

// dstの初期化処理
  int initpixels[] = new int[width * height];
  dst.setPixels(initpixels, 0, width, 0, 0, width, height);
では出力画像の初期化を行っています。
initpixelsの型はint[]で、その大きさは総画素数(width * height)に等しいです。
ちなみにandroidではひとつの画素値はintで与えられており、
24bit~17bitまでが赤、16bit~9bitまでが緑、8bit~1bitが青となっています。
従ってある画素値をvalueとしたとき、RGB成分はそれぞれ
// RGBの取得
  int R = (value & 0x00FF0000) >> 16;
  int G = (value & 0x0000FF00) >> 8;
  int B = (value & 0x000000FF);
とすることで取得できますね。

最後に計算結果をBimapインスタンスにセットします。
// ピクセル値をセットする
  dst.setPixels(dstpixels, 0, width, 0, 0, width, height);
これにはBitmap.setPixelsを利用します。
setPixelsは7個の引数があります。
Referenceをみると次のようになっています。

public void setPixels (int[] pixels, int offset, int stride, int x, int y, int width, int height)

多くの場合、計算した結果の画素数とそれをセットしたいBitmapのインスタンスの画素数は同じであると思うので,
offset = 0,
Stride = 画像の横方向の画素数,
width = Strideと一緒,
height = 画像の縦方向の画素数
でいいかと思います。

以上簡単な画像処理に関する解説でした。


入門Google Androidプログラミング
伊原 頌二 藤枝 崇史 柴田 文彦
インプレスジャパン
売り上げランキング: 20532
おすすめ度の平均: 4.0
3 わかりやすいが間違いが多い
4 索引が充実していれば…
5 「GLSerfaceView」クラスを使ったサンプル有り

0 件のコメント:

コメントを投稿