cv::VideoWriter の使い方【OpenCV/C++】〜動画ファイルを書き出す〜

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

cv::VideoWriter の使い方【OpenCV/C++】〜動画ファイルを書き出す〜

cv::VideoWriter を使うと、Mat フレームを連続して書き込み、MP4・AVI などの動画ファイルとして保存できます。カメラ映像の録画・画像処理結果の可視化・テスト動画の生成など、実務で頻繁に登場するクラスです。

最小構成はこれだけです。

cv::VideoWriter writer("out.mp4", cv::VideoWriter::fourcc('m','p','4','v'), 30.0, cv::Size(640, 480));
writer.write(frame);

動作環境

  • OpenCV 4.x
  • コンパイル例: g++ -std=c++17 main.cpp $(pkg-config --cflags --libs opencv4) -o main

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


基本の使い方

カメラ映像をキャプチャしながら MP4 ファイルへ書き出す最小サンプルです。

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

int main() {
    // カメラを開く(デバイスID 0)
    cv::VideoCapture cap(0);
    if (!cap.isOpened()) {
        std::cerr << "カメラを開けませんでした" << std::endl;
        return 1;
    }

    // 解像度をキャプチャ元から取得
    int width  = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
    int height = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));

    // VideoWriter を初期化
    // fourcc: mp4v コーデック、30fps、取得解像度に合わせる
    cv::VideoWriter writer(
        "output.mp4",
        cv::VideoWriter::fourcc('m', 'p', '4', 'v'),
        30.0,
        cv::Size(width, height)
    );

    if (!writer.isOpened()) {
        std::cerr << "VideoWriter を開けませんでした(コーデック未対応の可能性あり)" << std::endl;
        return 1;
    }

    cv::Mat frame;
    std::cout << "'q' キーで録画終了" << std::endl;

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

        // フレームを書き込む(BGR 3チャンネル必須)
        writer.write(frame);

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

    // writer はデストラクタで自動クローズ。明示的に呼ぶ場合は release()
    writer.release();
    cap.release();
    cv::destroyAllWindows();
    return 0;
}

実行結果

'q' キーで録画終了
(ウィンドウにカメラ映像が表示され、'q' で終了すると output.mp4 が生成される)

主要な行の解説

行 内容
VideoWriter::fourcc(...) 4文字コードでコーデックを指定するクラスメソッド
30.0 フレームレート(fps)。整数ではなく double で渡す
cv::Size(width, height) 書き込むフレームの解像度。この値と実際の Mat サイズが一致しないとフレームが無視される
writer.isOpened() 初期化の成否チェック。必ず確認する
writer.write(frame) フレームを1枚書き込む。<< 演算子でも可

引数と戻り値

コンストラクタ / open()

cv::VideoWriter(
    const std::string& filename,  // 出力ファイルパス
    int fourcc,                   // コーデックの4文字コード
    double fps,                   // フレームレート
    cv::Size frameSize,           // フレーム解像度
    bool isColor = true           // true: BGR カラー / false: グレースケール
);
引数 型 説明
filename std::string 出力先パス。拡張子でコンテナ形式が変わる
fourcc int VideoWriter::fourcc('m','p','4','v') などで生成
fps double 再生フレームレート
frameSize cv::Size 書き込むフレームの幅・高さ
isColor bool グレースケールで書く場合は false

よく使うコーデック一覧

fourcc コンテナ 用途・備考
mp4v .mp4 広く使える汎用 MPEG-4。macOS/Linux で安定
avc1 .mp4 H.264(環境依存。FFmpeg ビルドが必要な場合あり)
XVID .avi Windows 環境で安定して動作することが多い
MJPG .avi Motion JPEG。可逆性が高くデバッグ向き
0 .avi 非圧縮(ファイルサイズ大・品質劣化なし)

実践例

1. 静止画の連番から動画を生成する

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

int main() {
    const int FRAME_COUNT = 60;
    const cv::Size SIZE(640, 480);

    cv::VideoWriter writer(
        "slideshow.mp4",
        cv::VideoWriter::fourcc('m', 'p', '4', 'v'),
        15.0,
        SIZE
    );

    if (!writer.isOpened()) {
        std::cerr << "VideoWriter 初期化失敗" << std::endl;
        return 1;
    }

    for (int i = 0; i < FRAME_COUNT; ++i) {
        // 連番画像を読み込む(frame_000.png ~ frame_059.png を想定)
        char buf[64];
        std::snprintf(buf, sizeof(buf), "frames/frame_%03d.png", i);
        cv::Mat img = cv::imread(buf);

        if (img.empty()) {
            std::cerr << "画像が読み込めません: " << buf << std::endl;
            continue;
        }

        // サイズが異なる場合はリサイズして合わせる
        if (img.size() != SIZE) {
            cv::resize(img, img, SIZE);
        }

        writer.write(img);
    }

    writer.release();
    std::cout << "slideshow.mp4 を出力しました" << std::endl;
    return 0;
}

2. 左右反転した映像を書き出す

画像処理の結果をそのまま録画したい場面の典型例です。cv::flip の使い方も参照してください。

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

int main() {
    cv::VideoCapture cap("input.mp4");
    if (!cap.isOpened()) {
        std::cerr << "入力動画を開けませんでした" << std::endl;
        return 1;
    }

    int width  = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
    int height = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
    double fps = cap.get(cv::CAP_PROP_FPS);

    cv::VideoWriter writer(
        "flipped.mp4",
        cv::VideoWriter::fourcc('m', 'p', '4', 'v'),
        fps,
        cv::Size(width, height)
    );

    if (!writer.isOpened()) {
        std::cerr << "VideoWriter 初期化失敗" << std::endl;
        return 1;
    }

    cv::Mat frame, flipped;
    while (cap.read(frame)) {
        // 左右反転(flipCode=1)
        cv::flip(frame, flipped, 1);
        writer.write(flipped);
    }

    writer.release();
    cap.release();
    std::cout << "flipped.mp4 を出力しました" << std::endl;
    return 0;
}

実行結果

flipped.mp4 を出力しました
(input.mp4 の全フレームを左右反転した動画が生成される)

つまずきポイント

⚠️ isOpened() が false になる:コーデック未インストール

最多の失敗原因です。mp4v や avc1 は FFmpeg ビルドの OpenCV でないと使えない環境があります。まず MJPG + .avi で動作確認し、問題なければ目的のコーデックへ切り替えるのが安全です。

// 動作確認用の保険コーデック
cv::VideoWriter writer("test.avi", cv::VideoWriter::fourcc('M','J','P','G'), 30.0, size);

⚠️ frameSize と実際の Mat サイズが一致しないとフレームが無視される

VideoWriter の frameSize と write() に渡す Mat の cols × rows が一致しないと、エラーも出ずにフレームがスキップされます。空の動画ができてしまった場合はここを最初に疑ってください。resize() で明示的に合わせるのが確実です。

⚠️ グレースケール動画を書き出す場合は isColor = false が必要

グレースケール(1チャンネル)フレームをそのまま write() すると、多くのコーデックで正しく書き出せません。コンストラクタの第5引数を false にし、かつ Mat が CV_8UC1 であることを確認してください。BGR→グレー変換には cvtColor を使います。

cv::VideoWriter writer("gray.avi",
    cv::VideoWriter::fourcc('M','J','P','G'),
    30.0, size,
    false  // isColor = false
);

関連する関数


まとめ

cv::VideoWriter は初期化時にコーデック・fps・解像度を固定し、あとは write() でフレームを流し込むだけのシンプルな設計です。トラブルの大半はコーデック未対応と frameSize のミスマッチなので、まず isOpened() チェックと MJPG での動作確認を習慣にすると安定します。

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

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

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

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