Cv2.BoundingRect / Cv2.MinAreaRect の使い方【OpenCV/C#(OpenCvSharp)】〜外接矩形を求める〜
輪郭(contour)に対して外接矩形を求める関数が Cv2.BoundingRect と Cv2.MinAreaRect です。前者は軸平行(水平・垂直)な矩形、後者は回転を考慮した最小面積の矩形を返します。物体検出やトリミング処理の前処理として頻繁に使われます。
// 軸平行外接矩形
Rect rect = Cv2.BoundingRect(contour);
// 最小面積外接矩形(回転あり)
RotatedRect rotRect = Cv2.MinAreaRect(contour);
動作環境
- OpenCV 4.x(OpenCvSharp4)
- .NET 8 コンソールアプリ
- NuGet:
OpenCvSharp4・OpenCvSharp4.runtime.win(Windows 実行時)
環境構築がまだの方は環境構築ガイドを先にどうぞ。
基本の使い方
以下のサンプルでは、バイナリ画像から輪郭を検出し、BoundingRect(青)と MinAreaRect(緑)をそれぞれ描画して保存します。
using OpenCvSharp;
// バイナリ画像を生成(白い矩形を斜めに傾けて描画)
using var src = new Mat(400, 600, MatType.CV_8UC3, Scalar.Black);
// 傾いた多角形を描画して「傾いた物体」を模擬する
Point[] polygon =
[
new Point(150, 80),
new Point(350, 50),
new Point(420, 200),
new Point(220, 230),
];
Cv2.FillConvexPoly(src, polygon, Scalar.White);
// グレースケール化 → 二値化
using var gray = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
using var binary = new Mat();
Cv2.Threshold(gray, binary, 128, 255, ThresholdTypes.Binary);
// 輪郭検出
Cv2.FindContours(
binary,
out Point[][] contours,
out HierarchyIndex[] hierarchy,
RetrievalModes.External,
ContourApproximationModes.ApproxSimple);
using var dst = src.Clone();
foreach (var contour in contours)
{
// --- BoundingRect: 軸平行外接矩形 ---
Rect boundingRect = Cv2.BoundingRect(contour);
Cv2.Rectangle(dst, boundingRect, Scalar.Blue, 2);
// --- MinAreaRect: 最小面積外接矩形(回転あり)---
RotatedRect rotatedRect = Cv2.MinAreaRect(contour);
// RotatedRect の4頂点を取得して描画
Point2f[] boxPoints = Cv2.BoxPoints(rotatedRect);
// float → Point に変換してポリライン描画
Point[] boxPointsInt = Array.ConvertAll(boxPoints, p => new Point((int)p.X, (int)p.Y));
Cv2.Polylines(dst, [boxPointsInt], isClosed: true, Scalar.LimeGreen, 2);
}
Cv2.ImWrite("result.png", dst);
Console.WriteLine("result.png を保存しました。");
実行すると result.png が保存され、傾いた白い図形に対して 青の軸平行矩形(BoundingRect)と 緑の回転矩形(MinAreaRect)が重ねて描画された画像が得られます。MinAreaRect の方が物体にぴったりフィットしていることが確認できます。
result.png を保存しました。
コードの要点
| 行の処理 | ポイント |
|---|---|
Cv2.FindContours |
外部輪郭のみ取得(RetrievalModes.External) |
Cv2.BoundingRect(contour) |
Rect を返す。X・Y・Width・Height をそのまま使える |
Cv2.MinAreaRect(contour) |
RotatedRect を返す。Center・Size・Angle を持つ |
Cv2.BoxPoints(rotatedRect) |
RotatedRect の4頂点(Point2f[])を取得 |
Cv2.Polylines |
4頂点を線で結んで回転矩形を描画 |
引数と戻り値
Cv2.BoundingRect
| 引数/戻り値 | 型 | 説明 |
|---|---|---|
array |
IEnumerable<Point> |
対象の輪郭点列 |
| 戻り値 | Rect |
軸平行外接矩形(X, Y, Width, Height) |
Cv2.MinAreaRect
| 引数/戻り値 | 型 | 説明 |
|---|---|---|
points |
IEnumerable<Point2f> または IEnumerable<Point> |
対象の輪郭点列 |
| 戻り値 | RotatedRect |
回転外接矩形(Center, Size, Angle) |
RotatedRect のプロパティ
| プロパティ | 型 | 説明 |
|---|---|---|
Center |
Point2f |
矩形の中心座標 |
Size |
Size2f |
矩形の幅と高さ |
Angle |
float |
回転角度(度) |
実践例
物体ごとにバウンディングボックスを切り出す
物体検出後のROI(Region of Interest)切り出しは BoundingRect が便利です。
using OpenCvSharp;
using var src = Cv2.ImRead("objects.png");
if (src.Empty()) { Console.WriteLine("画像を読み込めませんでした。"); return; }
using var gray = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
using var binary = new Mat();
Cv2.Threshold(gray, binary, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
Cv2.FindContours(
binary,
out Point[][] contours,
out _,
RetrievalModes.External,
ContourApproximationModes.ApproxSimple);
int index = 0;
foreach (var contour in contours)
{
// 小さなノイズ輪郭を除外
if (Cv2.ContourArea(contour) < 500) continue;
Rect roi = Cv2.BoundingRect(contour);
// Mat のインデクサで ROI を切り出し
using var cropped = new Mat(src, roi);
Cv2.ImWrite($"crop_{index++}.png", cropped);
}
Console.WriteLine($"{index} 個の物体を切り出しました。");
回転角度を利用した傾き補正
MinAreaRect の Angle を使って画像の傾きを補正するケースです。
using OpenCvSharp;
using var src = Cv2.ImRead("tilted_text.png");
if (src.Empty()) { Console.WriteLine("画像を読み込めませんでした。"); return; }
using var gray = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
using var binary = new Mat();
Cv2.Threshold(gray, binary, 0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);
Cv2.FindContours(
binary,
out Point[][] contours,
out _,
RetrievalModes.External,
ContourApproximationModes.ApproxSimple);
if (contours.Length == 0) { Console.WriteLine("輪郭が検出されませんでした。"); return; }
// 最大面積の輪郭を対象にする
var largest = contours.MaxBy(c => Cv2.ContourArea(c))!;
RotatedRect rotRect = Cv2.MinAreaRect(largest);
double angle = rotRect.Angle;
// OpenCV の Angle 定義: Width < Height のとき -90〜0 度
if (rotRect.Size.Width < rotRect.Size.Height)
angle += 90.0;
// 回転行列を生成して傾き補正
using var rotMat = Cv2.GetRotationMatrix2D(rotRect.Center, angle, 1.0);
using var corrected = new Mat();
Cv2.WarpAffine(src, corrected, rotMat, src.Size(), InterpolationFlags.Cubic);
Cv2.ImWrite("corrected.png", corrected);
Console.WriteLine($"補正角度: {angle:F2} 度 → corrected.png を保存しました。");
つまずきポイント
⚠️ MinAreaRect の Angle の解釈に注意
RotatedRect.Angle は OpenCV 4.x では −90 〜 0 度の範囲で返ります。矩形の幅と高さの大小関係によって「どちらが長辺か」が変わるため、傾き補正時は Width < Height かどうかを確認して角度を調整する必要があります。上記の実践例を参考にしてください。
⚠️ BoxPoints の戻り値は Point2f[] であり整数座標ではない
Cv2.BoxPoints は Point2f[] を返します。Cv2.Polylines や Cv2.FillPoly に渡すには Point[](整数)へ変換が必要です。そのまま渡そうとするとコンパイルエラーになるか、意図しない丸め誤差が生じます。
// NG: Point2f[] をそのまま Polylines に渡せない
// OK: Array.ConvertAll で Point に変換する
Point[] pts = Array.ConvertAll(boxPoints, p => new Point((int)p.X, (int)p.Y));
⚠️ 空の輪郭に対して呼び出すと例外が発生する
FindContours の結果が空配列のまま BoundingRect や MinAreaRect を呼ぶと実行時例外になります。contours.Length == 0 のチェックと、面積によるフィルタリング(Cv2.ContourArea(contour) < 閾値)を必ず入れましょう。
関連する関数
- Cv2.FindContours の使い方【OpenCV/C#(OpenCvSharp)】〜輪郭を検出する〜:外接矩形の前処理として必須の輪郭検出
- Cv2.ContourArea / Cv2.ArcLength の使い方【OpenCV/C#(OpenCvSharp)】〜輪郭の面積・周長を求める〜:ノイズ輪郭の除外に使う面積計算
- Cv2.DrawContours の使い方【OpenCV/C#(OpenCvSharp)】〜輪郭を描画する〜:矩形と合わせて輪郭を可視化するときに活用
その他、Cv2.MinEnclosingCircle(最小包含円)・Cv2.ConvexHull(凸包)も輪郭の形状記述に関連します。
まとめ
Cv2.BoundingRectは軸平行の外接矩形をRectで返す。ROI 切り出しや座標取得に最適。Cv2.MinAreaRectは回転を考慮した最小面積矩形をRotatedRectで返す。傾き補正や精密な形状解析に使う。Angleの解釈とBoxPointsの型変換は C#(OpenCvSharp)固有の落とし穴なので要注意。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。
→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード
