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::minMaxLoc — 最小値・最大値とその位置を取得する
- cv::countNonZero — 非ゼロ画素数のカウント(マスク画素数の確認にも使える)
- cv::absdiff の使い方【OpenCV/C++】〜差分画像を作る〜 — 差分画像に対して
meanStdDevを適用することが多い - cv::add / addWeighted の使い方【OpenCV/C++】〜画像の加算・ブレンド合成〜 — 統計量を使ってレベル補正する際に併用
まとめ
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仕様書・サンプルコード

