技術 約7分で読めます

NDLOCRを3か月やった記録と周辺の実装いろいろ

国立国会図書館のOCRエンジン「NDLOCR」を最初に触ったのが2025年12月で、それから3か月でDocker版→段組の力技→Lite版→LLM校正と4本の記事を書いた。その間に別の人がLiteをブラウザに載せていて、アプローチの違いが面白かったのであわせて紹介する。

自分がやったこと

Docker版で地獄を見た(2025年12月)

NDLOCR Docker イメージビルドの成功手順

仕事で「これ動くの?」と言われて軽い気持ちで手を出したのが始まり。公式DockerfileがCUDA 12移行中で全く動かず、有志のsyoyo版リポジトリを使い、Python 3.8のget-pip.pyを手動で差し替えてようやくビルドが通った。GPU必須、CUDA依存、ビルド時間も長い。動かすだけで一苦労だった。

段組が壊滅的だったので力技で切った(2025年12月)

NDLOCRの段組認識問題をヒストグラム解析で力技解決

Docker版が動いても4段組の縦書き書籍を食わせたら読み順がバラバラ。Layout Parserを入れようとしたらDetectron2がWindowsでビルドできず断念。結局PyMuPDFで画像化してヒストグラムの谷で段の境界を検出し、4分割してからNDLOCRに渡す力技で解決した。

Lite版が出て全部解決した(2026年2月)

NDLOCR-LiteをWindowsで動かしてみた

2026年2月にNDLOCR-Liteが公開された。GPU不要、DRAM 1GBで動く、pip installで入る。前回の苦労は何だったのかと思うくらいあっさり動いた。大中小の文字列長モデルをMoE的に振り分ける設計で、CPUオンリーでも1画像数秒。段組+表組みの認識もDocker版とは比較にならないくらい良い。

MacでLLM校正まで試した(2026年2月)

NDLOCR-LiteとローカルLLMで昭和の文書をOCR校正する

Apple Silicon Macにセットアップして、OCR結果をローカルLLMで校正する実験。Qwen 3.5の画像直読みとSwallowのテキスト校正を比較した。昭和38年の文書では「一方交通」を「一方通行」に直してしまうなど、LLMが原文を現代語に書き換える問題が出た。OCR→画像直読み→テキスト校正の3段構えで人間が差分確認するのがベスト、という結論になった。

他の人がやったこと

NDLOCR-Liteをブラウザに載せた人がいる

ndlocrlite-web(yuta1984氏)

自分がCLIでパイプライン組んでる間に、NDLOCR-Liteのモデルを丸ごとブラウザに載せた実装が出ていた。ONNX Runtime WebのWASMバックエンドで動かしていて、サーバー通信なしで完結する。

技術的にはDEIMv2でレイアウト検出、PARSeq(30/50/100文字対応の3モデル)で文字認識という構成で、Lite版本体と同じ多段パイプラインをブラウザ上に再現している。モデル合計146MBを初回にダウンロードしてIndexedDBにキャッシュ、Web Workerで推論するのでUIはブロックされない。

自分のCLI環境だと1画像数秒で終わるが、WASMだとネイティブより遅くなるはずなのでどの程度かは気になる。動かしてないのでわからない。データを外部に送らずに済む点は業務用途で強い。自分がocr-web-2025の記事でブラウザOCRの限界を書いたときはTesseract.jsの精度に絶望していたが、NDLOCR-LiteのモデルがONNXで配布されているおかげでブラウザ実装の選択肢が生まれた。

GoバインディングでCLIツール化した人もいる

go-ndlocr(mattn氏)

Go界隈では有名なmattn氏がNDLOCRのONNXモデルをGoから直接叩くバインディングを作っている。レイアウト検出と文字認識をGoのライブラリとして使えるようにしたもので、CLIツールとしても動く。Pythonを入れずにシングルバイナリで配布できるのがGoらしい。

アプローチの違い

自分はCLI + ローカルLLMで「OCR結果を後段で賢く直す」方向に進んだが、ブラウザ版は「そもそもインストール不要にする」方向に振っている。同じモデルからこれだけ違うものが出てくるのは面白い。

自分も以前はブラウザOCRをいろいろ試していたのに今回ブラウザ実装を考えなかったのは、WASMの初回ロードが重い、モデル146MBのダウンロードも重い、配信元をどこまで信用するかという問題もある、というのが理由。あと正直なところ、そこまでOCRしたいわけでもない。仕事で必要になったときにサッと動かせればよくて、常時稼働のOCR基盤を作りたいわけではない。

ただブラウザ版には別の可能性も感じている。たとえばスマホのカメラで本のページを写して、見出しや単語をOCRで検出し、Web Speech APIで読み上げたり音声を再生するような使い方。絵本の動物をスマホで写したら鳴き声が聞こえる、参考書の英単語を写したらネイティブの発音が聞こえる、みたいなアナログとデジタルの結合だ。Tesseract.jsでこれをやりたかったが日本語の精度がゴミすぎて断念した経緯がある。NDLOCR-Liteの精度でブラウザ動作するなら、速度次第で実用になるかもしれない。試してないのでわからないが。

ブラウザではなくネイティブアプリでやる手もある。FlutterでカメラOCRアプリを作れば、ONNX Runtime Mobile + 音声再生が1アプリに収まる。モデル同梱でオフライン動作、配信元の信頼問題もない。

CC BY 4.0の意味

NDLOCR-LiteのライセンスはCC BY 4.0で、帰属表示さえすればONNXモデルをアプリにバンドルして配布できる。GoでもElectronでもTauriでもFlutterでも同梱可能で、ストアに出すのも問題ない。国の機関が作ったOCRモデルをこのライセンスで公開しているのはかなり太っ腹で、日本語OCRの選択肢としてはかなり使いやすい立ち位置にある。

ラズパイOCRステーション

NDLOCR-LiteはDRAM 1GBで動くと開発者が言い切っている。onnxruntimeはarm64のPyPIホイールが公式提供されているので、Raspberry Pi 5ならpip installで入ってそのまま動く可能性が高い。

速度の見積もりとしては、Windows記事でRyzen 7 5800HSのCPU推論が1枚3〜9秒だったので、Pi 5のCortex-A76だと1枚10〜30秒くらいになりそう。バッチ処理なら十分実用範囲。構成はホットフォルダ監視が一番シンプルで、FastAPIすら要らない。

flowchart LR
    A["スキャナ"] -->|画像出力| B["Samba共有<br/>scan_inbox/"]
    B -->|監視| C["Pi上の<br/>watchスクリプト"]
    C -->|OCR実行| D["NDLOCR-Lite<br/>CLI"]
    D -->|結果出力| E["ocr_output/<br/>TXT / JSON / 可視化画像"]
    E -->|Samba越しに参照| F["PC"]

スキャナの出力先をSamba共有にして、Piが監視、OCR結果を別フォルダに吐く。PCからはSamba越しに結果を見るだけ。Pi再起動してもinboxに残ってるファイルから再開できる。

LLM校正まで含めるとQwen 3.5クラスのモデルが必要で、Piには当然載らない。そうなるとPiに分離する意味がなくなって、素直にGPU積んだPCに全部載せたほうが早い。ラズパイ構成が活きるのはOCRだけで完結するケースに限られる。

コスト面でも微妙なところがあって、Pi 5の8GBモデルは約5.5万円。電源アダプタやケース、SDカードを足すと6万近くなる。その金額なら中古PCが買えてしまうし、NDLOCR-Liteを載せるだけなら中古PCのほうが楽。ただしPiは消費電力が数ワットでスキャナの横に置けるサイズ感なので、常時稼働で放置する運用なら電気代とスペースで勝る。

機密文書とエアギャップ

ラズパイ構成が本当に刺さるのは機密文書の処理だ。自治体の個人情報、法務の訴訟資料、病院のカルテ。こういう文書はGoogle Cloud Vision APIに投げた時点でコンプライアンス的にアウトな場合がある。クラウドOCRが「学習に使わない」と言っていても、外部に送信すること自体がNG。

選択肢を並べるとこうなる:

  • Adobe AcrobatのローカルOCR: 日本語微妙、縦書き弱い
  • Tesseract: 日本語精度がゴミ
  • NDLOCR-Lite: オフライン完結、日本語特化、縦書き+旧字体対応、CC BY 4.0

ネットワークから完全に切り離したPi 1台でOCRが完結する。閉域網ですら不要。PCにソフトを入れるのに情シスの承認がいるような環境でも、スタンドアロンのPiなら持ち込みやすい。

ブラウザ版は「データを外に送らない」点ではセキュリティに見えるが、配信元のJSやWASMバイナリを信頼する必要がある。自分のネットワーク内のPiでCLIを回すほうが信頼の起点が自分にある分、堅い。


OCR全般の話はこちら: 【OCR】2025年のウェブ実装の限界と知見まとめ