cv::flip / cv::rotate の使い方【OpenCV/C++】〜画像の反転・90度回転〜

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

cv::flip / cv::rotate の使い方【OpenCV/C++】〜画像の反転・90度回転〜

cv::flip は画像を上下・左右・両方向に反転し、cv::rotate は 90°単位で回転する関数です。前処理やデータ拡張、表示方向の補正など、実務でほぼ必ず使う場面があります。

最小構成はそれぞれ次のとおりです。

cv::flip(src, dst, 1);                          // 左右反転
cv::rotate(src, dst, cv::ROTATE_90_CLOCKWISE);  // 時計回り 90°回転

動作環境

  • OpenCV 4.x
  • C++17
  • ビルド例: g++ -std=c++17 main.cpp $(pkg-config --cflags --libs opencv4)

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


基本の使い方

#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::Mat flipped_h, flipped_v, flipped_both;
    cv::Mat rot90cw, rot90ccw, rot180;

    // ---- cv::flip ----
    // flipCode > 0: 左右反転(Y軸基準)
    cv::flip(src, flipped_h, 1);
    // flipCode == 0: 上下反転(X軸基準)
    cv::flip(src, flipped_v, 0);
    // flipCode < 0: 上下+左右反転
    cv::flip(src, flipped_both, -1);

    // ---- cv::rotate ----
    // 時計回り 90°
    cv::rotate(src, rot90cw, cv::ROTATE_90_CLOCKWISE);
    // 反時計回り 90°(= 時計回り 270°)
    cv::rotate(src, rot90ccw, cv::ROTATE_90_COUNTERCLOCKWISE);
    // 180°回転
    cv::rotate(src, rot180, cv::ROTATE_180);

    // 結果を保存
    cv::imwrite("flipped_h.png",    flipped_h);
    cv::imwrite("flipped_v.png",    flipped_v);
    cv::imwrite("flipped_both.png", flipped_both);
    cv::imwrite("rot90cw.png",      rot90cw);
    cv::imwrite("rot90ccw.png",     rot90ccw);
    cv::imwrite("rot180.png",       rot180);

    std::cout << "src サイズ: " << src.size() << std::endl;
    std::cout << "rot90cw サイズ: " << rot90cw.size() << std::endl;

    return 0;
}

実行結果

src サイズ: [640 x 480]
rot90cw サイズ: [480 x 640]

90° 回転すると幅と高さが入れ替わることが確認できます。cv::flip はサイズを変えず、cv::rotate の 90°/270° 回転はサイズが転置される点に注意してください。


引数と戻り値

cv::flip

void cv::flip(InputArray src, OutputArray dst, int flipCode);
引数 型 説明
src InputArray 入力画像(チャンネル数・深度は任意)
dst OutputArray 出力画像(src と同サイズ・同型)
flipCode int 0: 上下反転 / > 0 (例: 1): 左右反転 / < 0 (例: -1): 両方向反転

戻り値: なし(void)

cv::rotate

void cv::rotate(InputArray src, OutputArray dst, int rotateCode);
引数 型 説明
src InputArray 入力画像
dst OutputArray 出力画像(90°/270° 時はサイズが転置)
rotateCode int cv::ROTATE_90_CLOCKWISE / cv::ROTATE_90_COUNTERCLOCKWISE / cv::ROTATE_180

cv::rotate の定数一覧(OpenCV 4.x 時点):

定数 値 意味
cv::ROTATE_90_CLOCKWISE 0 時計回り 90°
cv::ROTATE_180 1 180°
cv::ROTATE_90_COUNTERCLOCKWISE 2 反時計回り 90°

実践例

実践例 1: カメラ映像の上下反転(ミラー表示)

Webカメラや産業カメラの取り付け方向によっては、フレームを毎回反転させる必要があります。cv::flip はインプレース(src と dst を同一にする)にも対応しています。

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

int main()
{
    cv::VideoCapture cap(0);
    if (!cap.isOpened()) {
        std::cerr << "カメラのオープンに失敗しました" << std::endl;
        return -1;
    }

    cv::Mat frame;
    while (true) {
        cap >> frame;
        if (frame.empty()) break;

        // インプレースで左右反転(ミラー表示)
        cv::flip(frame, frame, 1);

        cv::imshow("Mirror", frame);
        if (cv::waitKey(1) == 'q') break;
    }

    cv::destroyAllWindows();
    return 0;
}

インプレース指定(src と dst が同じ Mat)は cv::flip では問題なく動作します。


実践例 2: データ拡張で 4 方向の反転画像を生成

学習データを水増しする典型パターンです。元画像 1 枚から 4 枚生成します。

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

int main()
{
    cv::Mat src = cv::imread("input.png");
    if (src.empty()) {
        std::cerr << "画像の読み込みに失敗しました" << std::endl;
        return -1;
    }

    // flipCode と保存ファイル名の対応テーブル
    const std::vector<std::pair<int, std::string>> patterns = {
        {  1, "aug_lr.png"   },  // 左右反転
        {  0, "aug_ud.png"   },  // 上下反転
        { -1, "aug_both.png" },  // 両方向反転
    };

    // 元画像も含めて保存
    cv::imwrite("aug_orig.png", src);

    for (const auto& [code, filename] : patterns) {
        cv::Mat dst;
        cv::flip(src, dst, code);
        cv::imwrite(filename, dst);
        std::cout << filename << " を生成しました" << std::endl;
    }

    return 0;
}

実行すると次のように表示されます。

aug_lr.png を生成しました
aug_ud.png を生成しました
aug_both.png を生成しました

つまずきポイント

⚠️ flipCode の符号を混同しやすい

0 が上下、正数が左右、負数が両方向という対応は直感と逆に感じる場合があります。覚え方の目安として「軸番号」で考えると整理しやすいです。

flipCode == 0  → X軸(水平軸)を基準に折り返す → 上下反転
flipCode == 1  → Y軸(垂直軸)を基準に折り返す → 左右反転
flipCode == -1 → 両軸 → 上下+左右

コード中にマジックナンバーをそのまま書くと後から意味が分からなくなるため、コメントまたは名前付き定数を添えることを推奨します。


⚠️ cv::rotate は 90°単位の整数回転しかできない

任意角度の回転には cv::warpAffine を使う必要があります。cv::rotate に整数以外の回転角を渡すことはできず、rotateCode には定数値(0/1/2)以外を渡しても定義された動作になりません。45° 回転などを実装したい場合は cv::warpAffine を選んでください。


⚠️ 90°回転後のサイズを前提にした処理でクラッシュする

cv::rotate で 90° や 270° 回転した Mat は幅と高さが入れ替わります。その後の処理(ROI 切り出しや他画像との演算など)で元のサイズを前提にしているとアサーションエラーが発生します。回転後は必ず dst.size() を確認し、後続処理のサイズを合わせてください。

// ⚠️ rot90cw は縦横が反転しているのに src と同サイズで ROI を取ると assertion エラー
cv::Rect roi(0, 0, src.cols, src.rows);  // NG: rot90cw ではオーバー
cv::Mat cropped = rot90cw(roi);

関連する関数


まとめ

  • cv::flip は flipCode で上下・左右・両方向の反転を1関数でカバーし、インプレースにも対応します。
  • cv::rotate は ROTATE_90_CLOCKWISE などの定数で 90° 単位の回転を簡潔に記述できます。
  • 90°/270° 回転後はサイズが転置されるため、後続処理のサイズ前提に注意してください。

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

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

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

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