【Python】スクショ画像を文字認識して翻訳するツールを作ってみた!【Tesseract ×Googletrans】

Python
マイケル
マイケル
みなさんこんにちは!
マイケルです!!
エレキベア
エレキベア
クマ〜〜〜〜〜
マイケル
マイケル
突然ですが、みなさんはこんなことを思ったことはありませんか?
Woman hungry
マイケル
マイケル

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

エレキベア
エレキベア
(そうそう無いクマ・・・)
マイケル
マイケル
そんな要望に応えるべく、
スクリーンショットから文字認識して翻訳するツールを開発しました!
マイケル
マイケル
その名も・・・
 \スクショ翻訳くん!/
Screenshot 2020 10 13 1 01 12
エレキベア
エレキベア
(そのまんまクマ・・・。)
マイケル
マイケル
使い方は簡単3ステップ!
① 画像を用意してツールを開く

Screenshot 2020 10 13 0 54 39

② スクリーンショットを撮る

Screenshot 2020 10 13 0 54 39のコピー

Screenshot 2020 10 13 0 55 01

③ 翻訳結果が表示される

Screenshot 2020 10 13 0 55 11

Screenshot 2020 10 13 1 01 24
マイケル
マイケル
こんな感じでスクショ画像から文字認識して、翻訳してくれます!
エレキベア
エレキベア
確かにこれはいろんな場面で使えそうクマね
マイケル
マイケル
画像だけじゃなく、コピペできない文字を読み込んだりとかできそうだね。
マイケル
マイケル
今回はこのツールの概要と
実装方法について解説していくよ!
エレキベア
エレキベア
楽しみクマ〜〜〜〜
スポンサーリンク

スクショ翻訳くんの概要

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

全体の処理

Screenshot 2020 10 12 22 03 59
マイケル
マイケル
言語はPythonを使用していて、

①フォルダ監視
 →スクリーンショットの保存フォルダを監視して、ファイルが作成されたら読み込む。
②画像認識
 →読み込んだファイルを画像認識して文字を読み込む。
③翻訳認識
 →読み込んだ文字を翻訳して表示する。

といった流れになっています!

エレキベア
エレキベア
スクリーンショットは別の機能を使うのクマね
マイケル
マイケル
最初は範囲指定のスクショもPythonで実装しようと思ってたけど、
中々一癖ありそうだったので分けることにしたんだ。
マイケル
マイケル
例としては、WindowsならSnipping Tool、Macなら Cmd+Shift+4
で選択範囲のスクショが撮ることができるよ!
エレキベア
エレキベア
普段よく使う機能クマね

フォルダ監視について

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

参考:
Python WatchDog – フォルダの監視を行う

エレキベア
エレキベア
ファイル作成だけじゃなく、削除や変更も監視できるのクマね
マイケル
マイケル
これも汎用性が高くて中々便利だよね

画像認識について

マイケル
マイケル
そして画像認識はGoogleが開発している
「Tesseract OCR」という文字認識エンジンを使ってみました。
エレキベア
エレキベア
OCRとしては有名なエンジンクマね
マイケル
マイケル
オープンソースで採用例も多いみたいだね。
今回はPythonから呼び出すために「PyOCR」というPythonパッケージを使用したよ!

翻訳処理について

マイケル
マイケル
そして最後に翻訳処理!
google翻訳と通信して翻訳する「googletrans」というpythonパッケージを使用しました!
エレキベア
エレキベア
Google翻訳に送って翻訳してもらうクマね
マイケル
マイケル
そんな感じだね!
翻訳制度は間違い無いけど、欠点としては
ネットに繋がっていないと使えないというところかな・・・。
エレキベア
エレキベア
こればかりは仕方ないクマね
無料で使える分いいと思うクマ

実装方法

マイケル
マイケル
それでは、これまでの機能を使った実装方法を見ていきます!
環境としては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()」メソッドでファイル作成を感知しています。
Screenshot 2020 10 13 23 27 06
マイケル
マイケル
今回作成するツールは読み込んだテキストをGUI上に表示するため、
上記のように検知結果をキューに格納して順に実行しています。
エレキベア
エレキベア
複数検知して同時に更新するのを防ぐクマね

        # 監視フォルダパス
        self.watch_path = "【スクリーンショット保存パス】"
マイケル
マイケル
ちなみにこちらの変数には各自、
スクリーンショットの保存パスを指定しましょう!
エレキベア
エレキベア
承知クマ〜〜〜

画像認識

マイケル
マイケル
そしてキューからイベントを実行する際、
下記部分で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ファイル」で固定しています!

    # 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だけかもしれないけど、スクショ保存の直後に「.」から始まる隠しファイルとして検知されてしまう時があるから、
その対処として待機時間を設けているんだ!
エレキベア
エレキベア
検知が早すぎるのも問題クマね〜〜〜

翻訳処理

マイケル
マイケル
そして最後に翻訳処理は以下になります!


#########################
# スクショ翻訳クラス
#########################
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()」メソッドを呼び出して翻訳しています!
エレキベア
エレキベア
例のGoogle翻訳のやつクマね
マイケル
マイケル
こちらも今回は言語は固定として
英語から日本語への翻訳のみとしています。
マイケル
マイケル
以上でスクショ翻訳ツールの実装方法解説は終了です!
エレキベア
エレキベア
おつかれクマ〜〜〜〜〜

おわりに

マイケル
マイケル
というわけで、今回はOCR認識と翻訳機能を使った
ツールの作成だったけどどうだったかな?
エレキベア
エレキベア
便利なライブラリが充実していて楽しかったクマ〜〜〜〜〜
マイケル
マイケル
最近はほんと手軽にいろんなことができるようになったよね。
これからもいろんなものを作っていこう!
マイケル
マイケル
今回の課題と今後の改善点としては以下になります・・・。
課題とこれから
  • 誤った文字認識をしてしまうことがある。
  • →よく間違える文字はコード内で変換するなど、チューニングを行う!

  • 文字認識・翻訳処理の言語を「英語->日本語」のみで実装。
  • →他の言語にも対応するよう改造する!

エレキベア
エレキベア
まだまだ改善点がたくさんありそうクマね
マイケル
マイケル
ざーっと実装したからね〜〜
お時間ある方は、他の言語にも対応できるようぜひ挑戦してみてください!
マイケル
マイケル
それでは今日はこの辺で!
アデュー!!
エレキベア
エレキベア
クマ〜〜〜〜〜〜〜

【Python】スクショ画像を文字認識して翻訳するツールを作ってみた!【Tesseract ×Googletrans】 〜完〜

コメント