• AI

業務ハッカーへの道 (#2 画像認識による自動検証)

技術開発部の原田です。
通常業務の中から効率化できる部分を見つけて技術で解決する(ハックする)方法を提案しようと思います。

TL;DR ※まとめです

  • OpenCVのテンプレートマッチングにより、調査対象画像の中に正解画像が含まれるかを検出できる。
  • 正解画像の設定とそれに対する正解率の閾値設定という調整が済んでしまえば、自動検証まで行える。

はじめに

RPAに関連する話です。本稿では画像の比較による検証作業の自動化技術を紹介します。

システムを表示させることが自動化できたとしても実は道半ばです。
表示された画面に想定通りの結果が出力されているかどうかの確認まで自動化できれば良いのではないでしょうか。

というわけで本稿では、ある画像(調査対象画像)の中に、含まれるべき画像(正解画像)があるかどうかを調べる技術を例とともに提示したいと思います。
本稿が現場での目視確認が必要なテスト工数の削減に寄与することを願います。

本稿ではWindows10にPython3.6とAnacondaを導入しています。
実際Python3.Xと画像処理ライブラリOpenCV,科学計算ライブラリnumpyが使える環境があれば十分ですが、いろいろ揃っているので導入したまでです。
なお、Anacondaの導入やPython自体についての説明、画像認識手法の細かい部分についての解説は割愛します。

https://www.python.org
https://anaconda.org
https://opencv.org

本稿では以下を前提とします。

使用OS 問わない(Python3.Xが使えれば何でも良い)
前提知識 Pythonで簡単なスクリプトを記載できる(Python未経験であっても極力分かるようにしています)
使用方法 Pythonコード実行環境 iPython, jupyter notebookなど何でも良い
使用ソフトウェア Python(OpenCV,numpy)

ただソフトウェアの機能の特徴を羅列しても退屈なため、仮に課題を設定し、それを通してソフトウェアの機能を説明します。

課題設定

課題1

課題は以下の通りとします。

  • 正解画像を用意する。(日本郵政のページで某所の郵便番号の画像とする)
  • 調査対象画像を用意する。(日本郵政のページで正解画像を取得した場所のスクリーンショットとする)
  • 調査対象画像内に正解画像があるかを確認し、存在した場合は検出部分に四角形の目印を貼り付ける。
  • 比較した結果を別ファイルにして保存する。

正解画像が表示される想定のWEBの操作をしたエビデンスが調査対象画像で、今回は調査対象画像の中に正解画像が想定通り含まれるか?という、これまでは目視で確認していたような作業を想定しています。

まず、画像を準備します。
正解画像(埼玉県朝霞市泉水の郵便番号表示部分。「〒351-0024」という画像です。テキストではありません。)

contain01

調査対象画像(埼玉県朝霞市泉水の郵便番号を検索した結果の画面スクリーンショット)
evidence01

調査対象画像と正解画像をそれぞれ読み込み、調査対象画像の中に正解画像があるかどうかを探すコードを記載していきます。
※ 画像の大きさに注意してください。調査対象画像の大きさ > 正解画像 である必要があります。

画像ファイル名はそれぞれ以下の通りとします。XXは連番
正解画像:containXX
調査対象画像:evidenceXX
結果画像:outputXX

次に課題を解決するためのPythonのコードを記載します。iPython環境やjupyter notebookで実行すると良いでしょう。
また、コマンドを実行するディレクトリに正解画像ファイルと調査対象画像ファイルを配置してください。

課題1

# coding: utf-8
 
# ライブラリの読み込み
import cv2
import numpy as np
 
# 各種パラメータ設定
test_image_file = 'evidence01.png'
template_image_file = 'contain01.png'
output_image_file = 'output01.png'
method = cv2.TM_CCOEFF_NORMED
rectangle_color = (255,0,0)  # 青色
rectangle_line_width = 3     # 線の太さ
threshold = 0.7              # 画像一致率の閾値(0~1)
 
# 調査対象画像の読み込み
test_image_rgb = cv2.imread(test_image_file)
test_image_gray= cv2.cvtColor(test_image_rgb, cv2.COLOR_BGR2GRAY)
 
# 正解画像の読み込み(検出部分の描画のため、画像のサイズも取得しておく)
template_image_rgb = cv2.imread(template_image_file)
template_image_gray= cv2.cvtColor(template_image_rgb, cv2.COLOR_BGR2GRAY)
template_height = template_image_rgb.shape[0]
template_width  = template_image_rgb.shape[1]
 
# 調査対象画像に正解画像があるかを検出する
result = cv2.matchTemplate(test_image_gray,template_image_gray,method)
 
# 画像一致率の閾値を超えた結果の数だけに絞り込む
locations = np.where(result >= threshold)
 
# 調査対象画像の中に正解画像が含まれていた場所に四角形の枠を追記する
for point in zip(*locations[::-1]):
    cv2.rectangle(test_image_rgb, point, (point[0] + template_width, point[1] + template_height), rectangle_color, rectangle_line_width)
 
# 画像として出力する
cv2.imwrite(output_image_file,test_image_rgb)

いかがでしょうか。

実施の内容は以下の通りになっています。

L04 OpenCVのライブラリを読み込み
L05 NumPyのライブラリを読み込み(npというエイリアスをつけています)
L11 画像を検出する際のアルゴリズムを指定(詳細は割愛)
L14 画像の一致度合いの設定(0から1までのfloat値で指定。1に近いほどより厳密な一致を求めることになる)
L18 画像をグレースケールに変換(画像比較の際は、色の揺れを補正するためにグレースケールに変換することが慣例)
L27 画像の検出(調査対象画像から正解画像を探すことをテンプレートマッチングと呼ぶため、atchTemplateという関数名になっています)
L30 閾値をもって検出結果をフィルタする
L34 閾値を超えている箇所に四角形を描画する
L37 検出結果を画像として出力する

上記を実施すると、以下の画像ファイルが出力されます。
青色の四角形が検出出来た箇所を示しています。上手く検出できました。

output01

OpenCVのテンプレートマッチングでは、調査対象画像に対して正解画像を重ね合わせ、少しずつずらしながら、都度画像同士の相関性を計算しています。画像の測定点ごとに画像の類似度を評価しているということです。
閾値はその評価を甘くするか、厳密にするかの調整として用いています。

これでよし・・・とはなりません。
というのも、誤検出の有無について確認をしていないためです。場合によってはパラメータの修正が必要となります。

  • 正解となるはずの画像が正解とされること(←今確認したこと)
  • 不正解となるはずの画像が不正解とされること(←未確認)

そこで、不正解となるはずの画像を用意して確認してみます。
※ 適合率Precisionや再現率Recall、というかF値出せよ!とか硬いことを言わないでくださいw

課題2

課題は以下の通りとします。
課題1の補足として、別の画像(別の郵便番号)を用意した際に、画像検出がなされないこと。

別地点の正解画像を用意します。
正解画像(埼玉県朝霞市東弁財の郵便番号表示部分)※地点は似ていますが少し違います。上のものは351-0024、今回は351-0022です。

contain02

近しいですが郵便番号が異なるため、結果としては不一致=不正解となって欲しいところです。
正解画像ファイルだけを変えて実行した結果がこちらです。
output02

おっと、残念。想定通りではありません。「〒351-0022という画像がある」と判断されてしまっています。
これの原因としては、閾値が0.7と低い画像一致率で実施していたために起こります。
※ methodの違いによっても解決することもありますが、割愛します。

閾値をより厳しく0.95などにして実行すると、以下の通りになります。
これにより、無事「〒351-0022という画像がない」という結果が出ています。
output03

一応閾値0.95で課題1で用いた画像は検出されていることも確認しています。
output04

このように正解画像が複数あり、それらが近しい場合は、見分けの付く画像の選定及び閾値の設定をすると良いことになります。

ただ、閾値を極端に厳しくしすぎると、画面上僅かに表示が変わった(フォントが1ポイント小さくなった等)タイミングで、ヒットしていたものがヒットしなくなるということがありえます。
全体の完璧な一致を目指すよりも、真にキーとなる場所のみの一致を確認する方が良さそうです。

最後に

いかがでしょうか。本稿ではOpenCVの機能のほんの一部を紹介しました。
画像が含まれているかどうか、というテンプレートマッチングを使うことで、スクリーンショットの目視確認という作業を機械化できると思います。

なお、今回は正解画像があったとされた場所に四角形の描画をしていますが、ソースを改変して、検出点のある/ないを判別し結果のファイル名に反映するだけでも正常/異常検出として十分なのではないかと思われます。

この技術は単純に画像比較のために用いることができます。
そのため、正解画像や調査対象画像が必ずしもWEBの画面である必要はありません。(本稿ではWEBページのスクリーンショットで例示しましたが)

開いたPDFファイルやEXCELのファイルであっても、それを画像認識で比較することが可能であり、汎用性は高いと思います。
定型のルールをベースに値を目視で確認している場合、導入を検討できるのではないかと考えます。

この技術の使い所は以下の通りです。

  • デグレードが発生していないかを確認する回帰テスト
  • 画面を通した目視での実施内容確認の機械化

画像認識による自動検証の説明は以上となります。
もし普段の業務に画像を目視で確認している箇所があれば、このライブラリを用いて自動化と業務の効率化を図ってはいかがでしょうか。

ここまで読んでいただきありがとうございました。

備考

Javaでも画像検出は可能か?

はい、実施は可能です。
OpenCVは公式にC/C++,Java,Python向けのライブラリを提供しています。
使用方法に違いはほとんどありません。(言語仕様上、関数の引数が異なる程度)

今回Pythonを選択したのは、OpenCVというよりもNumpyの使い勝手の良さによるところが大きいです。
np.whereの1行でフィルタが出来るため。これを機にPythonを業務で使いませんか(笑)

関連記事

  1. 「エッジAI」への期待と課題

  2. 説明可能AIの実現方法:LIME、SHAP

  3. Google Colaboratory で無料のGPUを利用する

  4. 深層強化学習の学習経過を見てみた

  5. 外国人に「SCSKってAIの会社?」と言わせた話(国際情報オリンピック…

  6. お手軽な機械学習プラットフォーム、H2O

  7. 今、もっともアツい決定木「XGBoost」

  8. RGB画像からの深度推定手法の精度比較

PAGE TOP