Google Cloud VisionにOCRしてもらってテキスト検索可能なPDFを作る方法 (How to make a searchable PDF)

紙資料をスキャンして生成されるいわゆる画像的なPDFファイルを、どうしても電子的に検索したくなり、「検索可能PDF」の今時の作り方に挑戦してみた。おおよそ思い通りに出来たので、ブログ記事にしておきます。

ここでいう検索可能PDFとは、元データを光学式文字認識 (OCR) した結果のテキストを、元データとは異なるレイヤーに重ねている、テキストの検索【Ctrl+F】が効くPDFのこと。OCRのエンジンとしては、世界最高レベルの正確さが期待できるであろう、雲の上の「Google Cloud Vision API」を使うことにした。

OCRの他にも強力な機能を備えてそうな、Google Cloud Vision APIの簡単な紹介として、2015年12月公開の動画と、中の人による関連記事を貼っておく。

最初に下準備

項目 内容
実験環境 Xubuntu 16.04 (Ubuntu 16.04)

今回のアイデアは、次の記事を非常に参考にしています。m(_ _)m

また、OCRで抽出したテキストの内容や配置情報を保持する、「hOCR」というフォーマットの存在を初めて知りました。

gcv2hocrのインストール

参考ページの著者でもあるdinosauria123さん作の、gcv2hocr https://github.com/dinosauria123/gcv2hocr を次のようにインストールする。なお、同梱されているPython版「gcv2hocr.py」も元来は利用可能なようだが、中身の更新がおそらくC版に追いついていない気がしたので、今回はPython版ではなくC版をmakeして使っている。

$ git clone https://github.com/dinosauria123/gcv2hocr
$ cd gcv2hocr
$ make
$ sudo make install

hocr-pdfのインストール

https://github.com/tmbdev/hocr-tools を参考にhocr-toolsをインストールする。このツールセットのうちのhocr-pdfを後で使用する。

$ sudo apt install python-pip # pipをまだインストールしていない場合
$ sudo pip install hocr-tools

pdf4search.shの作成

  1. 下記のような約50行のbashスクリプトを自作した。これを pdf4search.sh として保存し、chmod +x pdf4search.shで実行権限を付与する。
  2. https://github.com/dinosauria123/gcv2hocr にある gcvocr.sh もあわせて保存し、同じくchmod +x gcvocr.shする。

この pdf4search.sh に関しては、中身がいろいろと雑だしダサいしすみません。後日時間があればGitHubにアップロードします。https://github.com/mah-jp/pdf4search にアップロードしました。スクリプト内に書き込んでおく必要がある、自身のAPI Keyの取得方法については、ここでは説明を省略。次のページなどを参照してください。

#!/bin/bash

# pdf4search.sh (ver.20171018)
# Usage: pdf4search.sh FILENAME.pdf

# References:
# [1] https://qiita.com/dinosauria123/items/0feb719eb935fea62dd9
# [2] https://github.com/dinosauria123/gcv2hocr
# [3] https://github.com/tmbdev/hocr-tools

# user's variables
GCP_APIKEY=*****Your-Google-Cloud-Platform-API-Key*****
COMMAND_GCVOCR=/path/to/gcvocr.sh # [2]
COMMAND_GCV2HOCR=/usr/local/bin/gcv2hocr # [2]
# variables
FILE_PDF="$1"
TMP_FILENAME=${FILE_PDF##*/}
FILE_PDF_FILENAME=${TMP_FILENAME%.*}
TMP_DIR=/tmp/pdf4search_${FILE_PDF_FILENAME}
TMP_DPI=300

# pdf -> png
mkdir -p "${TMP_DIR}"
pdftoppm -r ${TMP_DPI} -png "${FILE_PDF}" "${TMP_DIR}/page"

# png -> Google Cloud Vision -> hocr+jpg
for FILE_PNG in $( find ${TMP_DIR} -type f -name '*.png' | sort ); do
	TMP_FILENAME=${FILE_PNG##*/}
	FILE_PNG_FILENAME=${TMP_FILENAME%.*}
	FILE_HOCR=${TMP_DIR}/${FILE_PNG_FILENAME}.hocr
	FILE_JSON=${FILE_PNG}.json
	echo "gcvocr.sh: ${FILE_PNG} > ${FILE_JSON}"
	${COMMAND_GCVOCR} "${FILE_PNG}" ${GCP_APIKEY}
	echo "gcv2hocr: ${FILE_JSON} ${FILE_HOCR}"
	${COMMAND_GCV2HOCR} "${FILE_JSON}" "${FILE_HOCR}"
	convert "${FILE_PNG}" "${TMP_DIR}/${FILE_PNG_FILENAME}.jpg"
done

# hocr+jpg -> pdf
echo "Generating: ${FILE_PDF_FILENAME}-ocr.pdf"
hocr-pdf "${TMP_DIR}/" > "${TMP_DIR}/${FILE_PDF_FILENAME}.pdf" # [3]
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/default -dNOPAUSE -dQUIET -dBATCH -sOutputFile="${FILE_PDF_FILENAME}-ocr.pdf" "${TMP_DIR}/${FILE_PDF_FILENAME}.pdf"
#cp -p "${TMP_DIR}/${FILE_PDF_FILENAME}.pdf" "${FILE_PDF_FILENAME}-ocr.pdf"

# cleanup
rm preout0.txt preout1.txt preout2.txt
rm -r "${TMP_DIR}"

検索可能PDFの作成と確認

(念の為) Google Cloud Vision APIの利用料について

Google Cloud Vision APIを「テキスト検出 (TEXT_DETECTION)」で利用する場合、利用料は「最初の1,000ユニット/月」は「無料」となっている。この規模を超える利用を行う可能性がある場合は、Google本家の料金表をご確認ください。

pdf4search.shの実行

活字やそれに近い整った文字が画像として載っているPDFファイル sample.pdf を用意し、pdf4search.shを次のように実行すると、Google Cloud Visionが抽出したテキストデータが重なっているPDFが、同じ場所に新規保存される。

$ pdf4search.sh ./sample.pdf # sample-ocr.pdfが保存される

PDFの中のテキストを確認

次の pdftotext, pdfgrep というようなコマンドを用いて、新規保存された検索可能PDFの中のテキストを確認できる。また、任意のPDF Viewerで全選択【Ctrl+A】してみて、テキストが選択可能かどうか確かめるのもよい。

$ pdftotext sample-ocr.pdf - # 第2引数は「-」, 中身のテキストが標準出力される

$ pdfgrep HOGE sample-ocr.pdf # 中身のテキストを対象にgrepが効く

しかし今のところ、原因不明の問題が一つある。

  • 今回作ったPDFファイル sample-ocr.pdf をMac OS X (10.12.6; Sierra) の「プレビュー」で開いたとき、テキストが正しく拾えない? (半角スペースの列になっている?)

作ってみた感想

  • Google Cloud VisionによるOCRは、普段見るフォントはかなり認識するようだし、文字列が多少傾いていても平気みたいだし、さすがに凄い
  • ただし、文字間のマージンを感度高めに表現するのか、テキスト認識後に単語が途中で分かれていることがよくある。逆にテキスト中のスペースをうまく取り除く処理をhOCRに対して施してもいいかも?
  • 検索可能PDFをより効率的に作成・利用するためには、まず、パソコンやサーバの特定フォルダ内のPDFファイルを自動で順次OCRしていく仕掛けがあればよさそうだ (そのためのpdf4search.shのラッパーは作成済み。これも公開するかな)

P.S. オープンソースなTesseract OCRも試した

実は当初、オープンソースなOCRソフトで、Tesseract OCR https://github.com/tesseract-ocr/tesseract というものがあると知り、次のコマンドでインストールして、

$ sudo apt install tesseract-ocr tesseract-ocr-jpn

https://github.com/ssh0/dotfiles/blob/master/bin/pdfocr にある使い方で、PDFの日本語テキストを認識させようとした。

しかしながら、デフォルトの状態では認識率がそこまで良くないようで、学習で辞書を鍛えていく手もあるとは思うがそこに手間をかけたくないので、本記事本編でのGoogle Cloud Visionを使う方針に切り替えたのであった。