C++ Opencv 動画から静止画を出力する
まずはソース
#include <iostream> #include <string> #include <sstream> #include <iomanip> #include <opencv2/opencv.hpp> int video_to_image(std::string result_image_name, std::string video_path, std::string ext) { cv::VideoCapture video(video_path); if (!video.isOpened()) { return -1; } int frame_num = video.get(cv::CAP_PROP_FRAME_COUNT); // {image_name}_00x.ext にするための桁数の取得 int digit = std::to_string(frame_num).length(); cv::Mat frame; int i; for (i = 0; i < frame_num; i++) { // フレームを取得する video >> frame; if (frame.empty()) { return -1; } // {image_name}_00x.extの文字列作成 std::stringstream ss; ss << result_image_name << "_" << std::setw(digit) << std::setfill('0') << i << ext; std::cout << ss.str() << std::endl; cv::imwrite(ss.str().c_str(), frame); } return i; }
関数解説
cv::VideoCapture video(video_path); if (!video.isOpened()) { return -1; }
この部分はVideoCaptureクラスのインスタンスを生成している部分です。
videoの部分がインスタンス名になり、動画情報を保持します。
video_pathは video.mp4
等をパスで指定してください。
video_pathが誤りの場合次の処理でreturn -1
します。
int frame_num = video.get(cv::CAP_PROP_FRAME_COUNT); // {image_name}_00x.ext にするための桁数の取得 int digit = std::to_string(frame_num).length();
この部分は少しだけ複雑(?)で保存する画像の名前に必要な情報を処理しています。
今回保存する動画の名前をhoge_000, hoge_001, ... , hoge999
のような感じにしたいと思っているので、そのためには動画には全部で何枚のフレームがあるかを確認しなければいけません。
そのためint frame_num = video.get(cv::CAP_PROP_FRAME_COUNT);
でフレームの数を取得しています。
その次の処理で10枚ならhoge_01, 100枚ならhoge_001 のような形にするためにフレーム数の桁数を計算しています。
cv::Mat frame; int i; for (i = 0; i < frame_num; i++) { // フレームを取得する video >> frame; if (frame.empty()) { return -1; } // {image_name}_00x.extの文字列作成 std::stringstream ss; ss << result_image_name << "_" << std::setw(digit) << std::setfill('0') << i << ext; std::cout << ss.str() << std::endl; cv::imwrite(ss.str().c_str(), frame); } return i;
cv::Mat
はopencvの画像情報を保持するクラスになります。
cv::Mat frame;
frameという名前のインスタンスを宣言しました。こ子に切り出していくフレーム情報を格納していきます。
切り出していく処理がvideo >> frame;
になります。
この処理でvideoに取り込んだ動画から1フレームを切り出してframeに格納しています。
std::stringstream ss; ss << result_image_name << "_" << std::setw(digit) << std::setfill('0') << i << ext;
ここの処理は保存する画像の名前を生成しています。
hoge_iという名前になるのですがsetwで桁数を指定してsetfillで0埋めをするという処理になります。
%03d
とかと同じ処理です。
cv::imwrite(ss.str().c_str(), frame);
ようやく書き出しです。
imwriteの引数がchar型なので変換しないといけないので、ss.str()でstring型へ、それをc_str()でchar型へ変換しています。
指定した名前でframeを書き出して終了です。
最後にカウンタiを返して、フレームの枚数を返却しています。
ここはframe_numを返しても同じです。
まとめ
解説というよりは自分用メモという感じです。
ここにメインを含めたプログラムの例を置いておきます。