Cv2.GetPerspectiveTransform の使い方【OpenCV/C#(OpenCvSharp)】〜射影変換行列を求める〜
Cv2.GetPerspectiveTransform は、画像上の4点対応から 3×3の射影変換行列(ホモグラフィ行列) を計算する関数です。求めた行列を Cv2.WarpPerspective に渡すことで、台形補正や書類スキャンの正面化を実現できます。
最小限の呼び出しは次の形です。
using var M = Cv2.GetPerspectiveTransform(srcPoints, dstPoints);
動作環境
- OpenCV 4.x(OpenCvSharp4)
- .NET 8 コンソールアプリ
- NuGet:
OpenCvSharp4+OpenCvSharp4.runtime.win(Windows実行時)
環境構築がまだの方は環境構築ガイドを先にどうぞ。
基本の使い方
斜めに撮影した四角形領域を、正面から見た矩形に変換するサンプルです。
using OpenCvSharp;
// --- 入力画像を用意(ここでは白紙の中に台形領域を描いたテスト画像を生成)
using var src = new Mat(600, 800, MatType.CV_8UC3, Scalar.White);
// 台形の4頂点(左上・右上・右下・左下の順)
var quad = new[]
{
new Point2f(150, 100), // 左上
new Point2f(650, 80), // 右上
new Point2f(700, 500), // 右下
new Point2f(100, 520), // 左下
};
// テスト用に台形を描画
var polyPts = Array.ConvertAll(quad, p => new Point((int)p.X, (int)p.Y));
Cv2.Polylines(src, new[] { polyPts }, isClosed: true, color: Scalar.Blue, thickness: 3);
// --- 出力先の4頂点(幅500×高さ400の矩形に正規化)
float dstW = 500f, dstH = 400f;
var dstPoints = new[]
{
new Point2f(0, 0),
new Point2f(dstW, 0),
new Point2f(dstW, dstH),
new Point2f(0, dstH),
};
// --- 射影変換行列を計算
using var M = Cv2.GetPerspectiveTransform(quad, dstPoints);
// --- 変換を適用
using var dst = new Mat();
Cv2.WarpPerspective(src, dst, M, new Size((int)dstW, (int)dstH));
// 結果を保存
Cv2.ImWrite("perspective_result.png", dst);
Console.WriteLine("perspective_result.png を保存しました。");
実行結果
perspective_result.png を保存しました。
perspective_result.png を開くと、台形だった四角形が 500×400 ピクセルの正面矩形に補正された画像になっています。
コード解説
| 箇所 | 内容 |
|---|---|
quad(srcPoints) |
変換前の4点。左上→右上→右下→左下の順に並べる |
dstPoints |
変換後に対応させたい4点 |
Cv2.GetPerspectiveTransform |
両点群から 3×3 の変換行列 M を返す |
Cv2.WarpPerspective |
M を使って画像全体をリマッピング |
using var M |
Mat を確実に解放するための using |
引数と戻り値
Mat Cv2.GetPerspectiveTransform(IEnumerable<Point2f> src, IEnumerable<Point2f> dst)
| 引数/戻り値 | 型 | 説明 |
|---|---|---|
src |
IEnumerable<Point2f> |
変換前の4点(必ず4点) |
dst |
IEnumerable<Point2f> |
変換後の4点(必ず4点) |
| 戻り値 | Mat(3×3, CV_64F) |
射影変換行列。WarpPerspective にそのまま渡せる |
⚠️ 点は必ず 4点 指定します。それ以外の点数では例外が発生します。
点の順序は src と dst で対応していれば任意ですが、一貫した順序(例: 左上→右上→右下→左下)を守らないと変換が破綻します。
実践例
実践例1: 書類スキャン(台形補正)
カメラで斜めに撮影した書類を正面化する典型パターンです。実際の製品では Cv2.FindContours で4隅を自動検出しますが、ここでは頂点を手動で指定するパターンで示します。
using OpenCvSharp;
// 実画像の読み込み
using var src = Cv2.ImRead("document.jpg");
if (src.Empty()) { Console.Error.WriteLine("画像を読み込めませんでした"); return; }
// 書類の4隅(ピクセル座標・実際は検出アルゴリズムで取得)
var srcPts = new[]
{
new Point2f( 80f, 60f), // 左上
new Point2f(560f, 40f), // 右上
new Point2f(580f, 780f), // 右下
new Point2f( 60f, 800f), // 左下
};
// A4比率(297:210 ≒ 3:2)を想定した出力サイズ
var dstPts = new[]
{
new Point2f( 0f, 0f),
new Point2f(600f, 0f),
new Point2f(600f, 840f),
new Point2f( 0f, 840f),
};
using var M = Cv2.GetPerspectiveTransform(srcPts, dstPts);
using var dst = new Mat();
Cv2.WarpPerspective(src, dst, M, new Size(600, 840),
flags: InterpolationFlags.Cubic); // 高品質補間
Cv2.ImWrite("scanned.jpg", dst);
Console.WriteLine("scanned.jpg を保存しました。");
InterpolationFlags.Cubic を指定することで、リサンプリング時の画質を向上できます。
実践例2: 逆変換で座標を元の画像に戻す
射影変換後の座標を元画像の座標に逆投影したい場合は、Cv2.InvertAffineTransform ではなく Mat.Inv() または Cv2.PerspectiveTransform を使います。
using OpenCvSharp;
// 変換行列を生成
var srcPts = new[] { new Point2f(100,80), new Point2f(500,60),
new Point2f(520,400), new Point2f(80,420) };
var dstPts = new[] { new Point2f(0,0), new Point2f(400,0),
new Point2f(400,360), new Point2f(0,360) };
using var M = Cv2.GetPerspectiveTransform(srcPts, dstPts);
using var Minv = M.Inv(); // 逆行列 = dst→src の変換
// 変換後画像上の点 (200, 180) を元画像座標へ
var dstCoord = new[] { new Point2f(200f, 180f) };
var srcCoord = Cv2.PerspectiveTransform(dstCoord, Minv);
Console.WriteLine($"元画像の対応座標: ({srcCoord[0].X:F1}, {srcCoord[0].Y:F1})");
元画像の対応座標: (310.0, 250.0) ← 入力値により変わります
つまずきポイント
⚠️ 戻り値の Mat を using で解放しないとメモリリークする
Cv2.GetPerspectiveTransform の戻り値は Mat(IDisposable)です。ネイティブメモリを確保しているため、using var M = ... で必ず解放してください。WarpPerspective の呼び出し後に確実に破棄されます。
⚠️ 点の順序を src/dst で揃えないと変換が壊れる
左上→右上→右下→左下の対応が1点でも食い違うと、画像が反転・折り返す奇妙な結果になります。デバッグ時は Cv2.Circle で各点を番号付きで描画して対応を確認するのが確実です。
⚠️ 4点以外を渡すと実行時例外
GetPerspectiveTransform は内部的に連立方程式を解くため、入力は厳密に4点である必要があります。点数が不定な場合は渡す前に Count == 4 をチェックしてください。5点以上の対応点からホモグラフィを求めたい場合は Cv2.FindHomography を使います。
関連する関数
Cv2.WarpPerspective—GetPerspectiveTransformで求めた行列を使って画像を変換する。セットで使う関数Cv2.FindHomography— 5点以上の対応点からロバスト推定でホモグラフィを求める。特徴点マッチングと組み合わせる場面で使用Cv2.PerspectiveTransform— 射影変換行列を使って点群を変換する- Cv2.FindContours の使い方【OpenCV/C#(OpenCvSharp)】〜輪郭を検出する〜 — 書類の4隅を自動検出する前処理として組み合わせが多い
- Cv2.Canny の使い方【OpenCV/C#(OpenCvSharp)】〜エッジ検出で輪郭を抽出する〜 — 書類領域の輪郭を得るためのエッジ検出
まとめ
Cv2.GetPerspectiveTransform は4点対応から射影変換行列を計算し、Cv2.WarpPerspective と組み合わせることで台形補正・書類スキャンなどの正面化処理を実現します。点の順序対応と Mat の確実な解放が実装上の要点です。5点以上の対応点が得られる場合は Cv2.FindHomography への切り替えも検討してください。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。
→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード
