文章目錄
-
-
-
- 一、說明
- 二、程式執行個體
- 三、結果展示
-
-
一、說明
在視訊中采用KMeans或者GMM的算法效率太低了,用來做視訊摳圖效果不好,這裡使用了一個更加便捷的方式。就是HSV格式。
由于在視訊中隻有的綠色的背景和前景的人物,且将HSV歸一化為:
H 0 - 180
S 0 - 255
V 0 - 255
是以在HSV格式中綠色的範圍是:
H 35 - 155
S 43 - 255
V 46 - 255
具體步驟如下:
- 幀圖像;
- 轉化為HSV;
- 模型mask;
- 背景融合替換;
- 顯示幀圖像;
- 下一幀;
- 完成。
過程中需要注意的是,背景與視訊中的人物和背景在讀取元素的時候需要保持一緻,不然達不到效果。另外就是需要融合的圖像的背景大小要與視訊的大小一緻。
二、程式執行個體
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
using namespace ml;
const char* title = "input video";
const char* result_win = "result video";
Mat background_01, background_02;
Mat replace_and_blend(Mat& frame, Mat& mask)
{
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* current = frame.ptr<uchar>(row); // 目前幀圖像
uchar* bgrow = background_01.ptr<uchar>(row); // 背景目前行
uchar* maskrow = mask.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++;
current += 3; // 目前幀,背景,前景要保持一緻
}
else if (m == 0) // 前景
{
*targetrow++ = *current++;
*targetrow++ = *current++;
*targetrow++ = *current++;
bgrow += 3; // 目前幀,背景,前景要保持一緻
}
else
{
b1 = *bgrow++;
g1 = *bgrow++;
r1 = *bgrow++;
b2 = *current++;
g2 = *current++;
r2 = *current++;
wt = m / 255.0;
b = b1 * wt + b2 * (1.0 - wt);
g = g1 * wt + g2 * (1.0 - wt);
r = r1 * wt + r2 * (1.0 - wt);
*targetrow++ = b;
*targetrow++ = g;
*targetrow++ = r;
}
}
}
return result;
}
int main()
{
background_01 = imread("D:/source/images/bg2.png"); //注意圖檔的大小與視訊一緻
background_02 = imread("D:/source/images/sky.png");
VideoCapture capture;
capture.open("D:/source/images/01.mp4");
if (!capture.isOpened())
{
puts("could not find the video file");
system("pause");
return -1;
}
namedWindow(title, WINDOW_AUTOSIZE);
namedWindow(result_win, WINDOW_AUTOSIZE);
Mat frame, hsv, mask;
int count = 0;
while (capture.read(frame))
{
cvtColor(frame, hsv, COLOR_BGR2HSV);
inRange(hsv, Scalar(35, 43, 46), Scalar(155, 255, 255), mask);
// 形态學操作
Mat k = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(mask, mask, MORPH_CLOSE, k);
erode(mask, mask, k);
GaussianBlur(mask, mask, Size(3, 3), 0, 0);
Mat result = replace_and_blend(frame, mask);
char c = waitKey(1);
if (c == 27) break;
imshow(result_win, result);
imshow(title, frame);
}
waitKey(0);
return 0;
}
三、結果展示
需要融合的背景圖檔:
視訊(這裡隻能是靜态圖檔了):
融合後的效果: