サブピクセルを推定する

 画像処理でパターンマッチングを行った場合、実数で計測位置が得られるものが多いです。 つまり、1ドットより細かい位置を割り出し、解像度を超えたような(?)結果を返してくれます。 最少情報単位は1ドットなのに、どうして、0.5ドットずれていますなんてことが言えるのか、 ちょっと魔術っぽいではありませんか?


実験材料を用意する

 実は仕事で丸マーク認識をやっていて、これだとコーナーエッジ検出が使えないので、今更ながらにドット比較によるパターンマッチングを実装し使っておりました。これだと、ドットを比較するわけですから、どうやったって答えは整数です。例えば、(3,3)を開始座標として画像を比較した時、もっとも誤差が少なかったよとか、そんな答えになります。

 これでは寂しいので、サブピクセルに挑戦します。画像とは、輝度(明るさ)情報の集まりです。で、カメラで撮影された画像ってのは、よほど縮小しないかぎり常識的には、明るいところから暗いところに輝度が突然変化するなんてことはなく、ゆるやかに何ドットかけて変化します。写真を大きく拡大して影のフチを観察すればわかります。この情報をゴソゴソ処理すれば、サブピクセルの位置が推定できそうです。

 まず、実験材料を用意しました。GIMPで、640ドット四方のビットマップ中央に丸を書き、ぼかしを数回かけます。(以下、これを元画像)これを64ドット四方に縮小したものを作り「画像0」とします。元画像に書いた丸を1ドット右にズラし、これを64ドット四方に縮小したものを「画像1」、同様に2ドットズラし縮小したものを「画像2」とします。 以下は、実験に使った画像です。目には、同じに見えます。


画像0

画像1

画像2

画像特徴の不変量は2回微分

 さきほどの画像群は、640ドット四方の段階で、1ドット右にズラし、それを1/10(辺比率)に縮小したのですから、0.1ドットのズレを持った画像になっているハズです。エッジの詳細はカメラで捉えたものとは異なるでしょうが、まずは実験なのでよしとします。 実験なので水平方向のみを考えます。水平ができれば、同じことを垂直にやって、斜めにズレていても、交互に2,3回やれば収束するのではないかと思います。

 明るいところから暗いところ、またはその逆の変化する位置を2枚の画像から取り出し比較すればよさそうです。エッジ点は、画像の隣接する画素同士を引き算して、大きくなったところを求めればよいですが(これを微分と呼ぶ)この大きいって判定がプログラム上面倒なので、もう一回微分します。すると、エッジの箇所で、値は0を跨いで変化します。

 このグラフは、ある画像の1ドット幅を横方向に見たときのイメージです。 青の線は、輝度の変化を、オレンジ線は、1回微分を、黄色線は2回微分した様子です。青が、明るさ10付近から、45付近に移動している途中で、黄色が0を跨いでいる様子がわかると思います。

 この方法なら、画像の明るさが変わっても、コントラスト(変化量)が変わっても、ある程度まで同じようにエッジを検出することができます。しかも、どの位置で0とクロスしたか「実数」で求めることができます。 もちろん、元の輝度情報は一般的な8ビットなら0〜255の範囲の整数、それを1回微分した値は±255の整数ですから、例えば2回微分の隣接値が-10と10であっても、ああ、ちょうど真ん中あたりでゼロクロスしているなということは言えても、どの程度正確かはわかりません。カメラ映像の場合、ノイズの影響もあるでしょう。そこで、比較画像のうち、このエッジ部分と思われる地点のデータを全て計算し、平均化することにします。

 注意したところとしては、明るいところから暗いところへの変化と、逆の変化では、最大傾き地点(ゼロクロス地点)が、内側または外側による可能性があるため、両方を別々に集計し、平均化すること。 それから、ノイズの影響を除去するためにある程度の変化(例えば輝度差5以上)で、かつゼロクロスしている地点のみを集計するようにしたことくらいです。プログラムでは以下のような結果を得ました。

画像の組み合わせ理論サブピクセル値計算サブピクセル値
画像0と画像10.10000.0948
画像1と画像20.10000.0951
画像0と画像20.20000.1972

 実は、この画像以外にも、さまざまな画像や、ズレ量で試しているのですが、全て計算サブピクセル量のほうが少なくでます。この原因はよくわかっていません。 0.005くらいは誤差がありますが、画像0,1,2を連続で見ても同じ画像にしか見えないのに、計算で概ね良い値が返ってくると気持ちの良いものです。

地点(35,22) 明→暗 画像Aサブピクセル= 0.41176 画像Bサブピクセル= 0.31818 2枚のズレ= 0.09358
地点(26,23) 暗→明 画像Aサブピクセル= 0.40476 画像Bサブピクセル= 0.19355 2枚のズレ= 0.21121
地点(25,24) 暗→明 画像Aサブピクセル= 0.24000 画像Bサブピクセル=-0.05405 2枚のズレ= 0.29405
地点(38,24) 明→暗 画像Aサブピクセル= 0.29412 画像Bサブピクセル= 0.05405 2枚のズレ= 0.24006
地点(24,25) 暗→明 画像Aサブピクセル= 0.25000 画像Bサブピクセル=-0.04545 2枚のズレ= 0.29545
地点(39,25) 明→暗 画像Aサブピクセル= 0.31250 画像Bサブピクセル= 0.04651 2枚のズレ= 0.26599
地点(23,26) 暗→明 画像Aサブピクセル= 0.42169 画像Bサブピクセル= 0.25373 2枚のズレ= 0.16796
地点(40,26) 明→暗 画像Aサブピクセル= 0.12727 画像Bサブピクセル=-0.22951 2枚のズレ= 0.35678
地点(22,27) 暗→明 画像Aサブピクセル= 0.66279 画像Bサブピクセル= 0.53000 2枚のズレ= 0.13279
地点(40,27) 明→暗 画像Aサブピクセル= 0.57471 画像Bサブピクセル= 0.46465 2枚のズレ= 0.11007
地点(22,28) 暗→明 画像Aサブピクセル= 0.40426 画像Bサブピクセル= 0.20339 2枚のズレ= 0.20087
地点(41,28) 明→暗 画像Aサブピクセル= 0.18333 画像Bサブピクセル=-0.20635 2枚のズレ= 0.38968
地点(41,29) 明→暗 画像Aサブピクセル= 0.43820 画像Bサブピクセル= 0.29167 2枚のズレ= 0.14654
地点(21,30) 暗→明 画像Aサブピクセル= 0.68831 画像Bサブピクセル= 0.56989 2枚のズレ= 0.11842
地点(41,30) 明→暗 画像Aサブピクセル= 0.53261 画像Bサブピクセル= 0.43011 2枚のズレ= 0.10250
地点(21,31) 暗→明 画像Aサブピクセル= 0.62353 画像Bサブピクセル= 0.51546 2枚のズレ= 0.10807
地点(41,31) 明→暗 画像Aサブピクセル= 0.58696 画像Bサブピクセル= 0.48936 2枚のズレ= 0.09759
地点(21,32) 暗→明 画像Aサブピクセル= 0.60674 画像Bサブピクセル= 0.51064 2枚のズレ= 0.09610
地点(41,32) 明→暗 画像Aサブピクセル= 0.58696 画像Bサブピクセル= 0.48936 2枚のズレ= 0.09759
地点(21,33) 暗→明 画像Aサブピクセル= 0.70270 画像Bサブピクセル= 0.56667 2枚のズレ= 0.13604
地点(41,33) 明→暗 画像Aサブピクセル= 0.52083 画像Bサブピクセル= 0.43333 2枚のズレ= 0.08750
地点(41,34) 明→暗 画像Aサブピクセル= 0.43333 画像Bサブピクセル= 0.29333 2枚のズレ= 0.14000
地点(22,35) 暗→明 画像Aサブピクセル= 0.40426 画像Bサブピクセル= 0.20339 2枚のズレ= 0.20087
地点(41,35) 明→暗 画像Aサブピクセル= 0.14815 画像Bサブピクセル=-0.20339 2枚のズレ= 0.35154
地点(22,36) 暗→明 画像Aサブピクセル= 0.64773 画像Bサブピクセル= 0.53000 2枚のズレ= 0.11773
地点(40,36) 明→暗 画像Aサブピクセル= 0.57955 画像Bサブピクセル= 0.47000 2枚のズレ= 0.10955
地点(23,37) 暗→明 画像Aサブピクセル= 0.42169 画像Bサブピクセル= 0.25000 2枚のズレ= 0.17169
地点(40,37) 明→暗 画像Aサブピクセル= 0.12963 画像Bサブピクセル=-0.23438 2枚のズレ= 0.36400
地点(24,38) 暗→明 画像Aサブピクセル= 0.25000 画像Bサブピクセル=-0.06522 2枚のズレ= 0.31522
地点(39,38) 明→暗 画像Aサブピクセル= 0.31250 画像Bサブピクセル= 0.04651 2枚のズレ= 0.26599
地点(25,39) 暗→明 画像Aサブピクセル= 0.24000 画像Bサブピクセル=-0.05405 2枚のズレ= 0.29405
地点(38,39) 明→暗 画像Aサブピクセル= 0.31481 画像Bサブピクセル= 0.02778 2枚のズレ= 0.28704
地点(26,40) 暗→明 画像Aサブピクセル= 0.40476 画像Bサブピクセル= 0.18750 2枚のズレ= 0.21726
地点(35,41) 明→暗 画像Aサブピクセル= 0.45000 画像Bサブピクセル= 0.31818 2枚のズレ= 0.13182

線形ゼロクロスによるサブピクセル推定= 0.197231

 これは、画像0(テキスト中は画像Aと表現)と画像2(テキスト中は画像Bと表現)のサブピクセル推定を実行したときのログの一部です。  「地点」と書かれているのは、画像0の中で、水平エッジがあると認識した地点、「画像Aサブピクセル」とは、画像0側で、ゼロクロス位置を推定した結果です。「2枚のズレ」が、両方の画像のズレをその1エッジから計測した結果です。0.36とか、0.08とか物騒(?)な数値も出ていますが、平均化すると、0.197になるようです。

 また、このデータを観察してみると、画像Bサブピクセルがマイナスになるケース、つまり、画像B側では、ゼロクロスが1ドット左で起きた場合に、値が高くなる傾向があるようです。逆にこれがないと、推定値は悪化する方向になります。これはバグのような気がします。ひょっとすると、ゼロクロスが2枚の画像内同一ドット間で見つからなかった場合は、別に集計、カウントし、平均化したほうが良いのかもしれません。


無作為研究所トップページに戻る

copyright(c)2011 by MUSAKUI-LABO