Cv2.WarpAffine の使い方【OpenCV/C#(OpenCvSharp)】〜アフィン変換で画像を回転・平行移動する〜

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

Cv2.WarpAffine の使い方【OpenCV/C#(OpenCvSharp)】〜アフィン変換で画像を回転・平行移動する〜

Cv2.WarpAffine は、2×3のアフィン変換行列を使って画像を回転・平行移動・スケーリングなどの幾何変換を行う関数です。変換行列を差し替えるだけであらゆる線形変換に対応でき、画像の前処理ステップとして幅広く使われます。

最小の使い方はこのとおりです。

using var M = Cv2.GetRotationMatrix2D(new Point2f(cx, cy), angle, scale);
Cv2.WarpAffine(src, dst, M, dst.Size());

動作環境

  • OpenCV 4.x(OpenCvSharp4)
  • .NET 8 コンソールアプリ
  • NuGet: OpenCvSharp4 + OpenCvSharp4.runtime.win(Windows実行時)

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

基本の使い方

画像を中心を軸に 45° 回転させる完全プログラムです。

using OpenCvSharp;

// 入力画像の読み込み
using var src = Cv2.ImRead("input.jpg", ImreadModes.Color);
if (src.Empty()) throw new Exception("画像を読み込めませんでした");

// 回転の基準点を画像中央に設定
var center = new Point2f(src.Width / 2f, src.Height / 2f);
double angle = 45.0;  // 回転角度(度)。正値で反時計回り
double scale = 1.0;   // スケール倍率

// 2×3 の回転行列を生成
using var M = Cv2.GetRotationMatrix2D(center, angle, scale);

// アフィン変換を適用
using var dst = new Mat();
Cv2.WarpAffine(
    src,                         // 入力画像
    dst,                         // 出力画像
    M,                           // 2×3 変換行列
    new Size(src.Width, src.Height), // 出力サイズ
    InterpolationFlags.Linear,   // 補間方法
    BorderTypes.Constant,        // 境界処理
    Scalar.Black                 // 境界色
);

Cv2.ImWrite("output_rotate45.jpg", dst);
Console.WriteLine("保存完了: output_rotate45.jpg");

実行すると、input.jpg を中心で 45° 回転した画像が output_rotate45.jpg に保存されます。画像の角は黒で塗りつぶされます。

保存完了: output_rotate45.jpg

行ごとの解説

行 内容
GetRotationMatrix2D 中心座標・角度・スケールから 2×3 回転行列を生成
WarpAffine 第4引数 Size 出力画像のサイズ。入力と変えると切り出し・拡張が可能
InterpolationFlags.Linear バイリニア補間。品質と速度のバランスが良い
BorderTypes.Constant 変換後に生じる余白を固定色で塗る
Scalar.Black 余白色の指定(Scalar.White なども使える)

引数と戻り値

Cv2.WarpAffine

引数 型 説明
src Mat 入力画像
dst Mat 出力画像(自動でサイズ・型が設定される)
m Mat 2×3 のアフィン変換行列
dsize Size 出力画像のサイズ
flags InterpolationFlags 補間方法(省略可、デフォルト: Linear)
borderMode BorderTypes 境界処理(省略可、デフォルト: Constant)
borderValue Scalar 境界色(省略可、デフォルト: 黒)

戻り値: なし(結果は dst に格納)

Cv2.GetRotationMatrix2D

引数 型 説明
center Point2f 回転の基準点
angle double 回転角度(度)。正値が反時計回り
scale double スケール倍率

戻り値: Mat(2×3 の回転行列)

実践例

例1: 平行移動

変換行列を手動で作成して、画像を右に 100px・下に 50px 移動します。

using OpenCvSharp;

using var src = Cv2.ImRead("input.jpg", ImreadModes.Color);
if (src.Empty()) throw new Exception("画像を読み込めませんでした");

// 平行移動行列 [1, 0, tx; 0, 1, ty] を直接組み立てる
double tx = 100.0; // X 方向の移動量(ピクセル)
double ty = 50.0;  // Y 方向の移動量(ピクセル)

using var M = new Mat(2, 3, MatType.CV_64FC1);
M.At<double>(0, 0) = 1.0; M.At<double>(0, 1) = 0.0; M.At<double>(0, 2) = tx;
M.At<double>(1, 0) = 0.0; M.At<double>(1, 1) = 1.0; M.At<double>(1, 2) = ty;

using var dst = new Mat();
Cv2.WarpAffine(src, dst, M, new Size(src.Width, src.Height));

Cv2.ImWrite("output_translate.jpg", dst);
Console.WriteLine("保存完了: output_translate.jpg");

例2: 出力サイズを変えてトリミングなしの全体回転

45° 回転すると四隅が欠けます。出力サイズを大きめにとって画像全体を収めるパターンです。

using OpenCvSharp;

using var src = Cv2.ImRead("input.jpg", ImreadModes.Color);
if (src.Empty()) throw new Exception("画像を読み込めませんでした");

double angle = 45.0;
double rad = angle * Math.PI / 180.0;

// 回転後に全体が収まる出力サイズを計算
int newW = (int)(src.Width * Math.Abs(Math.Cos(rad)) + src.Height * Math.Abs(Math.Sin(rad)));
int newH = (int)(src.Width * Math.Abs(Math.Sin(rad)) + src.Height * Math.Abs(Math.Cos(rad)));

// 出力画像の中心を基準に回転行列を作成
var center = new Point2f(newW / 2f, newH / 2f);
using var M = Cv2.GetRotationMatrix2D(center, angle, 1.0);

// 平行移動成分を追加して画像が中央に来るよう調整
M.At<double>(0, 2) += (newW - src.Width) / 2.0;
M.At<double>(1, 2) += (newH - src.Height) / 2.0;

using var dst = new Mat();
Cv2.WarpAffine(src, dst, M, new Size(newW, newH),
    InterpolationFlags.Linear, BorderTypes.Constant, Scalar.White);

Cv2.ImWrite("output_fullrotate.jpg", dst);
Console.WriteLine($"出力サイズ: {newW}x{newH}");

実行すると、元画像全体が欠けなく収まった回転済み画像が保存されます。

出力サイズ: 848x848  (入力が 600x600 の場合の例)

つまずきポイント

⚠️ GetRotationMatrix2D の戻り値も using で解放する

GetRotationMatrix2D は Mat を返します。これはネイティブメモリを持つオブジェクトなので、WarpAffine に渡した後も Dispose が必要です。using var M = ... を忘れるとメモリリークになります。

// NG: Dispose されない
var M = Cv2.GetRotationMatrix2D(center, angle, 1.0);
Cv2.WarpAffine(src, dst, M, dst.Size());

// OK: using で確実に解放
using var M = Cv2.GetRotationMatrix2D(center, angle, 1.0);
Cv2.WarpAffine(src, dst, M, dst.Size());

⚠️ 角度の符号が直感と逆になる場合がある

GetRotationMatrix2D の angle は、画像座標系(Y 軸が下向き) では正値が反時計回りになります。画面上で右回り(時計回り)に回転させたい場合は angle に負値を指定してください。期待と逆に回転している場合はまずここを疑いましょう。

⚠️ 変換行列の型は CV_64FC1 でなければならない

手動で変換行列を組み立てる際、MatType.CV_32FC1(float)で作成すると実行時エラーになります。WarpAffine に渡す行列は必ず CV_64FC1(double)を使ってください。

// NG
using var M = new Mat(2, 3, MatType.CV_32FC1);

// OK
using var M = new Mat(2, 3, MatType.CV_64FC1);

関連する関数

  • Cv2.GetRotationMatrix2D: 本記事で使用。中心・角度・スケールから回転行列を生成する
  • Cv2.GetAffineTransform: 対応する3点ペアから変換行列を自動計算する
  • Cv2.WarpPerspective: アフィン変換の上位版。ホモグラフィ(4点対応)による射影変換
  • Cv2.Resize: スケーリングのみが目的なら WarpAffine より高速で簡潔

まとめ

Cv2.WarpAffine は変換行列を差し替えるだけで回転・平行移動・スケーリングを統一的に扱える汎用関数です。回転行列の生成には Cv2.GetRotationMatrix2D を組み合わせると手間が省けます。using による Mat の確実な解放と、変換行列の型(CV_64FC1)に注意すれば、実務の前処理ステップとしてすぐに活用できます。

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

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

→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

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