1. はじめに
3年目に突入したエンジニアをしているものです。
ARIのアドベンドカレンダ17日目の記事となります!
アドベンドカレンダーへの参加も3年目ですね。
今回は個人的に作成したpythonコードの紹介をしようかと思います。
ちなみにタイトルの「リアルタイム」は過言なのでそのあたりはお目溢しいただければと思います。
背景と概要
最近PCゲームをいろいろ触るようになって改めて実感したのですが、インディーズゲームだと英語表示のみで日本語に対応していないものとかも多いです。
仕事柄英語に拒絶反応を起こしはしないですが、ゲームをしながらスッと読めるほどではありません。(ドキュメントを読める程度)
ということで、今回は画面に表示された英文を翻訳するアプリがあればいいなと思って作成したのでその紹介ができればと思います。
と言っても構想だけあって大枠はChatGPT任せです。
ChatGPTとのやり取りも乗せたかったのですが、実装したのは9月で履歴が残っていませんでした。。
処理の流れ
まず改めてやりたいこととしては、「画面の一部をキャプチャして翻訳してほしい」です。
ただ、メッセージが切り替わるたびに手動でキャプチャ取るのはアホらしいので、自動で取得して翻訳した結果を出力してほしいですよね。
ということで今回は下記のような流れで実装しています。
- メッセージが表示される画面上の特定領域を指定
- 指定した領域のキャプチャを一定時間ごとに取得
- キャプチャ画像から文字列を抽出
- Google翻訳で日本語に翻訳して出力
ゲームでは大体メインのメッセージウィンドウは固定の場所に出ることが多いので、画面上の場所を指定することで余計な情報を取らないようにしています。
実行環境
- Windows 11 Pro
- Python 3.11.6
- Tesseract OCRをインストールしておくこと
pyautogui # GUI操作の自動化ライブラリ
Pillow # 画像操作用ライブラリ
pytesseract # OCR処理用ライブラリ
opencv-python # 画像処理用ライブラリ
googletrans==4.0.0-rc1 # 翻訳用ライブラリ
certifi==2024.12.14
chardet==3.0.4
googletrans==4.0.0rc1
h11==0.9.0
h2==3.2.0
hpack==3.0.0
hstspreload==2024.12.1
httpcore==0.9.1
httpx==0.13.3
hyperframe==5.2.0
idna==2.10
MouseInfo==0.1.3
numpy==2.2.0
opencv-python==4.10.0.84
packaging==24.2
pillow==11.0.0
PyAutoGUI==0.9.54
PyGetWindow==0.0.9
PyMsgBox==1.0.9
pyperclip==1.9.0
PyRect==0.2.0
PyScreeze==1.0.1
pytesseract==0.3.13
pytweening==1.2.0
rfc3986==1.5.0
sniffio==1.3.1
ソースコード
from datetime import datetime
import cv2
import numpy as np
from PIL import ImageGrab
import pytesseract
from googletrans import Translator
# 事前にインストールしたTesseract OCRのパスを指定
pytesseract.pytesseract.tesseract_cmd = r'C:\workspace_tmp\Tesseract-OCR\tesseract.exe'
# 文字列を翻訳して返す
def translate_text(text, src='en', dest='ja'):
translator = Translator()
translation = translator.translate(text, src=src, dest=dest)
return translation.text
# 領域選択![Code_8gehLyF7cu.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660549/1de3b90b-ebbe-7828-eea5-fc68c309ffa5.gif)
def select_region():
# スクリーン全体をキャプチャ
screenshot = ImageGrab.grab()
screenshot_np = np.array(screenshot)
# 選択用ウィンドウを表示
r = cv2.selectROI("Select Region", screenshot_np, showCrosshair=True)
cv2.destroyAllWindows()
return r
# メイン処理
def monitor_screen(bbox, interval=5):
last_text = ""
while True:
# 指定された領域をキャプチャ
screenshot = ImageGrab.grab(bbox=bbox)
current_text = pytesseract.image_to_string(screenshot)
# 前回の文字と異なる場合、翻訳結果を出力
if current_text != last_text and current_text.strip():
translated_text = translate_text(current_text)
# コマンドラインに出力
print(f"\n{datetime.now().strftime('%Y/%m/%d %H:%M:%S')}\n{translated_text}")
last_text = current_text
# 待機(ms)
cv2.waitKey(interval * 100)
if __name__ == "__main__":
# 領域選択
bbox = list(select_region()) # (x, y, width, height) 形式で返される
bbox[2] += bbox[0]
bbox[3] += bbox[1]
bbox = tuple(bbox)
# モニターのサイズを取得
screen_width, screen_height = ImageGrab.grab().size
# bboxがスクリーンサイズを超えていないか確認
if bbox[0] < 0 or bbox[1] < 0 or bbox[2] > screen_width or bbox[3] > screen_height:
raise ValueError("bbox is out of screen bounds")
# 選択領域が空でなければ監視・翻訳を開始
if bbox[2] > 0 and bbox[3] > 0:
monitor_screen(bbox)
デモ
デモ用にこれまたChatGPTにサンプルの英文を用意してもらい、
今回はそれらを順番に表示したものに対して翻訳結果を確認しました。
終わりに
画面の一部を監視して、文字が変わったら翻訳結果を出力する事はできました。
ただし、コンソールに文字列が出ているだけだったり、よく見ると元の文が改行している箇所で翻訳が崩れていたり。
このままではとても使えないものになっています。
(実際ゲームの文字を読み込んでくれるのかという話はしない)
次の記事ではこのあたりを改善していきたいと思います。
最後までお読みいただきありがとうございました。
参考記事