图像分割实战-视频背景替换


1 . 读取并播放视频

利用 VideoCapture 类来对视频进行读取显示。有两种读入视频的方法:
先实例化再初始化 :
VideoCapture capture ;
capture .open(“bike.avi”);

在实例化的同时进行初始化;
VideoCapture capture (“bike.avi”);

例子代码:

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

#include<iostream>
using namespace cv;
using namespace std;
void ()
{

VideoCapture capture("bike.avi");
if (!capture.isOpened())
{
cout << "could not find the video file...n" << endl;
}
//循环显示每一帧
while (true)
{
Mat frame; //定义一个 Mat 变量,用于存储每一帧的图像
capture >> frame; //读取当前帧
if (!frame.empty())
{
imshow("Original Video", frame); //显示当前帧
waitKey(30); //延时 30ms
}
else
{
break;
}
}
}

int main()
{
test();
return 0;
}

2 . 案例实战

实现一个视频背景的替换,和上一节的图片背景替换类似,只是把视频分解成一帧一帧读出来进行处理。
步骤:

  • 分割算法的选择。算法可以选择 GMM 、KMeans 、基于色彩的处理方法、GRB与HSV色彩空间等,这里采用GRB与HSV色彩空间。

1.png | center | 300x0

  • 背景融合 - 高斯模糊。
  • 遮罩层生成。

基本流程图:

2.png | center | 300x0

例子代码:

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

#include<iostream>
using namespace cv;
大专栏  图像分割实战-视频背景替换ord">using namespace std;
Mat backgrount01;
Mat replaceAndBiend(Mat &frame, Mat &maskImg);
void ()
{
backgrount01 = imread("bg_01.jpg");
VideoCapture capture("01.mp4");

if (!capture.isOpened())
{
cout << "could not find the video file...n" << endl;
}
Mat frame,hsvImg,maskImg;
int count = 0;
namedWindow("Origianl Video", CV_WINDOW_NORMAL);
namedWindow("result Video", CV_WINDOW_NORMAL);
while (capture.read(frame))
{
//获取 mask
cvtColor(frame, hsvImg, COLOR_BGR2HSV);
inRange(hsvImg, Scalar(34, 43, 46), Scalar(155, 255, 255), maskImg);

//形态学操作
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(maskImg, maskImg, MORPH_CLOSE, kernel);
erode(maskImg, maskImg,kernel);
GaussianBlur(maskImg, maskImg, Size(3, 3), 0, 0);

Mat result = replaceAndBiend(frame, maskImg);
char c = waitKey(50);
if (c == 27)
{
break;
}
imshow("Origianl Video", frame);
imshow("result Video", result);
}
}
//进行通道混合的函数
Mat replaceAndBiend(Mat &frame, Mat &maskImg)
{
//返回结果图像
Mat result = Mat::zeros(frame.size(), frame.type());
int h = frame.rows;
int w = frame.cols;
int dims = frame.channels();

int m = 0;
double wt = 0;

int r = 0, g = 0, b = 0;
int r1 = 0, g1 = 0, b1 = 0;
int r2 = 0, g2 = 0, b2 = 0;

//这次用指针变量图像
for (int row = 0; row < h; row++)
{
uchar *curent = frame.ptr<uchar>(row);
uchar *bgrow = backgrount01.ptr<uchar>(row);
uchar *maskrow = maskImg.ptr<uchar>(row);
uchar *targetrow = result.ptr<uchar>(row);
for (int col=0; col < w; col++)
{
m = *maskrow++;
if (m == 255) //背景
{
//三个通道都赋予背景的值
*targetrow++ = *bgrow++;
*targetrow++ = *bgrow++;
*targetrow++ = *bgrow++;
curent += 3;
}
else if (m == 0) //前景
{
*targetrow++ = *curent++;
*targetrow++ = *curent++;
*targetrow++ = *curent++;
bgrow += 3;
}
else
{
b1 = *bgrow++;
g1 = *bgrow++;
r1 = *bgrow++;

b2 = *curent++;
g2 = *curent++;
r2 = *curent++;

//权重
wt = m / 255.0;
//通道混合
b = b1*wt + b2*(1.0 - w);
g = g1*wt + g2*(1.0 - w);
r = r1*wt + r2*(1.0 - w);

*targetrow++ = b;
*targetrow++ = g;
*targetrow++ = r;
}
}
}
return result;
}
int main()
{
test();
waitKey(0);
return 0;
}

效果图:

3.png | center | 300x0

例子图片链接:

VS+OpenCV安装包链接:



原文地址:https://www.cnblogs.com/lijianming180/p/12433083.html