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::VideoCapture — 動画の読み込み側。VideoWriter とセットで使うことが多い
- cv::flip / cv::rotate の使い方【OpenCV/C++】〜画像の反転・90度回転〜 — 録画前に前処理として使うことが多い
- cv::hconcat / vconcat の使い方【OpenCV/C++】〜画像を連結する〜 — 処理前後を並べて録画したい場合に活用
まとめ
cv::VideoWriter は初期化時にコーデック・fps・解像度を固定し、あとは write() でフレームを流し込むだけのシンプルな設計です。トラブルの大半はコーデック未対応と frameSize のミスマッチなので、まず isOpened() チェックと MJPG での動作確認を習慣にすると安定します。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。
→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

