cv::boundingRect / cv::minAreaRect の使い方【OpenCV/C++】〜外接矩形を求める〜
輪郭(コンター)に外接する矩形を求める関数が cv::boundingRect と cv::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: 傾きを推定して画像を正立させる
minAreaRect の angle を使い、傾いた文書や部品を水平に補正します。
#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::Mat を CV_32FC2 に変換してから渡すと結果が安定します。
関連する関数
外接矩形は単体で使うより、前段の処理とセットで使います。
- cv::findContours — 外接矩形を求める前に必ず使う輪郭検出関数
- cv::contourArea — 輪郭の面積でノイズ除外するときに組み合わせる
- エッジ検出からの流れ: cv::Canny の使い方【OpenCV/C++】〜エッジ検出の基本と閾値の決め方〜
- 二値化前のノイズ除去: cv::morphologyEx の使い方【OpenCV/C++】〜オープニング・クロージングでノイズ除去〜
- 膨張・収縮で輪郭を整形してから使う場面も多い: cv::erode / cv::dilate の使い方【OpenCV/C++】〜収縮・膨張処理の基本と実践〜
まとめ
cv::boundingRectは軸平行の外接矩形をcv::Rectで返す。ROI 切り出しに直結して使いやすい。cv::minAreaRectは回転を考慮した最小面積の外接矩形をcv::RotatedRectで返す。傾き補正や形状フィッティングに有効。angleの扱いと ROI の範囲クリップを押さえれば、実務でそのまま使えるレベルになる。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。

