Mat ROI の使い方【OpenCV/C#(OpenCvSharp)】〜画像の一部領域を切り出す〜
OpenCvSharp では Mat.SubMat() を使うと、画像の任意の矩形領域(ROI: Region of Interest)をゼロコピーで参照できます。切り出した領域への書き込みは元の Mat に反映されるため、部分処理・部分コピーの両方に活用できます。
最小コードのイメージ:
using var roi = src.SubMat(new Rect(x, y, width, height));
動作環境
- OpenCV 4.x(OpenCvSharp4)
- .NET 8 コンソールアプリ
- NuGet:
OpenCvSharp4+OpenCvSharp4.runtime.win(Windows実行時)
環境構築がまだの方は環境構築ガイドを先にどうぞ。
基本の使い方
using OpenCvSharp;
// 画像を読み込む
using var src = Cv2.ImRead("input.jpg");
if (src.Empty()) throw new Exception("画像が読み込めませんでした");
// ROI を Rect で指定して切り出す(ゼロコピー参照)
var roi = new Rect(100, 80, 200, 150); // x, y, width, height
using var roiMat = src.SubMat(roi);
// ROI を独立した Mat にコピーして保存する
using var cropped = roiMat.Clone();
Cv2.ImWrite("cropped.jpg", cropped);
Console.WriteLine($"元画像サイズ : {src.Width} x {src.Height}");
Console.WriteLine($"切り出しサイズ: {cropped.Width} x {cropped.Height}");
実行すると次のように表示されます:
元画像サイズ : 640 x 480
切り出しサイズ: 200 x 150
コードのポイント
| 行 | 解説 |
|---|---|
src.SubMat(roi) |
元 Mat のメモリを参照するビューを返す。コピーは発生しない |
roiMat.Clone() |
独立したメモリを持つ新しい Mat を作る。ファイル保存や別処理に渡す際に必須 |
using による解放 |
SubMat() が返す Mat も IDisposable。using を忘れるとネイティブメモリが漏れる |
引数と戻り値
Mat.SubMat(Rect roi)
| パラメータ | 型 | 説明 |
|---|---|---|
roi |
Rect |
切り出す矩形(x, y, width, height) |
| 戻り値 | Mat |
元 Mat を参照するビュー Mat |
Mat.SubMat(Range rowRange, Range colRange) (行・列レンジ指定)
| パラメータ | 型 | 説明 |
|---|---|---|
rowRange |
Range |
行方向の範囲(y 方向) |
colRange |
Range |
列方向の範囲(x 方向) |
| 戻り値 | Mat |
元 Mat を参照するビュー Mat |
// Rect 指定と等価な書き方
using var roiMat = src.SubMat(new Range(80, 230), new Range(100, 300));
⚠️ Rect が画像サイズをはみ出す場合は実行時例外になります。事前に境界チェックを行ってください。
実践例
例1: 検出領域を切り出してグレースケール処理する
物体検出で得た矩形を ROI として切り出し、そこだけ色変換する典型パターンです。
using OpenCvSharp;
using var src = Cv2.ImRead("scene.jpg");
if (src.Empty()) throw new Exception("画像が読み込めませんでした");
// 仮の検出結果(実際は物体検出の出力を使う)
var detectedRect = new Rect(50, 50, 120, 100);
// 画像境界をクランプして安全にROIを作る
var safeRect = new Rect(
Math.Max(0, detectedRect.X),
Math.Max(0, detectedRect.Y),
Math.Min(detectedRect.Width, src.Width - detectedRect.X),
Math.Min(detectedRect.Height, src.Height - detectedRect.Y)
);
using var roiView = src.SubMat(safeRect);
// ROI だけグレースケール変換して保存
using var gray = new Mat();
Cv2.CvtColor(roiView, gray, ColorConversionCodes.BGR2GRAY);
Cv2.ImWrite("roi_gray.jpg", gray);
Console.WriteLine("ROI のグレースケール画像を保存しました");
Cv2.CvtColor の詳細はCv2.CvtColor の使い方【OpenCV/C#】色空間をグレースケール・HSVに変換するを参照してください。
例2: ROI に矩形を書き込んで元画像に反映する
SubMat() はビュー参照なので、ROI への描画は元 Mat に直接反映されます。
using OpenCvSharp;
using var src = Cv2.ImRead("input.jpg");
if (src.Empty()) throw new Exception("画像が読み込めませんでした");
var targetRect = new Rect(100, 100, 200, 150);
// ROI を参照(Clone しない → 元画像と共有)
using var roiView = src.SubMat(targetRect);
// ROI 内に枠を描画 → src に反映される
// ROI 内の座標系は (0,0) 起点になる
Cv2.Rectangle(roiView, new Rect(0, 0, roiView.Width, roiView.Height),
new Scalar(0, 0, 255), 3);
// 結果を保存
Cv2.ImWrite("output_with_rect.jpg", src);
Console.WriteLine("ROI に矩形を描画して保存しました");
Cv2.Rectangle の使い方はCv2.Rectangle の使い方【OpenCV/C#】〜画像に矩形を描画する〜で詳しく解説しています。
また、処理結果の保存についてはCv2.ImWrite の使い方【OpenCV/C#】〜画像をファイルに保存する〜もあわせてご覧ください。
つまずきポイント
⚠️ SubMat() の戻り値も using で解放する
SubMat() が返す Mat はネイティブリソースを持つため、using で解放しないとメモリリークします。「ビューだから解放不要」という勘違いが多いので注意してください。
// NG: using なし
var roiMat = src.SubMat(rect); // Dispose されない
// OK
using var roiMat = src.SubMat(rect);
⚠️ ROI を独立して使うなら Clone() が必須
SubMat() はビューのため、元 Mat を Dispose すると ROI も無効になります。元画像のライフタイムと切り離したい場合は必ず .Clone() で独立コピーを作ってください。
using var roiMat = src.SubMat(rect).Clone(); // 独立したメモリ
⚠️ Rect が画像境界をはみ出すと即例外
C# の場合、はみ出した Rect を渡すと実行時に OpenCVException が発生します。Python のようにスライスが自動クランプされる挙動はありません。実務では Math.Min / Math.Max でのクランプ処理を必ず実装してください(実践例1を参照)。
関連する関数
- Mat の基本操作: Mat の使い方【OpenCV/C#(OpenCvSharp)】作成・初期化・基本操作
- 画像読み込み: Cv2.ImRead の使い方【OpenCV/C#(OpenCvSharp)】〜画像ファイルを読み込む〜
Mat.CopyTo(): ROI に別画像を貼り付ける際に組み合わせて使う関数Cv2.Resize(): 切り出した ROI をリサイズする際によく使う
まとめ
Mat.SubMat(Rect)で画像の矩形領域をゼロコピーで参照できる。- 元画像と切り離して扱う場合は
.Clone()を忘れずに。 SubMat()の戻り値もIDisposableなのでusingで解放する。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。

