【ITニュース解説】Measure ink and lighting before you binarize an image for OCR
2026年10月10日に「Dev.to」が公開したITニュース「Measure ink and lighting before you binarize an image for OCR」について初心者にもわかりやすく解説しています。
ITニュース概要
OCR前処理で安易な画像の二値化は、明るい文字の消失や照明ムラによる誤認識を引き起こす。これらはエラーにならず、気づきにくい問題だ。二値化処理を行う際は、インクの濃さや紙の明るさのムラを事前に測定し、適切な方法を選ぶべきである。
ITニュース解説
OCR(光学文字認識)のシステムを開発する際、画像の前処理は非常に重要だ。特に、画像を白黒の二値に変換する「二値化(バイナリゼーション)」という処理は、多くのOCRパイプラインで最初に行われることが多い。しかし、この二値化の処理には、一見すると問題ないように見えて、実はOCRの認識精度を大きく低下させてしまう二つの「静かな失敗」が潜んでいる。この記事では、それらの問題点と、どうすればそれらを未然に防げるかを詳しく解説する。
まず、多くの開発者が手軽に使う方法として、画像をグレースケール(白黒の濃淡画像)に変換した後、固定のしきい値(例として、ピクセル値128)を使って二値化する方法がある。画像データは、通常0(黒)から255(白)までのピクセル値で表現される。しきい値128とは、128より暗いピクセルは完全に黒(0)に、128より明るいピクセルは完全に白(255)に変換することを意味する。これはOpenCVのような画像処理ライブラリで簡単に一行のコードで実現できるため、広く利用されている。しかし、この手軽な方法には二つの大きな落とし穴がある。
一つ目の失敗は、「しきい値より明るい文字が消えてしまう」ことだ。例えば、ウェブページのフッターによく見られるような、薄い灰色の文字を考えてみよう。実験では、このような灰色の文字の最も暗い部分のピクセル値が153だった。この画像をしきい値128で二値化すると、文字のすべてのピクセル(153)がしきい値(128)よりも明るいため、「背景」と見なされて真っ白に変換されてしまう。結果として、OCRエンジンには何も文字情報が伝わらず、認識結果はゼロ文字となってしまう。これは、エラーメッセージが出ないため、開発者はOCRが単に文字を見つけられなかっただけだと思い込みやすい。
しきい値を調整しても問題は残る。もししきい値を160のように上げて、かろうじて文字のピクセル値(153)よりも高く設定すると、文字のストローク(線)の中心部分だけが黒として残り、文字全体が非常に細くなってしまう。この状態では、人間の目にはまだ文字として認識できても、OCRエンジンにとっては形が大きく崩れた文字として認識され、誤認識率が75.5%と著しく上昇してしまう。元の画像が0.0%の誤認識率だったことを考えると、これは許容できない劣化だ。さらに、背景に色が付いた画像、例えば赤いタグの上に白い文字が書かれているような場合でも同様の失敗が起こる。しきい値処理によって赤いタグが黒い塊として文字に重なったり、文字自体が消えてしまったりする。
二つ目の失敗は、「照明が不均一な場合、グローバルなしきい値では影の部分が真っ黒になる」ことだ。現実の世界でスマートフォンなどで撮影した写真では、光源の位置や影によって画像全体で明るさが均一でないことが多い。例えば、書類の一部に影が落ちているような画像を考えてみよう。この画像に「グローバルなしきい値」(画像全体に一つのしきい値を適用する方法)を適用すると、影で暗くなっている部分は背景の紙まで黒く変換されてしまうことがある。すると、その部分の文字は影の中に埋もれてしまい、OCRエンジンは文字を認識できなくなる。Otsu法のような自動でしきい値を決定する優れたアルゴリズムも、グローバルなしきい値の一種であるため、このような不均一な照明の環境では同じ問題に直面することがある。実験では、影がかかった画像でOtsu法が選んだしきい値では、影の部分が完全に真っ黒になり、OCRの認識エラー率が31.0%にも達し、文字が実際に失われていた。
この問題への有効な解決策が、「ローカル適応しきい値処理(Local adaptive thresholding)」だ。これは、画像全体で一つのしきい値を使うのではなく、画像の小さな領域ごとにその領域に適したしきい値を適用する方法だ。これにより、明るい部分と暗い部分が混在する画像でも、それぞれの領域で文字と背景を適切に分離できるようになる。実験では、このローカル適応しきい値処理を適用した結果、認識エラー率が19.0%まで改善し、失われた文字は一つもなかった。残りのエラーは、画像の傾きによる文字の並び順の問題であり、これは画像をまっすぐにする「傾き補正」によって解決可能だ。
これらの「静かな失敗」を避けるためには、単にグレースケール化と固定しきい値での二値化を安易に適用するのではなく、二値化の前に画像の内容をしっかり「測定」することが極めて重要になる。具体的には、以下の二点を必ず確認すべきだ。
- 「文字の実際の濃さ」: 画像内で最も明るい色で書かれている文字(例えば薄い灰色の文字)が、どのくらいのピクセル値を持っているか。その文字の最も暗いピクセル値が、設定しようとしているしきい値よりも明るい場合、その文字は二値化によって消えてしまう可能性がある。
- 「紙の明るさの広がり」: 画像の背景となる紙(またはスクリーン)の明るさが、画像全体でどの程度変動しているか。特に、暗い部分(影など)と明るい部分がある場合、グローバルなしきい値処理は不適切である可能性が高い。
上記の測定を行うための簡単な監査コードも提案されている。このコードは、画像の中心部分から「文字の最も暗いピクセル値(ink)」を測定し、同時に「局所的な紙の明るさの低い値(paper_low)」を、画像を膨張(dilate)させる処理を使って測定する。さらに、Otsu法によるしきい値も取得し、これらの値を使って以下のいずれかの警告を出す。
- 「固定しきい値がテキストを消去する」:もし文字の濃さが設定したしきい値より明るい場合。
- 「グローバルしきい値は紙を黒くする、適応型にするかスキップする」:もし紙の暗い部分がOtsu法で計算されたしきい値よりも暗い場合。
この監査コードは、薄い灰色の文字が消える問題や、影によって紙が黒くなる問題を効果的に検出できる。しかし、文字が細くなりすぎる問題や、色付きの背景で文字が欠けるといった複雑なケースはまだ完全には検出できないという限界もある。
結論として、OCRの前処理で「二値化」を適用する際は、その影響を十分に理解せずに導入すると、かえって認識精度を大きく損なう可能性がある。特別な理由がない限り、OCRエンジンにはできるだけ元のカラー画像やグレースケール画像をそのまま送るのが最も堅実な方法である。必要に応じて、画像の傾きや歪みを補正する「幾何学的補正」のみを行うのが望ましい。もし二値化がどうしても必要となる状況であれば、必ずその前に「最も明るい文字の最も暗いピクセル値」と「紙の明るさの変動範囲」を測定し、その画像にとって最適な処理方法を慎重に検討することが重要だ。安易な固定しきい値による二値化は、OCRの精度を低下させる「静かな失敗」につながることを肝に銘じておくべきだ。