ゲーム開発
Unity
UnrealEngine
C++
Blender
Houdini
ゲーム数学
ゲームAI
グラフィックス
サウンド
アニメーション
GBDK
制作日記
IT関連
ツール開発
フロントエンド関連
サーバサイド関連
WordPress関連
ソフトウェア設計
おすすめ技術書
音楽
DTM
楽器・機材
ピアノ
ラーメン日記
四コマ漫画
その他
おすすめアイテム
おもしろコラム
  • ゲーム開発
    • Unity
    • UnrealEngine
    • C++
    • Blender
    • Houdini
    • ゲーム数学
    • ゲームAI
    • グラフィックス
    • サウンド
    • アニメーション
    • GBDK
    • 制作日記
  • IT関連
    • ツール開発
    • フロントエンド関連
    • サーバサイド関連
    • WordPress関連
    • ソフトウェア設計
    • おすすめ技術書
  • 音楽
    • DTM
    • 楽器・機材
    • ピアノ
  • ラーメン日記
    • 四コマ漫画
      • その他
        • おすすめアイテム
        • おもしろコラム
      1. ホーム
      2. 20201012_02

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

      ツール開発PythonOCRGoogleTransTesseract
      2020-10-13

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

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

      エレキベア
      エレキベア
      (そうそう無いクマ・・・)
      マイケル
      マイケル
      そんな要望に応えるべく、
      スクリーンショットから文字認識して翻訳するツールを開発しました!
      マイケル
      マイケル
      その名も・・・
       \スクショ翻訳くん!/
      エレキベア
      エレキベア
      (そのまんまクマ・・・。)
      マイケル
      マイケル
      使い方は簡単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

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

      スクショ翻訳くんの概要

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

      全体の処理

      マイケル
      マイケル
      言語は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()」メソッドでファイル作成を感知しています。
      マイケル
      マイケル
      今回作成するツールは読み込んだテキストを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】 〜完〜


      ツール開発PythonOCRGoogleTransTesseract
      2020-10-13

      関連記事
      【プロシージャル】Pythonで学ぶ波動関数崩壊アルゴリズム(Wave Function Collapse)
      2025-06-22
      【Unity】Timeline × Excelでスライドショーを効率よく制作する
      2024-10-31
      【Node.js】廃止されたAmazonアソシエイト画像リンクをAmazon Product Advertising API経由で復活させる
      2024-01-08
      【Electron × Vue3】カテゴリ情報のCSVデータを操作するツールを作る
      2023-12-31
      【Electron × Vue3】画像をリサイズして任意の場所に保存するツールを作る
      2023-12-31
      【Electron × Vue3】Electron × Vue3 × TypeScript × Vite でツール開発環境を整える
      2023-12-31
      【Flutter3】Googleスプレッドシートと連携した英単語学習アプリを作る
      2022-12-11
      【Python】Pythonスクリプトをexe、app化する【cx_Breeze】
      2021-08-29