前言
本文将使用OpenCV C++ 进行绿幕视频背景替换。
一、图像预处理
背景
绿幕视频
首先,我们需要使用resize API将背景图尺寸修改与视频尺寸大小。这样才能进行后续的像素赋值操作。
Mat bg = imread("background.jpg"); //背景图
VideoCapture capture; //读取待处理的绿幕视频
capture.open("5.flv");
if (!capture.isOpened())
{
cout << "Can not open video!" << endl;
system("pause");
return -1;
}
int width = capture.get(CAP_PROP_FRAME_WIDTH);
int height = capture.get(CAP_PROP_FRAME_HEIGHT);
resize(bg, bg, Size(width, height), 1, 1, INTER_CUBIC); //将背景图resize成视频尺寸大小
二、HSV色彩空间转换
1. cvtColor色彩空间转换
cvtColor(frame, HSV, COLOR_BGR2HSV); //将原图转换成HSV色彩空间
2. inRange抠图
经百度查表,我们可以获取绿色HSV颜色分量范围
//绿色HSV颜色分量范围
int hmin = 35, smin = 43, vmin = 46;
int hmax = 77, smax = 255, vmax = 255;
由于我们已经将原图转换为HSV色彩空间,故可以使用inRange API将前景从绿幕中抠出来。inRange将两阈值内的像素置为255(即绿色被置为白色),阈值外的像素置为0(其他颜色被置为黑色)。故由此我们可以将前景抠出来。
//经过inRange API处理,输出一张二值图像,即将前景从绿幕中扣出来啦
inRange(HSV, Scalar(hmin, smin, vmin), Scalar(hmax, smax, vmax), mask);
mask图像,即从绿幕中抠出来的前景图。
三、背景替换
我们通过修改图像像素值达到替换背景目的。通过遍历视频图像像素值,当mask像素值为0时,表示此时图像像素为前景,将绿幕视频当前像素点赋给目标图像dst;当mask像素值为255时,表示此时图像像素为背景,将背景图当前像素点赋给目标图像dst。
Mat Replace_Background(Mat frame, Mat mask, Mat bg)
{
Mat dst = Mat::zeros(frame.size(), frame.type());
for (int i = 0; i < frame.rows; i++)
{
for (int j = 0; j < frame.cols; j++)
{
int p = mask.at<uchar>(i, j); //传入的mask是张二值图,p为当前mask像素值
if (p == 0)
{ //代表mask此时为前景,将绿幕视频中的前景像素赋给dst
dst.at<Vec3b>(i, j) = frame.at<Vec3b>(i, j);
}
else if (p == 255)
{
//代表mask此时为背景,将背景图像素赋给dst
dst.at<Vec3b>(i, j) = bg.at<Vec3b>(i,j);
}
}
}
return dst;
}
最终效果如图所示。
四、源码
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
Mat Replace_Background(Mat frame, Mat mask, Mat bg)
{
Mat dst = Mat::zeros(frame.size(), frame.type());
for (int i = 0; i < frame.rows; i++)
{
for (int j = 0; j < frame.cols; j++)
{
int p = mask.at<uchar>(i, j); //传入的mask是张二值图,p为当前mask像素值
if (p == 0)
{ //代表mask此时为前景,将绿幕视频中的前景像素赋给dst
dst.at<Vec3b>(i, j) = frame.at<Vec3b>(i, j);
}
else if (p == 255)
{
//代表mask此时为背景,将背景图像素赋给dst
dst.at<Vec3b>(i, j) = bg.at<Vec3b>(i,j);
}
}
}
return dst;
}
int main()
{
Mat bg = imread("background.jpg"); //背景图
VideoCapture capture; //读取待处理的绿幕视频
capture.open("5.flv");
if (!capture.isOpened())
{
cout << "Can not open video!" << endl;
system("pause");
return -1;
}
int width = capture.get(CAP_PROP_FRAME_WIDTH);
int height = capture.get(CAP_PROP_FRAME_HEIGHT);
resize(bg, bg, Size(width, height), 1, 1, INTER_CUBIC); //将背景图resize成视频尺寸大小
Mat frame, HSV, mask, dst;
//绿色HSV颜色分量范围
int hmin = 35, smin = 43, vmin = 46;
int hmax = 77, smax = 255, vmax = 255;
while (capture.read(frame))
{
cvtColor(frame, HSV, COLOR_BGR2HSV); //将原图转换成HSV色彩空间
//经过inRange API处理,输出一张二值图像,即将前景从绿幕中扣出来啦
inRange(HSV, Scalar(hmin, smin, vmin), Scalar(hmax, smax, vmax), mask);
dst = Replace_Background(frame, mask, bg);
imshow("demo", frame);
//imwrite("frame.jpg", frame);
imshow("mask", mask);
//imwrite("mask.jpg", mask);
imshow("dst", dst);
//imwrite("dst.jpg", dst);
char key = waitKey(10);
if (key == 27)
{
break;
}
}
destroyAllWindows();
capture.release();
system("pause");
return 0;
}
总结
本文使用OpenCV C++进行绿幕视频背景替换,关键步骤有以下几点。
1、将原图转换成HSV色彩空间。
2、使用inRange API将前景从绿幕中抠出来,得到一张二值图。
3、通过像素赋值操作达到背景替换效果。
到此这篇关于利用OpenCV实现绿幕视频背景替换的文章就介绍到这了,更多相关OpenCV绿幕视频背景替换内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!