石のセグメンテーションをWatershedアルゴリズムでやってみる
lanczos4で2倍に拡大し、PerspectiveTransformで上から見ているような絵に書き直した石敷き画像の石を一つ一つ領域分けしたいと思います。手作業で領域を切り分けてもいいのですが、面倒くさいので画像処理の助けを借りて、初期解ぐらいは半自動で得られるようにしようと思います。
このような画像の領域分けに使われるアルゴリズムは、グラフカット(GraphCut, GrabCut, LazySnapping)やWatershedが知られています。ここでは、古典的なWatershedアルゴリズムを使ってみたいと思います。
Watershed(分水嶺)アルゴリズムは、引数として切り分ける領域の種を要求します。[2]の例のように人の手作業で与えても構いません。
[1]では、コインのセグメンテーションを例に、下記のフローの手順で種を作る方法を紹介しています。
背景と前景が綺麗に分かれているコインの例の絵と、石敷きでは条件が異なるのでこの通りでは上手くいきませんが、まずは倣えでそのままやってみましょう。
https://gist.github.com/4cf96870d25f99911538.git
大したこと無いと甘く見てたら、結構時間掛かってしまいました。結果を見ていきましょう。
左:グレースケール
中:二値化(大津の方法)
右:ノイズ除去
左:背景マスク
中:前景マスク(距離変換結果を0.3*maxValで閾値処理)
右:未知領域マスク
左:距離変換
右:分水嶺
元の絵の段階で品質があまり高くないことが問題になっているような気がしますので、結果がもう一歩なのは分水嶺アルゴリズムが悪いのではないと思われます。この改善のためには、画像の前処理をしてやると良さそうです。
[1] Image Segmentation with Watershed Algorithm — OpenCV 3.0.0-dev documentation
[3] opencv / samples / cpp / watershed.cpp