
マイケル
みなさんこんにちは!
マイケルです!!
マイケルです!!

エレキベア
クマ〜〜〜〜〜

マイケル
突然ですが、みなさんはこんなことを思ったことはありませんか?


マイケル
↑こういう画像の中の文字を翻訳したい・・・。

エレキベア
(そうそう無いクマ・・・)

マイケル
そんな要望に応えるべく、
スクリーンショットから文字認識して翻訳するツールを開発しました!
スクリーンショットから文字認識して翻訳するツールを開発しました!

マイケル
その名も・・・
\スクショ翻訳くん!/


エレキベア
(そのまんまクマ・・・。)

マイケル
使い方は簡単3ステップ!
① 画像を用意してツールを開く
② スクリーンショットを撮る
③ 翻訳結果が表示される


マイケル
こんな感じでスクショ画像から文字認識して、翻訳してくれます!

エレキベア
確かにこれはいろんな場面で使えそうクマね

マイケル
画像だけじゃなく、コピペできない文字を読み込んだりとかできそうだね。

マイケル
今回はこのツールの概要と
実装方法について解説していくよ!
実装方法について解説していくよ!

エレキベア
楽しみクマ〜〜〜〜
スクショ翻訳くんの概要

マイケル
ツールの全体の流れとしてはこのようになっています!
全体の処理


マイケル
言語はPythonを使用していて、
①フォルダ監視
→スクリーンショットの保存フォルダを監視して、ファイルが作成されたら読み込む。
②画像認識
→読み込んだファイルを画像認識して文字を読み込む。
③翻訳認識
→読み込んだ文字を翻訳して表示する。
①フォルダ監視
→スクリーンショットの保存フォルダを監視して、ファイルが作成されたら読み込む。
②画像認識
→読み込んだファイルを画像認識して文字を読み込む。
③翻訳認識
→読み込んだ文字を翻訳して表示する。
といった流れになっています!

エレキベア
スクリーンショットは別の機能を使うのクマね

マイケル
最初は範囲指定のスクショもPythonで実装しようと思ってたけど、
中々一癖ありそうだったので分けることにしたんだ。
中々一癖ありそうだったので分けることにしたんだ。

マイケル
例としては、WindowsならSnipping Tool、Macなら Cmd+Shift+4
で選択範囲のスクショが撮ることができるよ!
で選択範囲のスクショが撮ることができるよ!

エレキベア
普段よく使う機能クマね
フォルダ監視について

マイケル
今回、フォルダ監視は「WatchDog」というPythonパッケージを使用しました。
参考:
Python WatchDog – フォルダの監視を行う

エレキベア
ファイル作成だけじゃなく、削除や変更も監視できるのクマね

マイケル
これも汎用性が高くて中々便利だよね
画像認識について

マイケル
そして画像認識はGoogleが開発している
「Tesseract OCR」という文字認識エンジンを使ってみました。
「Tesseract OCR」という文字認識エンジンを使ってみました。

エレキベア
OCRとしては有名なエンジンクマね

マイケル
オープンソースで採用例も多いみたいだね。
今回はPythonから呼び出すために「PyOCR」というPythonパッケージを使用したよ!
今回はPythonから呼び出すために「PyOCR」というPythonパッケージを使用したよ!
翻訳処理について

マイケル
そして最後に翻訳処理!
google翻訳と通信して翻訳する「googletrans」というpythonパッケージを使用しました!
google翻訳と通信して翻訳する「googletrans」というpythonパッケージを使用しました!

エレキベア
Google翻訳に送って翻訳してもらうクマね

マイケル
そんな感じだね!
翻訳制度は間違い無いけど、欠点としては
ネットに繋がっていないと使えないというところかな・・・。
翻訳制度は間違い無いけど、欠点としては
ネットに繋がっていないと使えないというところかな・・・。

エレキベア
こればかりは仕方ないクマね
無料で使える分いいと思うクマ
無料で使える分いいと思うクマ
実装方法

マイケル
それでは、これまでの機能を使った実装方法を見ていきます!
環境としてはOSはMac、Pythonは3.8を使用しました。
環境としてはOSはMac、Pythonは3.8を使用しました。
環境構築

マイケル
まずは使用するライブラリをpip, Homebrewでインストールしましょう!
pip install Pillow
pip install pyocr
pip install googletrans
pip install watchdog
brew install tcl-tk
brew install tesseract

エレキベア
ざっとインストールしたクマ〜〜〜
実装したコード

マイケル
インストールしたら、コードを実装していきます!

マイケル
全体のコードは以下になります!
from PIL import Image
import pyocr.builders
from googletrans import Translator
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer
import tkinter as tk
import os
import time
import sys
import queue
#########################
# スクショ翻訳クラス
#########################
class TransScreenShot(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
###############
# 環境変数
###############
# 監視フォルダパス
self.watch_path = "【スクリーンショット保存パス】"
# 変換言語(英語->日本語)
self.lang_trans_from = "de"
self.lang_trans_to = "ja"
# OCR読込言語(英語)
self.lang_read_from = "eng"
###############
# 変数
###############
self.queue = queue.Queue()
###############
# Tkウィジェット設定
###############
self.master = master
self.master.title("スクショ翻訳くん")
self.master.bind("<Destroy>", self.shutdown)
self.master.bind("<<WatchdogEvent>>", self.handle_watchdog_event)
self.pack()
# 変換前テキスト
self.from_text_label = tk.Label(self, text=u"【翻訳前】(英語)")
self.from_text_widget = tk.Text(self, width=70, height=15)
# 変換後テキスト
self.to_text_label = tk.Label(self, text=u"【翻訳後】(日本語)")
self.to_text_widget = tk.Text(self, width=70, height=15)
# 翻訳ボタン
self.trans_button = tk.Button(self, text=u"翻訳", command=self.do_trans_txt, width=20, height=2)
# レイアウト設定
self.create_widgets()
###############
# WatchDog設定
###############
# OCRツール読込
tools = pyocr.get_available_tools()
if len(tools) == 0:
print("No OCR tool found")
sys.exit(1)
self.tool = tools[0]
# WatchDogでの監視開始
handler = ChangeHandler(self)
self.observer = Observer()
self.observer.schedule(handler, self.watch_path, recursive=True)
self.observer.start()
# Tkレイアウト設定
def create_widgets(self):
self.from_text_label.grid(column=0, row=0, sticky=tk.W)
self.from_text_widget.grid(column=0, row=1, columnspan=5, sticky=(tk.N, tk.S, tk.E, tk.W))
self.to_text_label.grid(column=0, row=2, sticky=tk.W)
self.to_text_widget.grid(column=0, row=3, columnspan=5, sticky=(tk.N, tk.S, tk.E, tk.W))
self.trans_button.grid(column=0, row=4, columnspan=5)
# テキスト翻訳処理
def do_trans_txt(self):
translator = Translator()
trans = translator.translate(self.from_text_widget.get("1.0", "end -1c"),
src=self.lang_trans_from,
dest=self.lang_trans_to)
# TO_TEXTに反映
self.to_text_widget.delete("1.0", "end")
self.to_text_widget.insert("1.0", trans.text)
# WatchDogイベント(キュー実行)
def handle_watchdog_event(self, event):
# キューからイベントを取得
event = self.queue.get()
src_path = event.src_path
# png拡張子じゃなければreturn
root, ext = os.path.splitext(src_path)
if ".png" != ext:
return
# 保存中(隠しファイル)の場合
filename = os.path.basename(src_path)
if filename.startswith("."):
# 一文字目「.」を削除して1秒待機
src_path = os.path.dirname(src_path) + "/" + filename[1:]
time.sleep(1.0)
# OCRで画像からテキストに変換
txt = self.tool.image_to_string(
Image.open(src_path),
lang=self.lang_read_from,
builder=pyocr.builders.TextBuilder(tesseract_layout=6)
)
# 読み込んだ画像を削除
os.remove(src_path)
# 翻訳前テキスト設定
self.from_text_widget.delete("1.0", "end")
self.from_text_widget.insert("1.0", txt)
# 翻訳処理呼び出し
self.do_trans_txt()
# WatchDog通知処理
def notify(self, event):
# イベントをキューに格納
self.queue.put(event)
self.master.event_generate("<<WatchdogEvent>>", when="tail")
# WatchDogシャットダウン処理
def shutdown(self, event):
print("shutdown...")
self.observer.stop()
self.observer.join()
#########################
# 監視・OCR読込クラス
#########################
class ChangeHandler(FileSystemEventHandler):
def __init__(self, trans_screen_shot):
self.trans_screen_shot = trans_screen_shot
# 作成された時のイベント
def on_created(self, event):
self.trans_screen_shot.notify(event)
if __name__ == "__main__":
# GUI表示
root = tk.Tk()
ts = TransScreenShot(master=root)
ts.mainloop()

エレキベア
長くてわからないクマ〜〜〜〜

マイケル
これから細かく見ていくよ!
フォルダ監視

マイケル
まずはフォルダ監視の部分から!
#########################
# スクショ翻訳クラス
#########################
class TransScreenShot(tk.Frame):
def __init__(self, master=None):
・・・略・・・
# 監視フォルダパス
self.watch_path = "【スクリーンショット保存パス】"
・・・略・・・
self.queue = queue.Queue()
・・・略・・・
# WatchDogでの監視開始
handler = ChangeHandler(self)
self.observer = Observer()
self.observer.schedule(handler, self.watch_path, recursive=True)
self.observer.start()
・・・略・・・
# WatchDogイベント(キュー実行)
def handle_watchdog_event(self, event):
# キューからイベントを取得
event = self.queue.get()
src_path = event.src_path
・・・略・・・
# WatchDog通知処理
def notify(self, event):
# イベントをキューに格納
self.queue.put(event)
self.master.event_generate("<<WatchdogEvent>>", when="tail")
# WatchDogシャットダウン処理
def shutdown(self, event):
print("shutdown...")
self.observer.stop()
self.observer.join()
#########################
# 監視・OCR読込クラス
#########################
class ChangeHandler(FileSystemEventHandler):
def __init__(self, trans_screen_shot):
self.trans_screen_shot = trans_screen_shot
# 作成された時のイベント
def on_created(self, event):
self.trans_screen_shot.notify(event)
if __name__ == "__main__":
# GUI表示
root = tk.Tk()
ts = TransScreenShot(master=root)
ts.mainloop()

マイケル
WatchDogで監視するためのChangeHandlerクラスを定義して、
「on_created()」メソッドでファイル作成を感知しています。
「on_created()」メソッドでファイル作成を感知しています。


マイケル
今回作成するツールは読み込んだテキストをGUI上に表示するため、
上記のように検知結果をキューに格納して順に実行しています。
上記のように検知結果をキューに格納して順に実行しています。

エレキベア
複数検知して同時に更新するのを防ぐクマね
# 監視フォルダパス
self.watch_path = "【スクリーンショット保存パス】"

マイケル
ちなみにこちらの変数には各自、
スクリーンショットの保存パスを指定しましょう!
スクリーンショットの保存パスを指定しましょう!

エレキベア
承知クマ〜〜〜
画像認識

マイケル
そしてキューからイベントを実行する際、
下記部分でOCR画像認識を行います!
下記部分でOCR画像認識を行います!
#########################
# スクショ翻訳クラス
#########################
class TransScreenShot(tk.Frame):
def __init__(self, master=None):
・・・略・・・
# OCR読込言語(英語)
self.lang_read_from = "eng"
・・・略・・・
# OCRツール読込
tools = pyocr.get_available_tools()
if len(tools) == 0:
print("No OCR tool found")
sys.exit(1)
self.tool = tools[0]
・・・略・・・
# WatchDogイベント(キュー実行)
def handle_watchdog_event(self, event):
# キューからイベントを取得
event = self.queue.get()
src_path = event.src_path
# png拡張子じゃなければreturn
root, ext = os.path.splitext(src_path)
if ".png" != ext:
return
# 保存中(隠しファイル)の場合
filename = os.path.basename(src_path)
if filename.startswith("."):
# 一文字目「.」を削除して1秒待機
src_path = os.path.dirname(src_path) + "/" + filename[1:]
time.sleep(1.0)
# OCRで画像からテキストに変換
txt = self.tool.image_to_string(
Image.open(src_path),
lang=self.lang_read_from,
builder=pyocr.builders.TextBuilder(tesseract_layout=6)
)

マイケル
今回、読み取りを行う言語は「英語」、
読み取りファイルは「PNGファイル」で固定しています!
読み取りファイルは「PNGファイル」で固定しています!
# WatchDogイベント(キュー実行)
def handle_watchdog_event(self, event):
# キューからイベントを取得
event = self.queue.get()
src_path = event.src_path
# png拡張子じゃなければreturn
root, ext = os.path.splitext(src_path)
if ".png" != ext:
return
# 保存中(隠しファイル)の場合
filename = os.path.basename(src_path)
if filename.startswith("."):
# 一文字目「.」を削除して1秒待機
src_path = os.path.dirname(src_path) + "/" + filename[1:]
time.sleep(1.0)
# OCRで画像からテキストに変換
txt = self.tool.image_to_string(
Image.open(src_path),
lang=self.lang_read_from,
builder=pyocr.builders.TextBuilder(tesseract_layout=6)
)

エレキベア
ここの部分クマね
「# 保存中(隠しファイル)の場合」は何クマ?
「# 保存中(隠しファイル)の場合」は何クマ?

マイケル
よく気がついたね!
これはMacだけかもしれないけど、スクショ保存の直後に「.」から始まる隠しファイルとして検知されてしまう時があるから、
その対処として待機時間を設けているんだ!
これはMacだけかもしれないけど、スクショ保存の直後に「.」から始まる隠しファイルとして検知されてしまう時があるから、
その対処として待機時間を設けているんだ!

エレキベア
検知が早すぎるのも問題クマね〜〜〜
翻訳処理

マイケル
そして最後に翻訳処理は以下になります!
#########################
# スクショ翻訳クラス
#########################
class TransScreenShot(tk.Frame):
def __init__(self, master=None):
・・・略・・・
self.watch_path = "【スクリーンショット保存パス】"
# 変換言語(英語->日本語)
self.lang_trans_from = "de"
self.lang_trans_to = "ja"
・・・略・・・
# テキスト翻訳処理
def do_trans_txt(self):
translator = Translator()
trans = translator.translate(self.from_text_widget.get("1.0", "end -1c"),
src=self.lang_trans_from,
dest=self.lang_trans_to)
# TO_TEXTに反映
self.to_text_widget.delete("1.0", "end")
self.to_text_widget.insert("1.0", trans.text)
# WatchDogイベント(キュー実行)
def handle_watchdog_event(self, event):
・・・略・・・
# 翻訳前テキスト設定
self.from_text_widget.delete("1.0", "end")
self.from_text_widget.insert("1.0", txt)
# 翻訳処理呼び出し
self.do_trans_txt()

マイケル
読み込んだ文字を翻訳前テキストとして設定後、
「translator.translate()」メソッドを呼び出して翻訳しています!
「translator.translate()」メソッドを呼び出して翻訳しています!

エレキベア
例のGoogle翻訳のやつクマね

マイケル
こちらも今回は言語は固定として
英語から日本語への翻訳のみとしています。
英語から日本語への翻訳のみとしています。

マイケル
以上でスクショ翻訳ツールの実装方法解説は終了です!

エレキベア
おつかれクマ〜〜〜〜〜
おわりに

マイケル
というわけで、今回はOCR認識と翻訳機能を使った
ツールの作成だったけどどうだったかな?
ツールの作成だったけどどうだったかな?

エレキベア
便利なライブラリが充実していて楽しかったクマ〜〜〜〜〜

マイケル
最近はほんと手軽にいろんなことができるようになったよね。
これからもいろんなものを作っていこう!
これからもいろんなものを作っていこう!

マイケル
今回の課題と今後の改善点としては以下になります・・・。
課題とこれから
- 誤った文字認識をしてしまうことがある。
- 文字認識・翻訳処理の言語を「英語->日本語」のみで実装。
→よく間違える文字はコード内で変換するなど、チューニングを行う!
→他の言語にも対応するよう改造する!

エレキベア
まだまだ改善点がたくさんありそうクマね

マイケル
ざーっと実装したからね〜〜
お時間ある方は、他の言語にも対応できるようぜひ挑戦してみてください!
お時間ある方は、他の言語にも対応できるようぜひ挑戦してみてください!

マイケル
それでは今日はこの辺で!
アデュー!!
アデュー!!

エレキベア
クマ〜〜〜〜〜〜〜
【Python】スクショ画像を文字認識して翻訳するツールを作ってみた!【Tesseract ×Googletrans】 〜完〜
コメント