【VBA×画像処理】ビットマップ画像のグレースケール化

本ページでは、VBAで読み込んだビットマップ(BMP)画像を内部的に処理して、各ピクセルのRGB値をもとにグレースケール化を行う方法の解説をしていきます。グレースケール化とは、カラー画像を明るさ情報だけを持つモノクロ画像に変換する処理のことをいいます。非常にシンプルで基礎的な処理ですが、その後の画像処理の前準備としてよく使われる大事なステップでもあります。

 icon-warning 注意事項 

本ページではビットマップ(BMP)画像の読み込みと書き出しページで実装したクラスに画像処理を追加していきます。前提の機能となる画像の入出力機能を実装しているため事前に一読ください。

グレースケール化

グレースケール化とは、カラー画像を明るさ(輝度)情報のみで表現するモノクロ画像に変換する処理です。RGB画像では赤・緑・青の3つの値で1ピクセルを表現しますが、グレースケール画像では1つの輝度値で表すため、データ量が減り、画像処理の前処理としてもよく利用されます。

グレースケール化ではRGBの3成分を1つの輝度値に変換します。その際の代表的な方法は以下の3つです。輝度法は加重平均法の重みが規格化されただけの手法なので考え方的には同じものです。

 icon-picture-o  平均法  

この手法ではRGBの各成分を同じ比率で扱います。操作は非常に単純で各ピクセルに対しRGBそれぞれの成分の平均値を出すだけで式で表すと下記の通りです。この式が全ピクセルに対して行われます。処理は簡単ですが人の視覚特性を考慮していないため、色によっては不自然に見えることがあります。
 

\[\text{Gray}=\frac{R+G+B}{3}\]

 icon-picture-o  加重平均法

この手法ではRGBの各成分に異なる重みを与えて計算します。人間の視覚は緑に最も敏感で、次に赤、青にはあまり敏感ではないため、それを反映した係数を用います。一般的には下記のような式が使われます。これも全ピクセルに対して適用されます。平均法に比べると計算はやや複雑になりますが、視覚的に自然に近いグレースケール画像を得ることができます。
 

\[\text{Gray} = 0.3R + 0.59G + 0.11B\]

 icon-picture-o  輝度法

この手法は人の目の感度特性をさらに正確に考慮したもので、テレビや映像処理などで標準的に用いられています。国際的な規格(ITU-R BT.601やBT.709)に基づいた係数があり、代表的には次の式で表されます。加重平均法の係数がより正確に調整されており、自然で忠実な輝度を再現できます。
 

\[
\begin{cases}
\text{Gray} = 0.299R + 0.587G + 0.114B \quad \text{(BT.601)} \\
\text{Gray} = 0.2126R + 0.7152G + 0.0722B \quad \text{(BT.709)} \\
\text{Gray} = 0.2627R + 0.6780G + 0.0593B \quad \text{(BT.2020)}
\end{cases}
\]

 
上記のそれぞれの手法を比較すると下画像のようになります。平均法→加重平均法→輝度法の順で陰影がしっかりとついて人の目から見て自然なグレースケールになっていることがわかります。

 

サンプルコード

以下がグレースケール化を行うためのコードです。事前に用意しておいたclsBitmap内に下記コードをコピペすることで利用可能になります。処理内容は前項で解説した通り、全ピクセルを走査してRGBの成分値を入力としてグレースケールの値を計算していくだけです。下記コードでは引数でグレースケールへの変換方法を切り替えられるようになっているため、出力結果を見比べてみてください。

クラスモジュール (clsBitmapに追記)

'****************************************************************************
'*  グレースケール変換
'*
'*      (lMethod)   :グレースケール変換手法
'*                    0 = 平均法 / 1 = 加重平均法 / 2 = 輝度法
'****************************************************************************
Public Sub ConvertToGrayscale(Optional lMethod As Long = 2)

    m_rgbImageData = Grayscale(m_rgbImageData, lMethod)

End Sub
'----------------------------------------------------------------------------
'-  グレースケール変換
'----------------------------------------------------------------------------
Private Function Grayscale(rgbDataOrg() As RGBTRIPLE, _
                           Optional lMethod As Long = 2) As RGBTRIPLE()
 
    Dim rgbDataGray()  As RGBTRIPLE 'グレースケール画像RGBデータ

    Dim lHeight As Long
    Dim lWidth As Long
    Dim lX As Long
    Dim lY As Long
    Dim lR As Long '┐
    Dim lG As Long '│平均値計算時のオーバーフロー回避のためLong型(本来はByte型)
    Dim lB As Long '┘
    Dim dGray As Double
    Dim bGray As Byte

    '元画像情報を取得
    lHeight = UBound(rgbDataOrg, 1) + 1  '配列は0始まりなので+1で補正
    lWidth = UBound(rgbDataOrg, 2) + 1   '配列は0始まりなので+1で補正

    '配列サイズを定義(元画像と同じ2次元配列)
    ReDim rgbDataGray(UBound(rgbDataOrg, 1), UBound(rgbDataOrg, 2))

    'グレースケール変換
    For lY = 0 To lHeight - 1
        For lX = 0 To lWidth - 1
        
            lR = rgbDataOrg(lY, lX).rgbRed
            lG = rgbDataOrg(lY, lX).rgbGreen
            lB = rgbDataOrg(lY, lX).rgbBlue
            
            '変換方法別処理
            Select Case lMethod
                Case 0
                    dGray = (lR + lG + lB) / 3                      '平均法
                Case 1
                    dGray = 0.3 * lR + 0.59 * lG + 0.11 * lB        '加重平均法
                Case 2
                    dGray = 0.2126 * lR + 0.7152 * lG + 0.0722 * lB '輝度法
            End Select
            
            bGray = CByte(dGray)
        
            rgbDataGray(lY, lX).rgbRed = bGray
            rgbDataGray(lY, lX).rgbGreen = bGray
            rgbDataGray(lY, lX).rgbBlue = bGray
        Next
    Next

    Grayscale = rgbDataGray

End Function

 
 標準モジュール

Option Explicit
Sub main()

    Dim sPathBmpSrc As String
    Dim sPathBmpExport As String
    Dim oBitmap As clsBitmap

    sPathBmpSrc = "C:\...\source.bmp"
    sPathBmpExport = "C:\...\output.bmp"

    Set oBitmap = New clsBitmap
    Call oBitmap.LoadBitmap(sPathBmpSrc)        '画像読み込み
    Call oBitmap.ConvertToGrayscale(2)          'グレースケール化(輝度法)
    Call oBitmap.ExportBitmap24(sPathBmpExport) '画像出力

End Sub

使い方は非常にシンプルで上記コードのように既に用意しておいた画像の入出力処理の間に、画像処理であるグレースケール化の処理を呼び出すだけです。この画像処理部分の機能をさらに追加していくことで、様々な画像処理を簡単に適用することができるようになっていきます。
 

関連情報

 VBA×画像処理ページ

次回 >> 画像の二値化(白黒)
前回 >> 画像を読み込む / 画像を書き出す
 画像処理のメインページへ戻る

 参考

外部リンク:グレースケール – Wikipedia

Excel,VBA,画像処理