cv::mean / meanStdDev の使い方【OpenCV/C++】〜平均・標準偏差を求める〜

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

cv::mean / meanStdDev の使い方【OpenCV/C++】〜平均・標準偏差を求める〜

画像の明るさのばらつきや品質評価など、「画素値の統計量」が必要な場面は多い。cv::mean でチャンネルごとの平均値を、cv::meanStdDev で平均と標準偏差を同時に取得できる。

// 平均だけ取得
cv::Scalar avg = cv::mean(src);

// 平均と標準偏差を同時取得
cv::Mat mean, stddev;
cv::meanStdDev(src, mean, stddev);

動作環境

項目 内容
OpenCV 4.x
言語 C++17
ビルド例 g++ -std=c++17 main.cpp \pkg-config –cflags –libs opencv4“

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


基本の使い方

cv::mean

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

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

    // 画像全体の平均画素値を取得
    cv::Scalar avg = cv::mean(src);

    // グレースケールは [0] のみ有効
    std::cout << "平均画素値: " << avg[0] << std::endl;

    return 0;
}

実行結果(例):

平均画素値: 127.432

cv::Scalar は最大4要素(チャンネル数分)を保持します。グレースケールなら [0]、BGR画像なら [0]=B, [1]=G, [2]=R に値が入ります。


cv::meanStdDev

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

int main()
{
    cv::Mat src = cv::imread("sample.png", cv::IMREAD_COLOR);
    if (src.empty()) {
        std::cerr << "画像を読み込めませんでした" << std::endl;
        return 1;
    }

    // 平均と標準偏差を計算(戻り値は CV_64F の 1列 Mat)
    cv::Mat mean, stddev;
    cv::meanStdDev(src, mean, stddev);

    std::cout << "チャンネル  平均     標準偏差" << std::endl;
    const char* ch_name[] = {"B", "G", "R"};
    for (int i = 0; i < src.channels(); ++i) {
        std::cout << ch_name[i] << "  "
                  << mean.at<double>(i) << "  "
                  << stddev.at<double>(i) << std::endl;
    }

    return 0;
}

実行結果(例):

チャンネル  平均     標準偏差
B  112.341  45.821
G  130.027  42.193
R  98.654   51.076

mean と stddev はいずれも CV_64F 型の (channels × 1) Mat です。at<double>(i) でチャンネルごとの値を取り出せます。


引数と戻り値

cv::mean

引数/戻り値 型 説明
src cv::InputArray 入力画像(1〜4チャンネル・任意深度)
mask cv::InputArray (省略可)有効画素を示すマスク(CV_8U・非ゼロが対象)
戻り値 cv::Scalar チャンネルごとの平均値(最大4要素)

cv::meanStdDev

引数 型 説明
src cv::InputArray 入力画像(1〜4チャンネル・任意深度)
mean cv::OutputArray 出力: チャンネルごとの平均(CV_64F, channels×1)
stddev cv::OutputArray 出力: チャンネルごとの標準偏差(CV_64F, channels×1)
mask cv::InputArray (省略可)有効画素を示すマスク(CV_8U・非ゼロが対象)

実践例

実践例1: ROI(関心領域)を限定して統計量を取る

画像全体ではなく特定領域だけを評価したい場面は頻繁にあります。cv::Rect でROIを切り出すか、マスクを使う方法があります。

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

int main()
{
    cv::Mat src = cv::imread("sample.png", cv::IMREAD_GRAYSCALE);
    if (src.empty()) {
        std::cerr << "画像を読み込めませんでした" << std::endl;
        return 1;
    }

    // 画像中央の 100x100 領域だけを評価
    int cx = src.cols / 2;
    int cy = src.rows / 2;
    cv::Rect roi(cx - 50, cy - 50, 100, 100);

    // ROI はメモリコピーなしのビュー(浅いコピー)
    cv::Mat roi_mat = src(roi);

    cv::Mat mean, stddev;
    cv::meanStdDev(roi_mat, mean, stddev);

    std::cout << "ROI 平均: " << mean.at<double>(0)
              << "  標準偏差: " << stddev.at<double>(0) << std::endl;

    return 0;
}

実行結果(例):

ROI 平均: 135.214  標準偏差: 30.572

実践例2: マスクを使って特定領域の統計量を取る

円形マスクなど、cv::Rect で切り出せない形状にはマスクが有効です。cv::mean / cv::meanStdDev どちらも第3引数にマスクを渡せます。

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

int main()
{
    cv::Mat src = cv::imread("sample.png", cv::IMREAD_GRAYSCALE);
    if (src.empty()) {
        std::cerr << "画像を読み込めませんでした" << std::endl;
        return 1;
    }

    // 円形マスクを作成(中心・半径を指定)
    cv::Mat mask = cv::Mat::zeros(src.size(), CV_8U);
    cv::Point center(src.cols / 2, src.rows / 2);
    int radius = std::min(src.cols, src.rows) / 4;
    cv::circle(mask, center, radius, cv::Scalar(255), -1); // 塗りつぶし

    // マスクが非ゼロの画素のみ集計
    cv::Scalar avg = cv::mean(src, mask);
    std::cout << "円形領域の平均画素値: " << avg[0] << std::endl;

    cv::Mat mean, stddev;
    cv::meanStdDev(src, mean, stddev, mask);
    std::cout << "円形領域の標準偏差: " << stddev.at<double>(0) << std::endl;

    return 0;
}

実行結果(例):

円形領域の平均画素値: 141.083
円形領域の標準偏差: 28.441

マスク画像の作り方はcv::bitwise_and の使い方【OpenCV/C++】〜ビット演算とマスク処理〜も参考になります。

また、差分画像の品質評価に cv::meanStdDev を組み合わせることも多く、cv::absdiff の使い方【OpenCV/C++】〜差分画像を作る〜と合わせると実務で役立ちます。


つまずきポイント

⚠️ meanStdDev の出力は cv::Scalar ではなく cv::Mat

cv::mean の戻り値は cv::Scalar ですが、cv::meanStdDev の出力引数は cv::Mat(CV_64F)です。cv::Scalar で受け取ろうとするとコンパイルエラーになります。

// NG: Scalar で受け取ろうとしている
cv::Scalar mean, stddev;
cv::meanStdDev(src, mean, stddev); // エラー

// OK
cv::Mat mean, stddev;
cv::meanStdDev(src, mean, stddev);

⚠️ at の型指定を間違える

meanStdDev の出力 Mat は常に CV_64F(double)です。float や uchar で at<> を呼ぶと実行時にアサーションエラーになります。

// NG
float val = mean.at<float>(0);

// OK
double val = mean.at<double>(0);

⚠️ マスクのサイズ・型が一致していないと assertion

マスクは入力画像と同じサイズかつCV_8U(1チャンネル) である必要があります。BGR画像を読み込んでそのままマスクとして渡すと、実行時に cv::Exception が発生します。マスク生成後は mask.type() == CV_8U を確認する習慣をつけましょう。


関連する関数


まとめ

  • cv::mean はチャンネルごとの平均を cv::Scalar で返す。マスク対応。
  • cv::meanStdDev は平均と標準偏差を cv::Mat(CV_64F)で同時に返す。ROI・マスク両対応。
  • 出力の型(cv::Scalar か cv::Mat か)と at<double> の使い方をしっかり押さえれば、品質評価・露出判定・異常検知など幅広い場面で即戦力になる。

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

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

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

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