ドキュメントやターミナル、チャットに表示されたコードを「あとでメモしておこう」と思い、スクリーンショットだけが増えていくことがあります。画像は保存できても、後から検索したり、コードをコピーしたりするのは面倒です。
そこで今回は、PythonとOCRを使ってスクリーンショットから文字を抽出し、検索しやすいテキストメモに変換する方法を試しました。
結論から言うと、Tesseract OCRとpytesseract、Pillowを組み合わせれば、ローカル環境だけで簡単な技術メモ抽出ツールを作れます。特に、画像の拡大・グレースケール化・二値化を前処理として入れると、初期状態より読み取りやすくなりました。
今回作るもの
スクリーンショットを前処理してOCRにかけ、検索しやすいMarkdown形式の技術メモとして保存する流れです。
入力画像に含まれる文字をOCRで抽出し、Markdown形式のファイルとして保存します。
最終的には、次のような使い方を想定しています。
screenshot.png
↓
画像の前処理
↓
OCRで文字列を抽出
↓
tech-memo.md に保存
対象は、次のようなスクリーンショットです。
- ターミナルに表示されたコマンド
- エラーメッセージ
- API仕様や設定値
- 技術記事の一部
- コード断片
OCRは画像内の文字を完全に復元するものではありません。特にコードでは、0とO、1とl、全角と半角などを誤認識することがあります。そのため、抽出結果をそのまま実行するのではなく、検索・下書き・再利用のための補助として使う方針にしました。
必要な環境を準備する
Python側のライブラリをインストールします。
python -m venv .venv
Windowsの場合は、仮想環境を次のように有効化します。
.venv\Scripts\Activate.ps1
macOSやLinuxの場合は、次のコマンドです。
source .venv/bin/activate
続けて、必要なパッケージをインストールします。
pip install pillow pytesseract
pytesseractはPythonからTesseract OCRを呼び出すためのラッパーです。別途、Tesseract本体も必要になります。
Windowsでは、Tesseractをインストールした後、実行ファイルの場所をPythonから指定します。macOSではHomebrewを使う場合、次のようにインストールできます。
brew install tesseract
brew install tesseract-lang
日本語を認識するには、日本語の学習データも必要です。環境によっては、次のコマンドで日本語データを追加できます。
brew install tesseract-lang
インストール後、認識可能な言語を確認します。
tesseract --list-langs
出力にjpnやengが含まれていれば準備完了です。
OCR前に画像を前処理する
まず、画像をそのままOCRに渡すのではなく、読み取りやすい状態に変換します。今回試した前処理は次の3つです。
- 画像を2倍に拡大する
- グレースケールに変換する
- 二値化して背景と文字を分ける
スクリーンショットは、文字サイズが小さかったり、背景色が少し暗かったりします。拡大や二値化だけでも読み取り結果が改善するケースがありました。
ただし、二値化のしきい値を固定すると、画像によっては文字が消えることがあります。そのため、まずは固定値で試し、必要に応じて調整する形にしています。
Pythonで文字を抽出する
次のスクリプトをocr_memo.pyとして保存します。
from pathlib import Path
import sys
from PIL import Image, ImageEnhance, ImageFilter, ImageOps
import pytesseract
def preprocess_image(image_path: Path) -> Image.Image:
image = Image.open(image_path)
# 小さい文字を読みやすくするために拡大
image = image.resize(
(image.width * 2, image.height * 2),
Image.Resampling.LANCZOS,
)
# グレースケール化
image = ImageOps.grayscale(image)
# コントラストを少し強調
image = ImageEnhance.Contrast(image).enhance(1.8)
# 軽いノイズ除去
image = image.filter(ImageFilter.MedianFilter(size=3))
# しきい値で二値化
image = image.point(lambda pixel: 255 if pixel > 160 else 0)
return image
def extract_text(image: Image.Image) -> str:
# 日本語と英語を同時に認識
config = "--psm 6"
return pytesseract.image_to_string(
image,
lang="jpn+eng",
config=config,
)
def save_markdown(text: str, output_path: Path, source_path: Path) -> None:
content = f"""# OCR技術メモ
- 元画像: `{source_path.name}`
## 抽出結果
```text
{text.strip()}
"""
output_path.write_text(content, encoding="utf-8")
def main() -> None:
if len(sys.argv) != 2:
print("使い方: python ocr_memo.py screenshot.png")
sys.exit(1)
source_path = Path(sys.argv[1])
if not source_path.exists():
print(f"画像が見つかりません: {source_path}")
sys.exit(1)
try:
processed = preprocess_image(source_path)
text = extract_text(processed)
except Exception as error:
print(f"OCRに失敗しました: {error}")
sys.exit(1)
output_path = source_path.with_name(
f"{source_path.stem}_memo.md"
)
save_markdown(text, output_path, source_path)
print(f"保存しました: {output_path}")
if name == "main":
main()
実行します。
```bash
python ocr_memo.py screenshot.png
成功すると、同じフォルダに次のようなファイルが作成されます。
screenshot_memo.md
WindowsでTesseractの場所が自動検出されない場合は、pytesseractの設定を追加します。
pytesseract.pytesseract.tesseract_cmd = (
r"C:\Program Files\Tesseract-OCR\tesseract.exe"
)
この設定は、extract_textを呼び出す前に記述します。インストール先が異なる場合は、実際のパスに置き換えてください。
認識精度を上げるポイント
実際に複数のスクリーンショットで試したところ、画像の状態によって結果にかなり差が出ました。特に効果を感じたポイントをまとめます。
文字が小さい場合は先に拡大する
小さな文字をそのまま渡すと、記号や濁点が欠落しやすくなります。今回のスクリプトでは2倍にしていますが、元画像が小さい場合は3倍を試してもよいと思います。
ただし、拡大しすぎると処理時間が増え、輪郭がぼやけることがあります。
背景と文字の色を確認する
白背景に黒文字なら二値化が効きやすい一方、ダークテーマのターミナルでは文字と背景が逆になります。その場合は、二値化後に反転を試せます。
image = ImageOps.invert(image)
反転するかどうかは、OCRに渡す画像を保存して目視確認すると判断しやすくなります。
--psmを変更する
Tesseractの--psmは、画像内の文字の配置を指定するオプションです。
今回の--psm 6は、ある程度まとまったテキストブロック向けです。1行だけの画像なら--psm 7、ページ全体のような画像なら--psm 3を試せます。
config = "--psm 7"
コードのスクリーンショットでは、インデントや記号の認識が崩れることがあります。コードを正確に復元したい場合は、OCR後に元画像と照合する工程が必要です。
日本語と英語を分けて試す
日本語と英語を混在させると便利ですが、英数字中心の画像ではengだけの方が安定することもあります。
text = pytesseract.image_to_string(
image,
lang="eng",
config="--psm 6",
)
逆に、日本語の説明文が多い場合はjpn、両方が含まれる場合はjpn+engを使います。
技術メモとして運用する
抽出したMarkdownは、そのままメモとして保存できます。ファイル名に日付を付けると、後から探しやすくなります。
たとえば、次のように変更できます。
from datetime import datetime
date_text = datetime.now().strftime("%Y-%m-%d")
output_path = source_path.with_name(
f"{date_text}_{source_path.stem}_memo.md"
)
また、OCR結果の先頭に確認事項を書いておくと、後で見返したときに誤認識を修正しやすくなります。
## 確認メモ
- `O` と `0` は画像で確認する
- コマンドは実行前に公式ドキュメントと照合する
- 個人情報やアクセストークンが含まれていないか確認する
スクリーンショットには、環境変数、メールアドレス、社内URL、APIキーなどが写り込むことがあります。OCRの前後で、共有してよい内容かを確認するようにしています。
まとめ
Python、Pillow、Tesseract OCRを組み合わせると、スクリーンショットから技術メモを抽出できます。
今回の要点は次のとおりです。
-
pytesseractでPythonからTesseractを呼び出せる - OCR前の拡大・グレースケール化・二値化が有効
-
jpn+engで日本語と英語をまとめて扱える -
--psmを画像のレイアウトに合わせて変更する - コードや機密情報は、抽出後に必ず目視確認する
完璧な文字起こしを目指すよりも、「画像しかない情報を検索可能な下書きにする」用途で使うと、手軽で実用的です。まずは手元にあるターミナルのスクリーンショットを1枚使って、OCRの結果と元画像を見比べるところから始めるのがおすすめです。