Cv2.WarpPerspective の使い方【OpenCV/C#(OpenCvSharp)】〜射影変換で画像を補正する〜

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

Cv2.WarpPerspective は、4点の対応関係から求めた射影変換行列を使って画像を変換する関数です。斜めから撮影した書類の台形歪みを正面視に補正するといった処理を数行で実装できます。

Cv2.WarpPerspective(src, dst, M, new Size(dstW, dstH));

動作環境

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

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


基本の使い方

まず最もシンプルな例として、画像内の四角形領域を正面から見た矩形に変換します。

using OpenCvSharp;

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

// 変換元の4点(斜め撮影した書類の四隅など)
Point2f[] srcPoints =
[
    new(80,  20),   // 左上
    new(560, 60),   // 右上
    new(600, 780),  // 右下
    new(40,  740),  // 左下
];

// 変換先の4点(出力矩形の四隅)
int dstW = 500, dstH = 700;
Point2f[] dstPoints =
[
    new(0,    0),
    new(dstW, 0),
    new(dstW, dstH),
    new(0,    dstH),
];

// 射影変換行列を計算(3×3 行列)
using var M = Cv2.GetPerspectiveTransform(srcPoints, dstPoints);

// 射影変換を適用
using var dst = new Mat();
Cv2.WarpPerspective(src, dst, M, new Size(dstW, dstH));

Cv2.ImWrite("output.jpg", dst);
Console.WriteLine("射影変換完了: output.jpg");

実行結果

射影変換完了: output.jpg

output.jpg には、斜めに撮影された元画像が正面視の矩形に補正された結果が保存されます。

コードの要点

行 内容
Point2f[] srcPoints 元画像上の4点(時計回りで指定)
Point2f[] dstPoints 変換先の矩形の4点(同じ順番で対応)
Cv2.GetPerspectiveTransform 4点対応から 3×3 射影変換行列を生成
Cv2.WarpPerspective 行列を使って画像全体を変換

引数と戻り値

Cv2.WarpPerspective

引数 型 説明
src Mat 入力画像
dst Mat 出力画像(関数内で割り当て)
m Mat 3×3 射影変換行列
dsize Size 出力画像のサイズ
flags InterpolationFlags 補間方法(省略時: Linear)
borderMode BorderTypes 境界処理(省略時: Constant)
borderValue Scalar 境界の埋め色(省略時: 黒)

戻り値はありません(dst に結果が書き込まれます)。

Cv2.GetPerspectiveTransform

引数 型 説明
src IEnumerable<Point2f> 変換元の4点
dst IEnumerable<Point2f> 変換先の4点

戻り値: Mat(3×3 の CV_64F 行列)


実践例

書類スキャン補正(輪郭検出と組み合わせ)

実務では「撮影した書類の四隅を自動検出して補正」というパイプラインがよく登場します。ここでは四隅を手動で指定するパターンを完全コードで示します。輪郭の自動検出については Cv2.FindContours の使い方、エッジ検出については Cv2.Canny の使い方 をあわせて参照してください。

using OpenCvSharp;

// A4書類を斜め撮影したと仮定した画像を生成(実際はImReadで読み込む)
using var src = new Mat(800, 600, MatType.CV_8UC3, Scalar.White);
// 書類に見立てた四辺形を描画
Point[] quad =
[
    new(80, 50), new(540, 30), new(570, 750), new(50, 770)
];
Cv2.FillPoly(src, new[] { quad }, Scalar.LightBlue);
Cv2.Rectangle(src, new Rect(100, 80, 400, 600), Scalar.DarkGray, 2);

// 変換元・変換先
Point2f[] srcPts =
[
    new(80,  50),
    new(540, 30),
    new(570, 750),
    new(50,  770),
];

int w = 420, h = 594; // A4比率(縮小)
Point2f[] dstPts =
[
    new(0, 0),
    new(w, 0),
    new(w, h),
    new(0, h),
];

using var M   = Cv2.GetPerspectiveTransform(srcPts, dstPts);
using var dst = new Mat();

// InterpolationFlags.Cubic で高品質補間
Cv2.WarpPerspective(src, dst, M, new Size(w, h),
    InterpolationFlags.Cubic, BorderTypes.Constant, Scalar.White);

Cv2.ImWrite("scanned.jpg", dst);
Console.WriteLine($"出力サイズ: {dst.Width} x {dst.Height}");

実行結果

出力サイズ: 420 x 594

scanned.jpg に、射影補正された矩形画像が出力されます。

逆変換(補正後 → 元画像への座標マッピング)

変換行列の逆行列を使えば、補正後の座標を元画像の座標に戻せます。

using OpenCvSharp;

using var src = Cv2.ImRead("input.jpg", ImreadModes.Color);

Point2f[] srcPts = [new(80, 50), new(540, 30), new(570, 750), new(50, 770)];
Point2f[] dstPts = [new(0, 0), new(420, 0), new(420, 594), new(0, 594)];

using var M   = Cv2.GetPerspectiveTransform(srcPts, dstPts);
using var dst = new Mat();
Cv2.WarpPerspective(src, dst, M, new Size(420, 594));

using var Minv = new Mat();
Cv2.Invert(M, Minv);   // 逆行列を計算

// 補正後の画像を元の視点(元画像のサイズ)へ戻す
using var restored = new Mat();
Cv2.WarpPerspective(dst, restored, Minv,
    new Size(src.Width, src.Height));

💡 逆行列は Cv2.Invert で求められます(他の関数と同じ OpenCvSharp 名前空間の Cv2 クラスです)。


つまずきポイント

① GetPerspectiveTransform の戻り値 Mat を Dispose し忘れる

using var M = Cv2.GetPerspectiveTransform(srcPts, dstPts);

GetPerspectiveTransform は新規 Mat を返します。using を付けないとネイティブメモリがリークします。変換行列は小さい(3×3)ので気づきにくいですが、ループで呼ぶ処理では深刻になります。

② 4点の順番が合っていない

srcPoints と dstPoints は 同じ順番(例: 左上→右上→右下→左下)で対応している必要があります。順番が一点でもズレると、画像が鏡反転したり折り返したりして全く意図しない出力になります。時計回りで統一する習慣をつけると安全です。

③ InterpolationFlags の指定を省略すると品質が落ちる場合がある

デフォルトは InterpolationFlags.Linear(バイリニア)です。拡大変換時に画質を優先したい場合は Cubic(バイキュービック)、処理速度を優先したい場合は Nearest を明示的に指定してください。C++ の API では int で渡せる箇所も、OpenCvSharp では InterpolationFlags 列挙型を使います。


関連する関数


まとめ

  • Cv2.WarpPerspective は Cv2.GetPerspectiveTransform で得た 3×3 行列を渡すだけで射影変換が完了します。
  • 4点の対応順序を正しく揃えることと、変換行列 Mat の using による解放がC#実装の重要なポイントです。
  • 書類スキャン・俯瞰変換・AR マーカー補正など、実務での応用範囲は広い関数です。

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

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

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

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