pythonで業務効率化/RPA自作 – 検討 その3 OpenCV を試す。(1)

python
スポンサーリンク

ちまたで話題のRPA(Robotic Process Automation)をpythonで自作することで、業務効率化はもちろん、必要に応じて内製でカスタマイズできるシステム作成を目指します。

今回は使えそうなライブラリ OpenCV を試します。

-- 実行環境 --
Windows 10 64ビット版(1903)、python 3.7.4

スポンサーリンク

OpenCV

OpenCV はインテルが開発・公開したオープンソースのコンピュータビジョン向けライブラリで、画像や動画を処理する様々な機能が実装されています。前回検証した pyautogui の精度調整でもこのOpenCVが使用されているようです。今回はOpenCVを使うことで pyautogui で出来る事以上の制御が出来るか確認してみます。

画像検知/マッチング

OpenCVには様々なマッチング方式があります。いくつか試してみます。以下に今回の画面と検知対象画像を載せておきます。

キャプチャ画像
(capture.png)

検知対象
(target.png)

テンプレートマッチング

今回の目的はPC内の業務効率化のため、検知対象画像の回転や拡大縮小などは考慮しなくてもいいのではと考えています。そうした場合、簡易なテンプレートマッチングで十分目的達成できるんじゃないでしょうか。検証してみたいと思います。

import cv2
from PIL import ImageGrab

# スクリーンショット
ImageGrab.grab().save("D:\Sample-Source\capture.png")

#画像をグレースケールで読み込む
img_cap = cv2.imread(r"D:\Sample-Source\capture.png", 0)
img_tmp = cv2.imread(r"D:\Sample-Source\target.png", 0)

#マッチング実行
result = cv2.matchTemplate(img_cap, img_tmp, cv2.TM_CCOEFF_NORMED)

#検知領域の位置を取得
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
top_left = max_loc
w, h = img_tmp.shape[::-1]
bottom_right = (top_left[0] + w, top_left[1] + h)

#検出領域を四角で囲んで保存
result = cv2.imread("D:\Sample-Source\capture.png")
cv2.rectangle(result,top_left, bottom_right, (255, 0, 0), 2)
cv2.imwrite(r"D:\Sample-Source\result1.png", result)
なこ
なこ

ちゃんと検知対象が囲まれていますね!成功です!

ヒロ
ヒロ

12行目のテンプレートマッチングで指定しているパラメーター「TM_CCOEFF_NORMED」は類似度を計算する方法の一つで、方式次第で精度や変化に対する耐性が変わるようだよ。

なこ
なこ

環境や対象などで精度が高い比較方法が変わる可能性があるということですね。色々やってみないと分かりませんね~

ちなみに、検知対象がない場合どうなるんですか?

ヒロ
ヒロ

いいところに気づいたね!上記のソースでは問題があるんだ。下に実行結果を載せておくよ。

なこ
なこ

対象のアイコンを少し隠したんですね。って全然違うアイコンが選択されてしまっていますね

ヒロ
ヒロ

そうなんだ。matchTemplate はソース画像から「一番」精度が高い位置を返してくれるんであって、一番いい精度が低いということは当然ありえるんだ。

下に類似度をチェックするよう修正したソースを上げておくね。

import cv2
from PIL import ImageGrab

# スクリーンショット
ImageGrab.grab().save("D:\Sample-Source\capture.png")

#画像をグレースケールで読み込む
img_cap = cv2.imread(r"D:\Sample-Source\capture.png", 0)
img_tmp = cv2.imread(r"D:\Sample-Source\target.png", 0)

#マッチングテンプレートを実行
result = cv2.matchTemplate(img_cap, img_tmp, cv2.TM_CCOEFF_NORMED)

#検知領域の位置を取得
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
top_left = max_loc
w, h = img_tmp.shape[::-1]
bottom_right = (top_left[0] + w, top_left[1] + h)

print( "類似度:", max_val)

if max_val > 0.9 :
	#検出領域を四角で囲んで保存
	result = cv2.imread("D:\Sample-Source\capture.png")
	cv2.rectangle(result,top_left, bottom_right, (255, 0, 0), 2)
	cv2.imwrite(r"D:\Sample-Source\result1.png", result)
else:
	print( "検知対象が見つかりませんでした。")

検知対象あり(結果)

検知対象なし(結果)

なこ
なこ

ちゃんと対象あり/なしで動作しましたね!これなら使えそうです!

ヒロ
ヒロ

そうだね。類似度をどこまで許容するのかは悩ましいところだけどテンプレートマッチングを使う場合は必ず精度のチェックが必要というのは忘れないようにしてね。
ちなみに調べてないけどPyAutoGUIのlocateOnScreenとかはおそらくテンプレートマッチングを使っているんだと思うよ。

なこ
なこ

それじゃあPyAutoGUI使ったほうが楽ですね

テンプレートマッチングの問題点

いくつかの環境でテンプレートマッチングを試してみましたが、一つ正常に動作しないケースがありました。運用で回避できる内容なのでそれほどのデメリットではありませんが記載しておきます。

正常に動作しないケース

他のPCで作成した検知対象画像(テンプレート)を使ったマッチング処理

他のPCで作成したテンプレートを使用したマッチングが全く動作しませんでした。原因については正確には分かっていませんが、解像度などの差異から微妙に縮尺が変わり、類似度が下がっているのではと考えています。時間ある時に類似度や別の類似度計算方法で試してみたいと思います。

長くなったので、別のマッチング手法は次回にさせて頂きます。
では。

コメント

タイトルとURLをコピーしました