

基于HSV色彩空间的实时背景替换:


注:新更换的背景图必须和原视频的背景图尺寸一样。
相关API:
1. inRange()函数
opencv中的inRange()函数可实现二值化功能(这点类似threshold()函数),更关键的是可以同时
针对多通道进行操作,使用起来非常方便!主要是将在两个阈值内的像素值设置为白色(255),
而不在阈值区间内的像素值设置为黑色(0),该功能类似于之间所讲的双阈值化操作。
函数原型(C++):
void inRange(InputArray src, InputArray lowerb,
InputArray upperb, OutputArray dst);
参数解释:
- 参数1:输入要处理的图像,可以为单通道或多通道。
- 参数2:包含下边界的数组或标量。
- 参数3:包含上边界数组或标量。
- 参数4:输出图像,与输入图像src 尺寸相同且为CV_8U 类型。
请注意:该函数输出的dst是一幅二值化之后的图像。
代码演示:
#include<iostream>
#include<opencv2/opencv.hpp>
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<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;
}
结果展示:


这篇博客介绍了如何使用HSV色彩空间和OpenCV库进行实时背景替换。通过inRange()函数进行二值化处理,结合形态学操作如闭操作、腐蚀和高斯模糊,实现对前景和背景的精确分离。然后,利用权重融合方法将前景与预设背景进行混合,实现实时视频中的背景替换。背景图需与原视频尺寸一致。
5717

被折叠的 条评论
为什么被折叠?



