紙資料をスキャンして生成されるいわゆる画像的な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」というフォーマットの存在を初めて知りました。
参考ページの著者でもある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
https://github.com/tmbdev/hocr-tools を参考にhocr-toolsをインストールする。このツールセットのうちのhocr-pdfを後で使用する。
$ sudo apt install python-pip # pipをまだインストールしていない場合
$ sudo pip install hocr-tools
chmod +x pdf4search.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}"
Google Cloud Vision APIを「テキスト検出 (TEXT_DETECTION)」で利用する場合、利用料は「最初の1,000ユニット/月」は「無料」となっている。この規模を超える利用を行う可能性がある場合は、Google本家の料金表をご確認ください。
活字やそれに近い整った文字が画像として載っているPDFファイル sample.pdf を用意し、pdf4search.shを次のように実行すると、Google Cloud Visionが抽出したテキストデータが重なっているPDFが、同じ場所に新規保存される。
$ pdf4search.sh ./sample.pdf # sample-ocr.pdfが保存される
次の pdftotext, pdfgrep というようなコマンドを用いて、新規保存された検索可能PDFの中のテキストを確認できる。また、任意のPDF Viewerで全選択【Ctrl+A】してみて、テキストが選択可能かどうか確かめるのもよい。
$ pdftotext sample-ocr.pdf - # 第2引数は「-」, 中身のテキストが標準出力される
$ pdfgrep HOGE sample-ocr.pdf # 中身のテキストを対象にgrepが効く
しかし今のところ、原因不明の問題が一つある。
実は当初、オープンソースな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を使う方針に切り替えたのであった。