Cv2.GetPerspectiveTransform の使い方【OpenCV/C#(OpenCvSharp)】〜射影変換行列を求める〜

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

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.GetPerspectiveTransform は4点対応から射影変換行列を計算し、Cv2.WarpPerspective と組み合わせることで台形補正・書類スキャンなどの正面化処理を実現します。点の順序対応と Mat の確実な解放が実装上の要点です。5点以上の対応点が得られる場合は Cv2.FindHomography への切り替えも検討してください。

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

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

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

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