SikuliXでパソコン画面上の変化を監視する方法

SikuliXでパソコン画面上の変化を監視する方法

こんにちは、業務自動化ツール開発担当の吉池(@valmore_myoshi)です。

画面上の変化を監視したいと思ったことはありませんか?例えばポップアップを検出したり、特定の画像が現れるまで監視するといった処理が考えられます。

SikuliXでは、この監視機能が標準でついています。画面の変化だけでなく、特定の画像の表示非表示まで監視できるのでさまざまな場面で活用できます。

本記事では、SikuliXの監視機能に注目し、その使い方をわかりやすく解説します。

Region領域を監視する方法

パソコン画面上を監視するにはRegionで監視領域を指定します。Region領域ごとにオブザーバー(領域を監視する監視員みたいなもの)を一つ設置でき、オブザーバーは複数のイベントを監視できます。

例えば、特定の画像が画面上に表示されるまで監視する処理を見てみましょう。

# 監視領域を指定
reg = selectRegion()

# イベントハンドラを作成
def test(event):
    print('image is appeared')
    
# イベントを指定
reg.onAppear("someVisual.png", test)

# 指定秒数監視スタート
reg.observe(10)

最初に監視領域となるRegionを指定します。次にイベントハンドラを作成しますが、少し耳慣れない言葉かもしれません。イベントハンドラとは、見た目は普通の関数の形をしており、普段は何もせず待機していますが、特定のイベントが発生すると起動するものです。

上記のコードでは、Region.onAppear()を使って指定した画像が画面上に現れるのを監視しています。第一引数に検知したい画像、第二引数にイベントハンドラを指定することで、画像を検知したらイベントハンドラに指定した関数を実行します。

そして、最後にRegion.observe()で監視をスタートさせます。引数に秒数を指定することで監視時間を設定できます。

Regionの使い方に興味がある方はこちらの記事をご覧ください。
Regionとは?SikuliXで画面領域を扱うRegionクラスの基本的な使い方

監視する領域が狭いほど処理速度アップ!

監視領域が狭いほど検索に費やすリソースが少なくなるので処理速度が上がります。また、監視領域をスキャン(検索)する頻度にも依存します。通常のスキャンレート1秒間に3回スキャンですが、Settings.ObserveScanRateで調整できます。スキャンレートの指定は1秒あたりのスキャン回数で指定します。少しややこしいですね。

# 1秒間に0.2回スキャン。つまり、5秒に1回スキャン。
Settings.ObserveScanRate = 0.2

3種類の監視イベント

監視イベントは画像の表示を検知するRegion.onAppear()と画像の非表示を検知するRegion.onVanish()、画面上の変化を検知するRegion.onChange()の3種類あります。

画像の表示を検知するRegion.onAppear()

画面上に特定の画像が現れるのを監視するときはRegion.onAppear()を使いましょう。第一引数に検知したい画像、第二引数にイベントハンドラを指定します。通常は指定した画像を初めて検知した段階で終了しますが、続けて監視したい場合はObserveEvent.repeat()で繰り返し監視できます。

# 監視領域を指定
reg = selectRegion()

# イベントハンドラを作成
def test(event):
    print('image is appeared')

    # 連続して検知したい場合
    event.repeat()

# イベントを指定
reg.onAppear("someVisual.png", test)

# 指定秒数監視スタート
reg.observe(10)

画像の非表示を検知するRegion.onVanish()

特定の画像が画面上から消えるのを監視するときはRegion.onVanish()を使います。第一引数に監視したい画像、第二引数にイベントハンドラを指定します。Region.onVanish()も指定した画像が初めて消えたのを感知した段階で終了しますが、続けて監視したい場合はObserveEvent.repeat()で繰り返し監視できます。

# 監視領域を指定
reg = selectRegion()

# イベントハンドラを作成
def test(event):
    print('image is vanished')

    # 連続して検知したい場合
    event.repeat()

# イベントを指定
reg.onVanish("someVisual.png", test)

# 指定秒数監視スタート
reg.observe(10)

画面上の変化を検知するRegion.onChange()

画面上の変化を検知するにはRegion.onChange()を使います。第一引数には変化とみなす最小のピクセルサイズ(デフォルトは50ピクセル)を指定し、第二引数にイベントハンドラを指定します。これまで解説してきたRegion.onAppear()やRegion.onVanish()と異なり、指定した監視時間の間、連続して変化を感知し続けます。

# 監視領域を指定
reg = selectRegion()

# イベントハンドラを作成
def test(event):
    print('image is changed')
    
# イベントを指定
reg.onChange(50, test)

# 指定秒数監視スタート
reg.observe(10)

イベントハンドラからイベント情報ObserveEventを取得する

監視イベントにはイベントハンドラを指定すると、イベントハンドラに指定された関数には引数としてObserveEventが渡されます。ObserveEventにはイベントの情報が格納されており、イベントの種類や監視対象となったRegionを取得できます。

# 監視領域を指定
reg = selectRegion()

# イベントハンドラを作成
def test(event):
    # イベントの種類を取得
    print(event.getType())

    # 監視領域を取得
    target_reg = event.getRegion()

    # 監視を継続
    event.repeat()
    
# イベントを指定
reg.onAppear("1568789426396.png", test)

# 指定秒数監視スタート
reg.observe(10)

バックグラウンドで監視する方法

バックグラウンドで監視するにはRegion.observeInBackground()を使います。通常の監視、Region.observe()だと監視処理が終わるまで次のスクリプトに処理が移りませんが、バックグラウンド処理であれば即座に処理が実行されます

例えば下記のスクリプト、Region.observeInBackground()のあとにprint()していますが、監視処理を待たずに即座に実行されます。メインのスクリプトと監視処理を並行して実行したいときにオススメです。

# 監視領域を指定
reg = selectRegion()

# イベントハンドラを作成
def test(event):
    # イベントの種類を取得
    print('image is appeared')
    
# イベントを指定
reg.onAppear("1568790190755.png", test)

# 指定秒数監視スタート
reg.observeInBackground(10)
print('hello')

名前付きイベントの扱い方

イベントを指定するとき、返り値としてイベント固有の一意な文字列(イベント名)が返されます。一連のイベントはリスト形式で格納されており、イベント名を指定することでObserveEventを取得できます。一度イベントを取得するとリストからなくなります。

# 監視領域を指定
reg = selectRegion()

# イベントを指定
e = reg.onAppear("someVisual.png")

# 指定秒数監視スタート
reg.observe(10)

print 'has events?: ', reg.hasEvents()

# Region.getEvent()でObserveEventを取得
print(reg.getEvent(e))

print 'has events?: ', reg.hasEvents()
名前付きイベント実行結果
実行結果

まとめ

Regionで指定した領域を監視する方法を解説しました。指定した画像が現れるまで、あるいは消えるまでを監視し、画面上の変化も検知できます。

人の目で画面上を目視確認するよりもSikuliXによる監視処理に任せた方が圧倒的に楽で正確です。ぜひこの機会に監視の自動化をお試しください。