non div.

つな缶が大好きな大学生。書き溜めたコードを載せていきます。

【Excel】VBAで画像処理。画像の色調補正をする

今回は、VBAで画像のコントラスト補正をおこないます。
Excel上へ画像の展開の詳細はこの記事↓を見てください!
tsunakan97.hatenablog.com

線形な色調補正とS字を描く非線形な色調補正を行います。

線形な色調補正

f:id:tsunakan97:20160702233142p:plain
a1=0.2, a2=0.8, a3=0.1, a4=0.9


横軸が元の画像の画素値で、縦軸が補正後の画素値になります。
f:id:tsunakan97:20160702232200p:plain

255×a1より小さい画素値はすべて255×a3にして、255×a2より大きい画素値はすべて255×a4にします。そしてa1とa2の間は、直線でつなげて画素値とします。

'画像の線形変換!!
Function ToneMapping(image() As Byte, a1 As Double, a2 As Double, a3 As Double, a4 As Double)
    Dim c As Long, r As Long, color As Long
    Dim rMax As Long, cMax As Long
    rMax = UBound(image, 2)
    cMax = UBound(image, 1)
    Dim image2() As Double
    ReDim image2(cMax, rMax, 2)
    For r = 0 To rMax
        For c = 0 To cMax
            For color = 0 To 2
                image2(c, r, color) = image(c, r, color) / 255
            Next
        Next
    Next
    Dim myScale As Double
    Dim x As Double, xNew As Double

    myScale = (a4 - a3) / (a2 - a1)
    For r = 0 To rMax
        For c = 0 To cMax
            For color = 0 To 2
                x = image(c, r, color) / 255
                
                If x < a1 Then
                    xNew = a3
                ElseIf a2 < x Then
                    xNew = a4
                Else
                    xNew = myScale * (x - a1) + a3
                End If
                
                image(c, r, color) = xNew * 255
            Next
        Next
    Next
End Function

非線形な色調補正

S字のカーブを作り、中心より暗い画素はより暗く、中心より明るい画素はより明るくします。メリハリがつき、はっきりとした画像になります。
f:id:tsunakan97:20160702234622p:plain

今回はS字をつくるのに、正規分布確率密度関数積分することで得た関数を使います。
f:id:tsunakan97:20160702235118p:plain

f:id:tsunakan97:20160702234332p:plain


補正前後のヒストグラム(画素値の出現頻度)です。補正後のほうが山が左右に広がっており、暗い部分はより暗く、明るい部分はより明るくなっています
f:id:tsunakan97:20160702235836p:plain


画素ごとに毎回計算を行っていると時間がかかるので、先に返還後の画素値を格納したルックアップテーブルを作成して、参照するようにします。

'S字のトーンカーブ(正規分布確率密度関数の積分)
'による非線形濃度変換
Function ToneMapping3(image() As Byte)
    Dim c As Long, r As Long, color As Long
    Dim x As Byte
    Dim rMax As Long, cMax As Long
    rMax = UBound(image, 2)
    cMax = UBound(image, 1)
    Dim table(255) As Double, tabledx(255) As Double, table255(255) As Byte
    Dim i As Long
    
    Dim a1 As Double, a2 As Double, a3 As Double, a4 As Double, myScale As Double
    
    'tableを-3から3で正規化
    '±3SDの正規分布を積分するため
    a1 = 0
    a2 = 255
    a3 = -3
    a4 = 3
    myScale = (a4 - a3) / (a2 - a1)
    For i = 0 To 255
        table(i) = myScale * (i - a1) + a3
    Next
    
    'tableを正規分布の確率密度関数で計算
    For i = 0 To 255
       table(i) = (1 / Sqr((2 * 3.1416))) * Exp(-(table(i) ^ 2 / 2))
    Next
    
    'tableを積分してtabledxに代入
    For i = 0 To 255
        If i = 0 Then
            tabledx(i) = 0
        Else
            tabledx(i) = tabledx(i - 1) + table(i)
        End If
    Next
    
    'tabledxから画素値置換用のルックアップテーブルtable255を求める
    a1 = 0
    a2 = tabledx(255)
    a3 = 0
    a4 = 255
    myScale = (a4 - a3) / (a2 - a1)
    For i = 0 To 255
        table255(i) = CByte(myScale * (tabledx(i) - a1) + a3)
    Next
    
    'image()をtable255で濃度変換
    For r = 0 To rMax
        For c = 0 To cMax
            For color = 0 To 2
                x = image(c, r, color)
                image(c, r, color) = table255(x)
            Next
        Next
    Next
End Function


以下、全ソース。

Excelで画像の色調補正