2005~2013
昨日、唐突にOpenCVを使ったアプリケーションを作りました。
一体何がしたかったのかというと、
某ブラウザゲームの(ピーーーーー)がとてつもなく(ピーーーーーーー)ので
この際(ピーーー)を(ピーーーーーー)しようというのをふと思いつきまして、
手元にpythonがあったので、pythonを使ったOpenCVを使って実装できないかと思ってやってみました。
まず、OpenCVってなんじゃという人のための話ですが、
OpenCVとは簡単に言うと、コンピューター上で画像や動画の処置を行うためのライブラリです。
今回はこれのテンプレートマッチングを使って(ピーーー)を(ピーー)していきます。
まず最初にテンプレート画像となる(ピーーー)の画像をスクショします。
次にOpenCVに現在のPC画面のキャプチャをぶち込まないといけないのですが、
調べた限り、OpenCVには直接画面キャプチャをする方法はなかったので
今回はPILというライブラリをインストールします。今思えばOpenGL使えばよかったね!
ダウンロードはここから、Pillowを落としてきます。
今回はpython2.7を使用していくので Pillow‑2.7.0‑cp27‑none‑win32.whl をDLします。
whlファイルなので、インストールにはpipを使用しました。
pip install Pillow‑2.7.0‑cp27‑none‑win32.whl
pipがインストールされていればこんなかんじでインストールできますね。
今回はPILの中にあるImageGrabを使います。
次はOpenCVですが、これは公式サイトからDLします。
今回は、3.0はベータ版だったので2.4.10をDLしました。
これはexeファイルなので普通に起動してインストールします。特に環境変数の設定もせず入れるだけで使えました。
後はnumpyをインストールしました。これもここからDLします。
今回は面倒だったので最新版のexeファイルをDLしました。
以上で環境構築は終了です。ここからは簡単にプログラムについてです。
まずimportの部分です。
import cv2
import numpy as np
import time
import random
from PIL import ImageGrab
from ctypes import *
こんなかんじです。特記することもありませんね(´・ω・`)
次に画像キャプチャの部分です。
def ScreenCap(x1=0,y1=0,x2=0,y2=0):
if x1==y1==x2==y2==0:
img=ImageGrab.grab()
img.save("cap.png")
else:
img=ImageGrab.grab((x1,y1,x2,y2))
img.save("cap.png")
Javaのようにオーバーロードが使えればよかったのですが、残念ながらpythonにはないのでこうなっています。
呼び出すときに引数なしで画面全体を、引数ありで指定範囲[px]内の画像を取得してcap.pngに保存します。
次に保存した画像を呼び出します。ここではimreadメソッドを使っています。
temp = cv2.imread('img/temp.png',0)
今回はキャプチャ画像も一度保存してからimreadで再度呼び出しましたが、キャプチャした時点で保存せずに
def ScreenCap(x1=0,y1=0,x2=0,y2=0):
if x1==y1==x2==y2==0:
img=ImageGrab.grab()
cap = np.asarray(img)
else:
img=ImageGrab.grab((x1,y1,x2,y2))
cap = np.asarray(img)
return cap
return cv2.cvtColor(cap, cv2.COLOR_BGR2GRAY)
とすることで、そのままOpenCVで使用することができるっぽいです。ぽいぽい言ってるのは試してないからですね。
2/25追記:グレースケールに変換する工程を忘れてました。てへぺろ
これで動作確認でました。一旦画像に保存して実行する場合とは類似度の結果が異なります。
テンプレートマッチングとは、簡単にいえば、
1つの大きな画像からある特定の箇所のある位置を検索するものです。
例えば与えられた画像がコレで
探す対象であるテンプレート画像がコレであれば
このように探索画像のどの位置にテンプレート画像があるかを調べてくれます。
そしてテンプレートマッチングはプログラムにするとこんな感じになります。
def Temprate_matching(img,temp):
res = cv2.matchTemplate(img,temp,cv2.TM_SQDIFF)
w, h = temp.shape[::-1]
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
top_left = min_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
center=(top_left[0] + w/2,top_left[1] + h/2,min_val)
return center
今回は輝度差の2乗誤差を使う方法でマッチングをしているので、
結果の最低値であるmin_valがマッチング結果となります。
今回はcenterというtupleを作って、マッチング中心点の座標及びmin_valの値をreturnするようにしています。
プログラムについては以上ですね。あとは魔法のクリック関数くらいでしょうか。
def click(posx,posy):
windll.user32.SetCursorPos(random.randint(posx-5,posx+5),random.randint(posy-5,posy+5))
time.sleep(random.uniform(0.05,0.1))
windll.user32.mouse_event(0x2,0,0,0,0)
time.sleep(random.uniform(0.1,0.2))
windll.user32.mouse_event(0x4,0,0,0,0)
ここでその対策をしています。
(^・ω・)ノ RadiumProduction at curonet