今回は im2col 関数を試用してみます。どんな関数なのかとHelpを読めば “Convert image into series of columns” と書かれております。画像処理素人老人はナンジャラホイ状態です。これはフィルタなどより1段階ローレベルなところでベクタライゼーションを活用するためのデータ再配置のための関数みたいです。
※「手習ひデジタル信号処理」投稿順 Indexはこちら
※Windows11上の Scilab2024.0.0およびScilab上のScilab IPCVツールボックスを使用させていただいております。
into series of columns、列行列化?
画像にフィルタをかける場合を想像しても良いですし、AI処理などを考えてもいいと思いますが、大きなデータに対して定型的な処理を繰り返すのに、モダーンなプロセッサにほぼ漏れなく備わっているSIMD演算機構(ベクタ演算)を使わない手はありませぬ。ただし効率よくSIMD演算に「載せる」にはデータがメモリ上で整列しているのが望ましいのではないかと思われます。
今回練習してみる im2col 関数は、2次元の配列の「ある要素」を中心とした「2次元の固定サイズのブロック」を取り出し、該当のデータを列ベクトルとして配列してくれるものです。元の2次元配列の要素数だけブロックをスライディングしながら抽出していって列ベクトル化するので、縦(行数)はブロック・サイズ、横(列数)は要素数の結果が得られるというものです。当然、元の配列が画像であり、ブロックはフィルタをかける対象データという想定が一番しっくりきますが、そうでないデータの再配置にも利用可能じゃないかと思います。
im2col関数の処理例の動作を確認
以下では im2col 関数のHelpファイル記載の処理例をステップバイステップでおって動作を確認したいと思います。
-
- 処理対象の2次元配列の生成
処理対象は2次元の配列であればよいのですが、なるべく小さくということでしょう、4x4の正方行列として生成してます。こんな感じ。
A = testmatrix('mag',4);
なお、testmatrix()関数の第1引き数 ‘mag’ を与えて生成すると「魔法陣」が得られるみたいです。縦横斜めに合計が同じになるアレっす。まあ、今回はテキトーなサンプルデータということで利用されているだけだけれども。
-
- 列ベクトルの配列化
さて上記の4x4=16要素の配列Aから、3x3のブロックを9x1サイズの列ベクトル化して4x4の16ベクトル取り出すための処理が以下に。
B = im2col(A,[3 3]);
AとBの関係が分かるように色付け枠をつけた処理結果が以下に。
Aの左上の16を中心とした3x3要素(赤枠)、なお配列の外側にはみだす部分は0でパディングしている、が下のBの最左端の列ベクトル(赤枠)となります。上のオレンジの3x3ブロックが下のBの左から2番目の列ベクトル(オレンジ枠)に、そして上の11を中心とする3x3ブロック(青枠)が下のBの青枠の列ベクトルに再配置されているのが分かりますかね。
2次元に並んでいた(メモリの上ではトビトビの場所におかれていたハズ)が、列ベクトル(ScilabはFortran式みたいなので、列ベクトルはメモリ上連続でないかと思われます。知らんけど。)となり綺麗に整列されました。メモリの必要領域的にはブロックサイズから9倍以上(周囲のパディング含むので)の容量に膨れますが「後続の演算命令がベクトル化されていれば」一気に処理できる筈。
-
- 列ベクトル群の演算
処理例では ベタなmean関数で平均値もとめてます。meanがベクタライゼーション対応かどうかは知らず。なお、第2引数に1と書くと「列方向」に計算です。(2で行方向。)
C = mean(B,1);
Cは、元の2次元配列の要素数4x4=16個(16列)の行ベクトルとなりました。
-
- 元の配列サイズに戻す
これを「折りたたんで転置すれば」元の配列と同じ4x4の2次元の結果となります。こんな感じ。
D = matrix(C,[4,4])';
演算が列行列化(ベクタライゼーション)に対応しておれば、きっと功徳がある筈。ホントか?