/*********************************************
template_matching.cc
テンプレートマッチング(拡張Reduction使用)
*********************************************/
// 結果を挿入する1次元配列 result は分割無しで
// 各計算機が保有していることが前提
vs_module
template_matching(iImage data, iImage temp, ivalue result)
{
int o_width = orig_width(temp)/2;
int o_heigh = orig_heigh(temp)/2;
// 全比較が可能な領域以外はマッチングを行わない
vsSetBoundary2D(max(o_width, o_heigh));
parallel<2,2>(x,y) {
int sum = 0;
for(int j= -o_heigh; j < o_heigh; j+=2)
for(int i= -o_width; i < o_width; i+=2)
sum += abs(data[+i][+j] - temp[[i+o_width]][[j+o_heigh]]);
if(result[[0]] > sum) {
result[[0]] = sum;
result[[1]] = l2g_x(data, x); // local to global (アドレス変換)
result[[2]] = l2g_y(data, y); // local to global (アドレス変換)
}
}
// 各計算機の結果を統一する
vsUnion(result, vsMIN_DEPEND_ON_FIRST);
}
/****************************************
template_matching.vpe
テンプレートマッチング用
****************************************/
// 通信処理初期化 -------------
#pragma host_name host1
#pragma host_name host2
#pragma host_name host3
#pragma host_name host4
// データの初期化 -------------
imgLoad("all.pgm", data);
imgLoad("template.pgm", temp);
int result[3];
result[0] = 999999; // 適当な大きい数値を.
int c;
c = width(temp) / 2;
set(data, CACHE, c);
set(temp, DIVISION, ALL);
set(result,DIVISION,ALL);
module("template_matching", data, temp, result);
// 結果の表示 ----------------
put("matching point is (");
put(result[1]);
put(",");
put(result[2]);
put(")");
put(" at ");
put(result[0]);
put("\n");
- 全体画像、テンプレートの用意
- モジュールのコンパイル
% vs_makemodule template_matching.cc
- プログラムの実行
% vios_run < template_matching.vpe
- width(temp);
2次元変数、3次元変数の幅(Xの大きさ)を返す関数。VIOSの実行フローで使用できる関数のうちの一つ。
- set(temp,DIVISION,ALL);
2次元変数tempの分割方式をALLに設定している。これによりモジュールを実行するすべての計算機がテンプレート画像tempを得ることができる。
set(result,DIVISION,ALL);
1次元変数resultの分割方式をALLに設定している。1次元変数をモジュールの引数として渡す場合デフォルトで分割方式ALLとなるので、この記述は省略することが可能。
(注意)1次元変数は実行フロープログラムでは単に、整数型もしくは実数型の配列として定義すればよい。ただし、それをモジュールへ引数として渡す場合、モジュール内ではそれぞれivalue,fvalue型として扱う。
- put()関数
put関数は指定した文字列を標準出力に出力する
文字列は ” ”で囲う。
- orig_width(temp)
2次元変数tempのオリジナル画像(全体画像)の幅(Xの大きさ)を返す関数。
- parallel<2,2>(x,y) {}
parallel構文。
並列処理単位を2×2の4pixelとしている。
処理単位を大きくしているのはテンプレートマッチングにかかる時間を削減するためである。
参考: 100×100画像の場合にparallel{}内で行われる処理の総回数は
<1,1> の場合は10,000回
<2,2> の場合は 2,500回
となる
- sum += abs(data[+i][+j] - temp[[ i+o_width ]] [[ j+o_heigh ]]);
temp[[ i+o_width ]] [[ j+o_heigh ]])
2次元変数で temp[][] という記述は現在注目している画素からの相対値を表すということはすでに述べました。
それに対し、大括弧を2つ使用した配列アクセス ”temp[[ int num_x ]][[ int num_y ]]”は分割前の全体画像においての絶対位置をしめします。
このプログラムの場合 tempは ALL(全計算機が保持)なので、tempのどの画素に対してアクセスしても他の計算機との通信は起こりません。
- result[[1]] = l2g_x(data, x);
1次元配列においても 絶対位置アクセスは同様となります。
l2g_x(data,x)関数は、 X軸におけてローカル座標から全体座標への変換を行います。
x というのは、parallelのインデックス変数です。これは現在注目している画素のローカル座標位置を示します。
- vsUnion(result, vsMIN_DEPEND_ON_FIRST);
VIOS変数の統合を行う関数です。
テンプレートマッチングでは、テンプレートと原画像との画素値の差分が最も小さいところ探します。
そこで、各計算機はそれぞれ請け負った画像領域で最も差分が小さい位置を計算し、最終的にこの関数で最も小さい差分値をもっている計算機の値を採用します。
このVIOS変数resultは result[[0]]に最小差分値、result[[1]]にその差分値となった時のX座標、result[[2]]にはY座標が入っています。
この vsMIN_DEPEND_ON_FIRST は result変数の最初の値(result[[0]])の値が最も小さい計算機のresult値(result[[0]],result[[1]],result[[2]])を採用します。
実行結果
テンプレートと全体画像がもっともマッチした時のテンプレートの中心がある座標を出力します。