基于HSV色彩空间的实时背景替换:
注:新更换的背景图必须和原视频的背景图尺寸一样。
相关API:
opencv中的inRange()函数可实现二值化功能(这点类似threshold()函数),更关键的是可以同时
针对多通道进行操作,使用起来非常方便!主要是将在两个阈值内的像素值设置为白色(255),
而不在阈值区间内的像素值设置为黑色(0),该功能类似于之间所讲的双阈值化操作。
函数原型(C++):
void inRange(InputArray src, InputArray lowerb,
InputArray upperb, OutputArray dst);
参数解释:
请注意:该函数输出的dst是一幅二值化之后的图像。
代码演示:
#include
#include
using namespace std;
using namespace cv;
Mat replace_and_blend(Mat &frame, Mat &mask);
Mat background_01;
Mat background_02;
int main(int argc, char** argv)
{
background_01 = imread("E:/技能学习/opencv图像分割/bg_01.jpg");
background_02 = imread("E:/技能学习/opencv图像分割/bg_02.jpg");
VideoCapture capture;
capture.open("E:/技能学习/opencv图像分割/01.mp4");
if (!capture.isOpened())
{
cout << "could not load video!" << endl;
return -1;
}
char* title = "input video";
char* resultWin = "result video";
namedWindow(title, WINDOW_AUTOSIZE);
namedWindow(resultWin, WINDOW_AUTOSIZE);
Mat frame, hsv, mask;
while (capture.read(frame))
{
cvtColor(frame, hsv, COLOR_BGR2HSV);
inRange(hsv, Scalar(35, 43, 46), Scalar(155, 255, 255), mask);
//对mask进行形态学操作
Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
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("mask", mask);
imshow(resultWin, result);
imshow(title, frame);
}
waitKey(0);
destroyAllWindows();
return 0;
}
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();
//replace and blend
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(row);
uchar* bgrow = background_01.ptr(row);
uchar* maskrow = mask.ptr(row);
uchar* targetrow = result.ptr(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;
}
结果展示: