写在前面的话:
最近在做一些视频处理相关的东西,用到OpenCV里的videoIO相关函数,遇到很多坑,查了很多资料和博客,发现Learning OpenCV3是一本很不错的书,现将自己对videoIO这一部分的学习笔记整理在这,以便以后回顾。
- read
- write
Reading Video with the cv::VideoCapture Object
对象创建的三种方法:
// 1. Input filename
cv::VideoCapture::VideoCapture(
const string& filename
);
// 2. Video capture device id
cv::VideoCapture::VideoCapture(
int device
);
// 3.
cv::VideoCapture::VideoCapture();
构造函数的第一种:
在第一种方法中,传入视频路径,创建对象后,需要加入视频是否成功打开:
// e.g.
cv::VideoCapture cap("1.mp4");
if (!cap.isOpen()) {
std::cout << "Failed to open the video" << std::endl;
return -1;
}
视频打不开的常见原因:
- 视频路径错误
- 视频编码格式未知
后一种原因的解决方案:
you will need to have the appropriate library already residing on your computer in order to successfully read the video file.
构造函数的第二种:
通常为设备的代号,整型
小tip:
cv::VideoCapture cap(-1);
可打开一个窗口供以选择捕获视频的设备
构造函数的第三种:
cv::VideoCapture cap;
cap.open("video.avi");
读取视频帧数据
// 1. read function
bool cv::VideoCapture::read(
cv::OutputArray image // Image into which to read data, return true for read frame successfully, false for failue
);
// 2. >> operator
cv::VideoCapture& cv::VideoCapture::operator>>( cv::Mat& image // Image into which to read data
);
// NOTE:
// << return a reference to the original object, should check the return array is not empty
// 3. grab && retrieve function
bool cv::VideoCapture::grab( void ); // is designed simply to get it onto the computer as quickly as possible
bool cv::VideoCapture::retrieve(
cv::OutputArray image, // Image into which to read data
int channel = 0 // Used for multihead devices
);
// NOTE:
// can read images from mutiple cameras
// more general
设置&获取视频属性
double cv::VideoCapture::get(
int propid // Property identifier (see Table 8-4)
);
bool cv::VideoCapture::set(
int propid,
double value // Value to which to set the property
);
//Example 8-1. Unpacking a four-character code to identify a video codec
cv::VideoCapture cap( "my_video.avi" );
unsigned f = (unsigned)cap.get( cv::CAP_PROP_FOURCC );
char fourcc[] = {
(char) f, // First character is lowest bits
(char)(f >> 8), // Next character is bits 8-15
(char)(f >> 16), // Next character is bits 16-23
(char)(f >> 24), // Last character is bits 24-31
'\0' // and don't forget to terminate
};
Reading Video with the cv::VideoCapture Object
两种构造方式:
// 1. an uninitialized video object
cv::VideoWriter::VideoWriter();
// 2. an initialized video object
cv::VideoWriter::VideoWriter(
const string& filename, // output filename
int fourcc, // codec, use CV_FOURCC() macro
double fps, // Frame rate (stored in output file)
cv::Size frame_size, // Size of individual images
bool is_color = true // if false, you can pass gray frames
);
// e.g.
Don’t forget that you are providing characters (single quotes), not strings (double quotes).
同cv::VideoCapture,也有cv::VideoWriter::isOpened()方法暗示是否可以写视频,如果返回false,可能存在以下几点原因:
- 没有写权限
- 编码格式不可用
NOTES:
- The codecs available to you depend on your operating system installation and the additional libraries you have installed.
- For portable code, it is especially important to be able to gracefully handle the case in which the desired codec is not available on any particular machine.
写入视频的两个函数:
// 1. write function
cv::VideoWriter::write(
const Mat& image // Image to write as next frame
);
/*
NOTES:
- This image must have the same size as the size you gave to the writer when you configured it in the first place. - If you told the writer that the frames would be in color, this must also be a three-channel image.
*/
// 2. << Operator
my_video_writer << my_frame;
/*
NOTE:
once you have your video writer open, you can write images to the video stream in the same manner you would write to cout or a file ofstream object
*/
简单实例
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
int main() {
// params & input path && output path configure
int caseVideo = 6;
char pathInVideo[200], pathOutVideo[200];
sprintf(pathInVideo, "%d.avi", caseVideo);
sprintf(pathOutVideo, "%d_output.avi", caseVideo);
// read video
cv::VideoCapture cap(pathInVideo);
if (!cap.isOpened()) {
std::cerr << "Failed to open the video" << std::endl;
return -1;
}
int frameLength = cap.get(CAP_PROP_FRAME_COUNT);
// params for writting output video
cv::VideoWriter outputVideo;
cv::Size sWH = cv::Size((int)cap.get(CAP_PROP_FRAME_WIDTH),
(int)cap.get(CAP_PROP_FRAME_HEIGHT));
if (!outputVideo.open(pathOutVideo, cv::VideoWriter::fourcc('M', 'P', '4', '2'), cap.get(CAP_PROP_FPS), sWH)) {
std::cerr << "Failed to write video" << std::endl;
return -1;
}
// gauss filter frame by frame
for (int i = 0; i < frameLength; i++) {
std::cout << "Process the " << i << " frame" << std::endl;
cv::Mat inputImg, outputImg;
cap.read(inputImg);
if (!inputImg.empty()) {
cv::GaussianBlur(inputImg, outputImg, cv::Size(25, 25), 0.0, 0.0);
outputVideo.write(outputImg);
}
}
// release cap && outputVideo
cap.release();
outputVideo.release();
return 0;
}