cv::getRotationMatrix2D の使い方【OpenCV/C++】〜回転行列を作る〜

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

cv::getRotationMatrix2D の使い方【OpenCV/C++】〜回転行列を作る〜

cv::getRotationMatrix2D は、指定した中心点・角度・スケールから 2×3 のアフィン変換行列(回転行列)を生成する関数です。この行列を cv::warpAffine に渡すことで、画像を任意の点を中心に回転させられます。

最小の呼び出しはこれだけです。

cv::Mat M = cv::getRotationMatrix2D(center, angle, scale);

動作環境

  • OpenCV 4.x
  • コンパイル例: g++ -std=c++17 main.cpp \pkg-config –cflags –libs opencv4“

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


基本の使い方

画像を中心で 45° 回転させる最小の完全プログラムです。

#include <opencv2/opencv.hpp>
#include <iostream>

int main()
{
    // 画像を読み込む
    cv::Mat src = cv::imread("input.png");
    if (src.empty()) {
        std::cerr << "画像を読み込めませんでした" << std::endl;
        return 1;
    }

    // 回転中心を画像の中心に設定
    cv::Point2f center(src.cols / 2.0f, src.rows / 2.0f);

    // 45° 回転・スケール等倍の回転行列を生成
    double angle = 45.0;
    double scale = 1.0;
    cv::Mat M = cv::getRotationMatrix2D(center, angle, scale);

    // アフィン変換を適用して回転画像を得る
    cv::Mat dst;
    cv::warpAffine(src, dst, M, src.size());

    cv::imwrite("output.png", dst);
    std::cout << "回転行列:\n" << M << std::endl;

    return 0;
}

実行結果(標準出力)

回転行列:
[0.7071067811865476, 0.7071067811865475, -82.84271247461898;
 -0.7071067811865475, 0.7071067811865476, 200]
  • M は 2×3 の CV_64F 行列です。上段が X 成分への寄与、下段が Y 成分への寄与を表します。
  • angle は反時計回りを正とします(数学座標系)。Y 軸が下向きの画像座標系では、正の角度で時計回りに見えます。
  • cv::warpAffinesrc.size() を渡すと出力サイズが入力と同じになるため、回転によって画像の端がクロップされます(後述の実践例で対処法を示します)。

引数と戻り値

引数 説明
center cv::Point2f 回転の中心座標
angle double 回転角度(度数法・反時計回りが正)
scale double 拡大縮小倍率(1.0 で等倍)

戻り値: cv::Mat(2×3・CV_64F

生成される行列の構造は以下の通りです。

M = [ α,  β, (1-α)·cx - β·cy ]
    [-β,  α,  β·cx + (1-α)·cy ]

α = scale · cos(angle)
β = scale · sin(angle)

cx, cycenter の座標です。


実践例

画像全体が収まるサイズで回転する

src.size() をそのまま使うと四隅がクロップされます。回転後に全体が収まる出力サイズを計算することで、欠損なく回転できます。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <cmath>

int main()
{
    cv::Mat src = cv::imread("input.png");
    if (src.empty()) {
        std::cerr << "画像を読み込めませんでした" << std::endl;
        return 1;
    }

    const double angle = 30.0;
    const double rad   = angle * CV_PI / 180.0;
    const double cosA  = std::abs(std::cos(rad));
    const double sinA  = std::abs(std::sin(rad));

    // 回転後に全体が収まる出力サイズを計算
    int newW = static_cast<int>(src.cols * cosA + src.rows * sinA);
    int newH = static_cast<int>(src.cols * sinA + src.rows * cosA);

    // 回転中心は元画像の中心
    cv::Point2f center(src.cols / 2.0f, src.rows / 2.0f);
    cv::Mat M = cv::getRotationMatrix2D(center, angle, 1.0);

    // 新しいキャンバスの中心へ平行移動成分を補正
    M.at<double>(0, 2) += (newW - src.cols) / 2.0;
    M.at<double>(1, 2) += (newH - src.rows) / 2.0;

    cv::Mat dst;
    cv::warpAffine(src, dst, M, cv::Size(newW, newH));

    cv::imwrite("output_full.png", dst);
    std::cout << "出力サイズ: " << newW << " x " << newH << std::endl;

    return 0;
}

実行すると、output_full.png に画像全体が収まった状態で 30° 回転した結果が保存されます。M の平行移動成分(3列目)を直接書き換えることで、新しい中心へのオフセットを加算しています。


スケールと回転を同時に適用する

#include <opencv2/opencv.hpp>
#include <iostream>

int main()
{
    cv::Mat src = cv::imread("input.png");
    if (src.empty()) {
        std::cerr << "画像を読み込めませんでした" << std::endl;
        return 1;
    }

    cv::Point2f center(src.cols / 2.0f, src.rows / 2.0f);

    // 15° 回転しながら 0.8 倍に縮小
    cv::Mat M = cv::getRotationMatrix2D(center, 15.0, 0.8);

    cv::Mat dst;
    cv::warpAffine(src, dst, M, src.size(),
                   cv::INTER_LINEAR,          // 補間方法
                   cv::BORDER_CONSTANT,        // 境界処理
                   cv::Scalar(128, 128, 128)); // 余白をグレーで埋める

    cv::imwrite("output_scaled.png", dst);

    return 0;
}

cv::warpAffine の第5・6・7引数で補間方法と境界処理を指定できます。余白をグレーで埋めたいときは cv::BORDER_CONSTANTcv::Scalar を組み合わせます。cv::warpAffine の詳細はcv::warpAffine の使い方【OpenCV/C++】〜アフィン変換で画像を回転・平行移動する〜を参照してください。


つまずきポイント

⚠️ angle の符号と回転方向

angle は「数学的な反時計回りを正」とする定義です。画像座標系は Y 軸が下向きなので、angle = 30.0 を渡すと画面上では時計回りに 30° 回転したように見えます。直感と逆になりやすいため、まず小さい角度で動作確認するのがお勧めです。反時計回りに見せたい場合は負の値(-30.0)を渡してください。

⚠️ 戻り値の型は CV_64F

cv::getRotationMatrix2D の戻り値は必ず CV_64F(double)です。cv::warpAffine はこのまま渡せますが、行列の要素を自分で読み書きする際は M.at<double>(r, c) を使ってください。float でアクセスすると assertion エラーや値の破壊が起きます。

⚠️ 出力サイズを変えても回転中心の補正を忘れない

出力サイズを src.size() 以外に変更した場合、getRotationMatrix2D で生成した行列の平行移動成分はもとの画像サイズを基準に計算されています。実践例で示したように M.at<double>(0, 2)M.at<double>(1, 2) に差分を加算しないと、回転後の画像が意図しない位置にずれます。


関連する関数


まとめ

cv::getRotationMatrix2D は中心・角度・スケールを指定するだけで 2×3 の回転行列を生成する関数です。cv::warpAffine と組み合わせて使うのが基本で、出力サイズを変える場合は平行移動成分の補正を忘れないようにしてください。角度の符号と画像座標系の向きの関係だけ押さえておけば、実装でつまずくことはほとんどありません。

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

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。

→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

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