前回、画像入力ができるようになったので、今回はわざわざ信号処理用のコンボリューション関数を使ってそれにフィルタをかけてみます。「わざわざ」というのは画像処理用のモジュールに画像専用のフィルタ関数があるのに使わない、ということですが。「コンボリューション」するためにもいろいろある、と。
※「手習ひデジタル信号処理」投稿順 Indexはこちら
※動作確認に使用させていただいているのは、Scilab 6.1.1(Windows版)です。
コンボリューション
みんな大好きコンボリューション(畳み込み積分)ですが、AIでCNNとかやるときには避けて通れませぬ(CNNのCは「コンボリューショナル」だものね。)もちろん、手習ひさせていただいとりますデジタル信号処理でも礎とな?ホントか?
さてネットを漁っていて素晴らしいページに行き当たりました。コンボリューションに迷える子羊必読?の以下のページです。
東北工業大学 情報通信工学科 中川研究室 様
その冒頭近くの一節を以下に引用させていただきます。
たたみこみを勉強する年頃には、 つらいこともショックなこともあるでしょう。 留年が決定したとか、自転車盗まれたとか、 今日財布忘れて昼飯抜きだとか、 勇気を出して告白したのにごめんなさいされたとか、 その子がこともあろうに後輩と付き合い始めたとか、、、。
最初読み始めたときに、先生何を言ってらしゃるの、と思いました。しかし、上記の一文がそのままコンボリューション演算へと直結しておるのです。この発想恐るべし。必読でございます。
Scilab、Signal Processingの部のコンボリューション
いつもお世話になっているSignal Processingの部にはコンボリューションを求めるための関数が多数。その中で今回使ってみようと思うのが一番プリミティブそうな conv2 という関数です。conv2というからにはconv関数もあり以下のようです。
-
- conv 離散一次元畳み込み
- conv2 離散二次元畳み込み
まあ、一次元でなく二次元の方にしたのは「絵」なら処理したらぱっと見で分かるからお手軽、というだけのことであります。発想が貧しいな。
また上記関数のHelpをみると、大きなデータにはconvol関数使え、とか書かれており、あくまで上記はチョロいコンボリューションの入口みたいっす。
また、先ほども申し上げたとおり、画像処理用にはScilabも専用の関数群多数をお持ちです。多分、画像であればそちら使う方が効率的な筈。
そのままじゃconv2できない画像であった
前回、ありがちな baboon画像をロードして表示してみました。勿論色鮮やかなカラー画像です。当然、RGBの3要素から1画素ができておる筈。
たしかに3次元目に3プレーンあるようです。とりあえず使ってみるだけの今回なので、3画面処理するのはメンドイです。エイヤーと白黒グレイスケール画像にしてしまいます。処理はこんな感じ。
imGray = rgb2gray(im); imshow(imGray); imwrite(imGray, "image\baboonGray.png")
imshow()でbaboon様を拝顔。また使うつもりなのでセーブもしておきます。
確かに、RGB3プレーンの元データから、1画面のデータに変換されておりますが、種類が問題です。整数型とな。中身を覗けばUint8みたいっす。なぜに問題かと言えば、
Signal Processingのコンボリューション関数は実数か複素数
でないと処理できないのであります。整数型を渡すとエラーになります。普段Scilabは何も言わずに実数(Double)、複素数の世界に没入しているので、こうして整数型が登場すると慌てふためきます。どうしたら変換できるのだろう?
※2023年2月9日追記: 整数型からdouble型への変換はそのものズバリのdouble()関数で可能でした。この件についてはこちらを参照。
この整数型から浮動小数点型への変換という他の処理系では苦も無くできそうな問題に解決策がわからなかったこの忘却力の年寄は、以下のようにしてみました。
baboonGrayString = string(imGray); baboonGrayReal = strtod(baboonGrayString);
唯一、文字列型にはいかような型からも変換可能。そして文字列型を実数型にも変換可能であります。文字列を介するのはなんだかな~。もっといい方法ありそうなもんだけれど(なお、整数配列に実数を掛けたり、割ったりしても整数型で結果が返ってきました、トホホ。)
まあ、ようやく実数型の行列になったのでコンボリューションかけられるというものです。
ソーベルフィルタ
思いつくなかで一番簡単、という理由で、コンボリューションかけてみるのはソーベルフィルタです。3x3サイズでお楽。画像に適用すればエッジを強調してくれるもの。見ればその効果が一目瞭然。縦横の方向性あり、バーチカル版を転置してホリゾンタル版も作ってみました。こんな感じ。
sobelV = [-1 0 1; -2 0 2; -1 0 1]; sobelH = sobelV.';
いよいよコンボリューションかけてみる
まずはデフォルト設定で、上記のバーチカルとホリゾンタルを両方かけてみました。まずはバーチカルから。
svBaboon = conv2(sobelV, baboonGrayReal); imshow(svBaboon)
画像はこんな感じ。
続いてホリゾンタル版。
shBaboon = conv2(sobelH, baboonGrayReal); imshow(shBaboon)
画像はこちら。
どっちがどっちだかわからんけれども、まあ、処理はされてとるみたいです。しかし、気になったのは処理のオプションです。デフォルトでは”full”設定みたいだけれども、他の設定 ”same”とか”valid”にするとどうなのよ。それに、helpの処理例を真似っこして、
conv2関数にフィルタ先、画像後で渡しているけど、これで良いの?
以下のように3事例追加して様子を見てみましたぜ。
shBaboonSame = conv2(baboonGrayReal, sobelH, "same"); shBaboonSameInv = conv2(sobelH, baboonGrayReal, "same"); shBaboonValid = conv2(baboonGrayReal, sobelH, "valid");
conv2関数でsameオプション(元画像と同じサイズにする)使うときには
元画像(大きさ大きい)を先、フィルタ(大きさ小さい)を後にするべき
みたいです。conv2のhelpで逆にしているのは、convol関数での順番に引きずられているような気がします。まあ、デフォルト設定では順番関係ないのだけれど。ただ、生成されたサイズを見ると、デフォルト設定時のサイズに関するHelpの説明には納得いかない部分があるのだけれど。。。なお、vaildにするといわゆる「パディング」無の計算となり、結果サイズが小さくなるようです。
まあ、多少は慣れた?でもクセが強いのう。