動機
「坊ちゃんを探せ!」と、あとまさんがツイートをしたので探してみようと思いました。
坊ちゃんを探せ!#坊ちゃんの日 pic.twitter.com/2yHVQmDDuR
— あとま (@1atoma) 2016年11月10日
方針
- 元画像ファイルを保存する
- 元画像ファイルから探すべき画像を切り出してファイルとして保存する
- OpenCV の「テンプレートマッチング」を用いて、切り出した画像が元画像とマッチングするかを調べるコードを書く
- マッチングした座標(元画像)を出力する
実装
前述の方針に従ってひとつひとつ進めていきます。
1. 元画像ファイルを保存する
前掲のあとまさんのツイートの添付画像を保存します。表示されている画像を右クリックで保存するのではなく、画像のユニーク URI に:orig
オプションを付与してオリジナルの画像を保存します(https://pbs.twimg.com/media/Cw6NGAtUcAAKvyJ.jpg:orig)。
2. 元画像から探すべき画像を切り出してファイルとして保存する
元画像の右下に探すべき画像がありますので、そこの画像を切り出します。切り出す範囲に悩むところですが、「黒」の部分が含まれていると誤判別しやすくなるので、黒色の縁を含まない最大の切り出し範囲を設定しました(96x192)。これでもし判別できないようならば範囲を広げてやり直していきます。
なお、切り出したままの画像は 1ドット が 16x16 ですが、マッチングをさせたい画像は 1ドット が 8x8 ですので、縮小をしておくことを忘れないようにします。
3. OpenCV を用いてマッチングを調べる
OpenCV
の実装にはRuby
のgem
であるruby-opencv
を用います。
gem
をインストールするためにはもちろんOpenCV
がインストールされている必要があるので、Ubuntu ならばapt-get install libopencv-dev
あたりで入れておきます*1。
テンプレートマッチングのコードは、ruby-opencv
のコミッタである ser1zw さんがそのものズバリのサンプルコードを示してくれていますので、これをベースに書いていきましょう。
「探すべき画像(切り抜いた画像)」をsearch_target.png
とし、元画像をoriginal.jpg
という名前にすると、以下のようなコードになります。
require 'opencv' include OpenCV target_image = CvMat.load('search_target.png') original_image = CvMat.load('original.jpg') matching_result = original_image.match_template(target_image, :sqdiff) puts "マッチング画像の元画像での座標の始点は次のとおりです" puts "x: #{matching_result.min_max_loc[2].x}, y: #{matching_result.min_max_loc[2].y}"
4. マッチングした座標(元画像)を出力する
あとは実行するだけです。上掲のコードをsearch_bocchan.rb
として実行します。ついでに実行時間も計ります。
$ time ruby search_bocchan.rb マッチング画像の元画像での座標の始点は次のとおりです x: 378, y: 218 real 0m0.783s user 0m0.656s sys 0m0.084s
無事、座標が得られたようです。当該座標は元画像の左上のあたりに位置していて、確かめてみると目視では確かに一致しているように見えます*2。
かかった時間は 0.78秒 でした。
備考
こういうことをすると確実にモテないのでやめたほうがいいと思います*3。