cv::threshold の使い方【OpenCV/C++】〜二値化と大津の方法〜

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

cv::threshold の使い方【OpenCV/C++】〜二値化と大津の方法〜

cv::threshold は、グレースケール画像に対して閾値処理を行い、二値化やその他の画素変換を行う関数です。固定閾値を指定する方法に加え、THRESH_OTSU フラグを組み合わせると大津の方法による自動閾値算出も一発でできます。

最小の呼び出し形は次の通りです。

double retVal = cv::threshold(src, dst, thresh, maxval, type);

動作環境

  • OpenCV 4.x
  • C++17
  • ビルド例: g++ -std=c++17 main.cpp $(pkg-config --cflags --libs opencv4) -o main

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


基本の使い方

固定閾値による二値化

#include <opencv2/opencv.hpp>
#include <iostream>

int main()
{
    // グレースケールで読み込む
    cv::Mat src = cv::imread("input.png", cv::IMREAD_GRAYSCALE);
    if (src.empty()) {
        std::cerr << "画像の読み込みに失敗しました" << std::endl;
        return 1;
    }

    cv::Mat dst;
    // 閾値 128 を超えたら 255、以下は 0
    double retVal = cv::threshold(src, dst, 128.0, 255.0, cv::THRESH_BINARY);

    std::cout << "使用した閾値: " << retVal << std::endl;

    cv::imwrite("output_fixed.png", dst);
    return 0;
}

実行結果:

使用した閾値: 128

output_fixed.png に白黒二値化された画像が保存されます。固定閾値の場合、戻り値は指定した thresh がそのまま返ります。

行ごとの解説:

  • cv::imread(..., cv::IMREAD_GRAYSCALE) でグレースケールとして読み込みます。カラー画像を cv::threshold に渡すとチャンネルごとに処理されてしまうため、事前にグレースケール化するのが基本です。
  • 第3引数 thresh(128.0)が閾値、第4引数 maxval(255.0)が条件を満たした画素に書き込む値です。
  • 第5引数 typecv::THRESH_BINARY を指定すると、src(x,y) > thresh なら maxval、そうでなければ 0 になります。
  • 戻り値 retVal は大津の方法を使ったときだけ意味を持ちます(後述)。

引数と戻り値

引数 説明
src cv::InputArray 入力画像。8ビットまたは32ビット浮動小数点のシングルチャンネル推奨
dst cv::OutputArray 出力画像。src と同サイズ・同型
thresh double 閾値。THRESH_OTSU 使用時は無視される
maxval double THRESH_BINARY / THRESH_BINARY_INV で使われる最大値。通常 255.0
type int 閾値処理タイプ(下表参照)。THRESH_OTSU / THRESH_TRIANGLE とOR合成可能
type 定数 説明
cv::THRESH_BINARY src > threshmaxval、それ以外 → 0
cv::THRESH_BINARY_INV THRESH_BINARY の白黒反転
cv::THRESH_TRUNC src > threshthresh、それ以外は変更なし
cv::THRESH_TOZERO src > thresh → そのまま、それ以外 → 0
cv::THRESH_TOZERO_INV THRESH_TOZERO の反転
cv::THRESH_OTSU 大津の方法で閾値を自動決定(8ビット限定)
cv::THRESH_TRIANGLE トライアングル法で閾値を自動決定(8ビット限定)

戻り値: double 型で、実際に使用された閾値を返します。固定閾値の場合は thresh がそのまま、THRESH_OTSU の場合は自動算出された値が返ります。


実践例

大津の方法で自動二値化する

照明ムラがなく、前景と背景がある程度分離できる画像であれば、大津の方法が有効です。閾値を手動チューニングしなくてよいため、バッチ処理との相性が良好です。

#include <opencv2/opencv.hpp>
#include <iostream>

int main()
{
    cv::Mat src = cv::imread("input.png", cv::IMREAD_GRAYSCALE);
    if (src.empty()) {
        std::cerr << "画像の読み込みに失敗しました" << std::endl;
        return 1;
    }

    // ノイズを先に除去しておくと大津の精度が上がる
    cv::Mat blurred;
    cv::GaussianBlur(src, blurred, cv::Size(5, 5), 0);

    cv::Mat dst;
    // THRESH_OTSU を OR で組み合わせる。thresh 引数(0.0)は無視される
    double otsuThresh = cv::threshold(blurred, dst, 0.0, 255.0,
                                      cv::THRESH_BINARY | cv::THRESH_OTSU);

    std::cout << "大津の方法で決定した閾値: " << otsuThresh << std::endl;

    cv::imwrite("output_otsu.png", dst);
    return 0;
}

実行結果例:

大津の方法で決定した閾値: 112

算出された閾値は戻り値から取得できるため、ログに記録しておくとデバッグ時に便利です。


カラー画像を二値化する実務パターン

カラー画像をそのまま渡すのではなく、cv::cvtColor でグレースケール変換してから渡します。

#include <opencv2/opencv.hpp>
#include <iostream>

int main()
{
    // カラーで読み込む
    cv::Mat src = cv::imread("input.png", cv::IMREAD_COLOR);
    if (src.empty()) {
        std::cerr << "画像の読み込みに失敗しました" << std::endl;
        return 1;
    }

    // グレースケールに変換してから二値化
    cv::Mat gray, dst;
    cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);

    double retVal = cv::threshold(gray, dst, 0.0, 255.0,
                                  cv::THRESH_BINARY | cv::THRESH_OTSU);

    std::cout << "閾値: " << retVal << std::endl;
    cv::imwrite("output_color2bin.png", dst);
    return 0;
}

つまずきポイント

⚠️ カラー画像をそのまま渡してしまう

cv::thresholdCV_8UC3 の Mat を渡すと、3チャンネルそれぞれに対して独立に閾値処理が走ります。見た目はエラーになりませんが、期待した白黒二値画像にはなりません。必ず cv::cvtColor でグレースケール化してから渡してください。

⚠️ THRESH_OTSU は 8 ビット画像限定

CV_32F など浮動小数点型の画像に THRESH_OTSU を使うと実行時エラーになります(OpenCV 4.x 時点)。浮動小数点画像には固定閾値か THRESH_TRIANGLE を使うか、事前に convertToCV_8U に変換してください。

⚠️ imread が空 Mat を返す場合

ファイルパスが間違っていたり、実行ファイルの作業ディレクトリが想定と違う場合、imread は例外を投げずに空の Mat を返します。empty() チェックを必ず入れてください。日本語パスはプラットフォームによって扱いが異なる点にも注意が必要です。詳細はcv::imread の使い方【OpenCV/C++】〜画像ファイルを読み込む〜を参照してください。


関連する関数

  • cv::adaptiveThreshold — 局所領域ごとに閾値を変えて二値化する。照明ムラがある場合に有効
  • cv::inRange — HSV等の特定色範囲でマスクを作る際に使う
  • cv::GaussianBlur — 二値化前のノイズ除去に定番
  • cv::Canny — エッジ検出。内部的に閾値処理を伴う

Windowsで OpenCV をリンクする際に LNK2019 が出た場合は opencv_world の使い方とリンク方法【OpenCV/C++ Windows】が参考になります。


まとめ

  • cv::threshold は固定閾値・大津・トライアングル法など複数の二値化モードを1関数でカバーする。
  • 大津の方法(THRESH_OTSU)は 8 ビットグレースケール限定で、戻り値から算出された閾値を確認できる。
  • カラー画像は必ず cv::cvtColor でグレースケール変換してから渡すのが実装の基本。

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

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。

→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

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