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仕様書・サンプルコード

