今日も微速転進

ここではないどこかへ

財務省の公開した交渉記録PDFをいじる その1(目次のPDF編)


スポンサーリンク

自分でモロに忘れそうなので備忘録として。

一時ファイルがじわじわと増殖するのでもっとスマートに行きたいところです。

作戦というか方針

まずは目次のPDFファイルから。

  1. 目次のPDFから交渉記録(応接記録)を機械可読(Computer Readable)な形式に変換
  2. マスク無しのPDFを画像化、再度PDFに変換して過去記事で紹介したAPIOCR
  3. 目次のページ番号から必要なページを割り出して、OCR結果を分割、どうにして添付資料のページを除去
  4. どうにかしてMarkdown
  5. 静的ページジェネレーターでWebページ化

この記事では「1. 」の部分。

問題は黒塗り部分。特定の操作で外せるのはいいけど、外してからOCRして明らかにやばい部分だけ伏せ字にする?

とりあえずやっていきます。

データの入手

財務省のWebサイトから、といいたいところですがそこはやはりWebアーカイブから黒塗りの外せる方を。

srad.jp

  • 20180523p-1.pdf
  • 20180523p-2.pdf
  • 20180523p-3.pdf
  • 20180523p-4.pdf

目次のOCR処理

目次のデータは素直に財務省のページから。

a244.hateblo.jp

20180523p-0.pdfというファイルです。

目次ファイル

一応、目次のPDFファイルについてもGoogle Cloud Vision OCROCRしてみました。残念ながら罫線が邪魔なのか、OCR結果がいまいち。通し番号の列が認識できていない。また、右端のページ番号も認識に失敗している。

水平方向の行を列ごとに細切れにされて出力されて扱いにくい。

Web APIでいくならMicrosoftAPIの法が良いかも。画像を切り出してTesseractでOCRしてみます。

このファイル、不思議なことに各ページが横に長い短冊状の画像が縦に37個結合したPDFになっていて理解不能。 何これ一体?

ファイルサイズを小さくしたかったの?

何はともあれ、表の罫線があるとGoogleOCR API、Tesseract両者とも結果がイマイチであるという点を考慮し、画像をぶった切ってTesseractでOCRする方向で。

本気で行くなら罫線と文字は接触していないので、ハフ変換で直線検出してやればいいのかな。

ちなみに"OpenCV line remove"でググると結構ヒットする。

罫線(水平線)の除去についてはLeptonicaによるサンプルがあります。

Removing dark lines from a light pencil drawing — Leptonica Documentation v1.68 documentation

画像の切り出し

まず目次のPDFから各ページを画像に変換。

$ mutool draw -o "index_page_%d.png" -r 300  pdf_masked/20180523p-0.pdf

-oで出力ファイルを指定。%dはページ番号が入ります。

GUIでやってもいいですが、表紙を除いた合計8ページから日付の列とページ番号の列を切り出せばよいのでコマンドで。

300dpiで画像化した場合、3ページ目以降は表の上端までの距離が概ね150ピクセル、表の見出しを含めると250ピクセルぐらい。

ものすごくざっくり欲しい列の位置を図で示しておく*1

f:id:atuyosi:20180602180107p:plain:w480

カラープロファイルを指定しないと下記のエラーが出るので、+profile "icc"オプションを追加。-noiseオプションでノイズ除去。

convert: profile 'icc': 'RGB ': RGB color space not permitted on grayscale PNG `output2_1.png' @ warning/png.c/MagickPNGWarningHandler/1744.

参考:ImageMagick で PNG の形式を変換 - awm-Tech

左側の日付の列を切り出す。

$ convert masked/index_page_2.png +profile "icc" -noise 4   -crop "480x2980+500+410" output2_1.png

同じように右側の列。

$ convert masked/index_page_2.png +profile "icc" -noise 4 -crop "180x2980+2000+410" output2_2.png

-cropオプションの引数は、切り抜くサイズ(横、縦)とx座標のオフセット、y座標のオフセット。

f:id:atuyosi:20180602204910p:plain f:id:atuyosi:20180602204916p:plain

理想を言えば罫線を除去したいところだがまあ妥協。

3ページ目以降。

$ convert masked/index_page_3.png +profile "icc" -noise 4 -crop "480x3100+500+280" output3_1.png
$ convert masked/index_page_3.png +profile "icc" -noise 4 -crop "180x3100+2000+280" output3_2.png

もう少し範囲を絞って縦の罫線をきっちり除去すべきだったか。

ImageMagick逆引きコマンドリファレンス

ImageMagick逆引きコマンドリファレンス

ImageMagickの日本語の本、あったのか(絶版)。

Tesseract 4.x

ビルドに必要なライブラリのインストール。

$ brew install --only-dependencies tesseract

最新版をソースからビルドしようかと一瞬だけ思いましたが、地味に面倒なので中途半端ですがHomebrew経由で最新版を。要するに4.x系でやりたかったというだけです。

Tesseract本体(開発版)。

$ brew install tesseract  --HEAD

学習用のツールはインストールせず。

現状のHomebrewパッケージの場合、--HEADオプションを付けると全言語の言語別データをダウンロードする。その際、ダウンロードされるのは以下のリポジトリのデータとなるので注意。

github.com

現状、tessdataは無印(3.0x用のデータを含む)、tessdata_fasttessdata_bestの3系統。

なお、Tesseract tessdata downloaderという補助ツールも提供されている。

github.com

4.x系向けのデータはengとかjpnのデータと、script(書字系?)別のデータ(EnglishとかJapaneseとか)で2種類ある。

現状、Japanese.traineddataなどscriptフォルダ直下のデータはそのままでは読み込まれないので、tessdataフォルダにコピーするかシンボリックリンクを作成する必要がるので注意。

今回の画像データで試した範囲ではjpn..traineddataで十分かな。Japanese.traineddataでは半角数字の前後で余計な空白が入る。

目次のOCR

$ tesseract output2_1.png ocr_text  -l jpn

引数は、

tesseract 画像ファイル 出力ファイルの接頭辞 オプション

出力ファイル名にstdoutを指定すると標準出力(つまりコンソール画面)に結果を出力する。

認識結果の例

$ tesseract output2_1.png stdout  -l jpn --psm 6
Warning. Invalid resolution 0 dpi. Using 70 instead.
平成25年6月28日
平成25年7月8日
平成25年7月25日
平成25年8月1日
平成25年8月13日
平成25年8月21日
平成25年9月2日
平成25年9月12日
平成25年10月4日
平成25年10月24日
平成25年10月27日
平成25年10月30日
平成25年11月4日
平成25年11月19日
平成26年12月16日
平成25年12月26日
平成25年12月27日
平成26年1月9日
平成26年1月27日
平成26年1月28日
平成26年1月31日
平成26年2月3日
平成26年2月13日
平成26年3月4日
平成26年3月6日
平成26年3月2日
平成26年4月15日

大変結構。

$ tesseract output2_2.png stdout -l jpn --psm 6 --oem 3
Warning. Invalid resolution 0 dpi. Using 70 instead.
]
18
19
19
22
24
26
27
35
36
42
44
46
47
50
53
55
56
63
64
73
75
77
78
81
84
87

数字の"1"の認識ミスは許容範囲内。

--psm (page segmentation mode)の値によっては最初の”1"を取りこぼすか、余計な空行が入ったりする。古いバージョンのTesseractのほうが数字の認識に関しては優秀だろうと思う。面倒なので試していない。

やはり面倒なのでスクリプトで一括。

#! /usr/local/bin/bash


convert masked/index_page_2.png +profile "icc" -noise 4   -crop "480x2980+500+410" cropped_2_1.png
convert masked/index_page_2.png +profile "icc" -noise 4 -crop "180x2980+2000+410" cropped_2_2.png

for i in `seq 3 9` ; do
    convert masked/index_page_${i}.png +profile "icc" -noise 4   -crop "480x3100+500+280" cropped_${i}_1.png
    convert masked/index_page_${i}.png +profile "icc" -noise 4 -crop "180x3100+2000+280" cropped_${i}_2.png
done


for j in `seq 2 9`; do
    echo "first ${j}"
    tesseract cropped_${j}_1.png ocr_text_${j}_1  -l jpn --psm 6 
    echo "2nd ${j}"
    tesseract cropped_${j}_2.png ocr_text_${j}_2  -l jpn --psm 6 
done

認識ミスは以下の通り。

  • 1ページ目 数字の"1"の認識ミス
  • 3ページ目 「平成26年6月17晶」。末尾の「日」を認識できず。
  • 4ページ目 末尾の「日」の認識ミス。余計な文字「|」
  • 5ページ目 末尾に余計な文字「409 .」
  • 6ページ目 余計な文字「征」「 .」。末尾の「日」の認識ミス。
  • 7ページ目 余計な文字「|」
  • 8ページ目。なぜか"810"が脱落。

あとは「日」が「昌」になったり「目」になっている箇所がいくつか。画像を拡大する処理が必要だったかな。

まあ手作業で修正できる範囲です。

末尾に^L(Form Feed: \f)がくっついているので後で除去する。

OCR結果のテキストファイルの結合

結合するファイル同士の行数が同じであるという前提で、pasteコマンドを使う。

#! /usr/local/bin/bash

for j in `seq 2 9`; do
    echo "target ${j}"
    paste ocr_text_${j}_1.txt  ocr_text_${j}_2.txt >> ocr_result_${j}.tsv 
done

前述の邪魔な^Lを除去する。

$ cat $(ls *.tsv) | tr -d '\f' | sed '/^[[:blank:]]*$/d' > page_list.tsv

参考:Linux パターン別ファイルの空行削除(除外)方法 | 俺的備忘録 〜なんかいろいろ〜

完成品:財務省の公開した国有地の取引に関する交渉記録の目次PDFから抜き出した日付とページ番号の対応表(2018年5月)

※ 不備があったので更新しています。

まとめ

とりあえず目次データをTSV化するところまで。

Tesseractのドキュメント構造解析処理がアレなのはともく、GoogleAPIも罫線入りの表が苦手だとはさすがに意外。

Cloud Vision APIの方は"TEXT_DETECTION"の方を試すのもありかもしれないですがそれはまた別の機会に。

次は本文データ(OCR済み)に挑みます。

続きます。

詳解 OpenCV 3 ―コンピュータビジョンライブラリを使った画像処理・認識

詳解 OpenCV 3 ―コンピュータビジョンライブラリを使った画像処理・認識

シェルプログラミング実用テクニック

シェルプログラミング実用テクニック

*1:いかにもやっつけ仕事

広告