cv::warpPerspective の使い方【OpenCV/C++】〜射影変換で画像を補正する〜
cv::warpPerspective は、4点の対応関係から求めた 3×3 のホモグラフィ行列を使って画像に射影変換を適用する関数です。斜めから撮影した書類の「正面補正」や、QRコード・マーカーの切り出しといった実務用途で頻繁に登場します。
最小構成はこれだけです。
cv::Mat H = cv::getPerspectiveTransform(src_pts, dst_pts);
cv::warpPerspective(src, dst, H, cv::Size(width, height));
動作環境
- OpenCV 4.x(4.5 以降推奨)
- コンパイル例:
g++ -std=c++17 main.cpp $(pkg-config --cflags --libs opencv4)
環境構築がまだの方は環境構築ガイドを先にどうぞ。
基本の使い方
斜め撮影された四角形領域を正面から見た矩形に変換するサンプルです。
#include <iostream>
#include <opencv2/opencv.hpp>
int main()
{
// 入力画像の読み込み
cv::Mat src = cv::imread("input.jpg");
if (src.empty()) {
std::cerr << "画像を読み込めませんでした" << std::endl;
return 1;
}
// 射影変換の入力側 4 点(時計回り: 左上, 右上, 右下, 左下)
std::vector<cv::Point2f> src_pts = {
{120.0f, 80.0f},
{520.0f, 60.0f},
{560.0f, 420.0f},
{ 80.0f, 440.0f}
};
// 出力先の矩形 4 点(幅 400 × 高さ 360 の正面矩形)
const float W = 400.0f, H = 360.0f;
std::vector<cv::Point2f> dst_pts = {
{ 0.0f, 0.0f},
{ W, 0.0f},
{ W, H },
{ 0.0f, H }
};
// 3×3 ホモグラフィ行列を取得
cv::Mat M = cv::getPerspectiveTransform(src_pts, dst_pts);
// 射影変換を適用
cv::Mat dst;
cv::warpPerspective(src, dst, M, cv::Size(static_cast<int>(W), static_cast<int>(H)));
cv::imwrite("output.jpg", dst);
std::cout << "出力サイズ: " << dst.cols << " x " << dst.rows << std::endl;
return 0;
}
実行結果(標準出力)
出力サイズ: 400 x 360
斜めに写っていた四角形領域が、400×360 ピクセルの正面矩形として output.jpg に書き出されます。
行ごとの解説
| 行 | ポイント |
|---|---|
getPerspectiveTransform |
入出力の 4 点対応から 3×3 行列を算出。点は 時計回り で揃えること |
warpPerspective 第3引数 |
変換行列(CV_64F・3×3) |
第4引数 dsize |
出力画像のサイズ。入力画像のサイズではないことに注意 |
引数と戻り値
void cv::warpPerspective(
InputArray src,
OutputArray dst,
InputArray M,
Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar()
);
| 引数 | 型 | 説明 |
|---|---|---|
src |
InputArray |
入力画像(任意チャンネル・任意深度) |
dst |
OutputArray |
出力画像(dsize のサイズで作られる) |
M |
InputArray |
3×3 変換行列(CV_64F 推奨) |
dsize |
Size |
出力画像のサイズ |
flags |
int |
補間方法 + WARP_INVERSE_MAP 指定可 |
borderMode |
int |
境界補完モード(BORDER_CONSTANT など) |
borderValue |
Scalar |
BORDER_CONSTANT 時の埋め色(デフォルト: 黒) |
主な flags の値
| 定数 | 内容 |
|---|---|
INTER_NEAREST |
最近傍補間(高速・低品質) |
INTER_LINEAR |
バイリニア補間(デフォルト・汎用) |
INTER_CUBIC |
バイキュービック補間(高品質・低速) |
WARP_INVERSE_MAP |
M を逆変換として扱う |
実践例
例1: findHomography を使った複数点対応(外れ値に強い)
4点ちょうどではなく、特徴点マッチングで得た多数の対応点からホモグラフィを推定する場合は cv::findHomography を使います。RANSAC で外れ値を除去できます。
#include <iostream>
#include <opencv2/opencv.hpp>
int main()
{
cv::Mat src = cv::imread("book.jpg");
if (src.empty()) {
std::cerr << "画像を読み込めませんでした" << std::endl;
return 1;
}
// 特徴点マッチング等で得た多数の対応点(例: 手動入力で代替)
std::vector<cv::Point2f> src_pts = {
{100.0f, 50.0f}, {400.0f, 45.0f},
{420.0f, 310.0f}, { 85.0f, 320.0f},
{250.0f, 180.0f} // 中間点を追加しても RANSAC が対応
};
std::vector<cv::Point2f> dst_pts = {
{ 0.0f, 0.0f}, {350.0f, 0.0f},
{350.0f, 280.0f}, { 0.0f, 280.0f},
{175.0f, 140.0f}
};
// RANSAC で外れ値を排除しながらホモグラフィを推定
cv::Mat H = cv::findHomography(src_pts, dst_pts, cv::RANSAC, 3.0);
if (H.empty()) {
std::cerr << "ホモグラフィ推定に失敗しました" << std::endl;
return 1;
}
cv::Mat dst;
cv::warpPerspective(src, dst, H, cv::Size(350, 280));
cv::imwrite("output_homography.jpg", dst);
std::cout << "完了: output_homography.jpg" << std::endl;
return 0;
}
例2: 輪郭検出と組み合わせた書類自動補正
cv::findContours + cv::approxPolyDP で検出した四角形輪郭を直接 warpPerspective に渡すパターンです。実務でよく使うパイプラインです。
#include <iostream>
#include <algorithm>
#include <opencv2/opencv.hpp>
// 四角形の4点を「左上・右上・右下・左下」の順に並べる
std::vector<cv::Point2f> sortCorners(std::vector<cv::Point2f>& pts)
{
// x+y が最小 → 左上、最大 → 右下
// x-y が最小 → 右上、最大 → 左下
std::vector<cv::Point2f> ordered(4);
std::vector<float> sum, diff;
for (auto& p : pts) { sum.push_back(p.x + p.y); diff.push_back(p.x - p.y); }
ordered[0] = pts[std::min_element(sum.begin(), sum.end()) - sum.begin()];
ordered[2] = pts[std::max_element(sum.begin(), sum.end()) - sum.begin()];
ordered[1] = pts[std::max_element(diff.begin(), diff.end()) - diff.begin()];
ordered[3] = pts[std::min_element(diff.begin(), diff.end()) - diff.begin()];
return ordered;
}
int main()
{
cv::Mat src = cv::imread("document.jpg");
if (src.empty()) {
std::cerr << "画像を読み込めませんでした" << std::endl;
return 1;
}
// グレースケール → エッジ検出 → 輪郭抽出
cv::Mat gray, edges;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
cv::GaussianBlur(gray, gray, cv::Size(5, 5), 0);
cv::Canny(gray, edges, 50, 150);
std::vector<std::vector<cv::Point>> contours;
cv::findContours(edges, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// 面積最大の四角形輪郭を探す
std::vector<cv::Point2f> docCorners;
double maxArea = 0.0;
for (auto& c : contours) {
std::vector<cv::Point> approx;
cv::approxPolyDP(c, approx, cv::arcLength(c, true) * 0.02, true);
if (approx.size() == 4) {
double area = std::abs(cv::contourArea(approx));
if (area > maxArea) {
maxArea = area;
docCorners.clear();
for (auto& p : approx)
docCorners.push_back(cv::Point2f(static_cast<float>(p.x),
static_cast<float>(p.y)));
}
}
}
if (docCorners.size() != 4) {
std::cerr << "書類の四角形を検出できませんでした" << std::endl;
return 1;
}
auto ordered = sortCorners(docCorners);
const float W = 595.0f, H = 842.0f; // A4 比率(px)
std::vector<cv::Point2f> dst_pts = {
{0.0f, 0.0f}, {W, 0.0f}, {W, H}, {0.0f, H}
};
cv::Mat M = cv::getPerspectiveTransform(ordered, dst_pts);
cv::Mat dst;
cv::warpPerspective(src, dst, M, cv::Size(static_cast<int>(W), static_cast<int>(H)));
cv::imwrite("doc_corrected.jpg", dst);
std::cout << "書類補正完了: doc_corrected.jpg" << std::endl;
return 0;
}
cv::findContours や cv::approxPolyDP の詳細はそれぞれの記事を参照してください。
つまずきポイント
⚠️ getPerspectiveTransform の点順序が合っていない
入力側と出力側の点が「同じ順序」で対応していなければなりません。時計回りに揃える・揃えないが混在すると、変換後の画像が裏返しになったり極端に歪んだりします。順序を間違えてもコンパイルエラーは出ないため、目視確認が必須です。
⚠️ dsize は出力サイズであり入力サイズではない
warpPerspective の第4引数に src.size() をそのまま渡すのはよくある間違いです。正面補正後は縦横比が変わることが多く、意図したサイズを明示的に指定する必要があります。
⚠️ 変換行列の型が CV_32F になっている
getPerspectiveTransform は CV_64F の行列を返します。一方、手動で cv::Mat に変換行列を入れる場合に float 配列から構築すると CV_32F になり、warpPerspective 内でアサーションエラーが発生することがあります。変換行列は必ず CV_64F で渡してください。
// NG: CV_32F になる
cv::Mat M = (cv::Mat_<float>(3,3) << ...);
// OK: CV_64F
cv::Mat M = (cv::Mat_<double>(3,3) << ...);
関連する関数
- cv::getPerspectiveTransform — 4点対応からホモグラフィ行列を算出(本記事で使用)
- cv::findHomography — 多数点の対応から RANSAC でホモグラフィを推定
- cv::perspectiveTransform — 点群に射影変換を適用(画像ではなく座標列に使う)
- cv::warpAffine の使い方【OpenCV/C++】 — アフィン変換(平行・回転・スケール)。自由度が低い分、3点対応で求まる
- cv::approxPolyDP の使い方【OpenCV/C++】 — 輪郭から四角形を抽出する前処理として必須
- cv::findContours の使い方【OpenCV/C++】 — 射影補正のための対象領域検出に使う
まとめ
cv::warpPerspective は cv::getPerspectiveTransform(または cv::findHomography)で得た 3×3 行列を受け取り、射影変換を画像全体に適用します。点の対応順序と出力サイズの指定、変換行列の型(CV_64F)の3点を正しく押さえれば、書類補正・マーカー切り出し・俯瞰変換など幅広い用途にそのまま使えます。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。

