10 人が閲覧(直近 30 日) AI

二値化とは?しきい値の決め方と大津・適応的の使い分けをOpenCVの実装で解説

二値化とは?しきい値の決め方と大津・適応的の使い分けをOpenCVの実装で解説

二値化は、画像の各画素を白と黒の2階調へ振り分ける処理です。やっているのは「しきい値と比べて上か下か」の判定だけで、原理は単純に尽きる。それでも実装で詰まるのは、しきい値をどう決めるかという一点に条件が集まるからです。この記事では、固定しきい値・大津の手法・適応的二値化を撮影条件から選び分ける基準、OpenCVのAPIが持つ入力の制約、OCRや外観検査の前処理としてどこまで二値化で粘るかの判断までを実装の解像度で整理しました。

まとめ|二値化で決まるのはしきい値の決め方と適用の単位

二値化の設計で実際に決まることは、突き詰めると2つしかありません。

1つ目はしきい値を誰が決めるか。人が固定値を書くのか、ヒストグラムから自動で算出させるのか、画素ごとに周囲を見て決めさせるのか。この3択が固定しきい値・大津の手法・適応的二値化に対応します。

2つ目はしきい値を画像全体に1つ持つか、画素ごとに持つかという適用の単位です。照明ムラや影のある画像で固定値や大津の手法が崩れるのは、明るい側の文字と暗い側の文字を1つの境目で切り分けられないからにほかなりません。撮影条件を固定できる環境なら、画像全体に1つで足ります。

そしてOCRの前処理に限れば、自前で二値化を掛けないほうが読み取れる場面があることを先に押さえてください。Tesseractは内部でOtsuを実行しており、その前に別の二値化を通すと処理が二重になる。手を入れる先はTesseract側のthresholding_methodだった、という結論は珍しくありません。

二値化とは何か|しきい値処理で画素を白と黒へ振り分ける仕組み

二値化(にちか)は、画像処理の入口に置かれる処理です。グレースケール画像が持つ0から255までの明るさを0か255かの2値へ落とし、以降の処理で「白い領域」「黒い領域」として面積や形を扱えるようにする下ごしらえだと考えてください。輪郭抽出も文字認識も対象と背景が分かれている前提の処理で、その分離を担います。明るさそのものではなく変化率で境目を取り出す方法は、エッジ検出とは?Canny法と微分フィルタの使い分けをOpenCVの実装で解説で扱っています。

画像処理全体での位置づけを俯瞰したい場合は、親記事の画像認識AIとは?仕組み・できること・開発の進め方をわかりやすく解説で前処理と認識の分担を先に押さえてください。

グレースケール変換を先に挟む理由と画素値が持つ意味のとらえ方

二値化の対象は原則としてグレースケール画像です。カラーのままでは、赤・緑・青のどのチャンネルを基準に白黒を決めるのかが定まりません。OpenCVではcv2.cvtColorで単チャンネルへ落とすか、読み込み時にcv2.IMREAD_GRAYSCALEを指定してから二値化へ進みます。

8ビットのグレースケールでは画素値は0(黒)から255(白)までの整数で、しきい値を128に置くとは、この数直線を128で切って上を白、下を黒に倒す操作にすぎません。意識しておきたいのは被写体の色ではなく明るさだけを見ているということ。色は濃いのに明るさが背景と近い対象は、グレースケールにした時点で背景と混ざり、どのしきい値でも分離できない。色で分けたいならHSV色空間で色相を抜くほうが筋がよく、二値化に持ち込む問題ではありません。

しきい値の上下で結果が変わる5種類の処理タイプと選び方の基準

OpenCVのThresholdTypesには、しきい値を超えた画素をどう扱うかで5種類が用意されています。4.xブランチと5.xブランチのヘッダで同じ定義を確認しました。

タイプ 値 しきい値超えの画素 それ以外の画素
THRESH_BINARY 0 maxvalへ倒す 0へ倒す
THRESH_BINARY_INV 1 0へ倒す maxvalへ倒す
THRESH_TRUNC 2 しきい値で頭打ち 元の値のまま
THRESH_TOZERO 3 元の値のまま 0へ倒す
THRESH_TOZERO_INV 4 0へ倒す 元の値のまま

純粋な二値化は先頭の2つだけで、残る3つは階調を残す処理です。判断が要るのはBINARYとBINARY_INVの選択で、後段が「白い塊」を探すのか「黒い塊」を探すのかで決まります。cv2.findContoursは白を対象物として扱うため、黒い文字を輪郭で追うならBINARY_INVで反転させておく。後段の都合から逆算して選ぶ、と覚えると迷いません。

このほかフラグとして、THRESH_MASK(値7)、THRESH_OTSU(値8)、THRESH_TRIANGLE(値16)、THRESH_DRYRUN(値128)が定義されています。最後のTHRESH_DRYRUNはしきい値の算出だけを行い二値化は実行しないフラグで、大津の手法が弾き出した値だけを検査したいときに使えます。

固定しきい値と大津の手法と適応的二値化を撮影条件から選び分ける判断軸

しきい値の決め方は3系統。優劣ではなく前提条件が違うだけで、撮影条件を固定できるかどうかを起点に選ぶと迷いが消えます。

決め方 成立する前提 崩れる条件 計算量
固定しきい値 照明と背景が一定 明るさの日内変動 最小
大津の手法 明暗が二山に分かれる 照明ムラ・片寄り 小
適応的二値化 局所では明暗が分かれる 広い無地の領域 中

固定しきい値が成立するのは撮影条件を作り込める現場だけという前提

数値を直接書く固定しきい値は、検査装置のように照明・カメラ・距離をすべて設計できる環境で強みが出ます。判定基準が数値としてコードに残るため再現性が高く、結果が変わったときも切り分けが早い。

逆に、スマートフォンで撮った書類や屋外の設備写真では成立しません。撮影のたびに明るさの分布が動くため、ある1枚で合わせた値が翌日には合わなくなる。「昨日まで読めていたのに」という不具合の多くは、固定しきい値を可変な環境へ持ち込んだ結果です。

大津の手法が分離度を基準にしきい値を自動で決める原理と前提条件

大津の手法(Otsu’s method)は、1979年に発表された論文で提案された、しきい値を画像から自動で決める手続きです。あるしきい値で画素を2つのクラスに分けたとき、クラス内の分散が小さくクラス間の分散が大きいほど、その値はきれいに分けられている。この分離の良さを0から255まで総当たりで計算し、最も良い値を採る。

人がヒストグラムを眺めて谷を探す作業を自動化したものだと考えると腑に落ちます。だからこそヒストグラムが二山に分かれていることが前提で、ここが崩れると結果も崩れる。文字がほとんど写っていない白紙に近いページでは、紙の微妙な濃淡を無理やり二分した結果が返ります。算出されたしきい値そのものを記録し、想定範囲から外れた画像を弾く仕組みを併せて置くのが安全です。OpenCVのthresholdがしきい値を戻り値で返すのは、この用途にそのまま使えます。

適応的二値化が近傍ごとに境目を計算して照明ムラを吸収する仕組み

適応的二値化は、画像全体に1つの境目を置くのをやめ、画素ごとに周囲だけを見てしきい値を決める方法です。OpenCVのadaptiveThresholdは2種類あり、ADAPTIVE_THRESH_MEAN_C(値0)は近傍の平均から定数Cを引いた値、ADAPTIVE_THRESH_GAUSSIAN_C(値1)はガウス窓で重み付けした加重和から定数Cを引いた値を、その画素のしきい値とします。

片側から光が当たって左が明るく右が暗い画像でも、近傍の中では文字と紙の明暗差が保たれているため分離できる。これが照明ムラに強い理由です。弱点もはっきりしていて、近傍に対象物が何も無い領域では紙のわずかなムラを拾い、偽の点を大量に出します。対処は後述するモルフォロジー処理か、定数Cを大きめに取って背景側へ倒す方向になります。

OpenCVのthresholdとadaptiveThresholdで書く二値化の実装

ここから実コードです。導入手順や画像の読み書きといった基本操作はOpenCVをPythonで使う画像処理入門|インストールから顔検出まで実コードで解説にまとめてあるため、本記事は二値化のAPIだけを扱います。なおPyPI上のopencv-pythonは2026年8月23日時点で5.0.0.93(2026年7月2日公開)が最新、4系は4.13.0.92(2026年2月5日公開)が最新で、以下のAPIは両系統で同じ形です。

cv2.thresholdの戻り値とTHRESH_OTSUを組み合わせる書き方

thresholdは引数を5つ取り、戻り値を2つ返します。第3引数がしきい値、第4引数がmaxval、第5引数が処理タイプです。THRESH_OTSUを足したときは第3引数の値が無視され、算出されたしきい値が第1戻り値として返ってきます。

import cv2

img = cv2.imread("sample.png", cv2.IMREAD_GRAYSCALE)

# 固定しきい値:128で切る
_, fixed = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY)

# 大津の手法:第3引数は無視され、算出値が t に入る
t, otsu = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
print("otsu threshold:", t)

第3引数へ0を渡すのは、無視される値だからという慣習です。意味のある数字を書くと読み手が固定しきい値と誤読する。tを捨てずにログへ残すと、後日の調査で「その画像で何が起きたか」を追えます。二値化後の画像だけ保存して算出値を捨てる実装は多いのですが、原因究明に効くのは数値です。

cv2.adaptiveThresholdのblockSizeとCが結果を動かす仕組み

adaptiveThresholdは引数を7つ取ります。blockSizeが近傍の一辺で、ヘッダには「3、5、7と続く」と書かれているとおり奇数を渡します。Cは平均または加重平均から引く定数で、公式ヘッダは「通常は正だがゼロや負でもよい」と明記されている。

import cv2

img = cv2.imread("doc.png", cv2.IMREAD_GRAYSCALE)
blur = cv2.GaussianBlur(img, (5, 5), 0)

dst = cv2.adaptiveThreshold(
    blur, 255,
    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
    cv2.THRESH_BINARY,
    31,   # blockSize:奇数。文字サイズより大きく取る
    10,   # C:大きくするほど背景側へ倒れる
)
cv2.imwrite("out.png", dst)

2つの引数の役割は単純です。blockSizeは「どれだけ広く周囲を見るか」で、対象の文字や欠陥より小さくすると内側だけで明暗を比べることになり、輪郭だけ残って中身が抜けます。文字高の2倍から3倍が出発点。Cは「どれだけ背景側に倒すか」で、上げれば背景のざらつきが消える代わりに細い線が痩せて切れ、0や負では拾いすぎます。実画像を10枚ほどで総当たりに確かめるのが近道です。

Otsuは8ビットと16ビットの単チャンネルのみという入力の制約

見落とされやすいのが入力型の制限です。OpenCVのヘッダには「現時点でOtsuの手法はCV_8UC1とCV_16UC1にのみ実装され、Triangleの手法はCV_8UC1にのみ実装されている」と注記されています。threshold自体はCV_8U・CV_16S・CV_16U・CV_32F・CV_64Fの複数チャンネルを受けますが、自動しきい値のフラグを足した瞬間に条件が狭まる構造です。

adaptiveThresholdの制約はさらに厳しく、入力は8ビット単チャンネル限定。thresholdTypeもTHRESH_BINARYかTHRESH_BINARY_INVに限られます。16ビットの産業用カメラ画像を渡してエラーになるのは、この制限に触れているからです。境界の画素はBORDER_REPLICATEとBORDER_ISOLATEDの組み合わせで処理されるため、端に対象物が接する検査では挙動を実測してください。

どちらでも分離しきれない劣化文書には、opencv_contribのximgprocにあるniBlackThresholdがあります。LocalBinarizationMethodsはNIBLACK(値0)、SAUVOLA(値1)、WOLF(値2)、NICK(値3)。本体には含まれず、opencv-contrib-pythonの導入が前提です。

二値化の前に置くノイズ除去と後に置くモルフォロジー処理の並べ方

二値化は単体で使う処理ではありません。前にぼかしを置き、後ろに形状の整形を置く。この3点セットで初めて実用的な結果になります。

二値化の前にぼかしを掛けて孤立した画素が暴れるのを抑える理由

センサーノイズで1画素だけ極端に明るい点があると、その点だけが白く残ります。二値化した後では本物の対象なのかノイズなのかを判別できないため、平滑化は前に置くのが順序です。cv2.GaussianBlurは全体をなめらかにする代わりに輪郭も少し鈍る。cv2.medianBlurは周囲の中央値で置き換えるため、ごま塩状のノイズを消しつつ輪郭を保てます。スキャン画像の点状ノイズなら中央値フィルタ、細かなざらつきならガウシアンから。カーネルを上げすぎると細い文字まで消えるので、3や5から始めます。

二値化の後にオープニングとクロージングで形の欠けと点を整える

二値化の結果には、背景に残った小さな白点と対象の内側に空いた黒い穴が付きものです。これを直すのがモルフォロジー処理で、収縮してから膨張するオープニングが白点を消し、膨張してから収縮するクロージングが穴を埋めます。

import cv2

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
opened = cv2.morphologyEx(dst, cv2.MORPH_OPEN, kernel)
closed = cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel)

カーネルは消したいノイズの大きさに合わせます。3×3で消えない点を追って5×5、7×7と上げると、細い線や小さな欠陥まで一緒に消える。「消したいものの最大サイズ」と「残したいものの最小サイズ」の間にカーネルが収まるかを先に確かめてください。重なっていれば分離できず、解像度か照明の見直しが要ります。

OCRの前処理として自前の二値化を掛けるべきかどうかを見極める基準

ここが実務でいちばん効く分岐です。読取率が上がらないときに前処理として二値化を自前で組む判断は、エンジンによっては逆効果になります。OCR全体の工程・種類・エンジン選定はOCRとは?光学文字認識の仕組み・種類・精度と実装での組み込み方を解説にまとめてあるので、ここでは二値化を渡すかどうかだけを扱います。

Tesseractは内部でOtsuを掛けるため前処理が二重になりやすい

Tesseractの公式ドキュメントImproveQuality.mdは「Tesseractはこれを内部で行う(Otsuアルゴリズム)が、ページ背景の濃さが不均一な場合は結果が不十分になりうる」と述べています。つまり二値化していない画像を渡しても、エンジン内部では必ず二値化されている。自前でadaptiveThresholdを掛けて渡すと、その結果へさらにOtsuが掛かります。

0と255しかない画像へOtsuを掛けても結果は変わらないため、致命的な破壊は起きません。問題は、自前の二値化で文字が痩せた・切れたという欠落がエンジンへ渡る前に確定することです。階調が残っていれば拾えた薄い文字が前処理で消える。読取率が落ちたときに辞書やモデルを疑うと、原因にたどり着けません。

thresholding_methodでSauvolaへ切り替える設定と既定値の中身

背景の濃さが不均一な帳票で読取率が伸びない場合、手を入れる先はTesseract側の設定です。公式ドキュメントは「Tesseract 5.0.0でLeptonicaベースの二値化手法が2つ(Adaptive OtsuとSauvola)追加された」と記載。ソースを追うとthresholding_methodの既定値はOtsuで、説明文は「0 = Otsu, 1 = LeptonicaOtsu, 2 = Sauvola」。Sauvola選択時は内部でpixSauvolaBinarizeTiledが呼ばれます。

tesseract input.png out -l jpn -c thresholding_method=2

Sauvola側で効くパラメータは2つです。thresholding_window_sizeは局所統計を測る窓のサイズで既定値0.33、これに画像のDPIを乗じた値が窓幅になります。thresholding_kfactorは分散に応じてしきい値を下げる係数で既定値0.34。DPIに連動するため、入力画像の解像度を偽ると窓幅もずれる点は注意してください。同ドキュメントが300dpi以上を推奨するのは、この窓幅にも効くからです。

クラウドOCRのAPIへ送る画像を二値化しないほうがよい理由

クラウドOCRのAPIは内部の前処理が非公開のブラックボックスです。多くは学習ベースの認識器で、階調やわずかな色情報を手がかりにしている可能性がある。ここへ二値化済みの画像を送ると、こちらが選んだ手法の失敗がそのまま渡ります。

判断としては、クラウドOCRには原則としてカラーかグレースケールのまま送り、傾き補正と解像度の調整だけを自前で行うのが安全側です。自前の二値化が効くのは、固定帳票で罫線や枠を自前で検出し、切り出した領域だけをエンジンへ渡す構成のとき。目的が文字認識ではなくレイアウト解析にあるケースです。

外観検査で二値化が効く条件と別の検査手法へ切り替える境界の見極め

外観検査は、二値化が素直に働く領域です。照明・カメラ・治具を設計できるため、固定しきい値で面積や個数を数える構成が今も通用します。二値化で押し切れる検査と学習ベースへ回すべき検査の切り分けは、画像検査の検査タスク別アルゴリズム選定と精度評価の置き方にまとめました。その照明・カメラ・治具をどう選ぶかは外観検査装置とは?カメラ・レンズ・照明の構成と選定基準を実装目線で解説にまとめました。検査全体の導入判断や手法の選択はAI外観検査とは?仕組み・ルールベースとの違いと導入判断を解説にまとめてあるため、ここでは二値化がどこで破綻するかに絞ります。二値化した画像で部品の有無や位置を照合する後段には、テンプレートマッチングの仕組みと類似度指標の選び方を組み合わせます。

照明ムラと影と低コントラストのどれが崩れると二値化は破綻するか

二値化を壊す要因は3つに整理できます。1つ目は照明ムラで、画面内に明るさの勾配があると全体で1つのしきい値が置けなくなる。これは適応的二値化で吸収できる範囲です。2つ目は影。対象の立体形状が作る影は欠陥と同じ暗い領域として写るため、しきい値をどう選んでも区別できません。処理では解けず、リング照明や同軸落射照明といった光学系の設計で消す問題になります。

3つ目が低コントラスト。透明フィルムの傷や白い部材の上の白い異物のように、明るさの差がノイズの振れ幅と同程度しかない対象です。ここが最も判断を誤りやすい。パラメータをいくら調整しても、数値として差が存在しない対象は分離できません。ヒストグラムを描いて山が1つしか無いなら、調整の時間は成果につながらないと判断してください。

二値化で粘る範囲と検査の設計そのものをやり直す分岐点の見極め

撤退ラインを先に決めておくと開発が長引きません。照明を変えて対象と背景の画素値の差が20階調以上あるなら、二値化とモルフォロジー処理で作り込む価値がある。ここに届くなら、判定基準が数値で残るルールベースのほうが保守も検証も軽く済みます。

逆に、照明を変えても差が10階調前後にとどまる、欠陥の見た目が個体ごとに変わる、良品側のばらつきが欠陥より大きい。この3つのいずれかに当たったら、作り込みを打ち切る局面です。選択肢は光学系を変えて差を作る(偏光板・波長・照明角度)か、学習ベースへ切り替えるかの2つ。前者が安く速く終わることが多く、画像処理の前に照明を疑うのが順序として正しい。切り替え先を古典側の別手法にするか学習ベースにするかは、画像処理AIとは?古典的手法とディープラーニングの使い分けを実装判断で解説の3軸で切り分けてください。

二値化を自社システムへ組み込むときの実装範囲と外部委託の線引き

どこまで自前で書き、どこから外へ出すかを整理します。

自社で実装できる範囲と外部へ回したほうが早い範囲の切り分け方

自社で完結させやすいのは、撮影条件が固定でき、対象が単純な形状で、判定が面積や個数で表せる場合です。ここまでならOpenCVのthresholdとモルフォロジー処理の組み合わせで足り、実装も検証も自チームで回せます。

一方で外へ出したほうが早いのは次の場面です。帳票が数十種類あり様式ごとに前処理を作り分ける。撮影環境が現場任せで照明設計から見直す。読取率の目標値が業務要件として決まっている。いずれも二値化のパラメータ調整ではなく前処理・エンジン選定・業務フローをまとめて設計し直す作業です。帳票のOCR化でこの規模に踏み込むなら、AI-OCR導入支援のように前処理の設計とエンジン選定を含めて相談できる体制のほうが、社内で試行を繰り返すより到達が早くなります。

分かれ目は「二値化が主題かどうか」です。主題なら自前で十分に戦えます。調整しても届かないなら、それは二値化ではなく撮影か構成の問題として扱ってください。

よくある質問

二値化とグレースケール変換は何が違いますか?

グレースケール変換は色情報を落として明るさだけの画像にする処理で、画素値は0から255の階調を保ちます。二値化はその階調を0と255の2値へ落とす処理で、順序はグレースケール変換が先です。

大津の二値化はどんな画像で失敗しますか?

明暗のヒストグラムが二山に分かれていない画像です。白紙に近いページ、明るさの勾配がある照明ムラの画像、対象と背景の明るさが近い低コントラストの画像では算出値が意味を持ちません。算出値をログに残し、想定範囲外を弾く仕組みを置いてください。

適応的二値化のblockSizeはどう決めればよいですか?

奇数が前提で、対象物より大きく取ります。文書なら文字高の2倍から3倍が出発点。小さすぎると内側だけで明暗を比較して中身が抜け、大きすぎると全体を1つのしきい値で切るのと変わりません。定数Cと合わせて実画像で確かめてください。

OCRの前に二値化してから渡すべきですか?

Tesseractは内部でOtsuの二値化を行うため、自前で二値化した画像を渡すと処理が二重になります。背景の濃さが不均一で読めない場合はthresholding_methodをSauvola(値2)へ切り替える設定変更から試してください。クラウドOCRには原則グレースケールかカラーのまま送るほうが安全です。

16ビットの画像に大津の二値化は使えますか?

OpenCVのヘッダによれば、OtsuはCV_8UC1とCV_16UC1で実装されているため16ビットの単チャンネルでも使えます。Triangleの手法はCV_8UC1のみ。ただしadaptiveThresholdは8ビット単チャンネル限定なので、16ビットの産業用カメラ画像は事前に8ビットへ変換してください。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

ほか 1 件の記事からもリンクされています。

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.06 テックブログ 大和証券の不正アクセスと約11万人分の口座番号:問い合わせ管理の委託先に残さない設計
  2. 2026.10.06 テックブログ 焼肉きんぐの不正アクセスと1,078万件の会員情報|全件規模の流出を防ぐAPIとログの点検
  3. 2026.10.06 テックブログ 原子力研究開発機構の不正アクセスと身分証画像の漏えい|研究支援サイトのファイル保管を点検する手順
  4. 2026.10.04 テックブログ デジタル庁GSSの不正アクセスと約24.6万件|CVSS中のVPN脆弱性を何で優先するか
  5. 2026.10.01 テックブログ AWS VPN Clientの使い方:6.x系のインストールとCLI・接続できない時の確認先

RELATED POSTS 関連記事

目次