cv::minMaxLoc の使い方【OpenCV/C++】〜最大値・最小値と位置を求める〜

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

cv::minMaxLoc の使い方【OpenCV/C++】〜最大値・最小値と位置を求める〜

cv::minMaxLoc は、cv::Mat 内の最小値・最大値とそれぞれの座標を一度に取得する関数です。輝度検査やテンプレートマッチングの結果解析など、画像処理の現場で頻繁に登場します。

最小限の呼び出し方は以下のとおりです。

double minVal, maxVal;
cv::Point minLoc, maxLoc;
cv::minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc);

動作環境

  • OpenCV 4.x
  • コンパイル例: g++ -std=c++17 main.cpp $(pkg-config --cflags --libs opencv4)

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

基本の使い方

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

int main()
{
    // グレースケールで読み込む(minMaxLoc はシングルチャンネルが前提)
    cv::Mat src = cv::imread("input.png", cv::IMREAD_GRAYSCALE);
    if (src.empty()) {
        std::cerr << "画像を読み込めませんでした" << std::endl;
        return 1;
    }

    double minVal, maxVal;
    cv::Point minLoc, maxLoc;

    // 最小値・最大値とその座標を取得
    cv::minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc);

    std::cout << "最小値: " << minVal << "  座標: " << minLoc << std::endl;
    std::cout << "最大値: " << maxVal << "  座標: " << maxLoc << std::endl;

    return 0;
}

実行結果(例):

最小値: 3  座標: [42, 17]
最大値: 251  座標: [128, 64]

各行の解説

  • cv::IMREAD_GRAYSCALE — minMaxLoc はシングルチャンネル cv::Mat を要求するため、グレースケールで読み込むか、事前に変換が必要です。
  • cv::minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc) — 5番目・6番目の引数に cv::Point* を渡すと座標も得られます。座標が不要なら nullptr を渡せます。
  • 結果の cv::Point は (x, y) = (列, 行) の順です。配列アクセス src.at<uchar>(maxLoc.y, maxLoc.x) と対応させる際に混同しやすいので注意してください。

引数と戻り値

引数 型 説明
src cv::InputArray 入力配列。シングルチャンネルのみ対応
minVal double* 最小値の格納先。不要なら nullptr
maxVal double* 最大値の格納先。不要なら nullptr
minLoc cv::Point* 最小値の座標の格納先。不要なら nullptr
maxLoc cv::Point* 最大値の座標の格納先。不要なら nullptr
mask cv::InputArray 処理対象領域を限定するマスク(省略可・デフォルト: cv::noArray())

戻り値: void

実践例

1. マスクを使って ROI 内の最大輝度点を探す

検査対象の領域だけを対象にしたい場合、マスクを活用します。

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

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

    // ROI 領域だけを有効にするマスクを作成
    cv::Mat mask = cv::Mat::zeros(src.size(), CV_8UC1);
    cv::Rect roi(50, 50, 200, 150);
    mask(roi) = 255;

    double minVal, maxVal;
    cv::Point minLoc, maxLoc;

    // マスク内だけで最小・最大を探索
    cv::minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc, mask);

    std::cout << "ROI内 最大値: " << maxVal << "  座標: " << maxLoc << std::endl;

    // 最大値の点に円を描いて確認
    cv::Mat disp;
    cv::cvtColor(src, disp, cv::COLOR_GRAY2BGR);
    cv::circle(disp, maxLoc, 8, cv::Scalar(0, 0, 255), 2);
    cv::imwrite("result.png", disp);

    return 0;
}

2. 差分画像の最大変化点を検出する

cv::absdiff で求めた差分画像に minMaxLoc を組み合わせると、フレーム間の最大変化点を素早く特定できます。

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

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

    // 差分画像を生成
    cv::Mat diff;
    cv::absdiff(frame1, frame2, diff);

    double minVal, maxVal;
    cv::Point minLoc, maxLoc;
    cv::minMaxLoc(diff, &minVal, &maxVal, &minLoc, &maxLoc);

    std::cout << "最大差分値: " << maxVal << "  座標: " << maxLoc << std::endl;

    // 最大変化点をマーキング
    cv::Mat result;
    cv::cvtColor(diff, result, cv::COLOR_GRAY2BGR);
    cv::circle(result, maxLoc, 10, cv::Scalar(0, 255, 0), 2);
    cv::imwrite("diff_result.png", result);

    return 0;
}

maxVal がしきい値を超えている場合にアラートを出す、という検査ロジックに自然につながります。

つまずきポイント

⚠️ マルチチャンネル画像を渡すと assertion エラー

cv::minMaxLoc にカラー画像(CV_8UC3 等)をそのまま渡すと実行時に assertion が発生します。

OpenCV Error: Assertion failed (cn == 1) in minMaxLoc

cv::cvtColor でグレースケール変換するか、cv::split でチャンネルを分離してから渡してください。チャンネルごとの最大値が必要な場合は cv::minMaxIdx との組み合わせを検討します。

⚠️ Point の (x, y) と at(row, col) の軸が逆

maxLoc.x は列方向(横)、maxLoc.y は行方向(縦)です。ピクセル値を at で取り出す際は次のように書きます。

uchar val = src.at<uchar>(maxLoc.y, maxLoc.x);  // 正しい順序

at<uchar>(maxLoc.x, maxLoc.y) と書くと、境界外アクセスやズレた画素を参照してしまいます。

⚠️ 浮動小数点 Mat での値のスケールに注意

CV_32F や CV_64F の cv::Mat(cv::normalize で [0.0, 1.0] に正規化した画像など)でも minMaxLoc は正しく動作しますが、CV_8U に変換した後に呼ぶと値が 0〜255 にスケールされている点を忘れがちです。検査値を数値として使う場合は変換前の Mat に対して呼ぶようにしましょう。

関連する関数

まとめ

cv::minMaxLoc はシングルチャンネルの cv::Mat に対して最小値・最大値とその座標を一度に返します。マスクを活用すれば ROI 内に絞った探索も簡単です。マルチチャンネル画像への誤適用と Point(x, y) の軸順だけ押さえておけば、実務での利用で困ることはほぼありません。

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

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

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

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