Androidアプリ開発 画像編集 ImageViewの画像にグレースケールをかける

2017年03月19日(編集2017年03月21日)
このエントリーをはてなブックマークに追加

Androidアプリ開発でImageViewを使って画像を表示する機会は多いと思います。また、画像を加工する必要があることもあると思います。
この記事は、AndroidアプリでImageViewにグレースケールをかける方法を記載した記事です。

環境はAndroid 7.1 (API level 25) です。

環境

  • macOS Sierra
  • android sdk 25
  • Oracle jdk version 1.8.0_72
  • Android Studio 2.3

難易度

中級者向け

サンプルコード

Android-Media-Demo

グレースケール

グレーススケールは、画像の色の表現方法で、白と黒とその中間の何段階かの灰色のみを使った画像のことです。

グレースケール実装

Androidでは、グレースケールを実装する方法は2つあります。
1つは、ColorFilterを使ってImageViewにフィルターを設定する方法。もう1つはBitmapオブジェクトのpixelを操作する方法です。

この記事では両方の実装方法を説明します。

動作の動画確認

記事の内容を実装後のアプリの動作動画です。

ColorFilter実装

ImageViewの明るさを調整するために、ImageView#setColorFilterメソッドが用意されています。まずは、この方法で画像にカラーフィルタをかけてみましょう。

画面のベースになるImageFragmentを作成します。
クラス名はImageFragmentにします。

{project_folder}/ImageFragment.java
    /**
     * グレースケール
     */
    private void grayScale() {
        ColorMatrix matrix = new ColorMatrix();
        matrix.setSaturation(0);
        ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
        imageView.setColorFilter(filter);
    }
        

■ 実装の解説

1. ColorMatrix

ColorMatrixはピクセルの色を変化させるためのクラスです。

ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
        

setSaturationメソッドは、色の彩度に影響を与えるように行列を設定します。値0を設定すると、色をグレースケールにマッピングします。

ColorMatrixは抽象クラスなので、継承したColorMatrixColorFilterクラスを使います。

ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
imageView.setColorFilter(filter);
        

imageView#setColorFilterで、カラーフィルターを設定します。

ビルド

上記のコードビルドして動作を確認します。

fig1. ColorMatrix グレースケール

画像にグレースケールが設定されました。

また、画像処理は重い処理なので処理時間も重要です。なので、必ず処理時間を計測しましょう。
ColorMatrixを使った処理時間は

0ms
        

でした。

単純平均法

次はグレースケールの単純平均法でImageViewの画像を変更します。単純平均法はグレースケール変換後の値 YをR,G,Bの平均値とする方法です。Androidに単純平均法の実装ライブラリはないので、直接Bitmapを操作します。

{project_folder}/ImageFragment.java
    /**
     * Bitmapを使ったグレースケール
     * 単純平均法
     * grayscale using Bitmap
     * SimpleMeanMethod
     */
    private void grayScaleSimpleMeanMethod() {
        Bitmap mutableBitmap = getMutableBitmap();

        int width = mutableBitmap.getWidth();
        int height = mutableBitmap.getHeight();
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {

                // Returns the Color at the specified location.
                int pixel = mutableBitmap.getPixel(i, j);

                int red = Color.red(pixel);
                int green = Color.green(pixel);
                int blue = Color.blue(pixel);

                int average = (red + green + blue) / 3;
                int gray_rgb = Color.rgb(average, average, average);

                mutableBitmap.setPixel(i, j, gray_rgb);
            }
        }
        imageView.setImageBitmap(mutableBitmap);
    }

    /**
     * 変更可能なbitmapを返す
     * Returns changeable bmp
     *
     * @return
     */
    private Bitmap getMutableBitmap() {
        BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
        Bitmap bitmap = drawable.getBitmap();

        // 変更可能なbitmap
        Bitmap mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
        return mutableBitmap;
    }
        

1. mutableBitmap

ImageViewから取得したBitmapはImmutableです。Immutableは、状態を変更できないオブジェクトです。
Immutableのままではgrayscaleを適用できないので、mutableなBitmapを作成します。mutableは、状態を変更できるオブジェクトです。

Bitmap mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
        

Bitmapのコピーを作成することで、mutableなBitmapを作成することができます。

Bitmap.Config.ARGB_8888は各ピクセルを4バイトに格納します。

具体的には、Alpha/Red/Green/Blueを各8bitで格納します。8 * 4 = 32bit。32bit = 4byte。

つまり、各ピクセルを4バイト(4byte/pixel)に格納します。

2. getPixel

ピクセルは、Bitmap#getPixelメソッドで取得できます。

int pixel = mutableBitmap.getPixel(i, j);
        

ピクセルは色情報の最小単位です。ARGB_8888を指定しているので、赤・青・緑・Alpha情報が含まれています。

3. Color取得

ピクセルは色情報の最小単位です。Colorメソッドでピクセルから赤・青・緑各色の値を取得できます。

int red = Color.red(pixel);
int green = Color.green(pixel);
int blue = Color.blue(pixel);
        

Colorクラスは、int型で色を扱うことができます。色は、アルファ、赤、緑、青の4バイトで構成されます。 透明度はアルファコンポーネントに格納され、カラーコンポーネントには格納されません。

4. 計算

単純平均法はグレースケール変換後の値YをR,G,Bの平均値とする方法です。つまり、Red と Green と Blue を足して 3 で割った値です。

int average = (red + green + blue) / 3;
        

5. setPixel

setPixelメソッドでピクセルに色を設定することができます。

int gray_rgb = Color.rgb(average, average, average);

mutableBitmap.setPixel(i, j, gray_rgb);
        

平均値をrgbの値に変換して設定します。Alphaは変更しません。

ビルド

上記のコードビルドして動作を確認します。

fig2. 単純平均法 グレースケール

画像にグレースケールが設定されました。

画像処理は重い処理なので処理時間も重要です。計測しておきましょう。単純平均法を使った処理時間は

5144ms
        

です。
Bitmapを直接処理しているので遅いです。

加重平均法

次はグレースケールの加重平均法でImageViewの画像を変更します。加重平均法はグレースケール変換後の値 Yを係数, R,G,Bを使った式で計算する方法です。式の係数は,日本やアメリカで使われているテレビ放送の規格で使われている係数で、各色に対する人間の視感的特性から実験的に求められた値です。Androidに加重平均法のライブラリはないので、直接Bitmapを操作します。

{project_folder}/ImageFragment.java
    /**
     * Bitmapを使ったグレースケール
     * NTSC 係数による加重平均法
     * grayscale using Bitmap
     * NTSC Coef. method
     */
    private void grayScaleNTSCCoefMethod() {
        Bitmap mutableBitmap = getMutableBitmap();

        int width = mutableBitmap.getWidth();
        int height = mutableBitmap.getHeight();
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {

                // Returns the Color at the specified location.
                int pixel = mutableBitmap.getPixel(i, j);

                int red = Color.red(pixel);
                int green = Color.green(pixel);
                int blue = Color.blue(pixel);

                // RGB 値をグレースケール値に変換
                double gray_scale_value = 0.2989 * red + 0.5870 * green + 0.1140 * blue;
                int gray_scale = (int) gray_scale_value;

                int gray_rgb = Color.rgb(gray_scale, gray_scale, gray_scale);

                mutableBitmap.setPixel(i, j, gray_rgb);
            }
        }
        imageView.setImageBitmap(mutableBitmap);
    }

    /**
     * 変更可能なbitmapを返す
     * Returns changeable bmp
     *
     * @return
     */
    private Bitmap getMutableBitmap() {
        BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
        Bitmap bitmap = drawable.getBitmap();

        // 変更可能なbitmap
        Bitmap mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
        return mutableBitmap;
    }
        

1. 計算

グレースケール変換後の値 Y の計算式以外は、単純平均法と同じです。なので、計算式以外の説明は、単純平均法を参考にしてください。

加重平均法の式は

Y = 0.298912 * R + 0.586611 * G + 0.114478 * B
        

です。なので、上記の式をそのまま当てはめます。

double gray_scale_value = 0.2989 * red + 0.5870 * green + 0.1140 * blue;
        

小数点を扱うので、64ビット倍精度浮動小数点数のdoubleを使います。
計算後は、int型にキャストし、rgbの値に変換します。あとは、ピクセルに値を設定すればOKです。

ビルド

上記のコードビルドして動作を確認します。

fig2. 単純平均法 グレースケール

画像にグレースケールが設定されました。

画像処理は重い処理なので処理時間も重要です。計測しておきましょう。単純平均法を使った処理時間は

4944ms
        

です。

結論

Androidでは、様々な画像変換方法が利用できます。上記の方法の他にも、OpenCV等のライブラリを使っても変換できます。なので、作成するアプリの目的に合った方法で実装すると良いでしょう。grayscaleに関しては、ColorFilterを使うのが一番だと思います。

関連記事

タグ検索で調べてみよう

Android7.1 画像処理