导航

OpenCV-Utils学习日志:VideoWriter使用样例

Posted on 2020-02-01 22:45  dzyBK  阅读(327)  评论(0编辑  收藏  举报

1.VideoWriter可将数据流保存为指定格式的视频或图像序列:

         (1)录制为视频数据,需要指定视频的完整路径,如/root/data/vtest.avi;同时需要指定fourcc、帧率、图像尺寸及是否保存为彩色,fourcc值参见OpenCV官网指定的链接。

         (2)保存为图像序列,需要指定图像序列的完整路径,其中路径中的文件名的格式同C言语中prinf的格式,可参见《CV学习日志:C语言中文件IO使用要点》。如/root/data/ima%d.png;如/root/data/ima%03d.png,这里%03d表示图像名序列号是整数、占宽三位、不足三位的高位是零填充。同时,需要设置fourcc或帧率为0。

2.VideoWriter常用的函数是构造和write

         (1)构造函数:用于创建数据流。

         (2)write函数:写一帧数据流。

3.AboutVideoIOVideoCaptureVideoWriter的综合使用样例,其功能如下:

         (1)打开数据流功能:可打开相机、视频或图像序列,相机指定设备号、视频和图像序列指定完整路径。

         (2)保存数据流功能:按空格保存图像到给定的目录或默认的workDir/data,图像名是时间戳,单位纳秒。

         (3)帧显示时间设置功能:默认每帧显示30毫秒,可指定为期望显示的时间,其中设为零表示一直显示直到按下任意键。

         (4)帧高度宽度设置功能:对于相机数据流,可指定相机支持的尺寸,否则为相机默认的输出尺寸。

         (5)录制数据流功能:按1开始或继续录制图像到给定的目录或默认的workDir/data,按2暂停录制。

         (6)录制时帧率设置功能:当帧率设置为0时,录制为图像序列videoio*.png,否则录制为视频videoio.avi。

         (7)录制时编码设置功能:即VideoWriter::fourcc码,当帧率设置为0时,此设置无效,内部自动置为0。

         (8)录制时色彩设置功能:当设置为0时录制为灰度流,否则录制为彩色流,默认录制为彩色流。

         (9)自动生成配置文件功能:首次运行或配置文件不存在将自动生成workDir/videoio.yml,然后修改配置项为期望值后重启。

         可在https://github.com/opencv/opencv/tree/master/samples/data下载vtest.avi和left*.jpg测试视频流和图像序列。

         也可参见关于VedioCapture的使用样例《OpenCV-Utils学习日志:VideoCapture使用样例

 

         以下是详细代码,依赖于C++14、OpenCV4.x和Spdlog。

  1 #include <opencv2/opencv.hpp>
  2 #include <opencv2/core/utils/filesystem.hpp>
  3 #include <spdlog/spdlog.h>
  4 using namespace std;
  5 using namespace cv;
  6 
  7 #ifndef StrPairKey
  8 #define StrPairKey(key) make_pair(#key, key)
  9 #define StrPairVal(val) make_pair(val, #val)
 10 #endif
 11 
 12 class AboutVideoIO
 13 {
 14 public:
 15     map<int, pair<int, string>> capProps =
 16     {
 17         make_pair(0, StrPairVal(CAP_PROP_POS_MSEC)),
 18         make_pair(1, StrPairVal(CAP_PROP_POS_FRAMES)),
 19         make_pair(2, StrPairVal(CAP_PROP_FRAME_COUNT)),
 20         make_pair(3, StrPairVal(CAP_PROP_POS_AVI_RATIO)),
 21 
 22         make_pair(4, StrPairVal(CAP_PROP_FRAME_WIDTH)),
 23         make_pair(5, StrPairVal(CAP_PROP_FRAME_HEIGHT)),
 24         make_pair(6, StrPairVal(CAP_PROP_FPS)),
 25         make_pair(7, StrPairVal(CAP_PROP_FOURCC)),
 26         make_pair(8, StrPairVal(CAP_PROP_FORMAT)),
 27         make_pair(9, StrPairVal(CAP_PROP_MODE)),
 28 
 29         make_pair(10, StrPairVal(CAP_PROP_BRIGHTNESS)),
 30         make_pair(11, StrPairVal(CAP_PROP_HUE)),
 31         make_pair(12, StrPairVal(CAP_PROP_SATURATION)),
 32         make_pair(13, StrPairVal(CAP_PROP_CONTRAST)),
 33         make_pair(14, StrPairVal(CAP_PROP_GAIN)),
 34         make_pair(15, StrPairVal(CAP_PROP_EXPOSURE))
 35     };
 36 
 37 public:
 38     struct VideoIO
 39     {
 40         char imaFrom[512] = "0";
 41         char saveDir[512] = "./data";
 42         int waitTime = 30;
 43         int deviceRows = 0;
 44         int deviceCols = 0;
 45         int writeFPS = 24;
 46         char writeFourcc[8] = "DX50";
 47         bool writeColor = true;
 48         void write(FileStorage& fs)
 49         {
 50             fs << "imaFrom" << imaFrom; fs.writeComment("deviceId like\"0\" or videoPath like\"/root/data/vtest.avi\" or imaListPath like\"/root/data/left%03d.jpg)\"", true);
 51             fs << "saveDir" << saveDir; fs.writeComment("auto created if not existing", true);
 52             fs << "waitTime" << waitTime; fs.writeComment("0-wait for pressing any key", true);
 53             fs << "deviceRows" << deviceRows; fs.writeComment("0-auto size", true);
 54             fs << "deviceCols" << deviceCols; fs.writeComment("0-auto size", true);
 55             fs << "writeFPS" << writeFPS; fs.writeComment("0-save as videoio*.png or else videoio.avi", true);
 56             fs << "writeFourcc" << writeFourcc;
 57             fs << "writeColor" << writeColor;
 58         }
 59         void read(FileStorage& fs)
 60         {
 61             strcpy(imaFrom, fs["imaFrom"].string().c_str());
 62             strcpy(saveDir, fs["saveDir"].string().c_str());
 63             fs["waitTime"] >> waitTime;
 64             fs["deviceRows"] >> deviceRows;
 65             fs["deviceCols"] >> deviceCols;
 66             fs["writeFPS"] >> writeFPS;
 67             strcpy(writeFourcc, fs["writeFourcc"].string().c_str());
 68             fs["writeColor"] >> writeColor;
 69         }
 70         string print(string savePath = "")
 71         {
 72             string str;
 73             str += fmt::format("imaFrom: {}\n", imaFrom);
 74             str += fmt::format("saveDir: {}\n", saveDir);
 75             str += fmt::format("waitTime: {}\n", waitTime);
 76             str += fmt::format("deviceRows: {}\n", deviceRows);
 77             str += fmt::format("deviceCols: {}\n", deviceCols);
 78             str += fmt::format("writeFPS: {}\n", writeFPS);
 79             str += fmt::format("writeFourcc: {}\n", writeFourcc);
 80             str += fmt::format("writeColor: {}\n", writeColor);
 81             if (savePath.empty() == false) { FILE* out = fopen(savePath.c_str(), "w"); fprintf(out, str.c_str()); fclose(out); }
 82             return str;
 83         }
 84         static VideoIO GetOne(string fsPath, bool doPrint = true)
 85         {
 86             VideoIO videoIO;
 87             if (cv::utils::fs::exists(fsPath) == false)
 88             {
 89                 cv::utils::fs::createDirectories(getFilePathInfo(fsPath));
 90                 FileStorage fs(fsPath, FileStorage::WRITE);
 91                 videoIO.write(fs);
 92                 fs.release();
 93                 //memset(&videoIO, 0, sizeof(videoIO));
 94                 spdlog::critical("No exist: {}", fsPath);
 95                 spdlog::info("Created file: {}", fsPath);
 96                 spdlog::info("Modify default values and relaunch");
 97             }
 98             else
 99             {
100                 FileStorage fs(fsPath, FileStorage::READ);
101                 videoIO.read(fs);
102                 fs.release();
103             }
104             if (doPrint) spdlog::info(videoIO.print());
105             return videoIO;
106         }
107         static string getFilePathInfo(string path, int mode = 0/*0=dir 1=basename 2=extname 3=dirbasename 4=filename*/)
108         {
109             int ind1 = (int)path.find_last_of('/');
110             int ind2 = (int)path.find_last_of('.');
111             if (mode == 0) return path.substr(0, ind1);
112             else if (mode == 1) return path.substr(ind1 + 1, ind2 - ind1 - 1);
113             else if (mode == 2) return path.substr(ind2 + 1);
114             else if (mode == 3) return path.substr(0, ind2);
115             else return path.substr(ind1 + 1);
116         }
117     };
118 
119 public:
120     void TestMe(int argc = 0, char** argv = 0)
121     {
122         //0.GetParams
123         string videoioCfgPath = "./videoio.yml";
124         VideoIO videoIO = VideoIO::GetOne(videoioCfgPath);
125 
126         //1.CreatDirectory
127         utils::fs::createDirectories(videoIO.saveDir);
128         spdlog::set_pattern("%v"); spdlog::info(videoIO.print());
129 
130         //2.OpenStream
131         VideoCapture cap;
132         if (std::strlen(videoIO.imaFrom) == 1)
133             if (cap.open(atoi(videoIO.imaFrom)) == false) { spdlog::critical("Failed to open device: {}", videoIO.imaFrom); return; }
134         if (std::strlen(videoIO.imaFrom) > 1)
135             if (cap.open(videoIO.imaFrom) == false) { spdlog::critical("Failed to open file: {}", videoIO.imaFrom); return; }
136 
137         //3.SetDevice
138         if (videoIO.deviceRows != 0) cap.set(CAP_PROP_FRAME_HEIGHT, videoIO.deviceRows);
139         if (videoIO.deviceCols != 0) cap.set(CAP_PROP_FRAME_WIDTH, videoIO.deviceCols);
140 
141         //4.GetDevice
142         spdlog::info("cap.isOpened(): {}", cap.isOpened());
143         spdlog::info("cap.getBackendName(): ", cap.getBackendName());
144         for (map<int, pair<int, string>>::iterator it = capProps.begin(); it != capProps.end(); ++it)
145             spdlog::info("cap.get({}): {}", it->second.second, cap.get(it->second.first));
146 
147         //5.CreatStream
148         string path = fmt::format("{}/{}", videoIO.saveDir, videoIO.writeFPS == 0 ? "videoid%04d.png" : "videoio.avi");
149         int fourcc = videoIO.writeFPS == 0 ? 0 : VideoWriter::fourcc(videoIO.writeFourcc[0], videoIO.writeFourcc[1], videoIO.writeFourcc[2], videoIO.writeFourcc[3]);
150         VideoWriter wrt(path, fourcc, videoIO.writeFPS, Size((int)cap.get(CAP_PROP_FRAME_WIDTH), (int)cap.get(CAP_PROP_FRAME_HEIGHT)), videoIO.writeColor);
151         spdlog::info("wrt.isOpened(): {}", wrt.isOpened());
152         spdlog::info("wrt.getBackendName(): ", wrt.getBackendName());
153         spdlog::info("wrt.get(VIDEOWRITER_PROP_QUALITY): {}", wrt.get(VIDEOWRITER_PROP_QUALITY));
154         spdlog::info("wrt.get(VIDEOWRITER_PROP_FRAMEBYTES): {}", wrt.get(VIDEOWRITER_PROP_FRAMEBYTES));
155         spdlog::info("wrt.get(VIDEOWRITER_PROP_NSTRIPES): {}", wrt.get(VIDEOWRITER_PROP_NSTRIPES));
156         spdlog::info("wrt.get(VIDEOWRITER_PROP_IS_COLOR ): {}", wrt.get(VIDEOWRITER_PROP_IS_COLOR));
157 
158         //6.ReadWriteStream
159         cv::namedWindow(__FUNCTION__, WINDOW_NORMAL);
160         spdlog::info("Press space to save one and q/Q to exit");
161         spdlog::info("press 1 to start/continue and 2 to stop recording");
162         Mat frame; int flag = 0;
163         while (cap.read(frame))
164         {
165             //6.1 ShowImage
166             cv::imshow(__FUNCTION__, frame);
167             int c = cv::waitKey(videoIO.waitTime);
168             if (c == 'q' || c == 'Q') break;
169 
170             //6.2 SaveImage
171             if (c == ' ')
172             {
173                 string savePath = videoIO.saveDir + fmt::format("/{}.png", chrono::time_point_cast<chrono::nanoseconds>(chrono::system_clock::now()).time_since_epoch().count());
174                 cv::imwrite(savePath, frame);
175                 spdlog::info("Saved to: " + savePath);
176             }
177 
178             //6.3 RecordImage
179             if (c == '1' || c == '2') flag = c;
180             if (flag == '1') { wrt.write(frame); spdlog::info("Record timestamp: {}", chrono::time_point_cast<chrono::nanoseconds>(chrono::system_clock::now()).time_since_epoch().count()); }
181         }
182         cv::destroyWindow(__FUNCTION__);
183     }
184 };
185 
186 int main(int argc, char** argv) { AboutVideoIO me; me.TestMe(argc, argv); return 0; }
View Code