PDFファイルにOCRを使ってみた

2020-10-23

概要

PDFファイルをOCR使ってみたので共有します

きっかけ

  • 不動産関連で働いてる友人からなんとかならないかと質問されました。
  • 法務局から渡されたpdfデータを紙に印刷して、画像から特定の文字(「単独」「仮登記」「根抵当権」など)を見つけて住所を打ち込むらしいです。
  • コントロールFしろって思ったんですが、pdfファイルは印刷した紙をスキャンした画像データでした
  • 画像に対してOCR使ったらいい感じになるかも、、、と思って興味を持ちました
  • 法務局から与えられてくるデータは毎月膨大な数更新されるらしいので、精度の問題で抜けがあっても問題ないらしいです

OCRについて

OCR(Optical Character Recognition/Reader、オーシーアール、光学的文字認識)とは、手書きや印刷された文字を、イメージスキャナやデジタルカメラによって読みとり、コンピュータが利用できるデジタルの文字コードに変換する技術

https://ja.wikipedia.org/wiki/光学文字認識

使用例

  • 教科書を写真撮って、OCRのアプリで文字にしてから、それを切りはりしてレポートを作ったりしてました。
  • sansanの名刺とか
  • レシートとか

他にも探したら無限にあるかと思います。

実際にOCRを使う

APIで文字データのみ返ってくるのが一番いいんでしょうけど、コントロールFで検索しても十分業務効率は上がるはずなので試してます。

前提

色々使ってみました

この文字は正しく認識できるけどこれはできないみたいなのある。今回は文字認識の精度に加えて以下のようなものも重視します。

  • 住所の崩れ具合
  • 「単独」って文字で検索がかけれるか

各サービス使ってみる

google document

  • すごい楽にできます。インタスタントな感じ。
  • が精度は後述の他のものより劣ります。あと見辛いし文字サイズ変わるし、謎の文字列入る。
  • 文字変換のパターンはやっぱりGCPと似てる

AWS textract

adobe acrobat pro

  • PDFに絞ると結構ぐぐると出てきました。PDF限定かと思います。
  • アドビ提供の、PDFファイルを作成・編集・加工・管理するためのソフト
  • ワード、エクセルファイルを生成できます。有料なのでadobeに課金してる友達に頼みました。
  • ワードいい感じな気がしました。
    • 文字認識自体の精度は一番な気がしました。
    • (後述のgcpよりもいいように見えましたが、精度がいいのか解像度が荒い故なのかはわからないですね)
    • ところどころ表として読み込んでいたり、
    • レイアウトに一貫性がない( 【第240 8 0号 あたりで破綻 )
  • エクセルは、ぐちゃぐちゃって感じです。
  • 添付ファイルに色々載ってます

GCP visionAPI

  • ググって一番多く出てきた。
  • ほぼサンプルコード動いてくれたので助かったです。https://cloud.google.com/vision/docs/pdf?hl=ja
  • google document文字のパターンが似てました。
  • 添付ファイルのgoogle.txtです
  • 行がずれてて死にました。のちに角度を変えて再トライしました。

azure computer vision API

  • GCPと競合するやつ
  • 触ってみたかったが、GCPでなんとかなりそうで後回しになり、結局今日に間に合わなかったす🙇‍♂️
  • あとググっても実装例少ないような気がしました。PHPだとさらに減ってました。
  • 文字の精度は基本的に1番は精度とお金的にもgcpのがいいらしいです(画像にもよる)(会社の人Mさん)
  • 精度の比較してる記事をまあまあ見ましたがGCPの方が精度いいって言ってるの多かったです。

あと伺ったらpython自作もできるそうですが、精度azure,gcpに勝てなさそうだそうです。そんで流石にだるいなってなったんでやってみようとも思わずです。(会社の人)

文字の精度自体はadobeかgcpもおんなじくらいかと思いました。わずかにadobeの方がいいような気がしました。
そんなに多くないpdfファイルを扱うだけだったらコードとか書かないでadobeでやっちゃった方が早いなと思いました。

GCP visionAPIでなんとか頑張ってみる

  • データベースに入れた後、データがズレてることに気づいて死にました。
  • 文字の精度が良くても、表の行がずれてるとなると致命的。
  • 死んだと思ったので、会社の人に聞く。他の手段を探そうとしました。
    • 画像と各ソフトの相性もあるので、いろいろやってみた方がいいっぽい。これは捉えられて、こっちでは無理みたいな。
    • 自作もある
    • 画像側をいじってた(画像の色を変える)

ということで画像いじる作戦をやってみる

  • トリミングしてみるけど、オリジナルと全く一緒でダメでした。
  • トリミングしたタイミングで画像が傾いてることに気づきました
  • なのでいい感じに画像を傾けたらちゃんと読み込んでくれるんじゃないかと思いました。

ちなみにblock、paragraph、word、symbolっていう単位に分かれてます。このblockがずれてる。

https://cloud.google.com/vision/docs/fulltext-annotations?hl=ja

レシートを例に。(https://qiita.com/ayuma/items/bf5645894803769edc72)

回転してみた。

PHPでPDFファイルを扱う

ファイルを回転する

  • TCPDF
  • FPDI

TCPDF

  • 「PHP PDF」で検索するとだいぶ出てきた。
  • PDFを出力するライブラリ

FPDI

  • TCPDFクラスを継承してるライブラリ。
  • 既存のPDFファイルを読み込む

ファイルを圧縮を解除する

エラー。(圧縮技術が使われたファイルは、FPDIのフリープランはサポートしてません。)

This PDF document probably uses a compression technique which is not supported by the free parser shipped with FPDI.

ググった感じだと、解決策を3つ見つけた

  • そこらへんに転がってるサービスを使う(https://smallpdf.com/jp/compress-pdf 、adobe acrobat pro)
  • 他言語(pythonとか楽そう)のpdf扱うライブラリ
  • QPDFというコマンドラインプログラムを使う

一番手っ取り早そうな QPDFに決めた

brew install qpdf
qpdf --force-version=1.4 template.pdf uncompressed.pdf

回転する処理

use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
use setasign\Fpdi\Tcpdf\Fpdi;

private function rotate($request)
    {
        $unixTime = time();
        $fileName = $unixTime.self::PDF_EXTENSION;

        $request->file->storeAs(self::ORIGINAL_FILE_DIR_NAME, $fileName);
        //storageに保存

        $pdf = new Fpdi();

        try {
            $pageNum = $pdf->setSourceFile($this->getOriginalFilePath($fileName));
        } catch (CrossReferenceException $e) {
            //エラーを吐いたら圧縮処理をかける
            $this->uncompress($fileName);
            $pageNum = $pdf->setSourceFile($this->getUncompressedFilePath($fileName));
        }

        for($i = 1; $i < $pageNum+1; $i++){
            $importPage = $pdf->importPage($i);
            $pdf->addPage();
            $pdf->Rotate($request->get('angle'));
            $pdf->useTemplate($importPage, 0, 0);
        }

        $pdf->Output($this->getRotatedFilePath($fileName),'F');
        //storageに保存
    }

    private function uncompress($fileName)
    {
        exec('qpdf --force-version=1.4 '. $this->getOriginalFilePath($fileName) .' ' . $this->getUncompressedFilePath($fileName));
    }

結果

  • -0.5度(反時計回り)は0度とおんなじ結果。並行に見えたけどな。
  • -1度だと成功。
  • -2度も-1とおんなじ結果になりました。
  • -4度は少し崩れた。
  • -6は-4とおんなじくらい

これ-4度↓

これ-6↓

これも-6↓

添付ファイルについて

  • 0.pdfはオリジナル
  • -1.pdfは反時計回りに1度
  • google.txtはオリジナルをGCPにかけたときに帰ってきたテキストをコピペして貼り付けた
  • adobe.txtはワードファイルのをコピペして貼り付けた

いじったコード
https://github.com/shlia34/ocr

終わり

拡大,縮小とか表の行で画像を分割したりするとうまいこといくかもっていう、、。また今度。