cv::boundingRect / cv::minAreaRect の使い方【OpenCV/C++】〜外接矩形を求める〜

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

cv::boundingRect / cv::minAreaRect の使い方【OpenCV/C++】〜外接矩形を求める〜

輪郭(コンター)に外接する矩形を求める関数が cv::boundingRectcv::minAreaRect です。前者は軸に平行な外接矩形、後者は回転を考慮した最小面積の外接矩形を返します。物体検出の後処理や ROI(関心領域)の切り出しで頻繁に使う関数です。

最小限のコードイメージはこちらです。

cv::Rect rect = cv::boundingRect(contour);          // 軸平行外接矩形
cv::RotatedRect rrect = cv::minAreaRect(contour);   // 最小面積外接矩形(回転あり)

動作環境

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

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


基本の使い方

白い矩形領域を含む画像から輪郭を検出し、2種類の外接矩形を描画する完全サンプルです。

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

int main()
{
    // テスト用画像を生成(黒背景に白い傾いた四角形)
    cv::Mat src = cv::Mat::zeros(400, 600, CV_8UC3);
    std::vector<cv::Point> poly = {
        {150, 80}, {380, 50}, {420, 250}, {120, 280}
    };
    cv::fillPoly(src, std::vector<std::vector<cv::Point>>{poly},
                 cv::Scalar(255, 255, 255));

    // グレースケール変換 → 二値化
    cv::Mat gray, bin;
    cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
    cv::threshold(gray, bin, 127, 255, cv::THRESH_BINARY);

    // 輪郭検出
    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(bin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

    if (contours.empty()) {
        std::cerr << "輪郭が検出されませんでした" << std::endl;
        return 1;
    }

    cv::Mat dst = src.clone();

    for (const auto& contour : contours) {
        // --- cv::boundingRect: 軸平行外接矩形 ---
        cv::Rect brect = cv::boundingRect(contour);
        cv::rectangle(dst, brect, cv::Scalar(0, 255, 0), 2); // 緑色

        // --- cv::minAreaRect: 最小面積外接矩形(回転あり)---
        cv::RotatedRect rrect = cv::minAreaRect(contour);

        // RotatedRect の4頂点を取得して描画
        cv::Point2f pts[4];
        rrect.points(pts);
        for (int i = 0; i < 4; ++i) {
            cv::line(dst, pts[i], pts[(i + 1) % 4],
                     cv::Scalar(0, 0, 255), 2); // 赤色
        }

        // 中心・サイズ・角度をコンソールに出力
        std::cout << "boundingRect : " << brect << std::endl;
        std::cout << "minAreaRect center : " << rrect.center
                  << "  size : " << rrect.size
                  << "  angle : " << rrect.angle << std::endl;
    }

    cv::imshow("result", dst);
    cv::waitKey(0);
    return 0;
}

実行結果

boundingRect : [302 x 232 from (118, 49)]
minAreaRect center : [269.5, 164.5]  size : [232.8, 302.1]  angle : -79.3
  • 緑の矩形cv::boundingRect(X/Y 軸に平行)
  • 赤の矩形cv::minAreaRect(形状にフィットした回転あり)

傾いた形状に対しては minAreaRect の方が面積が小さく、形状に密着します。


引数と戻り値

cv::boundingRect

引数 / 戻り値 説明
array InputArray 輪郭点群(std::vector<cv::Point> など)
戻り値 cv::Rect 軸平行外接矩形(x, y, width, height)

cv::minAreaRect

引数 / 戻り値 説明
points InputArray 輪郭点群(std::vector<cv::Point> または cv::Point2f
戻り値 cv::RotatedRect 回転外接矩形(center, size, angle を持つ)

cv::RotatedRect のメンバ

メンバ 説明
center cv::Point2f 矩形の中心座標
size cv::Size2f 矩形の幅・高さ
angle float 回転角(度)。長辺が水平から何度傾いているか
points(pts) メソッド 4頂点を cv::Point2f[4] に格納する

実践例

実践例 1: バイナリ画像から複数オブジェクトの ROI を切り出す

検査画像や OCR の前処理でよく使うパターンです。各輪郭の外接矩形で ROI を切り出し、個別に処理します。

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

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

    cv::Mat gray, bin;
    cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
    cv::threshold(gray, bin, 0, 255,
                  cv::THRESH_BINARY_INV | cv::THRESH_OTSU); // 大津の二値化

    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(bin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

    int idx = 0;
    for (const auto& c : contours) {
        // 面積が小さいノイズは除外
        if (cv::contourArea(c) < 100.0) continue;

        cv::Rect r = cv::boundingRect(c);

        // 画像範囲内に収まるようにクリップ(必須)
        r &= cv::Rect(0, 0, src.cols, src.rows);

        cv::Mat roi = src(r);
        std::string fname = "roi_" + std::to_string(idx++) + ".png";
        cv::imwrite(fname, roi);
        std::cout << "保存: " << fname << " " << r << std::endl;
    }
    return 0;
}

r &= cv::Rect(0, 0, src.cols, src.rows) で矩形を画像範囲内にクリップしています。これを忘れると範囲外アクセスで落ちます。


実践例 2: 傾きを推定して画像を正立させる

minAreaRectangle を使い、傾いた文書や部品を水平に補正します。

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

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

    cv::Mat gray, bin;
    cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
    cv::threshold(gray, bin, 127, 255, cv::THRESH_BINARY_INV);

    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(bin, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    if (contours.empty()) return 1;

    // 最大輪郭を対象にする
    auto& c = *std::max_element(contours.begin(), contours.end(),
        [](const auto& a, const auto& b){
            return cv::contourArea(a) < cv::contourArea(b);
        });

    cv::RotatedRect rrect = cv::minAreaRect(c);
    float angle = rrect.angle;

    // angle の符号・範囲は OpenCV バージョンで変わる場合がある。要確認
    std::cout << "検出角度: " << angle << " 度" << std::endl;

    // 中心を基準にアフィン回転
    cv::Mat M = cv::getRotationMatrix2D(rrect.center, angle, 1.0);
    cv::Mat dst;
    cv::warpAffine(src, dst, M, src.size(),
                   cv::INTER_LINEAR, cv::BORDER_REPLICATE);

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

つまずきポイント

⚠️ cv::RotatedRect::angle の解釈がバージョンで変わる

OpenCV 4.5 以前と以降で angle の符号や基準軸の定義が変更されています。「なぜか逆方向に回転する」という症状の原因になりがちです。実際にテスト画像で角度を確認してから補正方向を決めてください。公式のリリースノートを確認するか、実験で挙動を把握しておくのが確実です。

⚠️ cv::boundingRect で切り出した ROI が画像外にはみ出す

cv::findContours の結果はまれに画像端ギリギリの輪郭を返すことがあり、boundingRect が画像サイズを超える場合があります。r &= cv::Rect(0, 0, src.cols, src.rows) でクリップしないと src(r)assertion error で落ちます。

⚠️ cv::minAreaRect に cv::Point(整数)を渡すと精度が落ちる

minAreaRect の引数は cv::Point2f(浮動小数点)が望ましいです。cv::Point でも動作しますが、内部でキャストされるため、精密な角度推定が必要な場面では cv::MatCV_32FC2 に変換してから渡すと結果が安定します。


関連する関数

外接矩形は単体で使うより、前段の処理とセットで使います。


まとめ

  • cv::boundingRect は軸平行の外接矩形を cv::Rect で返す。ROI 切り出しに直結して使いやすい。
  • cv::minAreaRect は回転を考慮した最小面積の外接矩形を cv::RotatedRect で返す。傾き補正や形状フィッティングに有効。
  • angle の扱いと ROI の範囲クリップを押さえれば、実務でそのまま使えるレベルになる。

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

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

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

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