作成:2018/07/14
改訂:2018/11/18(64bit 版の Excel に対応)

Excel で試す画像処理の基礎

Menu > Image processing

1、概要

画像の特定周波数に対して通過させたり遮断させたりすることで、画像からノイズを除去したり画像をシャープに見せたりすることが出来ますが、その画像処理の基本である空間フィルタについて解説したページです。
Excel で空間フィルタを簡単に実行することが出来るサンプルマクロが付いてますので、実際に処理前後の画像を自分の目で確認することが出来ます。
Excel のマクロは、画像のピクセルデータをシート上へ展開、空間フィルタを実行、画像データを再エンコード(JPEG,BMP,TIFF,PNG,GIF のフォーマットに対応)、ファイルへ保存する機能が含まれてます。
プログラムは Excel VBA と Microsoft Visual C++ 2017 で作成した DLL を使ってますが、Excel VBA の空間フィルタ実行部分については修正方法も解説しますので、自分で各種フィルタを設計,試して頂ければと思います。

1-1、動作確認環境

・ OS : Windows7 Professional SP1,64bit版、又は Windows10 Home,32bit版
・ Office : Office 2010, 32bit 版又は 64bit版、又は Office 2013、32bit版


2、空間フィルタ

・画像に対して空間フィルタを使うと、画像ノイズを除去しぼかしたり、画像をシャープに見せたりすることが出来ます。画像ノイズを除去する場合は高周波成分をカット、画像をシャープに見せたい場合は高周波成分を強調させるようなフィルタ処理を行います。
画像での周波数が高い・低いという言い方は、近接画素の濃度変化が急な場合(数値の変化が大きい場合)は周波数が高い、近接画素の濃度変化が緩やかな場合(数値の変化が小さい場合)は周波数が低いという感覚で良いかと思います。
フィルタには JPEG 圧縮などに使われる離散コサイン変換(DCT)など、周波数領域に変換して処理を行う方法もありますが、こちらまた別の機会に Excelのマクロなどに実装して解説出来たらと考えてます。

2-1、近傍画素の処理

・空間フィルタは注目画素に近接した画素を含めた演算を行うことで処理します。注目画素と近接画素の濃度値に重み付けしたあと、それらの濃度値の和をとり、新しい注目画素の濃度とします。
これは積和演算によって表現され、注目画素と回りの8画素を使って処理する場合は3×3の近傍処理と言い、その計算式を(式1)に示します。


(式1)

・g(y,x) は処理後の濃度値を、f(y,x) は処理前の濃度値を表してます。a(k,l) は重み付けとして用いる値で、フィルタ係数などと呼びます。
 図1は重み付け係数と処理する画素の位置関係を表し、後述する Excel のセル座標に合うよう記載してます。


・注目画素を取り囲む画素1つずつ走査しながら計算してい行きます、図2はその計算イメージを表します。
一番外側の画素は計算出来ないので、処理後の画像とのつながりに違和感無いよう、処理前の濃度値をそのまま入れたり、0 を入れたり状況を見て適切に処理します。


(図2)

2-2、フィルタ係数

・各種フィルタについて特長を説明します。

平滑化(Smoothing)フィルタ

・高周波成分をカットして画像ノイズを除去するフィルタ、画像がボケた印象にもなります。
式2は注目画素の重みを w としたときのフィルタ係数で、w の値を大きくすると画像のボケ具合は緩和されます。


(式2)

Prewitt フィルタ

・低周波成分をカットして画像の輪郭を抽出するフィルタ、Prewitt は1次微分フィルタの1種で、周りのノイズの影響を受けにくいよう改良されたフィルタになります。
更に改良された Sobel フィルタというのもあります。


Laplacian フィルタ

・低周波成分をカットして画像の輪郭を抽出するフィルタ、Laplacian(ラブラシアン)は2次微分フィルタで、1次微分のフィルタより緩やかな濃度勾配でもエッジ検出が出来ます。


鮮鋭化(Sharpening)フィルタ

・元画像に Laplacian を引いたもの、Laplacianによって高周波成分が抽出されるので、画像を鮮鋭化するのに利用されてます。


3、サンプルマクロ

・以下に日本語版と英語版の2種類ありますので、どちらかダウンロードください。

◆ 日本語版はここから。(file size:88kByte)

◆ 英語版はここから。(file size:87kByte)

・ダウンロードしたファイルを解凍すると、下記3つのファイルがあります。

1、image_viewer2.xlsm → 画像のピクセルデータをシート上に展開して、空間フィルタをかけたりすることが出来るマクロ
2、image-vbif32.dll → 32bit 版の Excel から各種画像形式のフォーマットを読み書き出来るようにする DLL
3、image-vbif64.dll → 64bit 版の Excel から各種画像形式のフォーマットを読み書き出来るようにする DLL

コメント:
xlsx形式での書式上限は 64,000 通りを超えると、「セルの書式が多すぎるため、書式を追加できません」のエラーが出るので、RGB で色を付ける場合は 1色 32階調へ減色してセルに色を付けます。
画像ファイルへの保存機能などはありませんが、1677万色のフルカラーで色を付けられるバージョンもこちらにあります。

パソコンの環境設定

・Excel から image-vbif32.dll 、又は image-vbif64.dll を使えるように、Microsoft Visual C++2017 ランタイムの入手と、パソコンの環境設定を行ってください。(Excel ファイルを開くだけでは、このマクロは動作しません)
 環境設定の方法は、別の記事 '3、Excel で使う準備 ' を参照ください。


4、使用方法

Excel シート座標

・ Excel 上で画像ファイルを読み書きしたりフィルタ処理を実行する場合、Excel のセルは下図の通りに画像データが入っている事を前提にプログラムが動作します、画像データのセル位置はずらさないで下さい。

・1行目の2列(B列)からは画像幅方向のピクセル番号が入ってます、2行目の1列(A列)目からは画像高さ方向のピクセル番号が入ってます、画像データは2行2列(B列)目から入ります。
画像データは各セルに、8bit の単色データの場合は Byte 型(0~255 の範囲)の値又は文字列を、24bit の RGB(YCbCr) データの場合は、RGB(YCbCr) の順に文字列で 255,255,255 の様にシートへ書き込まれます。
また RGB(YCbCr) データの場合は、読み込み処理を Mid$ 関数を使って高速化しているので、常に文字列の長さが 11 文字になるようシートへ書き込んでください。(1byte 3文字に満たなかった場合は空白文字を追加する)


機能説明

・ image_viewer2.xlsm を立ち上げると、Image タブが表示されますので、その中のボタンをクリックするとプログラムが立ち上がります。
このリボンは image_viewer2.xlsm のシートを作業対象としている時には出て、他のワークブックへ行くと表示されなくなります。
他のワークブックでもこのリボンを表示したい場合は、ファイルを image_viewer2.xlam のアドイン形式に保存しなおして、アドイン登録して使ってください。

・ 各ボタンの機能説明
[Read file] : 画像ファイルを読み込んで、シートへ要素展開する。
[Save file] : 要素展開されたシートデータから、画像ファイルへ保存する。
[Save GraphR] : GraphR 形式の CSV データを作成して保存する。
[Filter] : 空間フィルタをかける。

[Paint area] : 囲った範囲に色を付ける。
[Erase paint] : セルに付けた書式(色)を削除する。

※ [Paint area],[Erase paint]は、ほぼ前回の機能と同じなので、前回の記事 '4-3、Paint area ' を参照ください。


[Read file]

・ Read file ボタンを押すと、Open file dialog が立ち上がるので、Excel へ展開したい画像ファイルを選んで開く(O)ボタンを押してください。
対応している画像フォーマットは、JPEG,BMP,TIFF,PNG,GIF 形式で、RGB の各要素 8bit×3 = 24bit の画像データを扱うことを想定してます。
あまり大きなサイズの画像を展開しようとすると Excel が固まってしまいますので、適切に画素を間引きしてから開いてください。

[参考] 自分のパソコンでは、1920×1080 Pixcel の JPEG ファイルを開いたとき、セルに色を付けない場合は 7秒、セルに色を付けた場合は 90秒程度、処理に時間がかかりました。


・ 次に "取り込む色の選択" ダイアログが表示されたら、Excel へ展開したいデータを選んで OK ボタンを押してください。
1、RGB,YCC = 3原色又は YCbCr 形式に変換して 24bit データで取り込みます。
2、Red,Green,Blue = 赤色又は緑色又は青色のみ 8bit データで取り込みます。
3、Y(輝度),Cb(B-Y),Cr(R-Y) = 輝度信号又は色差信号へ変換して8bit データで取り込みます。

※ YCbCr の 計算式
Y = 0.299×R + 0.587×G + 0.114×B
Cb =  -0.168736×R - 0.331264×G + 0.5×B + 128
Cr = 0.5×R - 0.418688×G - 0.081312×B + 128


・ 次に "セルに色(濃淡)つけますか?" のメッセージボックスが表示されたら、'はい' か 'いいえ' を選択してください。
フルカラーで色付けすると 「セルの書式が多すぎるため、書式を追加できません」 のランタイムエラーが出るので、24bit データの場合は1色 32 階調、RGB で 32,768 階調に減色して色づけしてます。単色データの場合はそのまま 256階調で色づけします。

※ Excel の制約で、xlsx形式での書式上限は 64,000 通りの様です。


・ 下図は RGB で取り込み、"セルに色(濃淡)つけますか?" のメッセージに 'はい' を選択し画像を読み込んだときの画面で、 320×212 Pixcel の画像データを表示。

※ 画像の出展:月刊山と渓谷 2018年7月号(999号)


・ 下図は RGB で取り込み、"セルに色(濃淡)つけますか?" のメッセージに 'はい' を選択し画像を読み込んだときの画面で、976×646 Pixcel の画像データを表示。


[Save file]

・ 画像ファイルへ保存したい場合は、保存したいシートを選択して[Save file] ボタンを押してください、画像ファイルへ保存のダイアログが表示されますので、ファイル名を付けて保存してください。
解像度の設定はしてませんので、ビューアによっては元の画像と表示の大きさが変わることがあります、JPEG 形式で保存した場合の圧縮率は、
0.1~1.0 の範囲で 0.9 で保存されます。


[Filter]

・ Filter かけたいシートを選択して Filter ボタンを押すと、フィルターの選択ダイアログが表示されるので、選んでOKボタンを押してください。
'2-2、フィルタ係数' の項で説明したフィルターが試しにかけられます。

・ 次に "セルに色(濃淡)つけますか?" の問い合わせに 'はい' を選んだ場合は、下図の '何色つけますか' のダイアログが続けて表示されます。
RGB を選んだ場合は、そのまま RGB で色を付けます。YCbCr を選んだ場合は、RGB に戻して色を付けます。
Red,Cr(R-Y) を選んだ場合は赤色に、 Blue,Cb(B-Y) を選んだ場合は青色に、Green を選んだ場合は緑色に色を付けます。
Y(輝度) を選んだ場合は、白黒に色を付けます。

※ RGB のデータに YCbCr で色づけ(又は逆)すると、正しい色が付きません、3色データに単色で色づけ(又は逆)すると、何も色が付かないようにプログラムされてます。


・下図は平滑化(Smoothing)を選んだ場合の画像例で、新しいシート(ここでは 'Image2' タブ)が作成されて、処理後の結果がそのシートに入ります。


[Save GraphR]

・ 保存したいシートを選択して [Save GraphR] ボタンを押すと、'名前を付けて保存' のダイアログが表示されますので、ファイル名を付けて保存してください。GraphR 形式の CSV データが作成されます。

※ GraphR 形式の場合、RGB や YCbCr の 24bit (3色)データは指定しないでください、必ず単色の 8bit データを指定してください。
3次元グラフ作成ソフト GraphR は https://www.graph-project.com/?page_id=34&lang=ja などからダウンロード出来ます。

・下図は Y(輝度) のデータを GraphR で、 2D,3D,平滑化(Smoothing)後の 3D 順に表示させて 3 枚の画像を保存、別のソフトで GIF アニメに加工して表示した例です。


・下図は Laplacian フィルタ実行後 GraphR で表示した例です。


5、プログラムの変更方法

・VBE エディタを立ち上げ、VBAProject(image_viewer2.xlsm) ,Module1 のところにフィルタをかけるルーチンがあります。
 'Private Sub image_filter(control As IRibbonControl)' がフィルタを実行しているところの本体で、その中の Select Case 文の Case6(Option1) と Case7(Option7) が自由にコードを追加して良い部分です。(そこ以外も自由に変更してもらって構いませんが自己責任で)
3色フィルタかける部分と1色フィルタかける部分がありますので、2か所編集してください。


空間フィルタ実行 Sub


' 画像にフィルタをかける
Private Sub image_filter(control As IRibbonControl)

 
    ' フィルタの実行
    If dType = True Then
        
        ' RGB or YCC 3色の場合
        Select Case dlg2.cc
        
        
            ' 平滑化(Smoothing)
            Case 1
           
            
             ' Option1
            Case 6
                
                ' ここにフィルタコード書いてください
                
                MsgBox "現在機能未実装"
        
            ' Option2
            Case 7
        
                ' ここにフィルタコード書いてください
                
                MsgBox "現在機能未実装"
        
        End Select
           
      Else
    
        ' 単色の場合
        Select Case dlg2.cc
        
        
            ' 平滑化(Smoothing)
            Case 1
   
         
             ' Option1
            Case 6
                
                ' ここにフィルタコード書いてください
                
                MsgBox "現在機能未実装"
        
            ' Option2
            Case 7
        
                ' ここにフィルタコード書いてください
                
                MsgBox "現在機能未実装"
        
        End Select
        
    End If                          
 

変数の使い方

・ Excel のシートから読み込んだデータは 'ImgPixels(y, x, c)' の変数に入ってきますので、この変数からピクセルデータを拾って計算してください。
y=1 to Height, x= 1 to Width の変数範囲にデータが入ってて、c=0 to 2 の範囲で順に RGB のデータが入ってます。
Height=rc(Row Count)、Width=cc(Column count) の変数に入ってますので、ループを回す際に使ってください。
計算結果は 'fImgPixels(y, x, c)' へ格納してください。


積和演算式の書き方

・下記のような計算コードを書くと、何故か 'オーバーフローしました' のランタイムエラーが出ます。
→ これは意味不明、Visual Basic のバグ?


i = ImgPixels(y - 1, x - 1, 0) + ImgPixels(y - 1, x, 0) + ImgPixels(y - 1, x + 1, 0)
i = i + ImgPixels(y, x - 1, 0) + 2 * ImgPixels(y, x, 0) + ImgPixels(y, x + 1, 0)
i = i + ImgPixels(y + 1, x + 1, 0) + ImgPixels(y + 1, x, 0) + ImgPixels(y + 1, x + 1, 0)

・下記のように計算コードを直すと問題なく動きます。


i = ImgPixels(y - 1, x - 1, 0)
i = i + ImgPixels(y - 1, x, 0) + ImgPixels(y - 1, x + 1, 0)
i = i + ImgPixels(y, x - 1, 0) + 2 * ImgPixels(y, x, 0) + ImgPixels(y, x + 1, 0)
i = i + ImgPixels(y + 1, x + 1, 0) + ImgPixels(y + 1, x, 0) + ImgPixels(y + 1, x + 1, 0)

DLL 側の使い方

・画像ファイルへの再エンコードは DLL 側が担ってますので、その使い方を簡単に説明します。
FilePath は 文字列の最後に0を付加し、Unicode の Byte array に直して渡してください。
ImgBuf は DLL 内部で 'GUID_WICPixelFormat24bppBGR' の形式を指定してますので、1画素あたり 3byte 領域確保してください。
Width, Height, BufSize は Long 型の変数です。
Compress は Double 型の変数で、JPEG 保存した場合の圧縮率の指定で、0.1~1の範囲で指定してください。
ret は戻り値で 0=成功、0でない=失敗です。


' 関数宣言
Declare Function vb_image_WriteFile Lib "image-vbif.dll" (FilePath As Any, ImgBuf As Any, width As Long, _
	height As Long, BufSize As Long, Compress As Double) As Long
	
' 関数コール部分
 ret = vb_image_WriteFile(FilePath(0), ImgBuf(0), Width, Weight, BufSize, Compress)

・その他 DLL 側に実装している 'vb_image_CopyPixels' などの使い方は、 前回の記事 '5、DLL の使い方 ' を参照ください。


DLL のプロジェクトファイル

今回作成した DLL のプロジェクトファイル一式はここにあります。(file size:9kByte)
C++ に興味のある方は DLL 側もいじってみてください、Windows Imaging Component(WIC) Library を使ってますので、他の機能拡張も容易に出来ると思います。もっともここでの使い方は、ほぼ MSDN のサンプル通りです...

Visual Studio 2017 を使って、X86,Release で Build すると 32bit 版の image-vbif.dll が出来ます。


6、最後に

自分の勉強のつもりでプログラム書いてみました、Excel で画像ファイルを扱おうとすると、さすがに重たいです。
セルに書式付けなければ、あまりストレス無く使えると思いますが、すぐ画像も見てみたいし...ってところが軽快に使えないと。
他の畑(Python) とか気になる今日この頃です。


7、参考文献・URL

1、酒井幸市著:改訂版 ディジタル画像処理の基礎と応用-基本概念から顔画像認識まで-,CQ出版株式会社(2007)
2、WIC API Overview : https://msdn.microsoft.com/ja-jp/library/windows/desktop/ee719655(v=vs.85).aspx
3、Windows Imaging Component Reference : https://msdn.microsoft.com/en-us/library/windows/desktop/ee719902(v=vs.85).aspx