C++ Opencv 静止画から動画を作成する
まずはソース
#include <iostream> #include <string> #include <sstream> #include <iomanip> #include <opencv2/opencv.hpp> int image_to_video(std::string result, std::string image_name, std::string ext, int frame_num, double frame_rate) { // {image_name}_00x.ext にするための桁数の取得 int digit = std::to_string(frame_num).length(); std::stringstream base; base << image_name << "_" << std::setw(digit) << std::setfill('0') << 0 << ext; cv::Mat Img = cv::imread(base.str().c_str()); int fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v'); cv::VideoWriter writer(result, fourcc, frame_rate, cv::Size(Img.cols, Img.rows), true); for (int i = 0; i < frame_num; i++) { // {image_name}_00x.extの文字列作成 std::stringstream ss; ss << image_name << "_" << std::setw(digit) << std::setfill('0') << i << ext; std::cout << ss.str() << std::endl; // フレームを取得する Img = cv::imread(ss.str().c_str()); if (Img.empty()) { return -1; } // フレームの書き出し writer << Img; } return 0; }
関数解説
int digit = std::to_string(frame_num).length();
はimage_name_00x.jpgにするために、0埋めを何桁分するかというのを求めるための桁数の計算です。
フレーム数が10枚なら00.ext~, 100枚なら000.ext~になるように桁数を予め求めておきます。
std::stringstream base; base << image_name << "_" << std::setw(digit) << std::setfill('0') << 0 << ext; cv::Mat Img = cv::imread(base.str().c_str());
ここでは読み込むフレームの名前を求めています。
引数のimage_nameで、パスを含めて名前の番号の前までを指定しおきます。
例えばimage_000.jpg~image_999.jpgというフレームがあったとすると、ここの引数はimageになっています。
その名前に0埋めした番号とext 拡張子を追加して名前を生成しています。
ここではimage_name_0.jpgを求めています。理由はこの後。
int fourcc = cv::VideoWriter::fourcc('m', 'p', '4', 'v'); cv::VideoWriter writer(result, fourcc, frame_rate, cv::Size(Img.cols, Img.rows), true);
ここではVideoWriteクラスのインスタンスを生成しています。writerがインスタンス名になります。
fourccは生成する動画の拡張子で、指定はいくつかできるのですが今回はmp4限定でやっています。
Sizeで動画のサイズを決定できるのですが、ここではフレーム画像のサイズをそのまま動画のサイズにしています。
なので、先ほど1枚目のフレームを読み込んでいました。
1枚目のフレームをベース画像として、そのサイズに依存して動画を作成します。
最後のtrueはカラーか否かの設定ができます。
Img = cv::imread(ss.str().c_str());
あとはループで読み込む画像の名前を0~frame_numまで変化させつつ画像を読み込みます。
画像の読み込みはimreadを使うのですが、引数がchar型なので型変換を行います。
stringstreamからstring, stringからcharへこの1行では変換しています。
writer << Img;
最後に読み込んだ画像を動画へ追加していって、一つの動画を生成します。
ここでは読み込んだフレームを動画へ書き出しています。
まとめ
動画の書き出しは、静止画の書き出しの真逆なので、理解しやすかったです。
github.com メインも含めた関数の使用例をここに置いておくので、試しに動かしたい人はご利用ください。