Cv2.AdaptiveThreshold の使い方【OpenCV/C#(OpenCvSharp)】〜適応的二値化で照明ムラに強い処理を実現する〜

OpenCV for C#
📌 準備: OpenCV の環境構築がまだの方はこちら → C++ 環境構築ガイド / C#(OpenCvSharp)セットアップ

Cv2.AdaptiveThreshold は、画像内の局所的な輝度に応じて二値化の閾値を自動調整する関数です。均一な照明が確保できないシーン(文書スキャン・基板検査など)で、グローバル閾値の Cv2.Threshold より大幅に安定した結果が得られます。

最小コードはこちらです。

Cv2.AdaptiveThreshold(gray, dst, 255,
    AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, 11, 2);

動作環境

  • OpenCvSharp4(OpenCV 4.x 系)
  • NuGet: OpenCvSharp4 + OpenCvSharp4.runtime.win(Windows実行時)
  • .NET 8 コンソールアプリ(トップレベルステートメント)

環境構築がまだの方は環境構築ガイドを先にどうぞ。


基本の使い方

以下のサンプルは、グレースケール画像に対して適応的二値化を適用し、結果をファイルに保存します。

using OpenCvSharp;

// 入力画像の読み込み(グレースケール)
using var src = Cv2.ImRead("input.png", ImreadModes.Grayscale);
if (src.Empty()) throw new Exception("画像の読み込みに失敗しました");

using var dst = new Mat();

// 適応的二値化(ガウシアン重み付き局所平均を閾値として使用)
Cv2.AdaptiveThreshold(
    src,                                  // 入力(グレースケール必須)
    dst,                                  // 出力
    maxValue: 255,                        // 閾値を超えた画素に割り当てる値
    adaptiveMethod: AdaptiveThresholdTypes.GaussianC,  // 局所平均の計算方法
    thresholdType: ThresholdTypes.Binary, // 二値化タイプ
    blockSize: 11,                        // 局所領域のサイズ(奇数)
    c: 2                                  // 平均から引くオフセット値
);

// 結果を保存
Cv2.ImWrite("output_adaptive.png", dst);
Console.WriteLine("保存完了: output_adaptive.png");

実行すると output_adaptive.png が生成されます。照明ムラがある文書画像でも、文字部分が白抜き(または黒塗り)でくっきり二値化されているのが確認できます。

各引数の役割

  • blockSize: 11 — 各画素の閾値を計算する近傍領域の一辺(奇数のみ)。小さいほど細かい局所変動に追従、大きいほど大局的な明暗に対応します。
  • c: 2 — 計算した局所平均から引くオフセット。正の値にするとノイズ除去効果が増し、負にすると逆に感度が上がります。

引数と戻り値

引数名 型 説明
src Mat 入力画像(8ビットグレースケール必須)
dst Mat 出力画像(入力と同サイズ・同型)
maxValue double 条件を満たす画素に設定する値(通常 255)
adaptiveMethod AdaptiveThresholdTypes 局所平均の計算方式(下表参照)
thresholdType ThresholdTypes Binary または BinaryInv のみ有効
blockSize int 局所領域サイズ(奇数・3以上)
c double 局所平均から引くオフセット値

戻り値: なし(dst に書き込まれます)

AdaptiveThresholdTypes の選択肢

値 説明
MeanC 近傍の単純平均 − C を閾値とする
GaussianC 近傍のガウシアン重み付き平均 − C を閾値とする。エッジ付近のノイズに強い

実践例

例1: MeanC と GaussianC の比較出力

using OpenCvSharp;

using var src = Cv2.ImRead("document.png", ImreadModes.Grayscale);
if (src.Empty()) throw new Exception("画像の読み込みに失敗しました");

using var dstMean = new Mat();
using var dstGauss = new Mat();

// MeanC: 単純な局所平均を閾値に使用
Cv2.AdaptiveThreshold(src, dstMean, 255,
    AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 15, 5);

// GaussianC: ガウシアン重み付き平均を閾値に使用(エッジが滑らか)
Cv2.AdaptiveThreshold(src, dstGauss, 255,
    AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, 15, 5);

Cv2.ImWrite("result_mean.png", dstMean);
Cv2.ImWrite("result_gauss.png", dstGauss);
Console.WriteLine("比較画像を保存しました");

例2: グレースケール変換 → 二値化 → 保存のパイプライン

カラー画像を受け取り、グレースケール変換してから適応的二値化まで一気に行う典型的なパイプラインです。
グレースケール変換の詳細は Cv2.CvtColor の使い方【OpenCV/C#】色空間をグレースケール・HSVに変換する を参照してください。

using OpenCvSharp;

using var color = Cv2.ImRead("input_color.png");
if (color.Empty()) throw new Exception("画像の読み込みに失敗しました");

using var gray = new Mat();
using var binary = new Mat();

// カラー → グレースケール
Cv2.CvtColor(color, gray, ColorConversionCodes.BGR2GRAY);

// 適応的二値化(ノイズを減らしたいので blockSize を大きめに設定)
Cv2.AdaptiveThreshold(gray, binary, 255,
    AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, 21, 8);

// ファイルに保存(詳細は Cv2.ImWrite の記事を参照)
Cv2.ImWrite("binary_output.png", binary);
Console.WriteLine("二値化完了");

ファイル保存の詳細は Cv2.ImWrite の使い方【OpenCV/C#】〜画像をファイルに保存する〜 を参照してください。


つまずきポイント

⚠️ 入力画像が8ビットグレースケールでないと例外が発生する

AdaptiveThreshold はグレースケール(CV_8UC1)専用です。カラー画像(CV_8UC3)をそのまま渡すと OpenCVException がスローされます。必ず Cv2.CvtColor でグレースケールに変換してから渡してください。

// NG: カラー画像を直接渡す → 例外
Cv2.AdaptiveThreshold(colorMat, dst, 255, ...);

// OK: グレースケールに変換してから渡す
Cv2.CvtColor(colorMat, gray, ColorConversionCodes.BGR2GRAY);
Cv2.AdaptiveThreshold(gray, dst, 255, ...);

⚠️ blockSize は奇数かつ3以上でなければならない

blockSize に偶数や1を渡すと実行時に例外が発生します。コンフィグ等から動的に値を渡す場合は、必ず if (blockSize % 2 == 0) blockSize++; のような補正を入れましょう。

// NG: blockSize = 10(偶数)→ OpenCVException
Cv2.AdaptiveThreshold(gray, dst, 255, ..., blockSize: 10, c: 2);

// OK: blockSize = 11(奇数)
Cv2.AdaptiveThreshold(gray, dst, 255, ..., blockSize: 11, c: 2);

⚠️ Mat の Dispose 漏れに注意

new Mat() で生成した dst を using で囲まずに放置すると、ネイティブヒープ側のメモリが解放されません。ループ内で繰り返し呼ぶ処理では特に顕著にリークします。using var dst = new Mat(); を必ず徹底してください。


関連する関数


まとめ

Cv2.AdaptiveThreshold は、照明ムラや影のある画像に対してグローバル閾値より圧倒的に安定した二値化を提供します。blockSize と c の2パラメータを現場画像で調整するだけで実用レベルに達することが多く、文書・基板・ラベル検査などで幅広く活用できます。入力は必ず8ビットグレースケールに変換してから渡すことを忘れずに。

🛠 画像処理のプロが開発するSDK/API

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。

→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

タイトルとURLをコピーしました