Cv2.Threshold の使い方【OpenCV/C#(OpenCvSharp)】〜画像を二値化する(大津の方法含む)〜

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

Cv2.Threshold の使い方【OpenCV/C#(OpenCvSharp)】〜画像を二値化する(大津の方法含む)〜

Cv2.Threshold は、グレースケール画像の各ピクセルを閾値と比較して白または黒に振り分ける二値化関数です。固定閾値による単純な二値化から、大津の方法(Otsu’s method)による自動閾値決定まで1つの関数でカバーできます。

最小構成はこうなります。

double usedThresh = Cv2.Threshold(src, dst, 128, 255, ThresholdTypes.Binary);

動作環境

項目 内容
OpenCV 4.x(OpenCvSharp4)
言語 C# / .NET 8
NuGet OpenCvSharp4 + OpenCvSharp4.runtime.win(Windows実行時)
IDE Visual Studio 2022 / VS Code など

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

基本の使い方

using OpenCvSharp;

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

using var dst = new Mat();

// 固定閾値 128 で二値化(Binary)
double usedThresh = Cv2.Threshold(src, dst, 128, 255, ThresholdTypes.Binary);

Console.WriteLine($"使用した閾値: {usedThresh}");

Cv2.ImShow("src", src);
Cv2.ImShow("threshold_binary", dst);
Cv2.WaitKey(0);
Cv2.DestroyAllWindows();

実行すると、ピクセル値が 128 以上の画素は 255(白)、128 未満は 0(黒)になった二値画像がウィンドウに表示されます。コンソールには以下のように出力されます。

使用した閾値: 128

コードのポイント

  • ImreadModes.Grayscale で読み込むことで、最初からグレースケール1チャンネルの Mat が得られます。Cv2.Threshold はグレースケール画像(または単チャンネル)に対して使うのが基本です。
  • 戻り値 double は「実際に使われた閾値」です。固定閾値モードでは指定値がそのまま返りますが、大津の方法では自動計算された閾値が返るため、ログ出力やデバッグに重宝します。
  • src・dst ともに using で確実に解放しています。これは OpenCvSharp の鉄則です。

引数と戻り値

double Cv2.Threshold(Mat src, Mat dst, double thresh, double maxval, ThresholdTypes type)
引数 型 内容
src Mat 入力画像(グレースケール推奨)
dst Mat 出力画像(サイズ・型は自動設定)
thresh double 閾値(大津・三角の場合は無視される)
maxval double 閾値を超えたピクセルに割り当てる最大値(通常 255)
type ThresholdTypes 二値化の種類(下表参照)
戻り値 double 実際に使用された閾値

ThresholdTypes の主な値

値 内容
ThresholdTypes.Binary thresh 以上 → maxval、未満 → 0
ThresholdTypes.BinaryInv Binary の反転
ThresholdTypes.Trunc thresh 以上 → thresh、未満 → そのまま
ThresholdTypes.Tozero thresh 以上 → そのまま、未満 → 0
ThresholdTypes.TozeroInv Tozero の反転
ThresholdTypes.Otsu 大津の方法で自動閾値(Binary 等と OR で組み合わせる)
ThresholdTypes.Triangle 三角アルゴリズムで自動閾値(同上)

Otsu / Triangle は単体では使えず、ThresholdTypes.Binary | ThresholdTypes.Otsu のようにビット OR で組み合わせます。

実践例

大津の方法(Otsu)で自動閾値を決定する

照明ムラのある撮影環境で閾値を手で決めるのは困難です。大津の方法はヒストグラムのクラス間分散を最大化する閾値を自動決定するため、明暗がある程度分離できている画像に有効です。

using OpenCvSharp;

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

using var dst = new Mat();

// 大津の方法:thresh 引数は無視されるので 0 を渡す
double otsuThresh = Cv2.Threshold(
    src, dst,
    thresh: 0,
    maxval: 255,
    type: ThresholdTypes.Binary | ThresholdTypes.Otsu
);

Console.WriteLine($"大津の方法で決定された閾値: {otsuThresh}");

// 結果をファイルに保存
Cv2.ImWrite("output_otsu.png", dst);

Cv2.ImShow("Otsu result", dst);
Cv2.WaitKey(0);
Cv2.DestroyAllWindows();
大津の方法で決定された閾値: 112

画像の内容によって閾値は変わります。ImWrite の使い方は Cv2.ImWrite の使い方【OpenCV/C#】〜画像をファイルに保存する〜も参照してください。

カラー画像をグレースケール変換してから二値化する

カラー画像をそのまま Cv2.Threshold に渡すと3チャンネル分に閾値処理が適用されてしまいます。意図した二値化を行うには、先にグレースケール変換が必要です。

using OpenCvSharp;

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

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

// グレースケールに変換してから二値化
Cv2.CvtColor(color, gray, ColorConversionCodes.BGR2GRAY);

double thresh = Cv2.Threshold(
    gray, binary,
    thresh: 0,
    maxval: 255,
    type: ThresholdTypes.Binary | ThresholdTypes.Otsu
);

Console.WriteLine($"閾値: {thresh}");

Cv2.ImShow("binary", binary);
Cv2.WaitKey(0);
Cv2.DestroyAllWindows();

Cv2.CvtColor の詳細は Cv2.CvtColor の使い方【OpenCV/C#】色空間をグレースケール・HSVに変換するをご覧ください。

つまずきポイント

⚠️ カラー画像(3チャンネル)をそのまま渡してしまう

Cv2.Threshold はグレースケール(1チャンネル)画像を想定した関数です。BGR 3チャンネルの Mat を渡してもエラーにはなりませんが、各チャンネル独立に閾値処理されるため、期待した二値画像にはなりません。必ず Cv2.CvtColor でグレースケールに変換してから渡してください。

⚠️ Otsu/Triangle と thresh 引数の関係を誤解する

ThresholdTypes.Otsu や ThresholdTypes.Triangle を指定した場合、thresh 引数に渡した値は完全に無視されます。自動計算された閾値は戻り値の double から取得します。逆に言えば、「大津の方法で求めた閾値を別の処理にも流用したい」ときは戻り値を使ってください。

⚠️ Mat の Dispose 漏れによるネイティブメモリリーク

Mat は C++ ネイティブの画像バッファを内部に持つため、GC 任せでは解放されません。src・dst など、すべての Mat を using で囲む習慣をつけてください。ループ処理で大量の Mat を生成する場合は特に注意が必要です。

関連する関数

  • Cv2.AdaptiveThreshold — 局所領域ごとに閾値を計算する適応的二値化。照明ムラが激しい画像に有効です。
  • Cv2.CvtColor — Cv2.CvtColor の使い方【OpenCV/C#】。二値化の前処理としてセットで使います。
  • Cv2.ImWrite — Cv2.ImWrite の使い方【OpenCV/C#】。二値化結果をファイルに保存するときに使います。
  • Cv2.InRange — 指定した色範囲のマスク生成。カラー画像の二値化的な用途に。

まとめ

Cv2.Threshold は固定閾値・大津の方法・三角法など複数の二値化モードを ThresholdTypes の指定だけで切り替えられる汎用関数です。大津の方法(ThresholdTypes.Otsu)を使えば閾値をヒューリスティックに決める手間が省け、戻り値で実際の閾値を確認・再利用できます。カラー画像は必ず事前にグレースケール変換してから渡すことと、Mat の using による解放を徹底してください。

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

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

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

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