Androidアプリ開発 画像処理 ColorMatrixで画像にフィルターをかける

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

Androidアプリを作成するとき、ColorMatrixで画像にフィルター処理を施すことができます。
この記事は、ColorMatrixを使って、画像にフィルター処理をする方法を記載した記事です。

環境はAndroid 8.0 (API level 26) です。

環境

  • macOS Sierra
  • android sdk 26
  • Android Studio 2.3.3
  • kotlin 1.1.2

難易度

中級者向け(行列や画像処理の基本的な知識を含む)

サンプルコード

Android-Image-Demo

ColorMatrix

ColorMatrix(カラーマトリクス)は、RGB空間の座標を定義する行列です。Androidで用意されているColorMatrixクラスは、RGBAを扱う4×5の行列です。

fig1. ColorMatrix(カラーマトリクス)

上記の4 × 5 の行列は、回転やスケーリングなどの線形変換のみをサポートします。変換などの非線形変換を実行するには、5 x 5 行列を使用する必要があります。
つまり、Androidのカラーマトリクスは非線形変換をサポートしません。

非線形変換とは、積和演算で計算できないメディアンフィルターなどのことです。(この記事で理解する必要はありません)

色の表現

ビットマップの各ピクセルの色は、赤、緑、青、およびアルファの各成分に8ビットを使用する32ビットの数値で表します。

rgba(0,0,255,1)
        

rはRed(赤)、gはGreen(緑)、bはblue(青)、aはalpha(透明)を表しています。このrgbaの値は青色です。

他のrgbaも確認してみましょう。

rgba(255,0,0,1)は赤色、rgba(0,255,0,1)は緑色になります。

rgba(0,0,255,1)の各4つの成分の値は、0〜255の範囲の数値を使います。赤、緑、青の場合、0は輝度なしを表し、255は最大輝度を表します。アルファ成分0は完全な透明で、255は不透明です。

ColorMatrix仕様

ColorMatrixの値は、画像の色成分の割合です。0.0 が最小値で、1.0 が最大値です。
ColorMatrixの初期値は以下の通りです。

fig2. ColorMatrix 初期値(カラーマトリクス初期値)

例えば、画像の赤色を半分にする場合は以下のようなColorMatrixを生成します。

fig3. ColorMatrix 赤の成分を半分にする

上記のColorMatrixは、赤の成分を0.5倍するという意味になります。

計算

最後に、ColorMatrixの計算方法を説明します。

変換元画像のRGBAカラー値(R, G, B, A)を使って、変換後のカラー値(R', G', B', A')を以下のように求めます。

fig4. 変換後のカラー値(R', G', B', A')

(4×5)行列 × (5×1)行列 = (4×1)行列 の計算になります。
具体的な計算式は以下のようになります。

fig5. 変換後のカラー値(R', G', B', A')計算

単純な行列の内積の計算です。
計算式を見ると、e,j,o,tの列は、加算用の成分として用意されているのがわかります。
掛け算以外に、e,j,o,tの列で加算(あるいは減算)する成分を用意して、黒の色(0なので何をかけても0)の値をコントロールできるようにしているのがポイントです。

次に、変換行列がRGBカラーをどう変えるのか、具体的な例で示します。
まず、対角成分が1であとの成分が0の行列は「単位行列」と呼ばれます。ColorMatrixの初期値はこの単位行列です。この単位行列をRGBカラーの列ベクトルに乗じても、変換したベクトル成分のRGBカラー値は、もとのままで変わりません。

fig6. 単位行列の計算

画像をグレースケールに変換する場合を考えます。
単純なグレースケールをするには、Red(赤)、gはGreen(緑)、bはblue(青)の3つの成分の比率を等しくします。仮に1/3ずつとします。すると、以下の計算になります。

fig7. グレースケールの計算

全成分を1/3に変換したグレースケールは精度がよくないので、本来は違う値を利用しますが、考え方を理解することが大切です。

実装

ColorMatrix仕様で説明をした「画像の赤色を半分にする」カラーマトリクスを設定してみましょう。

{project_folder}/app/src/main/java/colormatrix/BasicColorMatrixActivity
class BasicColorMatrixActivity : AppCompatActivity() {

    private lateinit var btn_filtering: Button
    private lateinit var img: ImageView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_basic_color_matrix)

        btn_filtering = findViewById(R.id.btn_filter)
        btn_filtering.setOnClickListener {
            filter()
        }

        img = findViewById(R.id.img)
    }

    private fun filter() {
        val colorMatrix = ColorMatrix()
        colorMatrix.setScale(0.5f, 1.0f, 1.0f, 1.0f);
        img.colorFilter = ColorMatrixColorFilter(colorMatrix)
    }
}
          

■ 実装の解説

1. ColorMatrix生成

ColorMatrixを生成します。

val colorMatrix = ColorMatrix()
        

ColorMatrixの初期化で生成される行列は以下のような単位行列になります。

1 0 0 0 0 
0 1 0 0 0
0 0 1 0 0 
0 0 0 1 0
        

2. スケール計算

赤の成分を半分にします。

colorMatrix.setScale(0.5f, 1.0f, 1.0f, 1.0f);
        

setScaleメソッドを使うと以下のような計算されたcolorMatrixが作成されます。

0.5 0.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0 0.0
0.0 0.0 1.0 0.0 0.0 
0.0 0.0 1.0 1.0 0.0 
        

0.5 * 1.0 = 0.5 のように、各成分の値がスケーリングされています。

3. 画像に適用

img.colorFilter = ColorMatrixColorFilter(colorMatrix)
        

colorFilterにColorMatrixColorFilterを設定します。

以上で実装は完了です。

ビルド

上記のコードの動作を確認してみましょう。まず、変更前の画像Lenaです。

fig8. フィルター適用前

フィルターを適用します。

fig9. フィルター適用後

赤の要素が減り、青っぽさが強調されています。

ついで成分に1/3をかけたグレイスケールも確認してみます。

フィルターを適用します。

fig10. フィルター適用後

グレイスケール風のフィルターが適用されました。

結論

ColorMatrixを使うと画像にフィルター処理をおこなうことができます。
計算速度も最適化されているので、ColorMatrixで適応可能な場合は、ColorMatrixでフィルターを使って実装しましょう。

関連記事

タグ検索で調べてみよう

画像処理 Android8.0 kotlin1.1.1