Mat ROI の使い方【OpenCV/C#(OpenCvSharp)】〜画像の一部領域を切り出す〜

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

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() はビューのため、元 MatDispose すると ROI も無効になります。元画像のライフタイムと切り離したい場合は必ず .Clone() で独立コピーを作ってください。

using var roiMat = src.SubMat(rect).Clone(); // 独立したメモリ

⚠️ Rect が画像境界をはみ出すと即例外

C# の場合、はみ出した Rect を渡すと実行時に OpenCVException が発生します。Python のようにスライスが自動クランプされる挙動はありません。実務では Math.Min / Math.Max でのクランプ処理を必ず実装してください(実践例1を参照)。


関連する関数


まとめ

  • Mat.SubMat(Rect) で画像の矩形領域をゼロコピーで参照できる。
  • 元画像と切り離して扱う場合は .Clone() を忘れずに。
  • SubMat() の戻り値も IDisposable なので using で解放する。

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

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。

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

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