1.VideoCapture可以打开多种来源的数据流,但常见的是相机、视频及图像序列三类数据流:
(1)打开相机数据流,需要指定相机在主机上的设备编号,若主机上只有一个相机则编号通常是0。
(2)打开视频数据流,需要指定视频的完整路径,如/root/data/vtest.avi。
(3)打开图像序列流,需要指定图像序列的完整路径,其中路径中的文件名的格式同C言语中prinf的格式,可参见《CV学习日志:C语言中文件IO使用要点》。如/root/data下有ima1.png、ima2.png、…、ima123.png,则给定的文件名为/root/data/ima%d.png;如/root/data下有ima001.png、ima002.png、…、ima123.png,则给定的名为/root/data/ima%03d.png,这里%03d表示图像名序列号是整数、占宽三位、不足三位的高位是零填充。
2.VideoCapture常用的函数是构造、read、set及get:
(1)构造函数:打开数据流。
(2)read函数:读一帧数据流。
(3)set函数:设置VideoCapture属性值,常用属性是CAP_PROP_FRAME_HEIGHT和CAP_PROP_FRAME_WIDTH。
(4)get函数:获取VideoCapture属性值,常用属性是CAP_PROP_FRAME_HEIGHT和CAP_PROP_FRAME_WIDTH。
3.类AboutVideoCAP是VideoCapture的使用样例,其功能如下:
(1)打开数据流功能:可打开相机、视频或图像序列,相机指定设备号、视频和图像序列指定完整路径。
(2)保存数据流功能:按空格保存图像到给定的目录或默认的workDir/data,图像名是时间戳,单位纳秒。
(3)帧显示时间设置功能:默认每帧显示30毫秒,可指定为期望显示的时间,其中设为零表示一直显示直到按下任意键。
(4)帧高度宽度设置功能:对于相机数据流,可指定相机支持的尺寸,否则为相机默认的输出尺寸。
可在https://github.com/opencv/opencv/tree/master/samples/data下载vtest.avi和left*.jpg测试视频流和图像序列。
也可参见关于VedioCapture和VideoWriter的综合使用样例《OpenCV-Utils学习日志:VideoWriter使用要点》。
以下是详细代码,依赖于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 AboutVideoCAP 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 void TestMe(int argc = 0, char** argv = 0) 38 { 39 //0.GetParams 40 if (argc < 3) { spdlog::critical("Usage: appName streamFrom saveDir waitTime(Optional) deviceRows(Optional) deviceCols(Optional)"); return; } 41 string imaFrom = argv[1]; 42 string saveDir = argv[2]; 43 int waitTime = 30; if (argc > 3) waitTime = atoi(argv[3]); 44 int deviceRows = 0; if (argc > 4) deviceRows = atoi(argv[4]); 45 int deviceCols = 0; if (argc > 5) deviceCols = atoi(argv[5]); 46 47 //1.CreatDirectory 48 utils::fs::createDirectories(saveDir); 49 spdlog::set_pattern("%v"); spdlog::info("imaFrom: {} saveDir: {} waitTime: {} deviceRows: {} deviceCols: {}", imaFrom, saveDir, waitTime, deviceRows, deviceCols); 50 51 //2.OpenStream 52 VideoCapture cap; 53 if (imaFrom.size() == 1) 54 if (cap.open(atoi(imaFrom.c_str())) == false) { spdlog::critical("Failed to open device: {}", imaFrom); return; } 55 if (imaFrom.size() > 1) 56 if (cap.open(imaFrom) == false) { spdlog::critical("Failed to open file: {}", imaFrom); return; } 57 58 //3.SetDevice 59 if (imaFrom.size() == 1 && argc > 4) cap.set(CAP_PROP_FRAME_HEIGHT, deviceRows); 60 if (imaFrom.size() == 1 && argc > 5) cap.set(CAP_PROP_FRAME_WIDTH, deviceCols); 61 62 //4.GetDevice 63 spdlog::info("cap.isOpened(): {}", cap.isOpened()); 64 spdlog::info("cap.getBackendName(): ", cap.getBackendName()); 65 for (map<int, pair<int, string>>::iterator it = capProps.begin(); it != capProps.end(); ++it) 66 spdlog::info("cap.get({}): {}", it->second.second, cap.get(it->second.first)); 67 68 //5.ReadStream 69 cv::namedWindow(__FUNCTION__, WINDOW_NORMAL); 70 spdlog::info("Press space to save one and q/Q to exit"); 71 Mat frame; 72 while (cap.read(frame)) 73 { 74 //5.1 ShowImage 75 cv::imshow(__FUNCTION__, frame); 76 int c = cv::waitKey(waitTime); 77 if (c == 'q' || c == 'Q') break; 78 79 //5.2 SaveImage 80 if (c == ' ') 81 { 82 string savePath = saveDir + fmt::format("/{}.png", chrono::time_point_cast<chrono::nanoseconds>(chrono::system_clock::now()).time_since_epoch().count()); 83 cv::imwrite(savePath, frame); 84 spdlog::info("Saved to: " + savePath); 85 } 86 } 87 cv::destroyWindow(__FUNCTION__); 88 } 89 }; 90 91 int main(int argc, char** argv) { AboutVideoCAP me; me.TestMe(argc, argv); return 0; }