はじめに
Ruby Advent Calendar 2017 - Qiita の18日目の記事です。
動作環境
Ruby - 2.4.3
OpenCV - 2.4.13.4
モチベーション
個人開発でNakamyというサービスを開発しています。Nakamyは下記のようなサービスです。
Nakamyは友達のiPhoneの中身を覗けるサービスです。ホーム画面のスクリーンショットをアップロードすることで、Facebook上の友達とホーム画面を共有でき、友達がインストールしているアプリを見ることができます。
MVPとしてホーム画面のスクリーンショットをアップロードして友達と共有できる機能のみでα版としてリリースしたのですが、ゆくゆくは個人がどのアプリを保持しているのかという情報まで取得し、レコメンドなどに繋げたいと思っています。
そこで、ホーム画面のスクリーンショットの画像からどのアプリが入っているかという情報を得ることをゴールとします。
方法
今回は、OpenCVのテンプレートマッチングを試してみます。OpenCVはインテルが開発したオープンソースのコンピュータビジョン向けのライブラリです。
OpenCVのインストール
ruby-opencvがまだ3系に対応していないので、2系をインストールします。
$ brew install opencv@2
==> Summary
🍺 /usr/local/Cellar/opencv@2/2.4.13.4: 278 files, 35.6MB
RubyでOpenCVを使えるようにする
こちらのライブラリを使います。
ruby-opencv/ruby-opencv: Versioned fork of the OpenCV gem for Ruby
READMEに
$ gem install ruby-opencv -- --with-opencv-dir=/path/to/opencvdir
このように書かれているので、各自の環境に合わせて引数を渡してインストールします。
$ gem install ruby-opencv -- --with-opencv-dir=/usr/local/Cellar/opencv@2/2.4.13.4
これで、rubyでOpenCVを使う環境が整いました。
元となるデータを用意する
検出するアプリケーションの画像として、App Storeより、「Facebook」のアプリケーションのアイコン画像を収集しました。
今回は、「ホーム画面の中にFacebookアプリが含まれているかどうか」の判定を行います。
元となるホーム画面のスクリーンショットのデータとして、Facebookが含まれているパターンと含まれていないパターンのホーム画面を用意しました。
Facebookが含まれているパターン
僕のiPhoneのホーム画面のトップです。
Facebookが含まれていないパターン
Facebookのところをekiboに変更しました。
コード
用意したFacebookのアイコンをテンプレートとし、ホーム画面に対して、テンプレートマッチングを行う処理を書きました。
Facebookアイコンが含まれている場合はtrueを、含まれていない場合はfalseを出力します。
また、Facebookアイコンが含まれている場合はその箇所を赤色の矩形で囲み画像ファイルを出力します。
min_score
の 0.1
は閾値です。高くするほど、検出率は上がりますが、誤検出の可能性が高くなります。似ているアイコンが多く存在する場合など、閾値は調整が必要です。
require 'opencv'
include OpenCV
image = OpenCV::IplImage.load("images/home_screens/001.png")
template = OpenCV::IplImage.load("images/apps/facebook.jpg")
result = image.match_template(template, CV_TM_SQDIFF_NORMED)
min_score, max_score, min_point, max_point = result.min_max_loc
if min_score < 0.1
from = min_point
to = OpenCV::CvPoint.new(from.x + template.width, from.y + template.height)
image.rectangle!(from, to, :color => OpenCV::CvColor::Red, :thickness => 1)
p true
else
p false
end
image.save_image("images/outputs/001.png")
結果
Facebookが含まれているパターン
$ ruby home-screen-analyzer.rb
true
赤線で囲われていますね。
Facebookが含まれていないパターン
$ ruby home-screen-analyzer.rb
false
こちらの画像には赤線がありません。
おわりに
今回は、RubyでOpenCVを用いたテンプレートマッチングを行い、ホーム画面の中に特定のアプリがあるかどうかの判定を行いました。
実際にサービスに導入する際は、検証するアプリの数が膨大に増えるため、テンプレートマッチングだと計算量が多くなりすぎてしまうと思っています。代替案として、アイコンの配置でマスキングして、バッジなどの雑音を取り除いた上でアイコン毎に画像を切り出し、BASE64化して比較するのが良いのではと思っています。この辺、こうやった方がいいんじゃない?といったアドバイスなどがございましたら、コメントいただけますと助かります。