OpenCV入门教程01.12:视频处理

索引地址:系列索引

基础篇的文章处理的对象都是读取的一张图片,那么高级篇的第一篇就是连续图片,即视频。视频分为两种一种是本地视频,类似于Mp4/mkv文件,另一种是从摄像头、rtsp读取的实时视频流。

读取并显示本地视频

VideoCaptur()函数原型:

1
2
3
VideoCapture::VideoCapture()
VideoCapture::VideoCapture(const string& filename) //filename是视频名称(可以是相对路径也可以是绝对路径)
VideoCapture::VideoCapture(int device) //device是设备(摄像头等)的编号

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include <opencv2/opencv.hpp>
using namespace cv;

//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main() {
//【1】读入视频
VideoCapture capture("1.avi");

//【2】循环显示每一帧
while (1) {
Mat frame; //定义一个Mat变量,用于存储每一帧的图像
capture >> frame; //读取当前帧

//若视频播放完成,退出循环
if (frame.empty()) {
break;
}

imshow("Video", frame); //显示当前帧
waitKey(30); //延时30ms
}
return 0;
}

从程序所在的文件夹中读取名称为1.avi的视频文件,然后显示在界面上,视频播放完毕后自动退出程序.

play_video

读取并显示摄像头

摄像头功能是使用设备id,摄像头的默认id为0.

只需要将上面的代码修改一下就可以了.

1
2
//VideoCapture capture("1.avi");
VideoCapture capture(0);

opencv视频部分使用的是FFmpeg。

效果如下:

camera

获取视频属性信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
// 定义相关VideoCapture对象
VideoCapture capture;
// 读取视频文件
capture.open("beat.mp4");
// 判断视频流读取是否正确
if (!capture.isOpened()){
std::cout << "fail to open video!" << std::endl;
return -1;
}
// 获取视频相关信息-帧数
long nTotalFrame = capture.get(CV_CAP_PROP_FRAME_COUNT);
std::cout << "nTotalFrame = " << nTotalFrame << std::endl;
// 获取视频相关信息-帧像素宽高
int frameHeight = capture.get(CV_CAP_PROP_FRAME_HEIGHT);
int frameWidth = capture.get(CV_CAP_PROP_FRAME_WIDTH);
std::cout << "frameHeight = " << frameHeight << std::endl;
std::cout << "frameWidth = " << frameWidth << std::endl;
// 获取视频相关信息-帧率
double FrameRate = capture.get(CV_CAP_PROP_FPS);
std::cout << "FrameRate = " << FrameRate << std::endl;
cv::Mat frameImg;
// read方法获取显示帧
long nCount = 1;
while (true){
std::cout << " Current frame: " << nCount << std::endl;
capture >> frameImg;
// 判断当前读取文件
if (!frameImg.empty()){
imshow("frameImg", frameImg);
}
else{
break;
}
// 按下键盘上q键退出
if (char(waitKey(1)) == 'q'){
break;
}
nCount++;
}
// 视频释放
capture.release();
return 0;
}

测试结果为:

1
2
3
4
5
6
7
8
9
10
nTotalFrame = 7522
frameHeight = 480
frameWidth = 852
FrameRate = 25
Current frame: 1
Current frame: 2
Current frame: 3
Current frame: 4
Current frame: 5
...

保存至本地

视频文件简单读取和显示以及操作介绍完毕,能读就可以写,下面介绍将读取的帧在写入视频容器中。

流程为:

  • 获取视频信息
  • 分离每帧的RGB通道
  • 保存B通道数据为新视频
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
int main() {
// 视频读入与输出路径设置
string sourceVideoPath = "1.mp4";
string outputVideoPath = "2.mp4";
// 视频输入
VideoCapture inputVideo(sourceVideoPath,CAP_FFMPEG);
// 检测视频输入的有效性
if (!inputVideo.isOpened()) {
cout << "fail to open!" << endl;
return -1;
}
VideoWriter outputVideo;
// 获取视频分辨率
cv::Size videoResolution = cv::Size((int)inputVideo.get(CAP_PROP_FRAME_WIDTH),
(int)inputVideo.get(CAP_PROP_FRAME_HEIGHT));
double fps = inputVideo.get(CAP_PROP_FPS);
// 获取视频帧率
cout << "totalFrame:" << inputVideo.get(CAP_PROP_FRAME_COUNT) << endl;
// 获取视频总帧数
cout << "fps:" << inputVideo.get(CAP_PROP_FPS) << endl;
// 获取视频图像宽高
cout << "videoResolution:" << videoResolution.width << " " << videoResolution.height << endl;
// open方法相关设置
outputVideo.open(outputVideoPath, CAP_FFMPEG, 25.0, videoResolution, true);
if (!outputVideo.isOpened()) {
cout << "fail to open!" << endl;
return -1;
}
cv::Mat frameImg;
int count = 0;
// vector RGB分量
std::vector<cv::Mat> rgb;
cv::Mat resultImg;
for (int i = 0; i < 30; i++) {
inputVideo >> frameImg;
// 视频帧结束判断
if (!frameImg.empty()) {
count++;
cv::imshow("frameImg", frameImg);
// 分离出三通道rgb
cv::split(frameImg, rgb);
for (int i = 0; i < 3; i++) {
if (i != 0) {
// 提取B通道分量
rgb[ i ] = cv::Mat::zeros(videoResolution, rgb[ 0 ].type());
}
// 通道合并
cv::merge(rgb, resultImg);
}
cv::imshow("resultImg", resultImg);
outputVideo << resultImg;
} else {
break;
}
// 按下键盘上q键退出
if (char(waitKey(1)) == 'q') {
inputVideo.release();
outputVideo.release();
break;
}
}
std::cout << "writeTotalFrame:" << count << std::endl;

inputVideo.release();
outputVideo.release();
return 0;
}

编译运行,会报错

1
OpenCV: FFMPEG: tag 0x0000076c/'l???' is not found (format 'avi / AVI (Audio Video Interleaved)')'

将写部分修改为

1
outputVideo.open(outputVideoPath, VideoWriter::fourcc('M','J','P','G'), 25.0, videoResolution, true);

再次编译运行

输出结果为:

1
2
3
4
5
6
totalFrame:2530
fps:8.04132
videoResolution:1610 1030
OpenCV: FFMPEG: tag 0x47504a4d/'MJPG' is not supported with codec id 7 and format 'mp4 / MP4 (MPEG-4 Part 14)'
OpenCV: FFMPEG: fallback to use tag 0x7634706d/'mp4v'
writeTotalFrame:30

视频效果为:

play

我们拆分的是B通道,即Blue部分。

保存的文件为

files


OpenCV入门教程01.12:视频处理
https://blog.jackeylea.com/opencv/read-show-video-or-camera-with-opencv/
作者
JackeyLea
发布于
2020年9月9日
许可协议