Pythonで始めるDIY 第1章終 寿司打を自動化してみよう!

Pythonで始めるDIY 第1章終 寿司打を自動化してみよう!

重要な追記(2020年7月30日)

寿司打WebGL版の正式なQ&Aを見ていただくとわかりますが、現在ではこうした自動化ツールの利用を禁止しているようです。

このサイトで書かれていることは「過去にはこんなことがあったんだな」程度で留めておいてください。

本題

前回の続きです。今回が最終回です。

6. 取り出す画像の範囲を狭める

この作業が一番しんどいかもしれませんが笑

実行してみても分かる通り、認識精度があまり高くありませんでした。

というのも、前回までのプログラムでは、画像は枠線よりも外の部分となっており、無駄な部分まで認識させていたためです。

無駄な部分を認識させることを防ぐために、その部分をバッサリと切ってしまいましょう。

寿司打のお勧めコースでは6種類の枠線の長さがあるので、その部分のピクセルを確認してゆきたいと思います。

で、割愛しますが、確認した結果とプログラムを載せてゆきます。

...
# <body>に向かってキーを入力させる
target_xpath = '/html/body'
element = driver.find_element_by_xpath(target_xpath)
element.send_keys(" ")

# 画像の範囲を指定するためのリスト
im_ranges = [136, 124, 112, 100, 88, 76]

# PyOCRのツール
tool = pyocr.get_available_tools()[0]

from time import time
start = time()
while time() - start < 90.0:

    # 移動した
    # ファイル名
    fname = "sample_image.png"
    # スクショをする
    driver.save_screenshot(fname)

    # 画像をPILのImageを使って読み込む
    # ローマ字の部分を取り出す
    im = Image.open(fname).crop((0,230,500,254))

    # 画像の範囲を指定する
    for im_range in im_ranges:
        if im.getpixel((im_range, 0)) == (255, 255, 255, 255):
            im = im.crop((im_range+20, 0, 500-im_range-20, 24))
            break

    # tool で文字を認識させる
...

これによって、取り出した画像の範囲は狭まっており、実行してみればある程度精度が向上していることが分かると思います。

7. 画像を二値化して認識精度を上げる

ですが、これではまだ精度が高いとは言えません。

そのために文字の部分を二値化するということをしてゆきたいと思います(正確には画像を二値化とネガポジ変換をする)

コードを見てください。

...
    # 画像の範囲を指定する
    for im_range in im_ranges:
        if im.getpixel((im_range, 0)) == (255, 255, 255, 255):
            im = im.crop((im_range+20, 0, 500-im_range-20, 24))

            # 画像を二値化する
            im = im.convert("L")
            for i in range(im.size[0]):
                for j in range(im.size[1]):
                    if im.getpixel((i, j)) >= 128:
                        im.putpixel((i, j), 0)
                    else:
                        im.putpixel((i, j), 255)
            break

    # 画像がちゃんと切り取られているかの確認
    # im.save("sample.png")

    # tool で文字を認識させる
...

8. お腹いっぱい寿司を食べる

これで完成です。お疲れ様です。

ここまでくれば、あとはお腹いっぱい寿司を食べるだけです。

最後に

どうでしたか? 自動化した寿司打は上手く作れましたか?

こうやって自分で作ってみると、案外、楽しいものだと思います。

このプログラムを作ったことによって、あなたは、ブラウザー操作、文字認識などがができるようになりました!

上手くやれば、面倒なID、パスワード入力も自動化できたり、漫画の吹き出しから文章を取り出せる、なんてこともできるようになります。

ちなみに遅くなりましたが、自動化した寿司打のサンプルコードが、私のGitHubにアップロードしてあります。どうぞご査収ください。

今回までのコード全体

コードは以下に示します。GitHubにあげたものとは結構違いますが、このページで示したプログラムは以下のようになっています。

説明不足かもしれませんでしたが、ご静読、ありがとうございました。

from time import sleep
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from PIL import Image, ImageOps
import pyocr
import pyocr.builders

# Chrome Driverのパス
driver_path = './chromedriver'
# ドライバーを開く
driver = webdriver.Chrome(driver_path)

# ウィンドウサイズを固定
# +123としているのは
# 「Chromeは自動テストソフトウェアによって制御されています。」
# という部分を考慮している
window = (500, 420+123)
driver.set_window_size(*window)

# OpenGL版の寿司打を開く
target_url = 'http://typingx0.net/sushida/play.html'
driver.get(target_url)

# 寿司打のゲーム画面をずらすために書く
target_xpath = '//*[@id="game"]/div'
webgl_element = driver.find_element_by_xpath(target_xpath)
actions = ActionChains(driver)
actions.move_to_element(webgl_element).perform()

# クリックする前にロード時間待機
sleep(10)

# スタートボタンの座標
center_x = 250
center_y = 256

# スタートボタンをクリックする
actions = ActionChains(driver)
actions.move_to_element_with_offset(webgl_element, center_x, center_y).click().perform()

print("スタートボタンをクリックしました。")

# ボタンが表示されるまで待つ
sleep(2)

# お勧めコースをクリックする
actions = ActionChains(driver)
actions.move_to_element_with_offset(webgl_element, center_x, center_y).click().perform()

print("お勧めコースのボタンをクリックしました。")

# <body>に向かってキーを入力させる
target_xpath = '/html/body'
element = driver.find_element_by_xpath(target_xpath)
element.send_keys(" ")

# 画像の範囲を指定するためのリスト
im_ranges = [136, 124, 112, 100, 88, 76]

# PyOCRのツール
tool = pyocr.get_available_tools()[0]

from time import time
start = time()
while time() - start < 90.0:

    # 移動した
    # ファイル名
    fname = "sample_image.png"
    # スクショをする
    driver.save_screenshot(fname)

    # 画像をPILのImageを使って読み込む
    # ローマ字の部分を取り出す
    im = Image.open(fname).crop((0,230,500,254))

    # 画像の範囲を指定する
    for im_range in im_ranges:
        if im.getpixel((im_range, 0)) == (255, 255, 255, 255):
            im = im.crop((im_range+20, 0, 500-im_range-20, 24))

            # 画像を二値化する
            im = im.convert("L")
            for i in range(im.size[0]):
                for j in range(im.size[1]):
                    if im.getpixel((i, j)) >= 128:
                        im.putpixel((i, j), 0)
                    else:
                        im.putpixel((i, j), 255)
            break

    im.save("sample.png")

    # tool で文字を認識させる
    text = tool.image_to_string(im, lang='eng', builder=pyocr.builders.TextBuilder())

    # text を確認
    print(text)

    # 文字を入力させる
    element.send_keys(text)


input("何か入力してください")

# ドライバーを閉じる
driver.close()
driver.quit()

追記(2019年5月6日)

どうやら、scikit-imageというものを使った方が、画像処理は速くなるかもしれないので、良かったら試してみてください。