2012-04-03[n年前へ]
■「ウォーリーを探す出す」多重解像度解析コードを書いてみる!?
「ウォーリーを探し出す」Mathematica コードがとても面白く・参考になりました。そして、もしも「ウォーリーを探し出す」コードを書こうとしたならば、自分ならどんな風に書くだろう?と考えました。…そこで、試しに、書いてみることにしました。
まずは、画像を読み込みます。
waldo=Import["hoge"]そして、ウォーリーを見つけるには、「やはり、赤白シャツを頼りにすべし」というわけで、赤白模様を検出するための単チャンネルを作成します。ここで、2{1,-1,-1}.#&は、R-G-Bを計算する純(無名)関数です(Stack Over Flow のコードと同処理です。カスタマイズできるように純関数にしています)。
red=ImageApply[2{1,-1,-1}.#&,waldo]次は、ウォーリーを探す部分です。Stack Over Flow で書かれていたコードは「横方向の赤白線の上エッジ検出」を行い、「強いエッジがある部分にウォーリーがいる」という推定を行います。
しかし、その推定では、「ウォーリーが着ているシャツは、赤白横線が何本も入っている」とか「その赤白横線は、胴の形に添った形状をしている」といった情報は用いられていません。
そこで、「胴の形をした赤白横線模様」を作り、さらにその「模様」を用いた多重解像度解析(ウォーリーの大きさは未知ですから)をすることによりウォーリーの位置を推定する、というコードを書いてみました。
mask=Fold[ImageAdd,#[[1]],Rest[#]]&@Table[このコードでは、多重解像度解析を行った上で、ありとあらゆる解像度、すなわち、ありとあらゆる大きさのウォーリーがいる(だろう)位置を、一枚のマスク画像へと焼き付けます。
h=a;w=Floor[h/2];
corr = ImageApply[ 4 Abs[# - .5] &,
ImageCorrelate[red,
Image@ Table[Cos@y, {y, 1, 6 Pi, 6 Pi/h}, {h}],
NormalizedSquaredEuclideanDistance ]];
ImageApply[ #/(30 - 5) &,
Dilation[ImageApply[ If[# > .8, 1, 0] &, corr],
ConstantArray[1, 4 {h, w}]] ] , {a, 5, 30}]
そして、焼き付けた(推定した)「ウォーリーが立っている位置のマスク画像」を用いて、原画像からウォーリーを浮き上がらせてみます。それが、以下の(Stack Over Flowそのままの)最後のコードです。
ImageMultiply[waldo,
ImageAdd[ColorConvert[mask, "GrayLevel"], .5]]
試しに、「ウォーリーをさがすとはどういうことか」で使われていたサンプル画像に処理をかけてみると、次のようになります。これが、「ウォーリーを探す出す」多重解像度解析コードです!?
赤白模様の「壁」などにマッチしないようにしたい場合のために、下記のようなフィルタリングを加えると良いかもしれません(今回はコードを短くするために割愛しました)。
corr2 = ImageApply[ 4 Abs[# - .5] &,
ImageCorrelate[corr,
Image@ Table[
If[x^2 + y^2 < h, 1, 0], {y, -h, h}, {x, -h, h}],
NormalizedSquaredEuclideanDistance ] ];