狠狠撸

狠狠撸Share a Scribd company logo
础苍诲谤辞颈诲で画像処理リベンジ

  情報科学芸術大学院大学
     高井 大輔
自己紹介
?   で~ご@dego_96
?   情報科学芸術大学院大学 修士2年
?   高専、大学で画像処理の研究
?   Androidを初めて1年
※追加スライドです

        今回やること
?   ビット反転
?   グレイスケール化
?   コントラスト変換
?   2値化
はじめに
? 下準備フォルダの“HankoApp”をインポート
? ImageViewを使用して画像を表示
? レイアウトはxmlに記述(ImageViewだ
  け)
? 画像のリソースもxmlに記述
? メニューから画像処理を実行
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" >

  <ImageView
    android:id="@+id/ImageView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:contentDescription="@string/content_description"
    android:src=/slideshow/android-13781242/13781242/"@drawable/lenna" />

</LinearLayout>
自分の画像を使う場合
HankoApp -> res -> drawable-hdpi に自分のPNG画像を置く

android:src=/slideshow/android-13781242/13781242/"@drawable/lenna"   のlennaをファイル名(拡張子無し)に変
更
MainActivity.java(一部抜粋)
// -----------------------------------------------------------
// メニューメソッド
// -----------------------------------------------------------
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    menu.add(0, Menu.FIRST, 0, "実行");
    menu.add(0, Menu.FIRST + 1, 0, "保存");
    return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case Menu.FIRST:
        // 画像処理メソッドを実行
        ImageProcessing();
        break;
    case Menu.FIRST + 1:
        saveBitmapToSd(); // 画像を保存
        break;
    default:
        return false;
    }
    return true;
}
MainActivity.java(一部抜粋)
  private void ImageProcessing()
  {
    // ImageViewからBitmapを取得
    ImageView imageView = (ImageView)findViewById(R.id.ImageView);
    Bitmap bmp = ((BitmapDrawable)imageView.getDrawable()).getBitmap()
       .copy(Config.ARGB_8888, true);

      // 画像の横幅と縦幅を取得
      int width = bmp.getWidth();
      int height = bmp.getHeight();

      // ピクセルデータを取得
      int[] pixels = new int[width * height];
      bmp.getPixels(pixels, 0, width, 0, 0, width, height);

      /* ↓↓ ここから画像処理のコードを記述 */
      /* ここまで */

      // ビットマップにピクセルデータをセット
      bmp.setPixels(pixels, 0, width, 0, 0, width, height);

      // ImageViewにBitmapをセット
      imageView.setImageBitmap(bmp);
  }
Bitmapの取得
// ImageViewからBitmapを取得
ImageView imageView = (ImageView)findViewById(R.id.ImageView);
Bitmap bmp = ((BitmapDrawable)imageView.getDrawable()).getBitmap()
         .copy(Config.ARGB_8888, true);




         Bitmap.copy(Bitmap.Config config, boolean isMutable);

         Bitmap.Config
         ? Alpha_8         :Alpha のみ
         ? ARGB_4444       :ARGB各4bit (最大値は128)
         ? ARGB_8888       :ARGB各8bit (最大値は256)
         ? RGB_565         :R 5bit、G 6bit、B 5bit、Alpha無
         し

         isMutable (変更可能な)
         デフォルトは“false”、“true”にしないとsetPixelsでエ
         ラー
ピクセルデータにアクセス
int getPixel(int x, int y); ← 遅いので使わない
int setPixel(int x, int y); ← 遅いので使わない
void getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)
void setPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)

ピクセル情報は1次元配列
横幅と高さはBitmap.getWidth()とBitmap.getHeight()で取得可能

              0000 0000 0000 0000 0000 0000 0000 0000
                  Alpha           Red            Green           Blue

              例) r = (pixel & 0x00FF0000) >> 16
ビット反転

 // ビット反転を行う
 for (int i = 0; i < width * height; i++) {
    // ビット反転して透明度を最大値にする
    pixels[i] = ~pixels[i] | 0xFF000000;
 }

 ※Alpha値を反転すると何も見えなくなります
グレイスケール1

        平均値によるグレイスケール
        for (int i = 0; i < width * height; i++) {
          // RGBカラー値を取得
          int r = (pixels[i] & 0x00FF0000) >> 16;
          int g = (pixels[i] & 0x0000FF00) >> 8;
          int b = (pixels[i] & 0x000000FF) >> 0;

            // グレー色を作成
            int gray = (r + g + b) / 3; // 平均
            int pixel = 0xFF000000 | (gray << 16) | (gray << 8) | gray;

            // ピクセルデータにセット
            pixels[i] = pixel;
R G B   }


  3
グレイスケール2

                       テレビ方式よるグレイスケール
                       for (int i = 0; i < width * height; i++) {
                         // RGBカラー値を取得
                         int r = (pixels[i] & 0x00FF0000) >> 16;
                         int g = (pixels[i] & 0x0000FF00) >> 8;
                         int b = (pixels[i] & 0x000000FF) >> 0;

                           // グレー色を作成
                           int gray = (int)(0.299f * (float)r + 0.587f * (float)g
                                            + 0.114f * (float)b);
                           int pixel = 0xFF000000 | (gray << 16) | (gray << 8) | gray;

                           // ピクセルデータにセット
0.299R 0.587G 0.114B       pixels[i] = pixel;
                       }
コントラスト変换1
    元画像で min < V < max のと
    き  V min
    V                            255
            max min
        int bright[] = new int[width * height];
        int max = 0, min = 256;
        for (int i = 0; i < width * height; i++) {
          // グレー色を作成(テレビ方式)
          int gray = (int)(0.299f * (float)r + 0.587f * (float)g
                      + 0.114f * (float)b);
          bright[i] = gray;
          // 最大値と最小値を取得
          if (max < gray) max = gray;
          if (min > gray) min = gray;
        }
        for (int i = 0; i < width * height; i++) {
          float after = (float)(bright[i] - min)
                           / (float)(max - min) * 255f;
          int gray = (int)after;
          pixels[i] = (0xFF000000 | (gray << 16) |
                        (gray << 8) | gray);
        }
コントラスト変换1

             20
              |
            239




             0
             |
            255
コントラスト変换2




                                           緑の線は累積度数を示す



             ① LookUpTableを作成する(上側緑の線)
             ② LookUpTableに従って明度変換


ヒストグラム画像は http://www.mis.med.akita-u.ac.jp/~kata/image/lenna/equalize.html より
コントラスト変换2
2値化



  黒   白
大津の2値化
                    分離度が最大になる閾値を求める方法
                              クラス間分散
                    分離度                       B
                              クラス内分散          W

                              2          2
                         N1   1    N2    2
                     W
                              N1   N2
                                     2                2
                         N1    1         N2       2
                     B
閾値以下 ?   クラス1                      N1    N2
閾値以上 ?   クラス2
                         N : 画素数
閾値を0 ~ 255で分離度を計算        μ : 明度の平均
                         σ : 明度の分散

More Related Content

础苍诲谤辞颈诲で画像処理リベンジ

  • 2. 自己紹介 ? で~ご@dego_96 ? 情報科学芸術大学院大学 修士2年 ? 高専、大学で画像処理の研究 ? Androidを初めて1年
  • 3. ※追加スライドです 今回やること ? ビット反転 ? グレイスケール化 ? コントラスト変換 ? 2値化
  • 4. はじめに ? 下準備フォルダの“HankoApp”をインポート ? ImageViewを使用して画像を表示 ? レイアウトはxmlに記述(ImageViewだ け) ? 画像のリソースもxmlに記述 ? メニューから画像処理を実行
  • 5. main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ImageView android:id="@+id/ImageView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:contentDescription="@string/content_description" android:src=/slideshow/android-13781242/13781242/"@drawable/lenna" /> </LinearLayout>
  • 6. 自分の画像を使う場合 HankoApp -> res -> drawable-hdpi に自分のPNG画像を置く android:src=/slideshow/android-13781242/13781242/"@drawable/lenna" のlennaをファイル名(拡張子無し)に変 更
  • 7. MainActivity.java(一部抜粋) // ----------------------------------------------------------- // メニューメソッド // ----------------------------------------------------------- @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, Menu.FIRST, 0, "実行"); menu.add(0, Menu.FIRST + 1, 0, "保存"); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case Menu.FIRST: // 画像処理メソッドを実行 ImageProcessing(); break; case Menu.FIRST + 1: saveBitmapToSd(); // 画像を保存 break; default: return false; } return true; }
  • 8. MainActivity.java(一部抜粋) private void ImageProcessing() { // ImageViewからBitmapを取得 ImageView imageView = (ImageView)findViewById(R.id.ImageView); Bitmap bmp = ((BitmapDrawable)imageView.getDrawable()).getBitmap() .copy(Config.ARGB_8888, true); // 画像の横幅と縦幅を取得 int width = bmp.getWidth(); int height = bmp.getHeight(); // ピクセルデータを取得 int[] pixels = new int[width * height]; bmp.getPixels(pixels, 0, width, 0, 0, width, height); /* ↓↓ ここから画像処理のコードを記述 */ /* ここまで */ // ビットマップにピクセルデータをセット bmp.setPixels(pixels, 0, width, 0, 0, width, height); // ImageViewにBitmapをセット imageView.setImageBitmap(bmp); }
  • 9. Bitmapの取得 // ImageViewからBitmapを取得 ImageView imageView = (ImageView)findViewById(R.id.ImageView); Bitmap bmp = ((BitmapDrawable)imageView.getDrawable()).getBitmap() .copy(Config.ARGB_8888, true); Bitmap.copy(Bitmap.Config config, boolean isMutable); Bitmap.Config ? Alpha_8 :Alpha のみ ? ARGB_4444 :ARGB各4bit (最大値は128) ? ARGB_8888 :ARGB各8bit (最大値は256) ? RGB_565 :R 5bit、G 6bit、B 5bit、Alpha無 し isMutable (変更可能な) デフォルトは“false”、“true”にしないとsetPixelsでエ ラー
  • 10. ピクセルデータにアクセス int getPixel(int x, int y); ← 遅いので使わない int setPixel(int x, int y); ← 遅いので使わない void getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height) void setPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height) ピクセル情報は1次元配列 横幅と高さはBitmap.getWidth()とBitmap.getHeight()で取得可能 0000 0000 0000 0000 0000 0000 0000 0000 Alpha Red Green Blue 例) r = (pixel & 0x00FF0000) >> 16
  • 11. ビット反転 // ビット反転を行う for (int i = 0; i < width * height; i++) { // ビット反転して透明度を最大値にする pixels[i] = ~pixels[i] | 0xFF000000; } ※Alpha値を反転すると何も見えなくなります
  • 12. グレイスケール1 平均値によるグレイスケール for (int i = 0; i < width * height; i++) { // RGBカラー値を取得 int r = (pixels[i] & 0x00FF0000) >> 16; int g = (pixels[i] & 0x0000FF00) >> 8; int b = (pixels[i] & 0x000000FF) >> 0; // グレー色を作成 int gray = (r + g + b) / 3; // 平均 int pixel = 0xFF000000 | (gray << 16) | (gray << 8) | gray; // ピクセルデータにセット pixels[i] = pixel; R G B } 3
  • 13. グレイスケール2 テレビ方式よるグレイスケール for (int i = 0; i < width * height; i++) { // RGBカラー値を取得 int r = (pixels[i] & 0x00FF0000) >> 16; int g = (pixels[i] & 0x0000FF00) >> 8; int b = (pixels[i] & 0x000000FF) >> 0; // グレー色を作成 int gray = (int)(0.299f * (float)r + 0.587f * (float)g + 0.114f * (float)b); int pixel = 0xFF000000 | (gray << 16) | (gray << 8) | gray; // ピクセルデータにセット 0.299R 0.587G 0.114B pixels[i] = pixel; }
  • 14. コントラスト変换1 元画像で min < V < max のと き V min V 255 max min int bright[] = new int[width * height]; int max = 0, min = 256; for (int i = 0; i < width * height; i++) { // グレー色を作成(テレビ方式) int gray = (int)(0.299f * (float)r + 0.587f * (float)g + 0.114f * (float)b); bright[i] = gray; // 最大値と最小値を取得 if (max < gray) max = gray; if (min > gray) min = gray; } for (int i = 0; i < width * height; i++) { float after = (float)(bright[i] - min) / (float)(max - min) * 255f; int gray = (int)after; pixels[i] = (0xFF000000 | (gray << 16) | (gray << 8) | gray); }
  • 15. コントラスト変换1 20 | 239 0 | 255
  • 16. コントラスト変换2 緑の線は累積度数を示す ① LookUpTableを作成する(上側緑の線) ② LookUpTableに従って明度変換 ヒストグラム画像は http://www.mis.med.akita-u.ac.jp/~kata/image/lenna/equalize.html より
  • 19. 大津の2値化 分離度が最大になる閾値を求める方法 クラス間分散 分離度 B クラス内分散 W 2 2 N1 1 N2 2 W N1 N2 2 2 N1 1 N2 2 B 閾値以下 ? クラス1 N1 N2 閾値以上 ? クラス2 N : 画素数 閾値を0 ~ 255で分離度を計算 μ : 明度の平均 σ : 明度の分散