3414 words
17 minutes
OCRのお勉強をしたのでアプリケーションを作ってみた

OCRのお勉強をしたのでアプリケーションを作ってみた#

お久しぶりです、YAMAです。
今回はOCRのお勉強をしたので、スクリーンショットをするとOCRで文字を読み取ってコピーしてくれるアプリケーションを作った話を書いていこうと思います。

OCRとは#

OCR(Optical Character Recognition:光学文字認識)とは、紙の書類や画像に書かれた文字(活字や手書き文字)を、スキャナーやカメラで読み取り、コンピュータで編集・検索できるデジタルテキストに変換する技術です。
業務上でのメリットとしては、請求書や名刺などの手入力の手間を省き、データ入力作業を大幅に削減したり、かさばる紙の書類を電子データとしてPCやクラウド上で管理できるようになったり、などなどがあります。
いわゆる、ペーパーレスや、業務支援などができる技術です。
また最近のOCRはAI-OCRと呼ばれるもので、AIを活用して文字認識の精度を向上させているものもあります。
これの登場でより、精度の高い文字認識が可能となり、手書き文字の認識も可能になってきています。
詳しいOCRについては、話すと長くなるので、今回は割愛します。

アプリケーションを作ろうと思ったきっかけ#

私は半年ほど会社にて使用したアプリケーションを作成していたのですが、そこでOCRの技術を使用する機会がありました。
上記の話は、昔の記事OCR+AI翻訳システムをPython初心者が3ヶ月で作った話に書いてあります。
その時にOCRのお勉強をしたので、何かこの勉強から活かせないかと思い、3ヶ月ほど前に構想を練っていたものがこのアプリケーションです。
そして最近、やっとまとまった時間が取れたので、作成に取り掛かった次第です。
しかし、私はjavaの人間でして、Pythonは仕事で使う程度であり、個人開発の上ではあまり使ったことがありませんでした。
なので、個人開発でのPythonというのは久々であり、Pythonの勉強もかねて作成していこうと思いました。
さらにいうと私も大学3年生であり、インターンやら就活がはじまるので、何かしらの爪痕を残しておきたいという思いもありました。(インターン先があまり決まらない…)
そんなこんなで、今回のアプリケーションを作成することにしました。

一体どんなアプリケーションなのか#

今回作成したアプリケーションは、スクリーンショットをするとOCRで文字を読み取ってコピーしてくれるアプリケーションです。
Windows標準のスクリーンショット機能を使用して、スクリーンショットを撮ると、OCRで文字を読み取ってくれます。
それをクリップボードにコピーしてくれるので、あとは貼り付けるだけで使用できます。
またTTSも申し訳程度に搭載しており、OCRで読み取った文字を音声で読み上げてくれます。(使う機会はあまりないかもしれませんが…)
また今回のアプリケーションはStandaloneで動作するアプリケーションであり、基本的にWebなどを使用して作ることが多かった私的には、技術的にも知らない領域であり、勉強になりました。

しかし、初心者が作るものには代償がある。#

ここまでいいことばかりを書いてきましたが、初心者が作るものには代償があります。
特に私のような初心者が作るものには、不具合やらなんやらがつきものです。
今回のアプリケーションも例外ではなく、いくつか不具合や問題点がいくつもあります。(それはもう、数えきれないほど…(´;ω;`))

問題点1 「OCRの精度が悪い」#

はい、まずはこれです。一番悩んだ問題点です。
これはすごく単純明快で、軽量かつ、簡単に使用できるOCRを使用しているため、精度が悪いです。
普通に使用していても、文字が違う文字に変換されることが多々あります。
今回のアプリケーションでは在中のプロセスとして動かすつもりで作成をしていて、基本的にずっと動かすからには軽量である必要がありました。
なので、軽量かつ簡単に使用できるOCRを使用しているのですが、その代償として精度が悪いという問題が発生してしまいました。
これはどう対処しようかと悩んだのですが、結局のところ、軽量さをとってしまい、現在は精度が悪いままです。
別のOCRを検討中ではあるのですが、軽量さを犠牲にしてしまうと、アプリケーションの動作が重くなってしまうので、悩みどころです。(特に、ずっと動かすことを考えるとね…)

問題点2 「やりたいことに対してソースコードが思いつかない」#

これは単純に、私のPythonの知識不足です。
そもそもそんなにOCRを用いたアプリケーションやStandAloneのアプリをつくったことがないので、やりたいことに対してソースコードが思いつかないという問題が発生しました。
これは、Pythonの勉強をしていく中で、少しずつ解消していくと思ってコードを書いていっています。
とはいえ最初は本当に手探りで、「トレイに常駐させるってどうやるの?」「スクリーンショットを撮ったことをどうやって検知するの?」というレベルからのスタートでした。
公式ドキュメントを読んだり、AIに聞いたり、とにかく書いては動かしてを繰り返して、だんだんと「あ、こういう風に組めばいいのか」というのが見えてきた感じです。
JavaでいうところのクラスやスレッドのノリがPythonでもなんとなく通用したので、そこは経験が活きたかなと思います。(言語が違っても考え方は意外と一緒なんだなぁと)

問題点3 「Win+Shift+Sに割り込む問題」#

これも地味に悩んだやつです。
当初の構想では「Windows標準のスクリーンショット(Win+Shift+S)に上乗せして、撮った瞬間にOCRする」というのをやりたかったのですが、調べてみると、あの標準機能に直接割り込むのはかなり厳しいということが分かりました。
そこで発想を変えて、「Win+Shift+Sで撮ると画像がクリップボードに入る」という仕様を利用して、クリップボードを監視して、新しい画像が入ってきたら自動でOCRするという方式にしました。
結果的にこれが大正解で、ユーザーは今まで通りWin+Shift+Sを使うだけ、こちらは裏でこっそり画像を拾ってOCRする、という自然な体験になりました。
正攻法がダメなら搦め手で、というやつですね。(初心者なりに知恵を絞りました)

問題点4 「exe化とインストーラ地獄」#

これも結構しんどかったなぁって思います。
当初の予定通りexe化をして、GithubのReleasesにアップロードして、インストールできるようにしようと思っていたのでこちらは、exe化とインストーラ作成を行ったのですが、これがまぁ大変でした。
PyInstallerでパッケージングするとモデルやら依存ライブラリやらを巻き込んで、最終的に200MB超えの大きさになりました。(でかい…)
さらに、ただのexeだと配布しづらいので、Inno Setupでインストーラも作りました。
ここでこだわったのが、管理者権限なし(UACが出ない)でインストールできるようにするという点です。
これによりUACが出ないので管理者権限のない環境でもインストールできるようになりました。(これは大学で得た知識で何とかできました。Scoopありがとう。いつもお世話になっております。)
このへんは完全に未知の領域だったので、調べながら一個ずつ潰していく作業で、かなり勉強になりました。

逆に「やってよかった・勉強になった」こと#

こんな感じで、問題点や不具合は多々ありましたが、逆に「やってよかった・勉強になった」ことも多々ありました。
特にAIRIではDesktop版ではWebGUIを使用してSetupを作成していたので、私もそんな感じにできたらなぁと思いながら作ろうと思っていました。
しかし、当初どうやってWebGUIをPythonで作るかわからず、Tkinterで作ろうかと迷っていたのですが、調べてみると、PythonでWebGUIを作る方法がいくつかありました。
それが、PyWebViewです。
HTML/CSSで書いたUIを、ブラウザではなくネイティブの小窓に表示するという形にしました。
中身はFlaskで作っているのに、見た目は普通のデスクトップアプリ。いいとこ取りができて、ここはちょっと気に入っています。

コードの外側の勉強 ―― ライセンス#

これは完全に予想外の学びでした。
配布するにあたって「自分のコードはMITでいいや」と軽く考えていたのですが、よく見ると使っているライブラリのライセンスがバラバラなんですね。
Apache-2.0だったり、BSDだったり、中にはLGPLやMPLみたいな“コピーレフト系”のものも混じっていて、「これ、自分のコードMITで本当に大丈夫なの…?」と不安になりました。
調べた結果、自分のコードはMITのままでOK。ただし配布物には各ライブラリのライセンス表記を同梱する義務がある、ということが分かり、THIRD_PARTY_NOTICESという第三者ライセンス表記をきちんと用意しました。
コードを書くだけが開発じゃないんだなぁ、というのを実感した瞬間でした。(社会に出る前に知れてよかった)

ついでに:翻訳機能#

おまけ程度ですが、ローカルでLLM(Ollamaなど)を立ち上げているときは、OCRで読み取ったテキストを翻訳する機能もつけました。
クラウドのAPIを叩くのではなく、あくまでローカルで完結させたかったので、OpenAI互換のエンドポイントに投げる形にしています。
LLMが起動していないときは翻訳だけスキップして、OCRは普通に動く、というゆるい作りです。

技術スタック的な話#

  • 言語:Python 3.14(新しすぎて一部ライブラリが対応しているか冷や冷やしました)
  • OCR:RapidOCR(ONNX / CPU動作)+日本語モデル
  • UI:Flask + pywebview
  • 常駐・通知:pystray
  • 読み上げ:pyttsx3(オフライン)
  • 翻訳:ローカルLLM(OpenAI互換API)
  • 配布:PyInstaller + Inno Setup(per-userインストーラ)

今後の展望#

やっぱり一番はOCRの精度です。
「軽量さ」と「精度」はトレードオフなので、常駐前提の今の設計とどう折り合いをつけるか、引き続き悩みどころです。
精度の高いOCRに差し替えるのか、それとも「精読モード」みたいに必要なときだけ重いOCRを呼ぶのか、そのあたりを試していきたいと思っています。

まとめ#

初心者なりに、不具合と格闘しながらもなんとか形になりました。
あきらめる部分はあきらめつつ、できることをやっていく、というのが個人開発の醍醐味だなぁと感じました。
しかしずっとあきらめたままにはせず、技術は日々進歩し、個人開発は時間が無限なので、どんどん改善していきたいと思います。
Pythonの個人開発、Standaloneアプリ、exe化、ライセンス…と、普段Web中心の自分には知らないことだらけで、想像以上に勉強になった開発でした。
何より「使えるものが手元に残った」というのが嬉しいです。(就活で何か爪痕になればいいな…!)
最後まで読んでいただきありがとうございました。また何か作ったら書きます。

以上YAMAでした。

おまけ:アプリケーションのダウンロードリンク#

リリースページ v1.0.0 からダウンロードできます。
OCR_screen_captureのGithubのリンク